checkpoint,restore,list: don't call fatal

There is a mix of styles when handling CLI commands. In most cases we
return an error, which is handled from app.Run in main.go (it calls
fatal if there is an error).

In a few cases, though, we call fatal(err) from random places.

Let's be consistent and always return an error. The only exception is
runc exec, which needs to exit with a particular exit code.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
Kir Kolyshkin
2022-02-10 18:52:08 -08:00
parent 36786c361a
commit eb2f08dc4e
3 changed files with 28 additions and 15 deletions

View File

@@ -60,16 +60,24 @@ checkpointed.`,
return err return err
} }
if status == libcontainer.Created || status == libcontainer.Stopped { if status == libcontainer.Created || status == libcontainer.Stopped {
fatal(fmt.Errorf("Container cannot be checkpointed in %s state", status.String())) return fmt.Errorf("Container cannot be checkpointed in %s state", status.String())
} }
options := criuOptions(context) options, err := criuOptions(context)
if err != nil {
return err
}
if !(options.LeaveRunning || options.PreDump) { if !(options.LeaveRunning || options.PreDump) {
// destroy container unless we tell CRIU to keep it // destroy container unless we tell CRIU to keep it
defer destroy(container) defer destroy(container)
} }
// these are the mandatory criu options for a container // these are the mandatory criu options for a container
setPageServer(context, options) if err := setPageServer(context, options); err != nil {
setManageCgroupsMode(context, options) return err
}
if err := setManageCgroupsMode(context, options); err != nil {
return err
}
if err := setEmptyNsMask(context, options); err != nil { if err := setEmptyNsMask(context, options); err != nil {
return err return err
} }
@@ -109,27 +117,28 @@ func prepareImagePaths(context *cli.Context) (string, string, error) {
return imagePath, parentPath, nil return imagePath, parentPath, nil
} }
func setPageServer(context *cli.Context, options *libcontainer.CriuOpts) { func setPageServer(context *cli.Context, options *libcontainer.CriuOpts) error {
// xxx following criu opts are optional // xxx following criu opts are optional
// The dump image can be sent to a criu page server // The dump image can be sent to a criu page server
if psOpt := context.String("page-server"); psOpt != "" { if psOpt := context.String("page-server"); psOpt != "" {
address, port, err := net.SplitHostPort(psOpt) address, port, err := net.SplitHostPort(psOpt)
if err != nil || address == "" || port == "" { if err != nil || address == "" || port == "" {
fatal(errors.New("Use --page-server ADDRESS:PORT to specify page server")) return errors.New("Use --page-server ADDRESS:PORT to specify page server")
} }
portInt, err := strconv.Atoi(port) portInt, err := strconv.Atoi(port)
if err != nil { if err != nil {
fatal(errors.New("Invalid port number")) return errors.New("Invalid port number")
} }
options.PageServer = libcontainer.CriuPageServerInfo{ options.PageServer = libcontainer.CriuPageServerInfo{
Address: address, Address: address,
Port: int32(portInt), Port: int32(portInt),
} }
} }
return nil
} }
func setManageCgroupsMode(context *cli.Context, options *libcontainer.CriuOpts) { func setManageCgroupsMode(context *cli.Context, options *libcontainer.CriuOpts) error {
if cgOpt := context.String("manage-cgroups-mode"); cgOpt != "" { if cgOpt := context.String("manage-cgroups-mode"); cgOpt != "" {
switch cgOpt { switch cgOpt {
case "soft": case "soft":
@@ -139,9 +148,10 @@ func setManageCgroupsMode(context *cli.Context, options *libcontainer.CriuOpts)
case "strict": case "strict":
options.ManageCgroupsMode = criu.CriuCgMode_STRICT options.ManageCgroupsMode = criu.CriuCgMode_STRICT
default: default:
fatal(errors.New("Invalid manage cgroups mode")) return errors.New("Invalid manage cgroups mode")
} }
} }
return nil
} }
var namespaceMapping = map[specs.LinuxNamespaceType]int{ var namespaceMapping = map[specs.LinuxNamespaceType]int{

View File

@@ -117,7 +117,7 @@ func getContainers(context *cli.Context) ([]containerState, error) {
root := context.GlobalString("root") root := context.GlobalString("root")
list, err := os.ReadDir(root) list, err := os.ReadDir(root)
if err != nil { if err != nil {
fatal(err) return nil, err
} }
var s []containerState var s []containerState
@@ -131,7 +131,7 @@ func getContainers(context *cli.Context) ([]containerState, error) {
// Possible race with runc delete. // Possible race with runc delete.
continue continue
} }
fatal(err) return nil, err
} }
// This cast is safe on Linux. // This cast is safe on Linux.
uid := st.Sys().(*syscall.Stat_t).Uid uid := st.Sys().(*syscall.Stat_t).Uid

View File

@@ -109,7 +109,10 @@ using the runc checkpoint command.`,
logrus.Warn("runc checkpoint is untested with rootless containers") logrus.Warn("runc checkpoint is untested with rootless containers")
} }
options := criuOptions(context) options, err := criuOptions(context)
if err != nil {
return err
}
if err := setEmptyNsMask(context, options); err != nil { if err := setEmptyNsMask(context, options); err != nil {
return err return err
} }
@@ -124,10 +127,10 @@ using the runc checkpoint command.`,
}, },
} }
func criuOptions(context *cli.Context) *libcontainer.CriuOpts { func criuOptions(context *cli.Context) (*libcontainer.CriuOpts, error) {
imagePath, parentPath, err := prepareImagePaths(context) imagePath, parentPath, err := prepareImagePaths(context)
if err != nil { if err != nil {
fatal(err) return nil, err
} }
return &libcontainer.CriuOpts{ return &libcontainer.CriuOpts{
@@ -145,5 +148,5 @@ func criuOptions(context *cli.Context) *libcontainer.CriuOpts {
StatusFd: context.Int("status-fd"), StatusFd: context.Int("status-fd"),
LsmProfile: context.String("lsm-profile"), LsmProfile: context.String("lsm-profile"),
LsmMountContext: context.String("lsm-mount-context"), LsmMountContext: context.String("lsm-mount-context"),
} }, nil
} }