gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/runsc/cmd/list.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package cmd 16 17 import ( 18 "context" 19 "encoding/json" 20 "fmt" 21 "io" 22 "os" 23 "text/tabwriter" 24 "time" 25 26 "github.com/google/subcommands" 27 specs "github.com/opencontainers/runtime-spec/specs-go" 28 "gvisor.dev/gvisor/pkg/log" 29 "gvisor.dev/gvisor/runsc/cmd/util" 30 "gvisor.dev/gvisor/runsc/config" 31 "gvisor.dev/gvisor/runsc/container" 32 "gvisor.dev/gvisor/runsc/flag" 33 ) 34 35 // List implements subcommands.Command for the "list" command. 36 type List struct { 37 quiet bool 38 format string 39 sandbox bool 40 } 41 42 // Name implements subcommands.command.name. 43 func (*List) Name() string { 44 return "list" 45 } 46 47 // Synopsis implements subcommands.Command.Synopsis. 48 func (*List) Synopsis() string { 49 return "list containers started by runsc with the given root" 50 } 51 52 // Usage implements subcommands.Command.Usage. 53 func (*List) Usage() string { 54 return `list [flags]` 55 } 56 57 // SetFlags implements subcommands.Command.SetFlags. 58 func (l *List) SetFlags(f *flag.FlagSet) { 59 f.BoolVar(&l.quiet, "quiet", false, "only list container ids") 60 f.StringVar(&l.format, "format", "text", "output format: 'text' (default) or 'json'") 61 f.BoolVar(&l.sandbox, "sandbox", false, "limit output to sandboxes only") 62 } 63 64 // Execute implements subcommands.Command.Execute. 65 func (l *List) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcommands.ExitStatus { 66 if f.NArg() != 0 { 67 f.Usage() 68 return subcommands.ExitUsageError 69 } 70 71 conf := args[0].(*config.Config) 72 73 if err := l.execute(conf.RootDir, os.Stdout); err != nil { 74 util.Fatalf("%v", err) 75 } 76 return subcommands.ExitSuccess 77 } 78 79 func (l *List) execute(rootDir string, out io.Writer) error { 80 var ids []container.FullID 81 var err error 82 if l.sandbox { 83 ids, err = container.ListSandboxes(rootDir) 84 } else { 85 ids, err = container.List(rootDir) 86 } 87 if err != nil { 88 return err 89 } 90 91 if l.quiet { 92 for _, id := range ids { 93 fmt.Fprintln(out, id.ContainerID) 94 } 95 return nil 96 } 97 98 // Collect the containers. 99 var containers []*container.Container 100 for _, id := range ids { 101 c, err := container.Load(rootDir, id, container.LoadOpts{Exact: true}) 102 if err != nil { 103 log.Warningf("Skipping container %q: %v", id, err) 104 continue 105 } 106 containers = append(containers, c) 107 } 108 109 switch l.format { 110 case "text": 111 // Print a nice table. 112 w := tabwriter.NewWriter(out, 12, 1, 3, ' ', 0) 113 fmt.Fprint(w, "ID\tPID\tSTATUS\tBUNDLE\tCREATED\tOWNER\n") 114 for _, c := range containers { 115 fmt.Fprintf(w, "%s\t%d\t%s\t%s\t%s\t%s\n", 116 c.ID, 117 c.SandboxPid(), 118 c.Status, 119 c.BundleDir, 120 c.CreatedAt.Format(time.RFC3339Nano), 121 c.Owner) 122 } 123 _ = w.Flush() 124 case "json": 125 // Print just the states. 126 var states []specs.State 127 for _, c := range containers { 128 states = append(states, c.State()) 129 } 130 if err := json.NewEncoder(out).Encode(states); err != nil { 131 return fmt.Errorf("marshaling container state: %w", err) 132 } 133 default: 134 return fmt.Errorf("unknown list format %q", l.format) 135 } 136 return nil 137 }