func updateNodes(dockerCli *client.DockerCli, nodes []string, mergeNode func(node *swarm.Node) error, success func(nodeID string)) error { client := dockerCli.Client() ctx := context.Background() for _, nodeID := range nodes { node, _, err := client.NodeInspectWithRaw(ctx, nodeID) if err != nil { return err } err = mergeNode(&node) if err != nil { if err == errNoRoleChange { continue } return err } err = client.NodeUpdate(ctx, node.ID, node.Version, node.Spec) if err != nil { return err } success(nodeID) } return nil }
func runInstall(dockerCli *client.DockerCli, opts pluginOptions) error { named, err := reference.ParseNamed(opts.name) // FIXME: validate if err != nil { return err } named = reference.WithDefaultTag(named) ref, ok := named.(reference.NamedTagged) if !ok { return fmt.Errorf("invalid name: %s", named.String()) } ctx := context.Background() repoInfo, err := registry.ParseRepositoryInfo(named) authConfig := dockerCli.ResolveAuthConfig(ctx, repoInfo.Index) encodedAuth, err := client.EncodeAuthToBase64(authConfig) if err != nil { return err } requestPrivilege := dockerCli.RegistryAuthenticationPrivilegedFunc(repoInfo.Index, "plugin install") // TODO: pass acceptAllPermissions and noEnable flag options := types.PluginInstallOptions{ RegistryAuth: encodedAuth, Disabled: false, AcceptAllPermissions: opts.grantPerms, AcceptPermissionsFunc: acceptPrivileges(dockerCli, opts.name), PrivilegeFunc: requestPrivilege, } return dockerCli.Client().PluginInstall(ctx, ref.String(), options) }
func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error { ctx := context.Background() client := dockerCli.Client() var getRefFunc inspect.GetRefFunc switch opts.inspectType { case "container": getRefFunc = func(ref string) (interface{}, []byte, error) { return client.ContainerInspectWithRaw(ctx, ref, opts.size) } case "image": getRefFunc = func(ref string) (interface{}, []byte, error) { return client.ImageInspectWithRaw(ctx, ref) } case "task": if opts.size { fmt.Fprintln(dockerCli.Err(), "WARNING: --size ignored for tasks") } getRefFunc = func(ref string) (interface{}, []byte, error) { return client.TaskInspectWithRaw(ctx, ref) } case "": getRefFunc = inspectAll(ctx, dockerCli, opts.size) default: return fmt.Errorf("%q is not a valid value for --type", opts.inspectType) } return inspect.Inspect(dockerCli.Out(), opts.ids, opts.format, getRefFunc) }
func inspectAll(ctx context.Context, dockerCli *client.DockerCli, getSize bool) inspect.GetRefFunc { client := dockerCli.Client() return func(ref string) (interface{}, []byte, error) { c, rawContainer, err := client.ContainerInspectWithRaw(ctx, ref, getSize) if err == nil || !apiclient.IsErrNotFound(err) { return c, rawContainer, err } // Search for image with that id if a container doesn't exist. i, rawImage, err := client.ImageInspectWithRaw(ctx, ref) if err == nil || !apiclient.IsErrNotFound(err) { return i, rawImage, err } // Search for task with that id if an image doesn't exist. t, rawTask, err := client.TaskInspectWithRaw(ctx, ref) if err == nil || !(apiclient.IsErrNotFound(err) || isErrorNoSwarmMode(err)) { if getSize { fmt.Fprintln(dockerCli.Err(), "WARNING: --size ignored for tasks") } return t, rawTask, err } return nil, nil, fmt.Errorf("Error: No such container, image or task: %s", ref) } }
// MonitorTtySize updates the container tty size when the terminal tty changes size func MonitorTtySize(ctx context.Context, cli *client.DockerCli, id string, isExec bool) error { resizeTty := func() { height, width := cli.Out().GetTtySize() resizeTtyTo(ctx, cli.Client(), id, height, width, isExec) } resizeTty() if runtime.GOOS == "windows" { go func() { prevH, prevW := cli.Out().GetTtySize() for { time.Sleep(time.Millisecond * 250) h, w := cli.Out().GetTtySize() if prevW != w || prevH != h { resizeTty() } prevH = h prevW = w } }() } else { sigchan := make(chan os.Signal, 1) gosignal.Notify(sigchan, signal.SIGWINCH) go func() { for range sigchan { resizeTty() } }() } return nil }
// ForwardAllSignals forwards signals to the container func ForwardAllSignals(ctx context.Context, cli *client.DockerCli, cid string) chan os.Signal { sigc := make(chan os.Signal, 128) signal.CatchAll(sigc) go func() { for s := range sigc { if s == signal.SIGCHLD || s == signal.SIGPIPE { continue } var sig string for sigStr, sigN := range signal.SignalMap { if sigN == s { sig = sigStr break } } if sig == "" { fmt.Fprintf(cli.Err(), "Unsupported signal: %v. Discarding.\n", s) continue } if err := cli.Client().ContainerKill(ctx, cid, sig); err != nil { logrus.Debugf("Error sending signal: %s", err) } } }() return sigc }
func runInit(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts initOptions) error { client := dockerCli.Client() ctx := context.Background() req := swarm.InitRequest{ ListenAddr: opts.listenAddr.String(), AdvertiseAddr: opts.advertiseAddr, ForceNewCluster: opts.forceNewCluster, Spec: opts.swarmOptions.ToSpec(), } nodeID, err := client.SwarmInit(ctx, req) if err != nil { if strings.Contains(err.Error(), "could not choose an IP address to advertise") || strings.Contains(err.Error(), "could not find the system's IP address") { return errors.New(err.Error() + " - specify one with --advertise-addr") } return err } fmt.Fprintf(dockerCli.Out(), "Swarm initialized: current node (%s) is now a manager.\n\n", nodeID) if err := printJoinCommand(ctx, dockerCli, nodeID, true, false); err != nil { return err } fmt.Fprint(dockerCli.Out(), "To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.\n\n") return nil }
func runUpdate(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts swarmOptions) error { client := dockerCli.Client() ctx := context.Background() var updateFlags swarm.UpdateFlags swarm, err := client.SwarmInspect(ctx) if err != nil { return err } err = mergeSwarm(&swarm, flags) if err != nil { return err } err = client.SwarmUpdate(ctx, swarm.Version, swarm.Spec, updateFlags) if err != nil { return err } fmt.Fprintln(dockerCli.Out(), "Swarm updated.") return nil }
func pullImage(ctx context.Context, dockerCli *client.DockerCli, image string, out io.Writer) error { ref, err := reference.ParseNamed(image) if err != nil { return err } // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := registry.ParseRepositoryInfo(ref) if err != nil { return err } authConfig := dockerCli.ResolveAuthConfig(ctx, repoInfo.Index) encodedAuth, err := client.EncodeAuthToBase64(authConfig) if err != nil { return err } options := types.ImageCreateOptions{ RegistryAuth: encodedAuth, } responseBody, err := dockerCli.Client().ImageCreate(ctx, image, options) if err != nil { return err } defer responseBody.Close() return jsonmessage.DisplayJSONMessagesStream( responseBody, out, dockerCli.Out().FD(), dockerCli.Out().IsTerminal(), nil) }
func printJoinCommand(ctx context.Context, dockerCli *client.DockerCli, nodeID string, worker bool, manager bool) error { client := dockerCli.Client() swarm, err := client.SwarmInspect(ctx) if err != nil { return err } node, _, err := client.NodeInspectWithRaw(ctx, nodeID) if err != nil { return err } if node.ManagerStatus != nil { if worker { fmt.Fprintf(dockerCli.Out(), "To add a worker to this swarm, run the following command:\n docker swarm join \\\n --token %s \\\n %s\n", swarm.JoinTokens.Worker, node.ManagerStatus.Addr) } if manager { if worker { fmt.Fprintln(dockerCli.Out()) } fmt.Fprintf(dockerCli.Out(), "To add a manager to this swarm, run the following command:\n docker swarm join \\\n --token %s \\\n %s\n", swarm.JoinTokens.Manager, node.ManagerStatus.Addr) } } return nil }
func runCreate(dockerCli *client.DockerCli, opts *serviceOptions) error { apiClient := dockerCli.Client() createOpts := types.ServiceCreateOptions{} service, err := opts.ToService() if err != nil { return err } ctx := context.Background() // only send auth if flag was set if opts.registryAuth { // Retrieve encoded auth token from the image reference encodedAuth, err := dockerCli.RetrieveAuthTokenFromImage(ctx, opts.image) if err != nil { return err } createOpts.EncodedRegistryAuth = encodedAuth } response, err := apiClient.ServiceCreate(ctx, service, createOpts) if err != nil { return err } fmt.Fprintf(dockerCli.Out(), "%s\n", response.ID) return nil }
func runLoad(dockerCli *client.DockerCli, opts loadOptions) error { var input io.Reader = dockerCli.In() if opts.input != "" { file, err := os.Open(opts.input) if err != nil { return err } defer file.Close() input = file } if !dockerCli.Out().IsTerminal() { opts.quiet = true } response, err := dockerCli.Client().ImageLoad(context.Background(), input, opts.quiet) if err != nil { return err } defer response.Body.Close() if response.Body != nil && response.JSON { return jsonmessage.DisplayJSONMessagesToStream(response.Body, dockerCli.Out(), nil) } _, err = io.Copy(dockerCli.Out(), response.Body) return err }
func runRemove(dockerCli *client.DockerCli, opts *rmOptions) error { ctx := context.Background() var errs cli.Errors for _, name := range opts.plugins { named, err := reference.ParseNamed(name) // FIXME: validate if err != nil { return err } if reference.IsNameOnly(named) { named = reference.WithDefaultTag(named) } ref, ok := named.(reference.NamedTagged) if !ok { return fmt.Errorf("invalid name: %s", named.String()) } // TODO: pass names to api instead of making multiple api calls if err := dockerCli.Client().PluginRemove(ctx, ref.String(), types.PluginRemoveOptions{Force: opts.force}); err != nil { errs = append(errs, err) continue } fmt.Fprintln(dockerCli.Out(), name) } // Do not simplify to `return errs` because even if errs == nil, it is not a nil-error interface value. if errs != nil { return errs } return nil }
func runPS(dockerCli *client.DockerCli, opts psOptions) error { client := dockerCli.Client() ctx := context.Background() service, _, err := client.ServiceInspectWithRaw(ctx, opts.serviceID) if err != nil { return err } filter := opts.filter.Value() filter.Add("service", service.ID) if filter.Include("node") { nodeFilters := filter.Get("node") for _, nodeFilter := range nodeFilters { nodeReference, err := node.Reference(client, ctx, nodeFilter) if err != nil { return err } filter.Del("node", nodeFilter) filter.Add("node", nodeReference) } } tasks, err := client.TaskList(ctx, types.TaskListOptions{Filter: filter}) if err != nil { return err } return task.Print(dockerCli, ctx, tasks, idresolver.New(client, opts.noResolve)) }
func runPush(dockerCli *client.DockerCli, name string) error { named, err := reference.ParseNamed(name) // FIXME: validate if err != nil { return err } if reference.IsNameOnly(named) { named = reference.WithDefaultTag(named) } ref, ok := named.(reference.NamedTagged) if !ok { return fmt.Errorf("invalid name: %s", named.String()) } ctx := context.Background() repoInfo, err := registry.ParseRepositoryInfo(named) if err != nil { return err } authConfig := dockerCli.ResolveAuthConfig(ctx, repoInfo.Index) encodedAuth, err := client.EncodeAuthToBase64(authConfig) if err != nil { return err } return dockerCli.Client().PluginPush(ctx, ref.String(), encodedAuth) }
func runServiceScale(dockerCli *client.DockerCli, serviceID string, scale string) error { client := dockerCli.Client() ctx := context.Background() service, err := client.ServiceInspect(ctx, serviceID) if err != nil { return err } serviceMode := &service.Spec.Mode if serviceMode.Replicated == nil { return fmt.Errorf("scale can only be used with replicated mode") } uintScale, err := strconv.ParseUint(scale, 10, 64) if err != nil { return fmt.Errorf("invalid replicas value %s: %s", scale, err.Error()) } serviceMode.Replicated.Replicas = &uintScale err = client.ServiceUpdate(ctx, service.ID, service.Version, service.Spec) if err != nil { return err } fmt.Fprintf(dockerCli.Out(), "%s scaled to %s\n", serviceID, scale) return nil }
func runList(dockerCli *client.DockerCli, opts listOptions) error { ctx := context.Background() client := dockerCli.Client() services, err := client.ServiceList(ctx, types.ServiceListOptions{Filter: opts.filter.Value()}) if err != nil { return err } out := dockerCli.Out() if opts.quiet { PrintQuiet(out, services) } else { taskFilter := filters.NewArgs() for _, service := range services { taskFilter.Add("service", service.ID) } tasks, err := client.TaskList(ctx, types.TaskListOptions{Filter: taskFilter}) if err != nil { return err } nodes, err := client.NodeList(ctx, types.NodeListOptions{}) if err != nil { return err } PrintNotQuiet(out, services, nodes, tasks) } return nil }
func runDiff(dockerCli *client.DockerCli, opts *diffOptions) error { if opts.container == "" { return fmt.Errorf("Container name cannot be empty") } ctx := context.Background() changes, err := dockerCli.Client().ContainerDiff(ctx, opts.container) if err != nil { return err } for _, change := range changes { var kind string switch change.Kind { case archive.ChangeModify: kind = "C" case archive.ChangeAdd: kind = "A" case archive.ChangeDelete: kind = "D" } fmt.Fprintf(dockerCli.Out(), "%s %s\n", kind, change.Path) } return nil }
func copyFromContainer(ctx context.Context, dockerCli *client.DockerCli, srcContainer, srcPath, dstPath string, cpParam *cpConfig) (err error) { if dstPath != "-" { // Get an absolute destination path. dstPath, err = resolveLocalPath(dstPath) if err != nil { return err } } // if client requests to follow symbol link, then must decide target file to be copied var rebaseName string if cpParam.followLink { srcStat, err := statContainerPath(ctx, dockerCli, srcContainer, srcPath) // If the destination is a symbolic link, we should follow it. if err == nil && srcStat.Mode&os.ModeSymlink != 0 { linkTarget := srcStat.LinkTarget if !system.IsAbs(linkTarget) { // Join with the parent directory. srcParent, _ := archive.SplitPathDirEntry(srcPath) linkTarget = filepath.Join(srcParent, linkTarget) } linkTarget, rebaseName = archive.GetRebaseName(srcPath, linkTarget) srcPath = linkTarget } } content, stat, err := dockerCli.Client().CopyFromContainer(ctx, srcContainer, srcPath) if err != nil { return err } defer content.Close() if dstPath == "-" { // Send the response to STDOUT. _, err = io.Copy(os.Stdout, content) return err } // Prepare source copy info. srcInfo := archive.CopyInfo{ Path: srcPath, Exists: true, IsDir: stat.Mode.IsDir(), RebaseName: rebaseName, } preArchive := content if len(srcInfo.RebaseName) != 0 { _, srcBase := archive.SplitPathDirEntry(srcInfo.Path) preArchive = archive.RebaseArchiveEntries(content, srcBase, srcInfo.RebaseName) } // See comments in the implementation of `archive.CopyTo` for exactly what // goes into deciding how and whether the source archive needs to be // altered for the correct copy behavior. return archive.CopyTo(preArchive, srcInfo, dstPath) }
func runCreate(dockerCli *client.DockerCli, opts createOptions) error { client := dockerCli.Client() ipamCfg, err := consolidateIpam(opts.ipamSubnet, opts.ipamIPRange, opts.ipamGateway, opts.ipamAux.GetAll()) if err != nil { return err } // Construct network create request body nc := types.NetworkCreate{ Driver: opts.driver, Options: opts.driverOpts.GetAll(), IPAM: network.IPAM{ Driver: opts.ipamDriver, Config: ipamCfg, Options: opts.ipamOpt.GetAll(), }, CheckDuplicate: true, Internal: opts.internal, EnableIPv6: opts.ipv6, Labels: runconfigopts.ConvertKVStringsToMap(opts.labels), } resp, err := client.NetworkCreate(context.Background(), opts.name, nc) if err != nil { return err } fmt.Fprintf(dockerCli.Out(), "%s\n", resp.ID) return nil }
func runEvents(dockerCli *client.DockerCli, opts *eventsOptions) error { eventFilterArgs := filters.NewArgs() // Consolidate all filter flags, and sanity check them early. // They'll get process in the daemon/server. for _, f := range opts.filter { var err error eventFilterArgs, err = filters.ParseFlag(f, eventFilterArgs) if err != nil { return err } } options := types.EventsOptions{ Since: opts.since, Until: opts.until, Filters: eventFilterArgs, } responseBody, err := dockerCli.Client().Events(context.Background(), options) if err != nil { return err } defer responseBody.Close() return streamEvents(responseBody, dockerCli.Out()) }
func runTasks(dockerCli *client.DockerCli, opts tasksOptions) error { client := dockerCli.Client() ctx := context.Background() nodeRef, err := nodeReference(client, ctx, opts.nodeID) if err != nil { return nil } node, err := client.NodeInspect(ctx, nodeRef) if err != nil { return err } filter := opts.filter.Value() filter.Add("node", node.ID) if !opts.all { filter.Add("desired_state", string(swarm.TaskStateRunning)) filter.Add("desired_state", string(swarm.TaskStateAccepted)) } tasks, err := client.TaskList( ctx, types.TaskListOptions{Filter: filter}) if err != nil { return err } return task.Print(dockerCli, ctx, tasks, idresolver.New(client, opts.noResolve)) }
func runList(dockerCli *client.DockerCli, opts listOptions) error { ctx := context.Background() client := dockerCli.Client() services, err := client.ServiceList(ctx, types.ServiceListOptions{Filter: opts.filter.Value()}) if err != nil { return err } out := dockerCli.Out() if opts.quiet { printQuiet(out, services) } else { taskFilter := filters.NewArgs() for _, service := range services { taskFilter.Add("service", service.ID) } tasks, err := client.TaskList(ctx, types.TaskListOptions{Filter: taskFilter}) if err != nil { return err } running := map[string]int{} for _, task := range tasks { if task.Status.State == "running" { running[task.ServiceID]++ } } printTable(out, services, running) } return nil }
func runCommit(dockerCli *client.DockerCli, opts *commitOptions) error { ctx := context.Background() name := opts.container reference := opts.reference var config *containertypes.Config if opts.config != "" { config = &containertypes.Config{} if err := json.Unmarshal([]byte(opts.config), config); err != nil { return err } } options := types.ContainerCommitOptions{ Reference: reference, Comment: opts.comment, Author: opts.author, Changes: opts.changes.GetAll(), Pause: opts.pause, Config: config, } response, err := dockerCli.Client().ContainerCommit(ctx, name, options) if err != nil { return err } fmt.Fprintln(dockerCli.Out(), response.ID) return nil }
func runLogs(dockerCli *client.DockerCli, opts *logsOptions) error { ctx := context.Background() c, err := dockerCli.Client().ContainerInspect(ctx, opts.container) if err != nil { return err } if !validDrivers[c.HostConfig.LogConfig.Type] { return fmt.Errorf("\"logs\" command is supported only for \"json-file\" and \"journald\" logging drivers (got: %s)", c.HostConfig.LogConfig.Type) } options := types.ContainerLogsOptions{ ShowStdout: true, ShowStderr: true, Since: opts.since, Timestamps: opts.timestamps, Follow: opts.follow, Tail: opts.tail, Details: opts.details, } responseBody, err := dockerCli.Client().ContainerLogs(ctx, opts.container, options) if err != nil { return err } defer responseBody.Close() if c.Config.Tty { _, err = io.Copy(dockerCli.Out(), responseBody) } else { _, err = stdcopy.StdCopy(dockerCli.Out(), dockerCli.Err(), responseBody) } return err }
func runJoin(dockerCli *client.DockerCli, opts joinOptions) error { client := dockerCli.Client() ctx := context.Background() req := swarm.JoinRequest{ JoinToken: opts.token, ListenAddr: opts.listenAddr.String(), RemoteAddrs: []string{opts.remote}, } err := client.SwarmJoin(ctx, req) if err != nil { return err } info, err := client.Info(ctx) if err != nil { return err } _, _, err = client.NodeInspectWithRaw(ctx, info.Swarm.NodeID) if err != nil { // TODO(aaronl): is there a better way to do this? if strings.Contains(err.Error(), "This node is not a swarm manager.") { fmt.Fprintln(dockerCli.Out(), "This node joined a swarm as a worker.") } } else { fmt.Fprintln(dockerCli.Out(), "This node joined a swarm as a manager.") } return nil }
func runRemove(dockerCli *client.DockerCli, opts removeOptions, images []string) error { client := dockerCli.Client() ctx := context.Background() options := types.ImageRemoveOptions{ Force: opts.force, PruneChildren: !opts.noPrune, } var errs []string for _, image := range images { dels, err := client.ImageRemove(ctx, image, options) if err != nil { errs = append(errs, err.Error()) } else { for _, del := range dels { if del.Deleted != "" { fmt.Fprintf(dockerCli.Out(), "Deleted: %s\n", del.Deleted) } else { fmt.Fprintf(dockerCli.Out(), "Untagged: %s\n", del.Untagged) } } } } if len(errs) > 0 { return fmt.Errorf("%s", strings.Join(errs, "\n")) } return nil }
func runLogin(dockerCli *client.DockerCli, opts loginOptions) error { ctx := context.Background() clnt := dockerCli.Client() var serverAddress string var isDefaultRegistry bool if opts.serverAddress != "" { serverAddress = opts.serverAddress } else { serverAddress = dockerCli.ElectAuthServer(ctx) isDefaultRegistry = true } authConfig, err := dockerCli.ConfigureAuth(opts.user, opts.password, serverAddress, isDefaultRegistry) if err != nil { return err } response, err := clnt.RegistryLogin(ctx, authConfig) if err != nil { return err } if response.IdentityToken != "" { authConfig.Password = "" authConfig.IdentityToken = response.IdentityToken } if err := client.StoreCredentials(dockerCli.ConfigFile(), authConfig); err != nil { return fmt.Errorf("Error saving credentials: %v", err) } if response.Status != "" { fmt.Fprintln(dockerCli.Out(), response.Status) } return nil }
func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error { client := dockerCli.Client() getNetFunc := func(name string) (interface{}, []byte, error) { return client.NetworkInspectWithRaw(context.Background(), name) } return inspect.Inspect(dockerCli.Out(), opts.names, opts.format, getNetFunc) }
func runInspect(dockerCli *client.DockerCli, opts inspectOptions) error { client := dockerCli.Client() getVolFunc := func(name string) (interface{}, []byte, error) { i, err := client.VolumeInspect(context.Background(), name) return i, nil, err } return inspect.Inspect(dockerCli.Out(), opts.names, opts.format, getVolFunc) }