Skip to content

Commit 093c680

Browse files
nixprimegvisor-bot
authored andcommitted
runsc: implement -h and -help flags
This is consistent with runc; see containers/podman#27528. Before this change: ``` $ ./runsc --help Usage of ./runsc: $ echo $? 2 $ ./runsc ps --help <container-id> [ps options] -format="table": output format. Select one of: table or json (default: table) $ echo $? 2 ``` After this change: ``` $ ./runsc --help Usage: runsc <flags> <subcommand> <subcommand args> runsc is the gVisor container runtime. Functionality is provided by subcommands. For help with a specific subcommand, use "runsc help <subcommand>". Subcommands: checkpoint checkpoint current state of container (experimental) create create a secure container delete delete resources held by a container do Simplistic way to execute a command inside the sandbox. It's to be used for testing only. events display container events such as OOM notifications, cpu, memory, and IO usage statistics exec execute new process inside the container flags describe all known top-level flags help Print help documentation. kill sends a signal to the container list list containers started by runsc with the given root pause pause suspends all processes in a container port-forward port forward to a secure container ps ps displays the processes running inside a container restore restore a saved state of container (experimental) resume Resume unpauses a paused container run create and run a secure container spec create a new OCI bundle specification file start start a secure container state get the state of a container tar creates tar archives from container filesystems wait wait on a process inside a container Subcommands for debug: debug shows a variety of debug information read-control read a cgroups control value inside the container statefile shows information about a statefile symbolize Convert synthetic instruction pointers from kcov into positions in the runsc source code. Only used when Go coverage is enabled. usage Usage shows application memory usage across various categories in bytes. write-control write a cgroups control value inside the container Subcommands for helpers: cpu-features list CPU features supported on current machine install adds a runtime to docker daemon configuration mitigate mitigate mitigates the underlying system against side channel attacks nvproxy shows information about nvproxy support trace manages trace sessions for a given sandbox uninstall removes a runtime from docker daemon configuration Subcommands for internal use only: boot launch a sandbox process gofer launch a gofer process that proxies access to container files umount umount the specified directory lazily when one byte is read from sync-fd Subcommands for metrics: export-metrics export metric data for the sandbox metric-metadata export metric metadata of metrics registered in this build, in text proto format metric-server implements Prometheus metrics HTTP endpoint Additional help topics (Use "runsc help <topic>" to see help on the topic): platforms Print a list of available platforms. syscalls Print compatibility information for syscalls. Use "runsc flags" for a list of top-level flags $ echo $? 0 $ ./runsc ps --help <container-id> [ps options] -format="table": output format. Select one of: table or json (default: table) -h=false: equivalent to the 'help' flag -help=false: show this message and exit $ echo $? 0 ``` PiperOrigin-RevId: 836395969
1 parent bcd588a commit 093c680

File tree

7 files changed

+89
-29
lines changed

7 files changed

+89
-29
lines changed

runsc/cli/BUILD

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ package(
77

88
go_library(
99
name = "cli",
10-
srcs = ["cli.go"],
10+
srcs = [
11+
"cli.go",
12+
"help.go",
13+
],
1114
visibility = [
1215
"//runsc:__subpackages__",
1316
],

runsc/cli/cli.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,21 @@ var (
5858
// Run runs the binary, whose behavior is determined by the subcommand passed
5959
// on the command line. forEachCmd invokes the passed callback for each
6060
// supported subcommand.
61-
func Run(forEachCmd func(cb func(cmd subcommands.Command, group string))) {
61+
func Run(forEachCmd func(cb func(cmd subcommands.Command, group string), help *Help)) {
6262
// Set the start time as soon as possible.
6363
startTime := starttime.Get()
6464

65+
// Help flags, and help and flags commands, are generated automatically.
66+
flagHelp := flag.Bool("help", false, "show information about runsc subcommands and exit")
67+
flag.BoolVar(flagHelp, "h", false, "equivalent to the 'help' flag")
68+
help := NewHelp(subcommands.DefaultCommander)
69+
subcommands.Register(help, "")
70+
subcommands.Register(subcommands.FlagsCommand(), "")
71+
6572
// Register all commands.
66-
forEachCmd(subcommands.Register)
73+
forEachCmd(func(cmd subcommands.Command, group string) {
74+
subcommands.Register(&helpCommandWrapper{wrapped: cmd}, group)
75+
}, help)
6776

6877
// Register with the main command line.
6978
config.RegisterFlags(flag.CommandLine)
@@ -76,6 +85,12 @@ func Run(forEachCmd func(cb func(cmd subcommands.Command, group string))) {
7685
// All subcommands must be registered before flag parsing.
7786
flag.Parse()
7887

88+
// Are we showing help?
89+
if *flagHelp {
90+
help.printTopLevelHelp()
91+
os.Exit(0)
92+
}
93+
7994
// Are we showing the version?
8095
if flag.Get(flag.Lookup(versionFlagName).Value).(bool) {
8196
// The format here is the same as runc.

runsc/cmd/help.go renamed to runsc/cli/help.go

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package cmd
15+
package cli
1616

1717
import (
1818
"context"
@@ -64,22 +64,7 @@ func (h *Help) SetFlags(*flag.FlagSet) {}
6464
func (h *Help) Execute(ctx context.Context, f *flag.FlagSet, args ...any) subcommands.ExitStatus {
6565
switch f.NArg() {
6666
case 0:
67-
fmt.Fprintf(h.cdr.Output, "Usage: %s <flags> <subcommand> <subcommand args>\n\n", h.cdr.Name())
68-
fmt.Fprintf(h.cdr.Output, `runsc is the gVisor container runtime.
69-
70-
Functionality is provided by subcommands. For help with a specific subcommand,
71-
use "%s %s <subcommand>".
72-
73-
`, h.cdr.Name(), h.Name())
74-
h.cdr.VisitGroups(func(g *subcommands.CommandGroup) {
75-
h.cdr.ExplainGroup(h.cdr.Output, g)
76-
})
77-
78-
fmt.Fprintf(h.cdr.Output, "Additional help topics (Use \"%s %s <topic>\" to see help on the topic):\n", h.cdr.Name(), h.Name())
79-
for _, cmd := range h.commands {
80-
fmt.Fprintf(h.cdr.Output, "\t%-15s %s\n", cmd.Name(), cmd.Synopsis())
81-
}
82-
fmt.Fprintf(h.cdr.Output, "\nUse \"%s flags\" for a list of top-level flags\n", h.cdr.Name())
67+
h.printTopLevelHelp()
8368
return subcommands.ExitSuccess
8469
default:
8570
// Look for commands registered to the commander and print help explanation if found.
@@ -114,7 +99,64 @@ use "%s %s <subcommand>".
11499
return subcommands.ExitUsageError
115100
}
116101

102+
func (h *Help) printTopLevelHelp() {
103+
fmt.Fprintf(h.cdr.Output, "Usage: %s <flags> <subcommand> <subcommand args>\n\n", h.cdr.Name())
104+
fmt.Fprintf(h.cdr.Output, `runsc is the gVisor container runtime.
105+
106+
Functionality is provided by subcommands. For help with a specific subcommand,
107+
use "%s %s <subcommand>".
108+
109+
`, h.cdr.Name(), h.Name())
110+
h.cdr.VisitGroups(func(g *subcommands.CommandGroup) {
111+
h.cdr.ExplainGroup(h.cdr.Output, g)
112+
})
113+
114+
fmt.Fprintf(h.cdr.Output, "Additional help topics (Use \"%s %s <topic>\" to see help on the topic):\n", h.cdr.Name(), h.Name())
115+
for _, cmd := range h.commands {
116+
fmt.Fprintf(h.cdr.Output, "\t%-15s %s\n", cmd.Name(), cmd.Synopsis())
117+
}
118+
fmt.Fprintf(h.cdr.Output, "\nUse \"%s flags\" for a list of top-level flags\n", h.cdr.Name())
119+
}
120+
117121
// Register registers a new help command.
118122
func (h *Help) Register(cmd subcommands.Command) {
119123
h.commands = append(h.commands, cmd)
120124
}
125+
126+
// helpCommandWrapper implements subcommands.Command by wrapping another
127+
// subcommands.Command and adding -h and -help flags.
128+
type helpCommandWrapper struct {
129+
wrapped subcommands.Command
130+
help bool
131+
}
132+
133+
// Name implements subcommands.Command.Name.
134+
func (h *helpCommandWrapper) Name() string {
135+
return h.wrapped.Name()
136+
}
137+
138+
// Synopsis implements subcommands.Command.Synopsis.
139+
func (h *helpCommandWrapper) Synopsis() string {
140+
return h.wrapped.Synopsis()
141+
}
142+
143+
// Usage implements subcommands.Command.Usage.
144+
func (h *helpCommandWrapper) Usage() string {
145+
return h.wrapped.Usage()
146+
}
147+
148+
// SetFlags implements subcommands.Command.SetFlags.
149+
func (h *helpCommandWrapper) SetFlags(f *flag.FlagSet) {
150+
f.BoolVar(&h.help, "help", false, "show this message and exit")
151+
f.BoolVar(&h.help, "h", false, "equivalent to the 'help' flag")
152+
h.wrapped.SetFlags(f)
153+
}
154+
155+
// Execute implements subcommands.Command.Execute.
156+
func (h *helpCommandWrapper) Execute(ctx context.Context, f *flag.FlagSet, args ...any) subcommands.ExitStatus {
157+
if h.help {
158+
f.Usage()
159+
return subcommands.ExitSuccess
160+
}
161+
return h.wrapped.Execute(ctx, f, args...)
162+
}

runsc/cli/maincli/maincli.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ func Main() {
2929
}
3030

3131
// forEachCmd invokes the passed callback for each command supported by runsc.
32-
func forEachCmd(cb func(cmd subcommands.Command, group string)) {
33-
// Help and flags commands are generated automatically.
34-
help := cmd.NewHelp(subcommands.DefaultCommander)
35-
help.Register(new(cmd.Platforms))
36-
help.Register(new(cmd.Syscalls))
37-
cb(help, "")
38-
cb(subcommands.FlagsCommand(), "")
32+
func forEachCmd(cb func(cmd subcommands.Command, group string), help *cli.Help) {
33+
if help != nil {
34+
// For historical reasons, these subcommands are invoked as `runsc help
35+
// platforms` and `runsc help syscalls`.
36+
help.Register(new(cmd.Platforms))
37+
help.Register(new(cmd.Syscalls))
38+
}
3939

4040
// Register OCI user-facing runsc commands.
4141
cb(new(cmd.Checkpoint), "")

runsc/cli/maincli/maincli_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func TestFlagSetIdempotent(t *testing.T) {
6666
} else {
6767
cmds[group] = []subcommands.Command{cmd}
6868
}
69-
})
69+
}, nil)
7070

7171
for group, cmdList := range cmds {
7272
t.Run(group, func(t *testing.T) {

runsc/cmd/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ go_library(
4949
"exec.go",
5050
"fd_mapping.go",
5151
"gofer.go",
52-
"help.go",
5352
"install.go",
5453
"kill.go",
5554
"list.go",

runsc/flag/flag.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type Flag = flag.Flag
3131
// Aliases for flag functions.
3232
var (
3333
Bool = flag.Bool
34+
BoolVar = flag.BoolVar
3435
CommandLine = flag.CommandLine
3536
Duration = flag.Duration
3637
Float64 = flag.Float64

0 commit comments

Comments
 (0)