Skip to content

Commit

Permalink
system: add new subcommand "migrate"
Browse files Browse the repository at this point in the history
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: containers#2935

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
  • Loading branch information
giuseppe committed Apr 26, 2019
1 parent b6e2cba commit 525f0b3
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 4 deletions.
4 changes: 4 additions & 0 deletions cmd/podman/cliconfig/config.go
Expand Up @@ -581,6 +581,10 @@ type SystemRenumberValues struct {
PodmanCommand
}

type SystemMigrateValues struct {
PodmanCommand
}

type SystemDfValues struct {
PodmanCommand
Verbose bool
Expand Down
1 change: 1 addition & 0 deletions cmd/podman/commands.go
Expand Up @@ -77,6 +77,7 @@ func getSystemSubCommands() []*cobra.Command {
_pruneSystemCommand,
_renumberCommand,
_dfSystemCommand,
_migrateCommand,
}
}

Expand Down
14 changes: 11 additions & 3 deletions cmd/podman/libpodruntime/runtime.go
Expand Up @@ -9,17 +9,22 @@ import (
"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
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
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{}
storageOpts := storage.StoreOptions{}
storageSet := false
Expand Down Expand Up @@ -63,6 +68,9 @@ func getRuntime(c *cliconfig.PodmanCommand, renumber bool) (*libpod.Runtime, err
storageSet = true
storageOpts.GraphDriverOptions = c.GlobalFlags.StorageOpts
}
if migrate {
options = append(options, libpod.WithMigrate())
}

if renumber {
options = append(options, libpod.WithRenumber())
Expand Down
2 changes: 1 addition & 1 deletion cmd/podman/main_local.go
Expand Up @@ -103,7 +103,7 @@ func profileOff(cmd *cobra.Command) 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
}
podmanCmd := cliconfig.PodmanCommand{
Expand Down
50 changes: 50 additions & 0 deletions cmd/podman/system_migrate.go
@@ -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
}
21 changes: 21 additions & 0 deletions docs/podman-system-migrate.1.md
@@ -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)
1 change: 1 addition & 0 deletions docs/podman-system.1.md
Expand Up @@ -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. |
| 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. |
| migrate | [podman-system-migrate(1)](podman-system-migrate.1.md)| Migrate existing containers to a new podman version. |

## SEE ALSO
podman(1)
16 changes: 16 additions & 0 deletions libpod/options.go
Expand Up @@ -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

// WithShmDir sets the directory that should be mounted on /dev/shm.
Expand Down
20 changes: 20 additions & 0 deletions libpod/runtime.go
Expand Up @@ -100,6 +100,8 @@ type Runtime struct {
// unused.
doRenumber bool

doMigrate bool

// valid indicates whether the runtime is ready to use.
// valid is set to true when a runtime is returned from GetRuntime(),
// and remains true until the runtime is shut down (rendering its
Expand Down Expand Up @@ -962,6 +964,24 @@ func makeRuntime(runtime *Runtime) (err error) {
// further
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
}

Expand Down
48 changes: 48 additions & 0 deletions libpod/runtime_migrate.go
@@ -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
}

0 comments on commit 525f0b3

Please sign in to comment.