github.com/containerd/nerdctl/v2@v2.0.0-beta.5.0.20240520001846-b5758f54fa28/pkg/cmd/system/info.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package system 18 19 import ( 20 "context" 21 "fmt" 22 "io" 23 "sort" 24 "strings" 25 "text/template" 26 27 "github.com/containerd/containerd" 28 "github.com/containerd/log" 29 "github.com/containerd/nerdctl/v2/pkg/api/types" 30 "golang.org/x/text/cases" 31 "golang.org/x/text/language" 32 33 "github.com/containerd/containerd/api/services/introspection/v1" 34 "github.com/containerd/nerdctl/v2/pkg/formatter" 35 "github.com/containerd/nerdctl/v2/pkg/infoutil" 36 "github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat" 37 "github.com/containerd/nerdctl/v2/pkg/inspecttypes/native" 38 "github.com/containerd/nerdctl/v2/pkg/rootlessutil" 39 "github.com/containerd/nerdctl/v2/pkg/strutil" 40 "github.com/docker/go-units" 41 ) 42 43 func Info(ctx context.Context, client *containerd.Client, options types.SystemInfoOptions) error { 44 var ( 45 tmpl *template.Template 46 err error 47 ) 48 if options.Format != "" { 49 tmpl, err = formatter.ParseTemplate(options.Format) 50 if err != nil { 51 return err 52 } 53 } 54 55 var ( 56 infoNative *native.Info 57 infoCompat *dockercompat.Info 58 ) 59 switch options.Mode { 60 case "native": 61 di, err := infoutil.NativeDaemonInfo(ctx, client) 62 if err != nil { 63 return err 64 } 65 infoNative, err = fulfillNativeInfo(di, options.GOptions) 66 if err != nil { 67 return err 68 } 69 case "dockercompat": 70 infoCompat, err = infoutil.Info(ctx, client, options.GOptions.Snapshotter, options.GOptions.CgroupManager) 71 if err != nil { 72 return err 73 } 74 default: 75 return fmt.Errorf("unknown mode %q", options.Mode) 76 } 77 78 if tmpl != nil { 79 var x interface{} = infoNative 80 if infoCompat != nil { 81 x = infoCompat 82 } 83 w := options.Stdout 84 if err := tmpl.Execute(w, x); err != nil { 85 return err 86 } 87 _, err = fmt.Fprintln(w) 88 return err 89 } 90 91 switch options.Mode { 92 case "native": 93 return prettyPrintInfoNative(options.Stdout, infoNative) 94 case "dockercompat": 95 return prettyPrintInfoDockerCompat(options.Stdout, options.Stderr, infoCompat, options.GOptions) 96 } 97 return nil 98 } 99 100 func fulfillNativeInfo(di *native.DaemonInfo, globalOptions types.GlobalCommandOptions) (*native.Info, error) { 101 info := &native.Info{ 102 Daemon: di, 103 } 104 info.Namespace = globalOptions.Namespace 105 info.Snapshotter = globalOptions.Snapshotter 106 info.CgroupManager = globalOptions.CgroupManager 107 info.Rootless = rootlessutil.IsRootless() 108 return info, nil 109 } 110 111 func prettyPrintInfoNative(w io.Writer, info *native.Info) error { 112 fmt.Fprintf(w, "Namespace: %s\n", info.Namespace) 113 fmt.Fprintf(w, "Snapshotter: %s\n", info.Snapshotter) 114 fmt.Fprintf(w, "Cgroup Manager: %s\n", info.CgroupManager) 115 fmt.Fprintf(w, "Rootless: %v\n", info.Rootless) 116 fmt.Fprintf(w, "containerd Version: %s (%s)\n", info.Daemon.Version.Version, info.Daemon.Version.Revision) 117 fmt.Fprintf(w, "containerd UUID: %s\n", info.Daemon.Server.UUID) 118 var disabledPlugins, enabledPlugins []*introspection.Plugin 119 for _, f := range info.Daemon.Plugins.Plugins { 120 if f.InitErr == nil { 121 enabledPlugins = append(enabledPlugins, f) 122 } else { 123 disabledPlugins = append(disabledPlugins, f) 124 } 125 } 126 sorter := func(x []*introspection.Plugin) func(int, int) bool { 127 return func(i, j int) bool { 128 return x[i].Type+"."+x[i].ID < x[j].Type+"."+x[j].ID 129 } 130 } 131 sort.Slice(enabledPlugins, sorter(enabledPlugins)) 132 sort.Slice(disabledPlugins, sorter(disabledPlugins)) 133 fmt.Fprintln(w, "containerd Plugins:") 134 for _, f := range enabledPlugins { 135 fmt.Fprintf(w, " - %s.%s\n", f.Type, f.ID) 136 } 137 fmt.Fprintf(w, "containerd Plugins (disabled):\n") 138 for _, f := range disabledPlugins { 139 fmt.Fprintf(w, " - %s.%s\n", f.Type, f.ID) 140 } 141 return nil 142 } 143 144 func prettyPrintInfoDockerCompat(stdout io.Writer, stderr io.Writer, info *dockercompat.Info, globalOptions types.GlobalCommandOptions) error { 145 w := stdout 146 debug := globalOptions.Debug 147 fmt.Fprintf(w, "Client:\n") 148 fmt.Fprintf(w, " Namespace:\t%s\n", globalOptions.Namespace) 149 fmt.Fprintf(w, " Debug Mode:\t%v\n", debug) 150 fmt.Fprintln(w) 151 fmt.Fprintf(w, "Server:\n") 152 fmt.Fprintf(w, " Server Version: %s\n", info.ServerVersion) 153 // Storage Driver is not really Server concept for nerdctl, but mimics `docker info` output 154 fmt.Fprintf(w, " Storage Driver: %s\n", info.Driver) 155 fmt.Fprintf(w, " Logging Driver: %s\n", info.LoggingDriver) 156 fmt.Fprintf(w, " Cgroup Driver: %s\n", info.CgroupDriver) 157 fmt.Fprintf(w, " Cgroup Version: %s\n", info.CgroupVersion) 158 fmt.Fprintf(w, " Plugins:\n") 159 fmt.Fprintf(w, " Log: %s\n", strings.Join(info.Plugins.Log, " ")) 160 fmt.Fprintf(w, " Storage: %s\n", strings.Join(info.Plugins.Storage, " ")) 161 fmt.Fprintf(w, " Security Options:\n") 162 for _, s := range info.SecurityOptions { 163 m, err := strutil.ParseCSVMap(s) 164 if err != nil { 165 log.L.WithError(err).Warnf("unparsable security option %q", s) 166 continue 167 } 168 name := m["name"] 169 if name == "" { 170 log.L.Warnf("unparsable security option %q", s) 171 continue 172 } 173 fmt.Fprintf(w, " %s\n", name) 174 for k, v := range m { 175 if k == "name" { 176 continue 177 } 178 fmt.Fprintf(w, " %s: %s\n", cases.Title(language.English).String(k), v) 179 } 180 } 181 fmt.Fprintf(w, " Kernel Version: %s\n", info.KernelVersion) 182 fmt.Fprintf(w, " Operating System: %s\n", info.OperatingSystem) 183 fmt.Fprintf(w, " OSType: %s\n", info.OSType) 184 fmt.Fprintf(w, " Architecture: %s\n", info.Architecture) 185 fmt.Fprintf(w, " CPUs: %d\n", info.NCPU) 186 fmt.Fprintf(w, " Total Memory: %s\n", units.BytesSize(float64(info.MemTotal))) 187 fmt.Fprintf(w, " Name: %s\n", info.Name) 188 fmt.Fprintf(w, " ID: %s\n", info.ID) 189 190 fmt.Fprintln(w) 191 if len(info.Warnings) > 0 { 192 fmt.Fprintln(stderr, strings.Join(info.Warnings, "\n")) 193 } 194 return nil 195 }