github.com/kim0/docker@v0.6.2-0.20161130212042-4addda3f07e7/cli/command/system/info.go (about) 1 package system 2 3 import ( 4 "fmt" 5 "strings" 6 "time" 7 8 "golang.org/x/net/context" 9 10 "github.com/docker/docker/api/types" 11 "github.com/docker/docker/api/types/swarm" 12 "github.com/docker/docker/cli" 13 "github.com/docker/docker/cli/command" 14 "github.com/docker/docker/pkg/ioutils" 15 "github.com/docker/docker/utils" 16 "github.com/docker/docker/utils/templates" 17 "github.com/docker/go-units" 18 "github.com/spf13/cobra" 19 ) 20 21 type infoOptions struct { 22 format string 23 } 24 25 // NewInfoCommand creates a new cobra.Command for `docker info` 26 func NewInfoCommand(dockerCli *command.DockerCli) *cobra.Command { 27 var opts infoOptions 28 29 cmd := &cobra.Command{ 30 Use: "info [OPTIONS]", 31 Short: "Display system-wide information", 32 Args: cli.NoArgs, 33 RunE: func(cmd *cobra.Command, args []string) error { 34 return runInfo(dockerCli, &opts) 35 }, 36 } 37 38 flags := cmd.Flags() 39 40 flags.StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template") 41 42 return cmd 43 } 44 45 func runInfo(dockerCli *command.DockerCli, opts *infoOptions) error { 46 ctx := context.Background() 47 info, err := dockerCli.Client().Info(ctx) 48 if err != nil { 49 return err 50 } 51 if opts.format == "" { 52 return prettyPrintInfo(dockerCli, info) 53 } 54 return formatInfo(dockerCli, info, opts.format) 55 } 56 57 func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error { 58 fmt.Fprintf(dockerCli.Out(), "Containers: %d\n", info.Containers) 59 fmt.Fprintf(dockerCli.Out(), " Running: %d\n", info.ContainersRunning) 60 fmt.Fprintf(dockerCli.Out(), " Paused: %d\n", info.ContainersPaused) 61 fmt.Fprintf(dockerCli.Out(), " Stopped: %d\n", info.ContainersStopped) 62 fmt.Fprintf(dockerCli.Out(), "Images: %d\n", info.Images) 63 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Server Version: %s\n", info.ServerVersion) 64 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Storage Driver: %s\n", info.Driver) 65 if info.DriverStatus != nil { 66 for _, pair := range info.DriverStatus { 67 fmt.Fprintf(dockerCli.Out(), " %s: %s\n", pair[0], pair[1]) 68 69 // print a warning if devicemapper is using a loopback file 70 if pair[0] == "Data loop file" { 71 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.") 72 } 73 } 74 75 } 76 if info.SystemStatus != nil { 77 for _, pair := range info.SystemStatus { 78 fmt.Fprintf(dockerCli.Out(), "%s: %s\n", pair[0], pair[1]) 79 } 80 } 81 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Logging Driver: %s\n", info.LoggingDriver) 82 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Cgroup Driver: %s\n", info.CgroupDriver) 83 84 fmt.Fprintf(dockerCli.Out(), "Plugins: \n") 85 fmt.Fprintf(dockerCli.Out(), " Volume:") 86 fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Volume, " ")) 87 fmt.Fprintf(dockerCli.Out(), "\n") 88 fmt.Fprintf(dockerCli.Out(), " Network:") 89 fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Network, " ")) 90 fmt.Fprintf(dockerCli.Out(), "\n") 91 92 if len(info.Plugins.Authorization) != 0 { 93 fmt.Fprintf(dockerCli.Out(), " Authorization:") 94 fmt.Fprintf(dockerCli.Out(), " %s", strings.Join(info.Plugins.Authorization, " ")) 95 fmt.Fprintf(dockerCli.Out(), "\n") 96 } 97 98 fmt.Fprintf(dockerCli.Out(), "Swarm: %v\n", info.Swarm.LocalNodeState) 99 if info.Swarm.LocalNodeState != swarm.LocalNodeStateInactive { 100 fmt.Fprintf(dockerCli.Out(), " NodeID: %s\n", info.Swarm.NodeID) 101 if info.Swarm.Error != "" { 102 fmt.Fprintf(dockerCli.Out(), " Error: %v\n", info.Swarm.Error) 103 } 104 fmt.Fprintf(dockerCli.Out(), " Is Manager: %v\n", info.Swarm.ControlAvailable) 105 if info.Swarm.ControlAvailable { 106 fmt.Fprintf(dockerCli.Out(), " ClusterID: %s\n", info.Swarm.Cluster.ID) 107 fmt.Fprintf(dockerCli.Out(), " Managers: %d\n", info.Swarm.Managers) 108 fmt.Fprintf(dockerCli.Out(), " Nodes: %d\n", info.Swarm.Nodes) 109 fmt.Fprintf(dockerCli.Out(), " Orchestration:\n") 110 taskHistoryRetentionLimit := int64(0) 111 if info.Swarm.Cluster.Spec.Orchestration.TaskHistoryRetentionLimit != nil { 112 taskHistoryRetentionLimit = *info.Swarm.Cluster.Spec.Orchestration.TaskHistoryRetentionLimit 113 } 114 fmt.Fprintf(dockerCli.Out(), " Task History Retention Limit: %d\n", taskHistoryRetentionLimit) 115 fmt.Fprintf(dockerCli.Out(), " Raft:\n") 116 fmt.Fprintf(dockerCli.Out(), " Snapshot Interval: %d\n", info.Swarm.Cluster.Spec.Raft.SnapshotInterval) 117 fmt.Fprintf(dockerCli.Out(), " Heartbeat Tick: %d\n", info.Swarm.Cluster.Spec.Raft.HeartbeatTick) 118 fmt.Fprintf(dockerCli.Out(), " Election Tick: %d\n", info.Swarm.Cluster.Spec.Raft.ElectionTick) 119 fmt.Fprintf(dockerCli.Out(), " Dispatcher:\n") 120 fmt.Fprintf(dockerCli.Out(), " Heartbeat Period: %s\n", units.HumanDuration(time.Duration(info.Swarm.Cluster.Spec.Dispatcher.HeartbeatPeriod))) 121 fmt.Fprintf(dockerCli.Out(), " CA Configuration:\n") 122 fmt.Fprintf(dockerCli.Out(), " Expiry Duration: %s\n", units.HumanDuration(info.Swarm.Cluster.Spec.CAConfig.NodeCertExpiry)) 123 if len(info.Swarm.Cluster.Spec.CAConfig.ExternalCAs) > 0 { 124 fmt.Fprintf(dockerCli.Out(), " External CAs:\n") 125 for _, entry := range info.Swarm.Cluster.Spec.CAConfig.ExternalCAs { 126 fmt.Fprintf(dockerCli.Out(), " %s: %s\n", entry.Protocol, entry.URL) 127 } 128 } 129 } 130 fmt.Fprintf(dockerCli.Out(), " Node Address: %s\n", info.Swarm.NodeAddr) 131 } 132 133 if len(info.Runtimes) > 0 { 134 fmt.Fprintf(dockerCli.Out(), "Runtimes:") 135 for name := range info.Runtimes { 136 fmt.Fprintf(dockerCli.Out(), " %s", name) 137 } 138 fmt.Fprint(dockerCli.Out(), "\n") 139 fmt.Fprintf(dockerCli.Out(), "Default Runtime: %s\n", info.DefaultRuntime) 140 } 141 142 if info.OSType == "linux" { 143 fmt.Fprintf(dockerCli.Out(), "Security Options:") 144 ioutils.FprintfIfNotEmpty(dockerCli.Out(), " %s", strings.Join(info.SecurityOptions, " ")) 145 fmt.Fprintf(dockerCli.Out(), "\n") 146 } 147 148 // Isolation only has meaning on a Windows daemon. 149 if info.OSType == "windows" { 150 fmt.Fprintf(dockerCli.Out(), "Default Isolation: %v\n", info.Isolation) 151 } 152 153 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Kernel Version: %s\n", info.KernelVersion) 154 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Operating System: %s\n", info.OperatingSystem) 155 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "OSType: %s\n", info.OSType) 156 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Architecture: %s\n", info.Architecture) 157 fmt.Fprintf(dockerCli.Out(), "CPUs: %d\n", info.NCPU) 158 fmt.Fprintf(dockerCli.Out(), "Total Memory: %s\n", units.BytesSize(float64(info.MemTotal))) 159 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Name: %s\n", info.Name) 160 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "ID: %s\n", info.ID) 161 fmt.Fprintf(dockerCli.Out(), "Docker Root Dir: %s\n", info.DockerRootDir) 162 fmt.Fprintf(dockerCli.Out(), "Debug Mode (client): %v\n", utils.IsDebugEnabled()) 163 fmt.Fprintf(dockerCli.Out(), "Debug Mode (server): %v\n", info.Debug) 164 165 if info.Debug { 166 fmt.Fprintf(dockerCli.Out(), " File Descriptors: %d\n", info.NFd) 167 fmt.Fprintf(dockerCli.Out(), " Goroutines: %d\n", info.NGoroutines) 168 fmt.Fprintf(dockerCli.Out(), " System Time: %s\n", info.SystemTime) 169 fmt.Fprintf(dockerCli.Out(), " EventsListeners: %d\n", info.NEventsListener) 170 } 171 172 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Http Proxy: %s\n", info.HTTPProxy) 173 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "Https Proxy: %s\n", info.HTTPSProxy) 174 ioutils.FprintfIfNotEmpty(dockerCli.Out(), "No Proxy: %s\n", info.NoProxy) 175 176 if info.IndexServerAddress != "" { 177 u := dockerCli.ConfigFile().AuthConfigs[info.IndexServerAddress].Username 178 if len(u) > 0 { 179 fmt.Fprintf(dockerCli.Out(), "Username: %v\n", u) 180 } 181 fmt.Fprintf(dockerCli.Out(), "Registry: %v\n", info.IndexServerAddress) 182 } 183 184 // Only output these warnings if the server does not support these features 185 if info.OSType != "windows" { 186 if !info.MemoryLimit { 187 fmt.Fprintln(dockerCli.Err(), "WARNING: No memory limit support") 188 } 189 if !info.SwapLimit { 190 fmt.Fprintln(dockerCli.Err(), "WARNING: No swap limit support") 191 } 192 if !info.KernelMemory { 193 fmt.Fprintln(dockerCli.Err(), "WARNING: No kernel memory limit support") 194 } 195 if !info.OomKillDisable { 196 fmt.Fprintln(dockerCli.Err(), "WARNING: No oom kill disable support") 197 } 198 if !info.CPUCfsQuota { 199 fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs quota support") 200 } 201 if !info.CPUCfsPeriod { 202 fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu cfs period support") 203 } 204 if !info.CPUShares { 205 fmt.Fprintln(dockerCli.Err(), "WARNING: No cpu shares support") 206 } 207 if !info.CPUSet { 208 fmt.Fprintln(dockerCli.Err(), "WARNING: No cpuset support") 209 } 210 if !info.IPv4Forwarding { 211 fmt.Fprintln(dockerCli.Err(), "WARNING: IPv4 forwarding is disabled") 212 } 213 if !info.BridgeNfIptables { 214 fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-iptables is disabled") 215 } 216 if !info.BridgeNfIP6tables { 217 fmt.Fprintln(dockerCli.Err(), "WARNING: bridge-nf-call-ip6tables is disabled") 218 } 219 } 220 221 if info.Labels != nil { 222 fmt.Fprintln(dockerCli.Out(), "Labels:") 223 for _, attribute := range info.Labels { 224 fmt.Fprintf(dockerCli.Out(), " %s\n", attribute) 225 } 226 // TODO: Engine labels with duplicate keys has been deprecated in 1.13 and will be error out 227 // after 3 release cycles (1.16). For now, a WARNING will be generated. The following will 228 // be removed eventually. 229 labelMap := map[string]string{} 230 for _, label := range info.Labels { 231 stringSlice := strings.SplitN(label, "=", 2) 232 if len(stringSlice) > 1 { 233 // If there is a conflict we will throw out an warning 234 if v, ok := labelMap[stringSlice[0]]; ok && v != stringSlice[1] { 235 fmt.Fprintln(dockerCli.Err(), "WARNING: labels with duplicate keys and conflicting values have been deprecated") 236 break 237 } 238 labelMap[stringSlice[0]] = stringSlice[1] 239 } 240 } 241 } 242 243 fmt.Fprintf(dockerCli.Out(), "Experimental: %v\n", info.ExperimentalBuild) 244 if info.ClusterStore != "" { 245 fmt.Fprintf(dockerCli.Out(), "Cluster Store: %s\n", info.ClusterStore) 246 } 247 248 if info.ClusterAdvertise != "" { 249 fmt.Fprintf(dockerCli.Out(), "Cluster Advertise: %s\n", info.ClusterAdvertise) 250 } 251 252 if info.RegistryConfig != nil && (len(info.RegistryConfig.InsecureRegistryCIDRs) > 0 || len(info.RegistryConfig.IndexConfigs) > 0) { 253 fmt.Fprintln(dockerCli.Out(), "Insecure Registries:") 254 for _, registry := range info.RegistryConfig.IndexConfigs { 255 if registry.Secure == false { 256 fmt.Fprintf(dockerCli.Out(), " %s\n", registry.Name) 257 } 258 } 259 260 for _, registry := range info.RegistryConfig.InsecureRegistryCIDRs { 261 mask, _ := registry.Mask.Size() 262 fmt.Fprintf(dockerCli.Out(), " %s/%d\n", registry.IP.String(), mask) 263 } 264 } 265 266 if info.RegistryConfig != nil && len(info.RegistryConfig.Mirrors) > 0 { 267 fmt.Fprintln(dockerCli.Out(), "Registry Mirrors:") 268 for _, mirror := range info.RegistryConfig.Mirrors { 269 fmt.Fprintf(dockerCli.Out(), " %s\n", mirror) 270 } 271 } 272 273 fmt.Fprintf(dockerCli.Out(), "Live Restore Enabled: %v\n", info.LiveRestoreEnabled) 274 275 return nil 276 } 277 278 func formatInfo(dockerCli *command.DockerCli, info types.Info, format string) error { 279 tmpl, err := templates.Parse(format) 280 if err != nil { 281 return cli.StatusError{StatusCode: 64, 282 Status: "Template parsing error: " + err.Error()} 283 } 284 err = tmpl.Execute(dockerCli.Out(), info) 285 dockerCli.Out().Write([]byte{'\n'}) 286 return err 287 }