From feba94eb95f93fd571efff039cb7d7cdb5139169 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Tue, 8 Oct 2019 14:12:58 -0400 Subject: Migrate can move containers to a new runtime This is a horrible hack to work around issues with Fedora 31, but other distros might need it to, so we'll move it upstream. I do not recommend this functionality for general use, and the manpages and other documentation will reflect this. But for some upgrade cases, it will be the only thing that allows for a working system. Signed-off-by: Matthew Heon --- cmd/podman/cliconfig/config.go | 1 + cmd/podman/libpodruntime/runtime.go | 17 ++++++++++------- cmd/podman/system_migrate.go | 4 +++- docs/podman-system-migrate.1.md | 8 ++++++++ libpod/options.go | 22 ++++++++++++++++++++++ libpod/runtime.go | 4 ++++ libpod/runtime_migrate.go | 26 +++++++++++++++++++++++++- 7 files changed, 73 insertions(+), 9 deletions(-) diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go index 5b5225f02..4831b7971 100644 --- a/cmd/podman/cliconfig/config.go +++ b/cmd/podman/cliconfig/config.go @@ -651,6 +651,7 @@ type SystemRenumberValues struct { type SystemMigrateValues struct { PodmanCommand + NewRuntime string } type SystemDfValues struct { diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go index 6dafeb0b0..dd8c3f173 100644 --- a/cmd/podman/libpodruntime/runtime.go +++ b/cmd/podman/libpodruntime/runtime.go @@ -14,31 +14,31 @@ import ( ) // GetRuntimeMigrate gets a libpod runtime that will perform a migration of existing containers -func GetRuntimeMigrate(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { - return getRuntime(ctx, c, false, true, false, true) +func GetRuntimeMigrate(ctx context.Context, c *cliconfig.PodmanCommand, newRuntime string) (*libpod.Runtime, error) { + return getRuntime(ctx, c, false, true, false, true, newRuntime) } // GetRuntimeDisableFDs gets a libpod runtime that will disable sd notify func GetRuntimeDisableFDs(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { - return getRuntime(ctx, c, false, false, false, false) + return getRuntime(ctx, c, false, false, false, false, "") } // GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber func GetRuntimeRenumber(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { - return getRuntime(ctx, c, true, false, false, true) + return getRuntime(ctx, c, true, false, false, true, "") } // GetRuntime generates a new libpod runtime configured by command line options func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { - return getRuntime(ctx, c, false, false, false, true) + return getRuntime(ctx, c, false, false, false, true, "") } // GetRuntimeNoStore generates a new libpod runtime configured by command line options func GetRuntimeNoStore(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { - return getRuntime(ctx, c, false, false, true, true) + return getRuntime(ctx, c, false, false, true, true, "") } -func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber, migrate, noStore, withFDS bool) (*libpod.Runtime, error) { +func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber, migrate, noStore, withFDS bool, newRuntime string) (*libpod.Runtime, error) { options := []libpod.RuntimeOption{} storageOpts := storage.StoreOptions{} storageSet := false @@ -88,6 +88,9 @@ func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber, migra } if migrate { options = append(options, libpod.WithMigrate()) + if newRuntime != "" { + options = append(options, libpod.WithMigrateRuntime(newRuntime)) + } } if renumber { diff --git a/cmd/podman/system_migrate.go b/cmd/podman/system_migrate.go index 4a0afcfad..9c90aeb52 100644 --- a/cmd/podman/system_migrate.go +++ b/cmd/podman/system_migrate.go @@ -32,13 +32,15 @@ func init() { migrateCommand.Command = _migrateCommand migrateCommand.SetHelpTemplate(HelpTemplate()) migrateCommand.SetUsageTemplate(UsageTemplate()) + flags := migrateCommand.Flags() + flags.StringVar(&migrateCommand.NewRuntime, "new-runtime", "", "Specify a new runtime for all containers") } func migrateCmd(c *cliconfig.SystemMigrateValues) error { // We need to pass one extra option to NewRuntime. // This will inform the OCI runtime to start a migrate. // That's controlled by the last argument to GetRuntime. - r, err := libpodruntime.GetRuntimeMigrate(getContext(), &c.PodmanCommand) + r, err := libpodruntime.GetRuntimeMigrate(getContext(), &c.PodmanCommand, c.NewRuntime) if err != nil { return errors.Wrapf(err, "error migrating containers") } diff --git a/docs/podman-system-migrate.1.md b/docs/podman-system-migrate.1.md index d175d0344..d5e3bcb95 100644 --- a/docs/podman-system-migrate.1.md +++ b/docs/podman-system-migrate.1.md @@ -24,6 +24,14 @@ pause process. The `/etc/subuid` and `/etc/subgid` files can then be edited or changed with usermod to recreate the user namespace with the newly configured mappings. +## OPTIONS + +**--new-runtime**=*runtime* + +Set a new OCI runtime for all containers. +This can be used after a system upgrade which changes the default OCI runtime to move all containers to the new runtime. +There are no guarantees that the containers will continue to work under the new runtime, as some runtimes support differing options and configurations. + ## SYNOPSIS **podman system migrate** diff --git a/libpod/options.go b/libpod/options.go index ee44439ac..ddc5993af 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -463,6 +463,28 @@ func WithMigrate() RuntimeOption { } } +// WithMigrateRuntime instructs Libpod to change the default OCI runtime on all +// containers during a migration. This is not used if `MigrateRuntime()` is not +// also passed. +// Libpod makes no promises that your containers continue to work with the new +// runtime - migrations between dissimilar runtimes may well break things. +// Use with caution. +func WithMigrateRuntime(requestedRuntime string) RuntimeOption { + return func(rt *Runtime) error { + if rt.valid { + return define.ErrRuntimeFinalized + } + + if requestedRuntime == "" { + return errors.Wrapf(define.ErrInvalidArg, "must provide a non-empty name for new runtime") + } + + rt.migrateRuntime = requestedRuntime + + return nil + } +} + // WithEventsLogger sets the events backend to use. // Currently supported values are "file" for file backend and "journald" for // journald backend. diff --git a/libpod/runtime.go b/libpod/runtime.go index cdb5670ba..53165b830 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -114,6 +114,10 @@ type Runtime struct { doRenumber bool doMigrate bool + // System migrate can move containers to a new runtime. + // We make no promises that these migrated containers work on the new + // runtime, though. + migrateRuntime string // valid indicates whether the runtime is ready to use. // valid is set to true when a runtime is returned from GetRuntime(), diff --git a/libpod/runtime_migrate.go b/libpod/runtime_migrate.go index c363991e6..d85652232 100644 --- a/libpod/runtime_migrate.go +++ b/libpod/runtime_migrate.go @@ -5,14 +5,15 @@ package libpod import ( "context" "fmt" - "github.com/containers/libpod/pkg/util" "io/ioutil" "os" "path/filepath" "strconv" "syscall" + "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/rootless" + "github.com/containers/libpod/pkg/util" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -63,11 +64,34 @@ func (r *Runtime) migrate(ctx context.Context) error { } } + // Did the user request a new runtime? + runtimeChangeRequested := r.migrateRuntime != "" + requestedRuntime, runtimeExists := r.ociRuntimes[r.migrateRuntime] + if !runtimeExists && runtimeChangeRequested { + return errors.Wrapf(define.ErrInvalidArg, "change to runtime %q requested but no such runtime is defined", r.migrateRuntime) + } + for _, ctr := range allCtrs { + needsWrite := false + + // Reset pause process location oldLocation := filepath.Join(ctr.state.RunDir, "conmon.pid") if ctr.config.ConmonPidFile == oldLocation { logrus.Infof("changing conmon PID file for %s", ctr.ID()) ctr.config.ConmonPidFile = filepath.Join(ctr.config.StaticDir, "conmon.pid") + needsWrite = true + } + + // Reset runtime + if runtimeChangeRequested { + logrus.Infof("Resetting container %s runtime to runtime %s", ctr.ID(), r.migrateRuntime) + ctr.config.OCIRuntime = r.migrateRuntime + ctr.ociRuntime = requestedRuntime + + needsWrite = true + } + + if needsWrite { if err := r.state.RewriteContainerConfig(ctr, ctr.config); err != nil { return errors.Wrapf(err, "error rewriting config for container %s", ctr.ID()) } -- cgit v1.2.3-54-g00ecf