diff options
author | cdoern <cdoern@redhat.com> | 2022-01-14 13:49:34 -0500 |
---|---|---|
committer | cdoern <cdoern@redhat.com> | 2022-02-20 21:11:14 -0500 |
commit | 94df7015121759ce69f35f7e7735aa2e4a2dc71a (patch) | |
tree | 154e04dc3073acc57cecedfc703e6c1c4daf4bf1 /pkg/domain/infra | |
parent | f918a9418f5eeb00b289c127142953da2c394867 (diff) | |
download | podman-94df7015121759ce69f35f7e7735aa2e4a2dc71a.tar.gz podman-94df7015121759ce69f35f7e7735aa2e4a2dc71a.tar.bz2 podman-94df7015121759ce69f35f7e7735aa2e4a2dc71a.zip |
Implement Podman Container Clone
podman container clone takes the id of an existing continer and creates a specgen from the given container's config
recreating all proper namespaces and overriding spec options like resource limits and the container name if given in the cli options
this command utilizes the common function DefineCreateFlags meaning that we can funnel as many create options as we want
into clone over time allowing the user to clone with as much or as little of the original config as they want.
container clone takes a second argument which is a new name and a third argument which is an image name to use instead of the original container's
the current supported flags are:
--destroy (remove the original container)
--name (new ctr name)
--cpus (sets cpu period and quota)
--cpuset-cpus
--cpu-period
--cpu-rt-period
--cpu-rt-runtime
--cpu-shares
--cpuset-mems
--memory
--run
resolves #10875
Signed-off-by: cdoern <cdoern@redhat.com>
Signed-off-by: cdoern <cbdoer23@g.holycross.edu>
Signed-off-by: cdoern <cdoern@redhat.com>
Diffstat (limited to 'pkg/domain/infra')
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 91 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 4 |
3 files changed, 95 insertions, 4 deletions
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index a5c4647d7..92f5b1a80 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "os" "strconv" + "strings" "sync" "time" @@ -648,7 +649,7 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG for _, w := range warn { fmt.Fprintf(os.Stderr, "%s\n", w) } - rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), ic.Libpod, s) + rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), ic.Libpod, s, false, nil) if err != nil { return nil, err } @@ -971,7 +972,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta fmt.Fprintf(os.Stderr, "%s\n", w) } - rtSpec, spec, optsN, err := generate.MakeContainer(ctx, ic.Libpod, opts.Spec) + rtSpec, spec, optsN, err := generate.MakeContainer(ctx, ic.Libpod, opts.Spec, false, nil) if err != nil { return nil, err } @@ -1490,3 +1491,89 @@ func (ic *ContainerEngine) ContainerRename(ctx context.Context, nameOrID string, return nil } + +func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts entities.ContainerCloneOptions) (*entities.ContainerCreateReport, error) { + spec := specgen.NewSpecGenerator(ctrCloneOpts.Image, ctrCloneOpts.CreateOpts.RootFS) + var c *libpod.Container + c, err := generate.ConfigToSpec(ic.Libpod, spec, ctrCloneOpts.ID) + if err != nil { + return nil, err + } + + err = specgenutil.FillOutSpecGen(spec, &ctrCloneOpts.CreateOpts, []string{}) + if err != nil { + return nil, err + } + out, err := generate.CompleteSpec(ctx, ic.Libpod, spec) + if err != nil { + return nil, err + } + + // Print warnings + if len(out) > 0 { + for _, w := range out { + fmt.Println("Could not properly complete the spec as expected:") + fmt.Fprintf(os.Stderr, "%s\n", w) + } + } + + if len(ctrCloneOpts.CreateOpts.Name) > 0 { + spec.Name = ctrCloneOpts.CreateOpts.Name + } else { + n := c.Name() + _, err := ic.Libpod.LookupContainer(c.Name() + "-clone") + if err == nil { + n += "-clone" + } + switch { + case strings.Contains(n, "-clone"): + ind := strings.Index(n, "-clone") + 6 + num, _ := strconv.Atoi(n[ind:]) + if num == 0 { // clone1 is hard to get with this logic, just check for it here. + _, err = ic.Libpod.LookupContainer(n + "1") + if err != nil { + spec.Name = n + "1" + break + } + } else { + n = n[0:ind] + } + err = nil + count := num + for err == nil { + count++ + tempN := n + strconv.Itoa(count) + _, err = ic.Libpod.LookupContainer(tempN) + } + n += strconv.Itoa(count) + spec.Name = n + default: + spec.Name = c.Name() + "-clone" + } + } + + rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), ic.Libpod, spec, true, c) + if err != nil { + return nil, err + } + ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...) + if err != nil { + return nil, err + } + + if ctrCloneOpts.Destroy { + var time *uint + err := ic.Libpod.RemoveContainer(context.Background(), c, false, false, time) + if err != nil { + return nil, err + } + } + + if ctrCloneOpts.Run { + if err := ctr.Start(ctx, true); err != nil { + return nil, err + } + } + + return &entities.ContainerCreateReport{Id: ctr.ID()}, nil +} diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index cad8c4609..25e8f8556 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -392,7 +392,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if err != nil { return nil, err } - rtSpec, spec, opts, err := generate.MakeContainer(ctx, ic.Libpod, specGen) + rtSpec, spec, opts, err := generate.MakeContainer(ctx, ic.Libpod, specGen, false, nil) if err != nil { return nil, err } @@ -435,7 +435,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if err != nil { return nil, err } - rtSpec, spec, opts, err := generate.MakeContainer(ctx, ic.Libpod, specGen) + rtSpec, spec, opts, err := generate.MakeContainer(ctx, ic.Libpod, specGen, false, nil) if err != nil { return nil, err } diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 67e709486..aa4baf846 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -958,3 +958,7 @@ func (ic *ContainerEngine) ShouldRestart(_ context.Context, id string) (bool, er func (ic *ContainerEngine) ContainerRename(ctx context.Context, nameOrID string, opts entities.ContainerRenameOptions) error { return containers.Rename(ic.ClientCtx, nameOrID, new(containers.RenameOptions).WithName(opts.NewName)) } + +func (ic *ContainerEngine) ContainerClone(ctx context.Context, ctrCloneOpts entities.ContainerCloneOptions) (*entities.ContainerCreateReport, error) { + return nil, errors.New("cloning a container is not supported on the remote client") +} |