diff --git a/api/client/commands.go b/api/client/commands.go index ed328b8b57..caff794984 100644 --- a/api/client/commands.go +++ b/api/client/commands.go @@ -4,7 +4,6 @@ package client func (cli *DockerCli) Command(name string) func(...string) error { return map[string]func(...string) error{ "exec": cli.CmdExec, - "info": cli.CmdInfo, "inspect": cli.CmdInspect, "update": cli.CmdUpdate, }[name] diff --git a/api/client/info.go b/api/client/info.go deleted file mode 100644 index cf4d4fff0b..0000000000 --- a/api/client/info.go +++ /dev/null @@ -1,199 +0,0 @@ -package client - -import ( - "fmt" - "strings" - - "golang.org/x/net/context" - - Cli "github.com/docker/docker/cli" - "github.com/docker/docker/pkg/ioutils" - flag "github.com/docker/docker/pkg/mflag" - "github.com/docker/docker/utils" - "github.com/docker/engine-api/types/swarm" - "github.com/docker/go-units" -) - -// CmdInfo displays system-wide information. -// -// Usage: docker info -func (cli *DockerCli) CmdInfo(args ...string) error { - cmd := Cli.Subcmd("info", nil, Cli.DockerCommands["info"].Description, true) - cmd.Require(flag.Exact, 0) - - cmd.ParseFlags(args, true) - - info, err := cli.client.Info(context.Background()) - if err != nil { - return err - } - - fmt.Fprintf(cli.out, "Containers: %d\n", info.Containers) - fmt.Fprintf(cli.out, " Running: %d\n", info.ContainersRunning) - fmt.Fprintf(cli.out, " Paused: %d\n", info.ContainersPaused) - fmt.Fprintf(cli.out, " Stopped: %d\n", info.ContainersStopped) - fmt.Fprintf(cli.out, "Images: %d\n", info.Images) - ioutils.FprintfIfNotEmpty(cli.out, "Server Version: %s\n", info.ServerVersion) - ioutils.FprintfIfNotEmpty(cli.out, "Storage Driver: %s\n", info.Driver) - if info.DriverStatus != nil { - for _, pair := range info.DriverStatus { - fmt.Fprintf(cli.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(cli.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(cli.out, "%s: %s\n", pair[0], pair[1]) - } - } - ioutils.FprintfIfNotEmpty(cli.out, "Execution Driver: %s\n", info.ExecutionDriver) - ioutils.FprintfIfNotEmpty(cli.out, "Logging Driver: %s\n", info.LoggingDriver) - ioutils.FprintfIfNotEmpty(cli.out, "Cgroup Driver: %s\n", info.CgroupDriver) - - fmt.Fprintf(cli.out, "Plugins:\n") - fmt.Fprintf(cli.out, " Volume:") - fmt.Fprintf(cli.out, " %s", strings.Join(info.Plugins.Volume, " ")) - fmt.Fprintf(cli.out, "\n") - fmt.Fprintf(cli.out, " Network:") - fmt.Fprintf(cli.out, " %s", strings.Join(info.Plugins.Network, " ")) - fmt.Fprintf(cli.out, "\n") - - if len(info.Plugins.Authorization) != 0 { - fmt.Fprintf(cli.out, " Authorization:") - fmt.Fprintf(cli.out, " %s", strings.Join(info.Plugins.Authorization, " ")) - fmt.Fprintf(cli.out, "\n") - } - - fmt.Fprintf(cli.out, "Swarm: %v\n", info.Swarm.LocalNodeState) - if info.Swarm.LocalNodeState != swarm.LocalNodeStateInactive { - fmt.Fprintf(cli.out, " NodeID: %s\n", info.Swarm.NodeID) - if info.Swarm.Error != "" { - fmt.Fprintf(cli.out, " Error: %v\n", info.Swarm.Error) - } - if info.Swarm.ControlAvailable { - fmt.Fprintf(cli.out, " IsManager: Yes\n") - fmt.Fprintf(cli.out, " Managers: %d\n", info.Swarm.Managers) - fmt.Fprintf(cli.out, " Nodes: %d\n", info.Swarm.Nodes) - ioutils.FprintfIfNotEmpty(cli.out, " CACertHash: %s\n", info.Swarm.CACertHash) - } else { - fmt.Fprintf(cli.out, " IsManager: No\n") - } - } - - if len(info.Runtimes) > 0 { - fmt.Fprintf(cli.out, "Runtimes:") - for name := range info.Runtimes { - fmt.Fprintf(cli.out, " %s", name) - } - fmt.Fprint(cli.out, "\n") - fmt.Fprintf(cli.out, "Default Runtime: %s\n", info.DefaultRuntime) - } - - fmt.Fprintf(cli.out, "Security Options:") - ioutils.FprintfIfNotEmpty(cli.out, " %s", strings.Join(info.SecurityOptions, " ")) - fmt.Fprintf(cli.out, "\n") - - ioutils.FprintfIfNotEmpty(cli.out, "Kernel Version: %s\n", info.KernelVersion) - ioutils.FprintfIfNotEmpty(cli.out, "Operating System: %s\n", info.OperatingSystem) - ioutils.FprintfIfNotEmpty(cli.out, "OSType: %s\n", info.OSType) - ioutils.FprintfIfNotEmpty(cli.out, "Architecture: %s\n", info.Architecture) - fmt.Fprintf(cli.out, "CPUs: %d\n", info.NCPU) - fmt.Fprintf(cli.out, "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal))) - ioutils.FprintfIfNotEmpty(cli.out, "Name: %s\n", info.Name) - ioutils.FprintfIfNotEmpty(cli.out, "ID: %s\n", info.ID) - fmt.Fprintf(cli.out, "Docker Root Dir: %s\n", info.DockerRootDir) - fmt.Fprintf(cli.out, "Debug Mode (client): %v\n", utils.IsDebugEnabled()) - fmt.Fprintf(cli.out, "Debug Mode (server): %v\n", info.Debug) - - if info.Debug { - fmt.Fprintf(cli.out, " File Descriptors: %d\n", info.NFd) - fmt.Fprintf(cli.out, " Goroutines: %d\n", info.NGoroutines) - fmt.Fprintf(cli.out, " System Time: %s\n", info.SystemTime) - fmt.Fprintf(cli.out, " EventsListeners: %d\n", info.NEventsListener) - } - - ioutils.FprintfIfNotEmpty(cli.out, "Http Proxy: %s\n", info.HTTPProxy) - ioutils.FprintfIfNotEmpty(cli.out, "Https Proxy: %s\n", info.HTTPSProxy) - ioutils.FprintfIfNotEmpty(cli.out, "No Proxy: %s\n", info.NoProxy) - - if info.IndexServerAddress != "" { - u := cli.configFile.AuthConfigs[info.IndexServerAddress].Username - if len(u) > 0 { - fmt.Fprintf(cli.out, "Username: %v\n", u) - } - fmt.Fprintf(cli.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(cli.err, "WARNING: No memory limit support") - } - if !info.SwapLimit { - fmt.Fprintln(cli.err, "WARNING: No swap limit support") - } - if !info.KernelMemory { - fmt.Fprintln(cli.err, "WARNING: No kernel memory limit support") - } - if !info.OomKillDisable { - fmt.Fprintln(cli.err, "WARNING: No oom kill disable support") - } - if !info.CPUCfsQuota { - fmt.Fprintln(cli.err, "WARNING: No cpu cfs quota support") - } - if !info.CPUCfsPeriod { - fmt.Fprintln(cli.err, "WARNING: No cpu cfs period support") - } - if !info.CPUShares { - fmt.Fprintln(cli.err, "WARNING: No cpu shares support") - } - if !info.CPUSet { - fmt.Fprintln(cli.err, "WARNING: No cpuset support") - } - if !info.IPv4Forwarding { - fmt.Fprintln(cli.err, "WARNING: IPv4 forwarding is disabled") - } - if !info.BridgeNfIptables { - fmt.Fprintln(cli.err, "WARNING: bridge-nf-call-iptables is disabled") - } - if !info.BridgeNfIP6tables { - fmt.Fprintln(cli.err, "WARNING: bridge-nf-call-ip6tables is disabled") - } - } - - if info.Labels != nil { - fmt.Fprintln(cli.out, "Labels:") - for _, attribute := range info.Labels { - fmt.Fprintf(cli.out, " %s\n", attribute) - } - } - - ioutils.FprintfIfTrue(cli.out, "Experimental: %v\n", info.ExperimentalBuild) - if info.ClusterStore != "" { - fmt.Fprintf(cli.out, "Cluster Store: %s\n", info.ClusterStore) - } - - if info.ClusterAdvertise != "" { - fmt.Fprintf(cli.out, "Cluster Advertise: %s\n", info.ClusterAdvertise) - } - - if info.RegistryConfig != nil && (len(info.RegistryConfig.InsecureRegistryCIDRs) > 0 || len(info.RegistryConfig.IndexConfigs) > 0) { - fmt.Fprintln(cli.out, "Insecure Registries:") - for _, registry := range info.RegistryConfig.IndexConfigs { - if registry.Secure == false { - fmt.Fprintf(cli.out, " %s\n", registry.Name) - } - } - - for _, registry := range info.RegistryConfig.InsecureRegistryCIDRs { - mask, _ := registry.Mask.Size() - fmt.Fprintf(cli.out, " %s/%d\n", registry.IP.String(), mask) - } - } - return nil -} diff --git a/api/client/system/info.go b/api/client/system/info.go new file mode 100644 index 0000000000..56389d8424 --- /dev/null +++ b/api/client/system/info.go @@ -0,0 +1,206 @@ +package system + +import ( + "fmt" + "strings" + + "golang.org/x/net/context" + + "github.com/docker/docker/api/client" + "github.com/docker/docker/cli" + "github.com/docker/docker/pkg/ioutils" + "github.com/docker/docker/utils" + "github.com/docker/engine-api/types/swarm" + "github.com/docker/go-units" + "github.com/spf13/cobra" +) + +// NewInfoCommand creates a new cobra.Command for `docker info` +func NewInfoCommand(dockerCli *client.DockerCli) *cobra.Command { + cmd := &cobra.Command{ + Use: "info", + Short: "Display system-wide information", + Args: cli.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + return runInfo(dockerCli) + }, + } + return cmd + +} + +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 +} diff --git a/cli/cobraadaptor/adaptor.go b/cli/cobraadaptor/adaptor.go index e8a29c6817..5466840310 100644 --- a/cli/cobraadaptor/adaptor.go +++ b/cli/cobraadaptor/adaptor.go @@ -84,6 +84,7 @@ func NewCobraAdaptor(clientFlags *cliflags.ClientFlags) CobraAdaptor { registry.NewLogoutCommand(dockerCli), system.NewVersionCommand(dockerCli), volume.NewVolumeCommand(dockerCli), + system.NewInfoCommand(dockerCli), ) plugin.NewPluginCommand(rootCmd, dockerCli) diff --git a/cli/usage.go b/cli/usage.go index 0e2923740f..451c5e7756 100644 --- a/cli/usage.go +++ b/cli/usage.go @@ -9,7 +9,6 @@ type Command struct { // DockerCommandUsage lists the top level docker commands and their short usage var DockerCommandUsage = []Command{ {"exec", "Run a command in a running container"}, - {"info", "Display system-wide information"}, {"inspect", "Return low-level information on a container, image or task"}, {"update", "Update configuration of one or more containers"}, }