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 runImages(dockerCli *client.DockerCli, opts imagesOptions) error { ctx := context.Background() // Consolidate all filter flags, and sanity check them early. // They'll get process in the daemon/server. imageFilterArgs := filters.NewArgs() for _, f := range opts.filter { var err error imageFilterArgs, err = filters.ParseFlag(f, imageFilterArgs) if err != nil { return err } } matchName := opts.matchName options := types.ImageListOptions{ MatchName: matchName, All: opts.all, Filters: imageFilterArgs, } images, err := dockerCli.Client().ImageList(ctx, options) if err != nil { return err } f := opts.format if len(f) == 0 { if len(dockerCli.ConfigFile().ImagesFormat) > 0 && !opts.quiet { f = dockerCli.ConfigFile().ImagesFormat } else { f = "table" } } imagesCtx := formatter.ImageContext{ Context: formatter.Context{ Output: dockerCli.Out(), Format: f, Quiet: opts.quiet, Trunc: !opts.noTrunc, }, Digest: opts.showDigests, Images: images, } imagesCtx.Write() return nil }
func runList(dockerCli *client.DockerCli, opts listOptions) error { client := dockerCli.Client() netFilterArgs := filters.NewArgs() for _, f := range opts.filter { var err error netFilterArgs, err = filters.ParseFlag(f, netFilterArgs) if err != nil { return err } } options := types.NetworkListOptions{ Filters: netFilterArgs, } networkResources, err := client.NetworkList(context.Background(), options) if err != nil { return err } f := opts.format if len(f) == 0 { if len(dockerCli.ConfigFile().NetworksFormat) > 0 && !opts.quiet { f = dockerCli.ConfigFile().NetworksFormat } else { f = "table" } } sort.Sort(byNetworkName(networkResources)) networksCtx := formatter.NetworkContext{ Context: formatter.Context{ Output: dockerCli.Out(), Format: f, Quiet: opts.quiet, Trunc: !opts.noTrunc, }, Networks: networkResources, } networksCtx.Write() return nil }
func runLogout(dockerCli *client.DockerCli, serverAddress string) error { ctx := context.Background() var isDefaultRegistry bool if serverAddress == "" { serverAddress = dockerCli.ElectAuthServer(ctx) isDefaultRegistry = true } var ( loggedIn bool regsToLogout []string hostnameAddress = serverAddress regsToTry = []string{serverAddress} ) if !isDefaultRegistry { hostnameAddress = registry.ConvertToHostname(serverAddress) // the tries below are kept for backward compatibily where a user could have // saved the registry in one of the following format. regsToTry = append(regsToTry, hostnameAddress, "http://"+hostnameAddress, "https://"+hostnameAddress) } // check if we're logged in based on the records in the config file // which means it couldn't have user/pass cause they may be in the creds store for _, s := range regsToTry { if _, ok := dockerCli.ConfigFile().AuthConfigs[s]; ok { loggedIn = true regsToLogout = append(regsToLogout, s) } } if !loggedIn { fmt.Fprintf(dockerCli.Out(), "Not logged in to %s\n", hostnameAddress) return nil } fmt.Fprintf(dockerCli.Out(), "Removing login credentials for %s\n", hostnameAddress) for _, r := range regsToLogout { if err := client.EraseCredentials(dockerCli.ConfigFile(), r); err != nil { fmt.Fprintf(dockerCli.Err(), "WARNING: could not erase credentials: %v\n", err) } } return nil }
func runList(dockerCli *client.DockerCli, opts listOptions) error { client := dockerCli.Client() volFilterArgs := filters.NewArgs() for _, f := range opts.filter { var err error volFilterArgs, err = filters.ParseFlag(f, volFilterArgs) if err != nil { return err } } volumes, err := client.VolumeList(context.Background(), volFilterArgs) if err != nil { return err } f := opts.format if len(f) == 0 { if len(dockerCli.ConfigFile().VolumesFormat) > 0 && !opts.quiet { f = dockerCli.ConfigFile().VolumesFormat } else { f = "table" } } sort.Sort(byVolumeName(volumes.Volumes)) volumeCtx := formatter.VolumeContext{ Context: formatter.Context{ Output: dockerCli.Out(), Format: f, Quiet: opts.quiet, }, Volumes: volumes.Volumes, } volumeCtx.Write() return nil }
func runLogout(dockerCli *client.DockerCli, serverAddress string) error { ctx := context.Background() if serverAddress == "" { serverAddress = dockerCli.ElectAuthServer(ctx) } // check if we're logged in based on the records in the config file // which means it couldn't have user/pass cause they may be in the creds store if _, ok := dockerCli.ConfigFile().AuthConfigs[serverAddress]; !ok { fmt.Fprintf(dockerCli.Out(), "Not logged in to %s\n", serverAddress) return nil } fmt.Fprintf(dockerCli.Out(), "Remove login credentials for %s\n", serverAddress) if err := client.EraseCredentials(dockerCli.ConfigFile(), serverAddress); err != nil { fmt.Fprintf(dockerCli.Out(), "WARNING: could not erase credentials: %v\n", err) } return nil }
func runPs(dockerCli *client.DockerCli, opts *psOptions) error { ctx := context.Background() listOptions, err := buildContainerListOptions(opts) if err != nil { return err } containers, err := dockerCli.Client().ContainerList(ctx, *listOptions) if err != nil { return err } f := opts.format if len(f) == 0 { if len(dockerCli.ConfigFile().PsFormat) > 0 && !opts.quiet { f = dockerCli.ConfigFile().PsFormat } else { f = "table" } } psCtx := formatter.ContainerContext{ Context: formatter.Context{ Output: dockerCli.Out(), Format: f, Quiet: opts.quiet, Trunc: !opts.noTrunc, }, Size: listOptions.Size, Containers: containers, } psCtx.Write() return nil }
func runAttach(dockerCli *client.DockerCli, opts *attachOptions) error { ctx := context.Background() c, err := dockerCli.Client().ContainerInspect(ctx, opts.container) if err != nil { return err } if !c.State.Running { return fmt.Errorf("You cannot attach to a stopped container, start it first") } if c.State.Paused { return fmt.Errorf("You cannot attach to a paused container, unpause it first") } if err := dockerCli.CheckTtyInput(!opts.noStdin, c.Config.Tty); err != nil { return err } if opts.detachKeys != "" { dockerCli.ConfigFile().DetachKeys = opts.detachKeys } options := types.ContainerAttachOptions{ Stream: true, Stdin: !opts.noStdin && c.Config.OpenStdin, Stdout: true, Stderr: true, DetachKeys: dockerCli.ConfigFile().DetachKeys, } var in io.ReadCloser if options.Stdin { in = dockerCli.In() } if opts.proxy && !c.Config.Tty { sigc := dockerCli.ForwardAllSignals(ctx, opts.container) defer signal.StopCatch(sigc) } resp, errAttach := dockerCli.Client().ContainerAttach(ctx, opts.container, options) if errAttach != nil && errAttach != httputil.ErrPersistEOF { // ContainerAttach returns an ErrPersistEOF (connection closed) // means server met an error and put it in Hijacked connection // keep the error and read detailed error message from hijacked connection later return errAttach } defer resp.Close() if c.Config.Tty && dockerCli.IsTerminalOut() { height, width := dockerCli.GetTtySize() // To handle the case where a user repeatedly attaches/detaches without resizing their // terminal, the only way to get the shell prompt to display for attaches 2+ is to artificially // resize it, then go back to normal. Without this, every attach after the first will // require the user to manually resize or hit enter. dockerCli.ResizeTtyTo(ctx, opts.container, height+1, width+1, false) // After the above resizing occurs, the call to MonitorTtySize below will handle resetting back // to the actual size. if err := dockerCli.MonitorTtySize(ctx, opts.container, false); err != nil { logrus.Debugf("Error monitoring TTY size: %s", err) } } if err := dockerCli.HoldHijackedConnection(ctx, c.Config.Tty, in, dockerCli.Out(), dockerCli.Err(), resp); err != nil { return err } if errAttach != nil { return errAttach } _, status, err := getExitCode(dockerCli, ctx, opts.container) if err != nil { return err } if status != 0 { return cli.StatusError{StatusCode: status} } return nil }
func prettyPrintInfo(dockerCli *client.DockerCli, info types.Info) error { fmt.Fprintf(dockerCli.Out(), "Containers: %d\n", info.Containers) fmt.Fprintf(dockerCli.Out(), " Running: %d\n", info.ContainersRunning) fmt.Fprintf(dockerCli.Out(), " Paused: %d\n", info.ContainersPaused) fmt.Fprintf(dockerCli.Out(), " Stopped: %d\n", info.ContainersStopped) fmt.Fprintf(dockerCli.Out(), "Images: %d\n", info.Images) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Server Version: %s\n", info.ServerVersion) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Storage Driver: %s\n", info.Driver) if info.DriverStatus != nil { for _, pair := range info.DriverStatus { fmt.Fprintf(dockerCli.Out(), " %s: %s\n", pair[0], pair[1]) // print a warning if devicemapper is using a loopback file if pair[0] == "Data loop file" { fmt.Fprintln(dockerCli.Err(), " WARNING: Usage of loopback devices is strongly discouraged for production use. Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.") } } } if info.SystemStatus != nil { for _, pair := range info.SystemStatus { fmt.Fprintf(dockerCli.Out(), "%s: %s\n", pair[0], pair[1]) } } ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Logging Driver: %s\n", info.LoggingDriver) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Cgroup Driver: %s\n", info.CgroupDriver) fmt.Fprintf(dockerCli.Out(), "Plugins: \n") fmt.Fprintf(dockerCli.Out(), " Volume:") fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Volume, " ")) fmt.Fprintf(dockerCli.Out(), "\n") fmt.Fprintf(dockerCli.Out(), " Network:") fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Network, " ")) fmt.Fprintf(dockerCli.Out(), "\n") if len(info.Plugins.Authorization) != 0 { fmt.Fprintf(dockerCli.Out(), " Authorization:") fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Authorization, " ")) fmt.Fprintf(dockerCli.Out(), "\n") } fmt.Fprintf(dockerCli.Out(), "Swarm: %v\n", info.Swarm.LocalNodeState) if info.Swarm.LocalNodeState != swarm.LocalNodeStateInactive { fmt.Fprintf(dockerCli.Out(), " NodeID: %s\n", info.Swarm.NodeID) if info.Swarm.Error != "" { fmt.Fprintf(dockerCli.Out(), " Error: %v\n", info.Swarm.Error) } fmt.Fprintf(dockerCli.Out(), " Is Manager: %v\n", info.Swarm.ControlAvailable) if info.Swarm.ControlAvailable { fmt.Fprintf(dockerCli.Out(), " ClusterID: %s\n", info.Swarm.Cluster.ID) fmt.Fprintf(dockerCli.Out(), " Managers: %d\n", info.Swarm.Managers) fmt.Fprintf(dockerCli.Out(), " Nodes: %d\n", info.Swarm.Nodes) fmt.Fprintf(dockerCli.Out(), " Orchestration:\n") fmt.Fprintf(dockerCli.Out(), " Task History Retention Limit: %d\n", info.Swarm.Cluster.Spec.Orchestration.TaskHistoryRetentionLimit) fmt.Fprintf(dockerCli.Out(), " Raft:\n") fmt.Fprintf(dockerCli.Out(), " Snapshot Interval: %d\n", info.Swarm.Cluster.Spec.Raft.SnapshotInterval) fmt.Fprintf(dockerCli.Out(), " Heartbeat Tick: %d\n", info.Swarm.Cluster.Spec.Raft.HeartbeatTick) fmt.Fprintf(dockerCli.Out(), " Election Tick: %d\n", info.Swarm.Cluster.Spec.Raft.ElectionTick) fmt.Fprintf(dockerCli.Out(), " Dispatcher:\n") fmt.Fprintf(dockerCli.Out(), " Heartbeat Period: %s\n", units.HumanDuration(time.Duration(info.Swarm.Cluster.Spec.Dispatcher.HeartbeatPeriod))) fmt.Fprintf(dockerCli.Out(), " CA Configuration:\n") fmt.Fprintf(dockerCli.Out(), " Expiry Duration: %s\n", units.HumanDuration(info.Swarm.Cluster.Spec.CAConfig.NodeCertExpiry)) if len(info.Swarm.Cluster.Spec.CAConfig.ExternalCAs) > 0 { fmt.Fprintf(dockerCli.Out(), " External CAs:\n") for _, entry := range info.Swarm.Cluster.Spec.CAConfig.ExternalCAs { fmt.Fprintf(dockerCli.Out(), " %s: %s\n", entry.Protocol, entry.URL) } } } fmt.Fprintf(dockerCli.Out(), " Node Address: %s\n", info.Swarm.NodeAddr) } if len(info.Runtimes) > 0 { fmt.Fprintf(dockerCli.Out(), "Runtimes:") for name := range info.Runtimes { fmt.Fprintf(dockerCli.Out(), " %s", name) } fmt.Fprint(dockerCli.Out(), "\n") fmt.Fprintf(dockerCli.Out(), "Default Runtime: %s\n", info.DefaultRuntime) } fmt.Fprintf(dockerCli.Out(), "Security Options:") ioutils.FprintfIfNotEmpty(dockerCli.Out(), " %s", strings.Join(info.SecurityOptions, " ")) fmt.Fprintf(dockerCli.Out(), "\n") ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Kernel Version: %s\n", info.KernelVersion) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Operating System: %s\n", info.OperatingSystem) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "OSType: %s\n", info.OSType) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Architecture: %s\n", info.Architecture) fmt.Fprintf(dockerCli.Out(), "CPUs: %d\n", info.NCPU) fmt.Fprintf(dockerCli.Out(), "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal))) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Name: %s\n", info.Name) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "ID: %s\n", info.ID) fmt.Fprintf(dockerCli.Out(), "Docker Root Dir: %s\n", info.DockerRootDir) fmt.Fprintf(dockerCli.Out(), "Debug Mode (client): %v\n", utils.IsDebugEnabled()) fmt.Fprintf(dockerCli.Out(), "Debug Mode (server): %v\n", info.Debug) if info.Debug { fmt.Fprintf(dockerCli.Out(), " File Descriptors: %d\n", info.NFd) fmt.Fprintf(dockerCli.Out(), " Goroutines: %d\n", info.NGoroutines) fmt.Fprintf(dockerCli.Out(), " System Time: %s\n", info.SystemTime) fmt.Fprintf(dockerCli.Out(), " EventsListeners: %d\n", info.NEventsListener) } ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Http Proxy: %s\n", info.HTTPProxy) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Https Proxy: %s\n", info.HTTPSProxy) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "No Proxy: %s\n", info.NoProxy) if info.IndexServerAddress != "" { u := dockerCli.ConfigFile().AuthConfigs[info.IndexServerAddress].Username if len(u) > 0 { fmt.Fprintf(dockerCli.Out(), "Username: %v\n", u) } fmt.Fprintf(dockerCli.Out(), "Registry: %v\n", info.IndexServerAddress) } // Only output these warnings if the server does not support these features if info.OSType != "windows" { if !info.MemoryLimit { fmt.Fprintln(dockerCli.Err(), "WARNING: No memory limit support") } if !info.SwapLimit { fmt.Fprintln(dockerCli.Err(), "WARNING: No swap limit support") } if !info.KernelMemory { fmt.Fprintln(dockerCli.Err(), "WARNING: No kernel memory limit support") } if !info.OomKillDisable { fmt.Fprintln(dockerCli.Err(), "WARNING: No oom kill disable support") } if !info.CPUCfsQuota { fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs quota support") } if !info.CPUCfsPeriod { fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs period support") } if !info.CPUShares { fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu shares support") } if !info.CPUSet { fmt.Fprintln(dockerCli.Err(), "WARNING: No cpuset support") } if !info.IPv4Forwarding { fmt.Fprintln(dockerCli.Err(), "WARNING: IPv4 forwarding is disabled") } if !info.BridgeNfIptables { fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-iptables is disabled") } if !info.BridgeNfIP6tables { fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-ip6tables is disabled") } } if info.Labels != nil { fmt.Fprintln(dockerCli.Out(), "Labels:") for _, attribute := range info.Labels { fmt.Fprintf(dockerCli.Out(), " %s\n", attribute) } } ioutils.FprintfIfTrue(dockerCli.Out(), "Experimental: %v\n", info.ExperimentalBuild) if info.ClusterStore != "" { fmt.Fprintf(dockerCli.Out(), "Cluster Store: %s\n", info.ClusterStore) } if info.ClusterAdvertise != "" { fmt.Fprintf(dockerCli.Out(), "Cluster Advertise: %s\n", info.ClusterAdvertise) } if info.RegistryConfig != nil && (len(info.RegistryConfig.InsecureRegistryCIDRs) > 0 || len(info.RegistryConfig.IndexConfigs) > 0) { fmt.Fprintln(dockerCli.Out(), "Insecure Registries:") for _, registry := range info.RegistryConfig.IndexConfigs { if registry.Secure == false { fmt.Fprintf(dockerCli.Out(), " %s\n", registry.Name) } } for _, registry := range info.RegistryConfig.InsecureRegistryCIDRs { mask, _ := registry.Mask.Size() fmt.Fprintf(dockerCli.Out(), " %s/%d\n", registry.IP.String(), mask) } } if info.RegistryConfig != nil && len(info.RegistryConfig.Mirrors) > 0 { fmt.Fprintln(dockerCli.Out(), "Registry Mirrors:") for _, mirror := range info.RegistryConfig.Mirrors { fmt.Fprintf(dockerCli.Out(), " %s\n", mirror) } } fmt.Fprintf(dockerCli.Out(), "Live Restore Enabled: %v\n", info.LiveRestoreEnabled) return nil }
func runInfo(dockerCli *client.DockerCli) error { info, err := dockerCli.Client().Info(context.Background()) if err != nil { return err } fmt.Fprintf(dockerCli.Out(), "Containers: %d\n", info.Containers) fmt.Fprintf(dockerCli.Out(), " Running: %d\n", info.ContainersRunning) fmt.Fprintf(dockerCli.Out(), " Paused: %d\n", info.ContainersPaused) fmt.Fprintf(dockerCli.Out(), " Stopped: %d\n", info.ContainersStopped) fmt.Fprintf(dockerCli.Out(), "Images: %d\n", info.Images) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Server Version: %s\n", info.ServerVersion) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Storage Driver: %s\n", info.Driver) if info.DriverStatus != nil { for _, pair := range info.DriverStatus { fmt.Fprintf(dockerCli.Out(), " %s: %s\n", pair[0], pair[1]) // print a warning if devicemapper is using a loopback file if pair[0] == "Data loop file" { fmt.Fprintln(dockerCli.Err(), " WARNING: Usage of loopback devices is strongly discouraged for production use. Either use `--storage-opt dm.thinpooldev` or use `--storage-opt dm.no_warn_on_loop_devices=true` to suppress this warning.") } } } if info.SystemStatus != nil { for _, pair := range info.SystemStatus { fmt.Fprintf(dockerCli.Out(), "%s: %s\n", pair[0], pair[1]) } } ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Execution Driver: %s\n", info.ExecutionDriver) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Logging Driver: %s\n", info.LoggingDriver) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Cgroup Driver: %s\n", info.CgroupDriver) fmt.Fprintf(dockerCli.Out(), "Plugins: \n") fmt.Fprintf(dockerCli.Out(), " Volume:") fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Volume, " ")) fmt.Fprintf(dockerCli.Out(), "\n") fmt.Fprintf(dockerCli.Out(), " Network:") fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Network, " ")) fmt.Fprintf(dockerCli.Out(), "\n") if len(info.Plugins.Authorization) != 0 { fmt.Fprintf(dockerCli.Out(), " Authorization:") fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Authorization, " ")) fmt.Fprintf(dockerCli.Out(), "\n") } fmt.Fprintf(dockerCli.Out(), "Swarm: %v\n", info.Swarm.LocalNodeState) if info.Swarm.LocalNodeState != swarm.LocalNodeStateInactive { fmt.Fprintf(dockerCli.Out(), " NodeID: %s\n", info.Swarm.NodeID) if info.Swarm.Error != "" { fmt.Fprintf(dockerCli.Out(), " Error: %v\n", info.Swarm.Error) } if info.Swarm.ControlAvailable { fmt.Fprintf(dockerCli.Out(), " IsManager: Yes\n") fmt.Fprintf(dockerCli.Out(), " Managers: %d\n", info.Swarm.Managers) fmt.Fprintf(dockerCli.Out(), " Nodes: %d\n", info.Swarm.Nodes) ioutils.FprintfIfNotEmpty(dockerCli.Out(), " CACertHash: %s\n", info.Swarm.CACertHash) } else { fmt.Fprintf(dockerCli.Out(), " IsManager: No\n") } } if len(info.Runtimes) > 0 { fmt.Fprintf(dockerCli.Out(), "Runtimes:") for name := range info.Runtimes { fmt.Fprintf(dockerCli.Out(), " %s", name) } fmt.Fprint(dockerCli.Out(), "\n") fmt.Fprintf(dockerCli.Out(), "Default Runtime: %s\n", info.DefaultRuntime) } fmt.Fprintf(dockerCli.Out(), "Security Options:") ioutils.FprintfIfNotEmpty(dockerCli.Out(), " %s", strings.Join(info.SecurityOptions, " ")) fmt.Fprintf(dockerCli.Out(), "\n") ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Kernel Version: %s\n", info.KernelVersion) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Operating System: %s\n", info.OperatingSystem) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "OSType: %s\n", info.OSType) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Architecture: %s\n", info.Architecture) fmt.Fprintf(dockerCli.Out(), "CPUs: %d\n", info.NCPU) fmt.Fprintf(dockerCli.Out(), "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal))) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Name: %s\n", info.Name) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "ID: %s\n", info.ID) fmt.Fprintf(dockerCli.Out(), "Docker Root Dir: %s\n", info.DockerRootDir) fmt.Fprintf(dockerCli.Out(), "Debug Mode (client): %v\n", utils.IsDebugEnabled()) fmt.Fprintf(dockerCli.Out(), "Debug Mode (server): %v\n", info.Debug) if info.Debug { fmt.Fprintf(dockerCli.Out(), " File Descriptors: %d\n", info.NFd) fmt.Fprintf(dockerCli.Out(), " Goroutines: %d\n", info.NGoroutines) fmt.Fprintf(dockerCli.Out(), " System Time: %s\n", info.SystemTime) fmt.Fprintf(dockerCli.Out(), " EventsListeners: %d\n", info.NEventsListener) } ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Http Proxy: %s\n", info.HTTPProxy) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Https Proxy: %s\n", info.HTTPSProxy) ioutils.FprintfIfNotEmpty(dockerCli.Out(), "No Proxy: %s\n", info.NoProxy) if info.IndexServerAddress != "" { u := dockerCli.ConfigFile().AuthConfigs[info.IndexServerAddress].Username if len(u) > 0 { fmt.Fprintf(dockerCli.Out(), "Username: %v\n", u) } fmt.Fprintf(dockerCli.Out(), "Registry: %v\n", info.IndexServerAddress) } // Only output these warnings if the server does not support these features if info.OSType != "windows" { if !info.MemoryLimit { fmt.Fprintln(dockerCli.Err(), "WARNING: No memory limit support") } if !info.SwapLimit { fmt.Fprintln(dockerCli.Err(), "WARNING: No swap limit support") } if !info.KernelMemory { fmt.Fprintln(dockerCli.Err(), "WARNING: No kernel memory limit support") } if !info.OomKillDisable { fmt.Fprintln(dockerCli.Err(), "WARNING: No oom kill disable support") } if !info.CPUCfsQuota { fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs quota support") } if !info.CPUCfsPeriod { fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs period support") } if !info.CPUShares { fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu shares support") } if !info.CPUSet { fmt.Fprintln(dockerCli.Err(), "WARNING: No cpuset support") } if !info.IPv4Forwarding { fmt.Fprintln(dockerCli.Err(), "WARNING: IPv4 forwarding is disabled") } if !info.BridgeNfIptables { fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-iptables is disabled") } if !info.BridgeNfIP6tables { fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-ip6tables is disabled") } } if info.Labels != nil { fmt.Fprintln(dockerCli.Out(), "Labels:") for _, attribute := range info.Labels { fmt.Fprintf(dockerCli.Out(), " %s\n", attribute) } } ioutils.FprintfIfTrue(dockerCli.Out(), "Experimental: %v\n", info.ExperimentalBuild) if info.ClusterStore != "" { fmt.Fprintf(dockerCli.Out(), "Cluster Store: %s\n", info.ClusterStore) } if info.ClusterAdvertise != "" { fmt.Fprintf(dockerCli.Out(), "Cluster Advertise: %s\n", info.ClusterAdvertise) } if info.RegistryConfig != nil && (len(info.RegistryConfig.InsecureRegistryCIDRs) > 0 || len(info.RegistryConfig.IndexConfigs) > 0) { fmt.Fprintln(dockerCli.Out(), "Insecure Registries:") for _, registry := range info.RegistryConfig.IndexConfigs { if registry.Secure == false { fmt.Fprintf(dockerCli.Out(), " %s\n", registry.Name) } } for _, registry := range info.RegistryConfig.InsecureRegistryCIDRs { mask, _ := registry.Mask.Size() fmt.Fprintf(dockerCli.Out(), " %s/%d\n", registry.IP.String(), mask) } } return nil }
func runStart(dockerCli *client.DockerCli, opts *startOptions) error { ctx, cancelFun := context.WithCancel(context.Background()) if opts.attach || opts.openStdin { // We're going to attach to a container. // 1. Ensure we only have one container. if len(opts.containers) > 1 { return fmt.Errorf("You cannot start and attach multiple containers at once.") } // 2. Attach to the container. container := opts.containers[0] c, err := dockerCli.Client().ContainerInspect(ctx, container) if err != nil { return err } // We always use c.ID instead of container to maintain consistency during `docker start` if !c.Config.Tty { sigc := dockerCli.ForwardAllSignals(ctx, c.ID) defer signal.StopCatch(sigc) } if opts.detachKeys != "" { dockerCli.ConfigFile().DetachKeys = opts.detachKeys } options := types.ContainerAttachOptions{ Stream: true, Stdin: opts.openStdin && c.Config.OpenStdin, Stdout: true, Stderr: true, DetachKeys: dockerCli.ConfigFile().DetachKeys, } var in io.ReadCloser if options.Stdin { in = dockerCli.In() } resp, errAttach := dockerCli.Client().ContainerAttach(ctx, c.ID, options) if errAttach != nil && errAttach != httputil.ErrPersistEOF { // ContainerAttach return an ErrPersistEOF (connection closed) // means server met an error and put it in Hijacked connection // keep the error and read detailed error message from hijacked connection return errAttach } defer resp.Close() cErr := promise.Go(func() error { errHijack := dockerCli.HoldHijackedConnection(ctx, c.Config.Tty, in, dockerCli.Out(), dockerCli.Err(), resp) if errHijack == nil { return errAttach } return errHijack }) // 3. Start the container. if err := dockerCli.Client().ContainerStart(ctx, c.ID, types.ContainerStartOptions{}); err != nil { cancelFun() <-cErr return err } // 4. Wait for attachment to break. if c.Config.Tty && dockerCli.IsTerminalOut() { if err := dockerCli.MonitorTtySize(ctx, c.ID, false); err != nil { fmt.Fprintf(dockerCli.Err(), "Error monitoring TTY size: %s\n", err) } } if attchErr := <-cErr; attchErr != nil { return attchErr } _, status, err := getExitCode(dockerCli, ctx, c.ID) if err != nil { return err } if status != 0 { return cli.StatusError{StatusCode: status} } } else { // We're not going to attach to anything. // Start as many containers as we want. return startContainersWithoutAttachments(dockerCli, ctx, opts.containers) } return nil }
func runRun(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts *runOptions, copts *runconfigopts.ContainerOptions) error { stdout, stderr, stdin := dockerCli.Out(), dockerCli.Err(), dockerCli.In() client := dockerCli.Client() // TODO: pass this as an argument cmdPath := "run" var ( flAttach *opttypes.ListOpts ErrConflictAttachDetach = fmt.Errorf("Conflicting options: -a and -d") ErrConflictRestartPolicyAndAutoRemove = fmt.Errorf("Conflicting options: --restart and --rm") ErrConflictDetachAutoRemove = fmt.Errorf("Conflicting options: --rm and -d") ) config, hostConfig, networkingConfig, err := runconfigopts.Parse(flags, copts) // just in case the Parse does not exit if err != nil { reportError(stderr, cmdPath, err.Error(), true) return cli.StatusError{StatusCode: 125} } if hostConfig.OomKillDisable != nil && *hostConfig.OomKillDisable && hostConfig.Memory == 0 { fmt.Fprintf(stderr, "WARNING: Disabling the OOM killer on containers without setting a '-m/--memory' limit may be dangerous.\n") } if len(hostConfig.DNS) > 0 { // check the DNS settings passed via --dns against // localhost regexp to warn if they are trying to // set a DNS to a localhost address for _, dnsIP := range hostConfig.DNS { if dns.IsLocalhost(dnsIP) { fmt.Fprintf(stderr, "WARNING: Localhost DNS setting (--dns=%s) may fail in containers.\n", dnsIP) break } } } config.ArgsEscaped = false if !opts.detach { if err := dockerCli.CheckTtyInput(config.AttachStdin, config.Tty); err != nil { return err } } else { if fl := flags.Lookup("attach"); fl != nil { flAttach = fl.Value.(*opttypes.ListOpts) if flAttach.Len() != 0 { return ErrConflictAttachDetach } } if opts.autoRemove { return ErrConflictDetachAutoRemove } config.AttachStdin = false config.AttachStdout = false config.AttachStderr = false config.StdinOnce = false } // Disable sigProxy when in TTY mode if config.Tty { opts.sigProxy = false } // Telling the Windows daemon the initial size of the tty during start makes // a far better user experience rather than relying on subsequent resizes // to cause things to catch up. if runtime.GOOS == "windows" { hostConfig.ConsoleSize[0], hostConfig.ConsoleSize[1] = dockerCli.GetTtySize() } ctx, cancelFun := context.WithCancel(context.Background()) createResponse, err := createContainer(ctx, dockerCli, config, hostConfig, networkingConfig, hostConfig.ContainerIDFile, opts.name) if err != nil { reportError(stderr, cmdPath, err.Error(), true) return runStartContainerErr(err) } if opts.sigProxy { sigc := dockerCli.ForwardAllSignals(ctx, createResponse.ID) defer signal.StopCatch(sigc) } var ( waitDisplayID chan struct{} errCh chan error ) if !config.AttachStdout && !config.AttachStderr { // Make this asynchronous to allow the client to write to stdin before having to read the ID waitDisplayID = make(chan struct{}) go func() { defer close(waitDisplayID) fmt.Fprintf(stdout, "%s\n", createResponse.ID) }() } if opts.autoRemove && (hostConfig.RestartPolicy.IsAlways() || hostConfig.RestartPolicy.IsOnFailure()) { return ErrConflictRestartPolicyAndAutoRemove } attach := config.AttachStdin || config.AttachStdout || config.AttachStderr if attach { var ( out, cerr io.Writer in io.ReadCloser ) if config.AttachStdin { in = stdin } if config.AttachStdout { out = stdout } if config.AttachStderr { if config.Tty { cerr = stdout } else { cerr = stderr } } if opts.detachKeys != "" { dockerCli.ConfigFile().DetachKeys = opts.detachKeys } options := types.ContainerAttachOptions{ Stream: true, Stdin: config.AttachStdin, Stdout: config.AttachStdout, Stderr: config.AttachStderr, DetachKeys: dockerCli.ConfigFile().DetachKeys, } resp, errAttach := client.ContainerAttach(ctx, createResponse.ID, options) if errAttach != nil && errAttach != httputil.ErrPersistEOF { // ContainerAttach returns an ErrPersistEOF (connection closed) // means server met an error and put it in Hijacked connection // keep the error and read detailed error message from hijacked connection later return errAttach } defer resp.Close() errCh = promise.Go(func() error { errHijack := dockerCli.HoldHijackedConnection(ctx, config.Tty, in, out, cerr, resp) if errHijack == nil { return errAttach } return errHijack }) } if opts.autoRemove { defer func() { // Explicitly not sharing the context as it could be "Done" (by calling cancelFun) // and thus the container would not be removed. if err := removeContainer(dockerCli, context.Background(), createResponse.ID, true, false, true); err != nil { fmt.Fprintf(stderr, "%v\n", err) } }() } //start the container if err := client.ContainerStart(ctx, createResponse.ID, types.ContainerStartOptions{}); err != nil { // If we have holdHijackedConnection, we should notify // holdHijackedConnection we are going to exit and wait // to avoid the terminal are not restored. if attach { cancelFun() <-errCh } reportError(stderr, cmdPath, err.Error(), false) return runStartContainerErr(err) } if (config.AttachStdin || config.AttachStdout || config.AttachStderr) && config.Tty && dockerCli.IsTerminalOut() { if err := dockerCli.MonitorTtySize(ctx, createResponse.ID, false); err != nil { fmt.Fprintf(stderr, "Error monitoring TTY size: %s\n", err) } } if errCh != nil { if err := <-errCh; err != nil { logrus.Debugf("Error hijack: %s", err) return err } } // Detached mode: wait for the id to be displayed and return. if !config.AttachStdout && !config.AttachStderr { // Detached mode <-waitDisplayID return nil } var status int // Attached mode if opts.autoRemove { // Autoremove: wait for the container to finish, retrieve // the exit code and remove the container if status, err = client.ContainerWait(ctx, createResponse.ID); err != nil { return runStartContainerErr(err) } if _, status, err = dockerCli.GetExitCode(ctx, createResponse.ID); err != nil { return err } } else { // No Autoremove: Simply retrieve the exit code if !config.Tty { // In non-TTY mode, we can't detach, so we must wait for container exit if status, err = client.ContainerWait(ctx, createResponse.ID); err != nil { return err } } else { // In TTY mode, there is a race: if the process dies too slowly, the state could // be updated after the getExitCode call and result in the wrong exit code being reported if _, status, err = dockerCli.GetExitCode(ctx, createResponse.ID); err != nil { return err } } } if status != 0 { return cli.StatusError{StatusCode: status} } return nil }
func runExec(dockerCli *client.DockerCli, opts *execOptions, container string, execCmd []string) error { execConfig, err := parseExec(opts, container, execCmd) // just in case the ParseExec does not exit if container == "" || err != nil { return cli.StatusError{StatusCode: 1} } if opts.detachKeys != "" { dockerCli.ConfigFile().DetachKeys = opts.detachKeys } // Send client escape keys execConfig.DetachKeys = dockerCli.ConfigFile().DetachKeys ctx := context.Background() response, err := dockerCli.Client().ContainerExecCreate(ctx, container, *execConfig) if err != nil { return err } execID := response.ID if execID == "" { fmt.Fprintf(dockerCli.Out(), "exec ID empty") return nil } //Temp struct for execStart so that we don't need to transfer all the execConfig if !execConfig.Detach { if err := dockerCli.CheckTtyInput(execConfig.AttachStdin, execConfig.Tty); err != nil { return err } } else { execStartCheck := types.ExecStartCheck{ Detach: execConfig.Detach, Tty: execConfig.Tty, } if err := dockerCli.Client().ContainerExecStart(ctx, execID, execStartCheck); err != nil { return err } // For now don't print this - wait for when we support exec wait() // fmt.Fprintf(dockerCli.Out(), "%s\n", execID) return nil } // Interactive exec requested. var ( out, stderr io.Writer in io.ReadCloser errCh chan error ) if execConfig.AttachStdin { in = dockerCli.In() } if execConfig.AttachStdout { out = dockerCli.Out() } if execConfig.AttachStderr { if execConfig.Tty { stderr = dockerCli.Out() } else { stderr = dockerCli.Err() } } resp, err := dockerCli.Client().ContainerExecAttach(ctx, execID, *execConfig) if err != nil { return err } defer resp.Close() errCh = promise.Go(func() error { return dockerCli.HoldHijackedConnection(ctx, execConfig.Tty, in, out, stderr, resp) }) if execConfig.Tty && dockerCli.IsTerminalIn() { if err := dockerCli.MonitorTtySize(ctx, execID, true); err != nil { fmt.Fprintf(dockerCli.Err(), "Error monitoring TTY size: %s\n", err) } } if err := <-errCh; err != nil { logrus.Debugf("Error hijack: %s", err) return err } var status int if _, status, err = dockerCli.GetExecExitCode(ctx, execID); err != nil { return err } if status != 0 { return cli.StatusError{StatusCode: status} } return nil }