mirror of https://github.com/containers/podman.git
system: add new subcommand "migrate"
it is useful to migrate existing containers to a new version of podman. Currently, it is needed to migrate rootless containers that were created with podman <= 1.2 to a newer version which requires all containers to be running in the same user namespace. Closes: https://github.com/containers/libpod/issues/2935 Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
parent
b6e2cbad0a
commit
525f0b30ac
|
@ -581,6 +581,10 @@ type SystemRenumberValues struct {
|
||||||
PodmanCommand
|
PodmanCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SystemMigrateValues struct {
|
||||||
|
PodmanCommand
|
||||||
|
}
|
||||||
|
|
||||||
type SystemDfValues struct {
|
type SystemDfValues struct {
|
||||||
PodmanCommand
|
PodmanCommand
|
||||||
Verbose bool
|
Verbose bool
|
||||||
|
|
|
@ -77,6 +77,7 @@ func getSystemSubCommands() []*cobra.Command {
|
||||||
_pruneSystemCommand,
|
_pruneSystemCommand,
|
||||||
_renumberCommand,
|
_renumberCommand,
|
||||||
_dfSystemCommand,
|
_dfSystemCommand,
|
||||||
|
_migrateCommand,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,17 +9,22 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GetRuntimeMigrate gets a libpod runtime that will perform a migration of existing containers
|
||||||
|
func GetRuntimeMigrate(c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
|
||||||
|
return getRuntime(c, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
// GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber
|
// GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber
|
||||||
func GetRuntimeRenumber(c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
|
func GetRuntimeRenumber(c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
|
||||||
return getRuntime(c, true)
|
return getRuntime(c, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRuntime generates a new libpod runtime configured by command line options
|
// GetRuntime generates a new libpod runtime configured by command line options
|
||||||
func GetRuntime(c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
|
func GetRuntime(c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
|
||||||
return getRuntime(c, false)
|
return getRuntime(c, false, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRuntime(c *cliconfig.PodmanCommand, renumber bool) (*libpod.Runtime, error) {
|
func getRuntime(c *cliconfig.PodmanCommand, renumber bool, migrate bool) (*libpod.Runtime, error) {
|
||||||
options := []libpod.RuntimeOption{}
|
options := []libpod.RuntimeOption{}
|
||||||
storageOpts := storage.StoreOptions{}
|
storageOpts := storage.StoreOptions{}
|
||||||
storageSet := false
|
storageSet := false
|
||||||
|
@ -63,6 +68,9 @@ func getRuntime(c *cliconfig.PodmanCommand, renumber bool) (*libpod.Runtime, err
|
||||||
storageSet = true
|
storageSet = true
|
||||||
storageOpts.GraphDriverOptions = c.GlobalFlags.StorageOpts
|
storageOpts.GraphDriverOptions = c.GlobalFlags.StorageOpts
|
||||||
}
|
}
|
||||||
|
if migrate {
|
||||||
|
options = append(options, libpod.WithMigrate())
|
||||||
|
}
|
||||||
|
|
||||||
if renumber {
|
if renumber {
|
||||||
options = append(options, libpod.WithRenumber())
|
options = append(options, libpod.WithRenumber())
|
||||||
|
|
|
@ -103,7 +103,7 @@ func profileOff(cmd *cobra.Command) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupRootless(cmd *cobra.Command, args []string) error {
|
func setupRootless(cmd *cobra.Command, args []string) error {
|
||||||
if os.Geteuid() == 0 || cmd == _searchCommand || cmd == _versionCommand || cmd == _mountCommand || strings.HasPrefix(cmd.Use, "help") {
|
if os.Geteuid() == 0 || cmd == _searchCommand || cmd == _versionCommand || cmd == _mountCommand || cmd == _migrateCommand || strings.HasPrefix(cmd.Use, "help") {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
podmanCmd := cliconfig.PodmanCommand{
|
podmanCmd := cliconfig.PodmanCommand{
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/containers/libpod/cmd/podman/cliconfig"
|
||||||
|
"github.com/containers/libpod/cmd/podman/libpodruntime"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
migrateCommand cliconfig.SystemMigrateValues
|
||||||
|
migrateDescription = `
|
||||||
|
podman system migrate
|
||||||
|
|
||||||
|
Migrate existing containers to a new version of Podman.
|
||||||
|
`
|
||||||
|
|
||||||
|
_migrateCommand = &cobra.Command{
|
||||||
|
Use: "migrate",
|
||||||
|
Args: noSubArgs,
|
||||||
|
Short: "Migrate containers",
|
||||||
|
Long: migrateDescription,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
migrateCommand.InputArgs = args
|
||||||
|
migrateCommand.GlobalFlags = MainGlobalOpts
|
||||||
|
return migrateCmd(&migrateCommand)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
migrateCommand.Command = _migrateCommand
|
||||||
|
migrateCommand.SetHelpTemplate(HelpTemplate())
|
||||||
|
migrateCommand.SetUsageTemplate(UsageTemplate())
|
||||||
|
}
|
||||||
|
|
||||||
|
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(&c.PodmanCommand)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error migrating containers")
|
||||||
|
}
|
||||||
|
if err := r.Shutdown(false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
% podman-system-migrate(1) podman
|
||||||
|
|
||||||
|
## NAME
|
||||||
|
podman\-system\-migrate - Migrate container to the latest version of podman
|
||||||
|
|
||||||
|
## SYNOPSIS
|
||||||
|
** podman system migrate**
|
||||||
|
|
||||||
|
## DESCRIPTION
|
||||||
|
** podman system migrate** migrates containers to the latest podman version.
|
||||||
|
|
||||||
|
**podman system migrate** takes care of migrating existing containers to the latest version of podman if any change is necessary.
|
||||||
|
|
||||||
|
## SYNOPSIS
|
||||||
|
**podman system migrate**
|
||||||
|
|
||||||
|
## SEE ALSO
|
||||||
|
`podman(1)`, `libpod.conf(5)`
|
||||||
|
|
||||||
|
# HISTORY
|
||||||
|
April 2019, Originally compiled by Giuseppe Scrivano (gscrivan at redhat dot com)
|
|
@ -17,6 +17,7 @@ The system command allows you to manage the podman systems
|
||||||
| info | [podman-system-info(1)](podman-info.1.md) | Displays Podman related system information. |
|
| info | [podman-system-info(1)](podman-info.1.md) | Displays Podman related system information. |
|
||||||
| prune | [podman-system-prune(1)](podman-system-prune.1.md) | Remove all unused data |
|
| prune | [podman-system-prune(1)](podman-system-prune.1.md) | Remove all unused data |
|
||||||
| renumber | [podman-system-renumber(1)](podman-system-renumber.1.md)| Migrate lock numbers to handle a change in maximum number of locks. |
|
| renumber | [podman-system-renumber(1)](podman-system-renumber.1.md)| Migrate lock numbers to handle a change in maximum number of locks. |
|
||||||
|
| migrate | [podman-system-migrate(1)](podman-system-migrate.1.md)| Migrate existing containers to a new podman version. |
|
||||||
|
|
||||||
## SEE ALSO
|
## SEE ALSO
|
||||||
podman(1)
|
podman(1)
|
||||||
|
|
|
@ -436,6 +436,22 @@ func WithRenumber() RuntimeOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMigrate instructs libpod to perform a lock migrateing while
|
||||||
|
// initializing. This will handle migrations from early versions of libpod with
|
||||||
|
// file locks to newer versions with SHM locking, as well as changes in the
|
||||||
|
// number of configured locks.
|
||||||
|
func WithMigrate() RuntimeOption {
|
||||||
|
return func(rt *Runtime) error {
|
||||||
|
if rt.valid {
|
||||||
|
return ErrRuntimeFinalized
|
||||||
|
}
|
||||||
|
|
||||||
|
rt.doMigrate = true
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Container Creation Options
|
// Container Creation Options
|
||||||
|
|
||||||
// WithShmDir sets the directory that should be mounted on /dev/shm.
|
// WithShmDir sets the directory that should be mounted on /dev/shm.
|
||||||
|
|
|
@ -100,6 +100,8 @@ type Runtime struct {
|
||||||
// unused.
|
// unused.
|
||||||
doRenumber bool
|
doRenumber bool
|
||||||
|
|
||||||
|
doMigrate bool
|
||||||
|
|
||||||
// valid indicates whether the runtime is ready to use.
|
// valid indicates whether the runtime is ready to use.
|
||||||
// valid is set to true when a runtime is returned from GetRuntime(),
|
// valid is set to true when a runtime is returned from GetRuntime(),
|
||||||
// and remains true until the runtime is shut down (rendering its
|
// and remains true until the runtime is shut down (rendering its
|
||||||
|
@ -962,6 +964,24 @@ func makeRuntime(runtime *Runtime) (err error) {
|
||||||
// further
|
// further
|
||||||
runtime.valid = true
|
runtime.valid = true
|
||||||
|
|
||||||
|
if runtime.doMigrate {
|
||||||
|
if os.Geteuid() != 0 {
|
||||||
|
aliveLock.Unlock()
|
||||||
|
locked = false
|
||||||
|
|
||||||
|
became, ret, err := rootless.BecomeRootInUserNS()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if became {
|
||||||
|
os.Exit(ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := runtime.migrate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package libpod
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *Runtime) migrate() error {
|
||||||
|
runningContainers, err := r.GetRunningContainers()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
allCtrs, err := r.state.AllContainers()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Infof("stopping all containers")
|
||||||
|
for _, ctr := range runningContainers {
|
||||||
|
logrus.Infof("stopping %s", ctr.ID())
|
||||||
|
if err := ctr.Stop(); err != nil {
|
||||||
|
return errors.Wrapf(err, "cannot stop container %s", ctr.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ctr := range allCtrs {
|
||||||
|
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")
|
||||||
|
if err := r.state.RewriteContainerConfig(ctr, ctr.config); err != nil {
|
||||||
|
return errors.Wrapf(err, "error rewriting config for container %s", ctr.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ctr := range runningContainers {
|
||||||
|
if err := ctr.Start(context.Background(), true); err != nil {
|
||||||
|
logrus.Errorf("error restarting container %s", ctr.ID())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue