From 3ce62d3cc4c9545e45c14b32896207d844325d6b Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Fri, 27 Oct 2023 07:22:32 -0400 Subject: [PATCH 1/2] Sort kube options alphabetically Signed-off-by: Daniel J Walsh --- pkg/api/handlers/libpod/kube.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pkg/api/handlers/libpod/kube.go b/pkg/api/handlers/libpod/kube.go index 402a6f8d77..56d3a313c0 100644 --- a/pkg/api/handlers/libpod/kube.go +++ b/pkg/api/handlers/libpod/kube.go @@ -20,19 +20,19 @@ func KubePlay(w http.ResponseWriter, r *http.Request) { decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder) query := struct { Annotations map[string]string `schema:"annotations"` - Network []string `schema:"network"` - TLSVerify bool `schema:"tlsVerify"` LogDriver string `schema:"logDriver"` LogOptions []string `schema:"logOptions"` + Network []string `schema:"network"` + NoHosts bool `schema:"noHosts"` + NoTrunc bool `schema:"noTrunc"` + PublishPorts []string `schema:"publishPorts"` + ServiceContainer bool `schema:"serviceContainer"` Start bool `schema:"start"` StaticIPs []string `schema:"staticIPs"` StaticMACs []string `schema:"staticMACs"` - NoHosts bool `schema:"noHosts"` + TLSVerify bool `schema:"tlsVerify"` Userns string `schema:"userns"` - PublishPorts []string `schema:"publishPorts"` - NoTrunc bool `schema:"noTrunc"` Wait bool `schema:"wait"` - ServiceContainer bool `schema:"serviceContainer"` }{ TLSVerify: true, Start: true, @@ -89,21 +89,21 @@ func KubePlay(w http.ResponseWriter, r *http.Request) { options := entities.PlayKubeOptions{ Annotations: query.Annotations, Authfile: authfile, - Username: username, - Password: password, + IsRemote: true, + LogDriver: logDriver, + LogOptions: query.LogOptions, Networks: query.Network, NoHosts: query.NoHosts, + Password: password, + PublishPorts: query.PublishPorts, Quiet: true, - LogDriver: logDriver, - LogOptions: query.LogOptions, + ServiceContainer: query.ServiceContainer, StaticIPs: staticIPs, StaticMACs: staticMACs, - IsRemote: true, + UseLongAnnotations: query.NoTrunc, + Username: username, Userns: query.Userns, - PublishPorts: query.PublishPorts, Wait: query.Wait, - ServiceContainer: query.ServiceContainer, - UseLongAnnotations: query.NoTrunc, } if _, found := r.URL.Query()["tlsVerify"]; found { options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) From 91df369ae6807d5d3c0adf37ea5caeb883c0284e Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Fri, 27 Oct 2023 07:23:53 -0400 Subject: [PATCH 2/2] podman kube play --replace should force removal of pods and containers Fixes: https://github.com/containers/podman/issues/20025 Signed-off-by: Daniel J Walsh --- pkg/api/handlers/libpod/kube.go | 2 + pkg/api/server/register_kube.go | 56 +++++++++++++++++-------- pkg/bindings/kube/types.go | 2 + pkg/bindings/kube/types_play_options.go | 15 +++++++ pkg/domain/infra/abi/play.go | 20 ++++++++- pkg/domain/infra/tunnel/kube.go | 2 +- test/system/700-play.bats | 21 ++++++++++ 7 files changed, 99 insertions(+), 19 deletions(-) diff --git a/pkg/api/handlers/libpod/kube.go b/pkg/api/handlers/libpod/kube.go index 56d3a313c0..1559bfbbcb 100644 --- a/pkg/api/handlers/libpod/kube.go +++ b/pkg/api/handlers/libpod/kube.go @@ -25,6 +25,7 @@ func KubePlay(w http.ResponseWriter, r *http.Request) { Network []string `schema:"network"` NoHosts bool `schema:"noHosts"` NoTrunc bool `schema:"noTrunc"` + Replace bool `schema:"replace"` PublishPorts []string `schema:"publishPorts"` ServiceContainer bool `schema:"serviceContainer"` Start bool `schema:"start"` @@ -97,6 +98,7 @@ func KubePlay(w http.ResponseWriter, r *http.Request) { Password: password, PublishPorts: query.PublishPorts, Quiet: true, + Replace: query.Replace, ServiceContainer: query.ServiceContainer, StaticIPs: staticIPs, StaticMACs: staticMACs, diff --git a/pkg/api/server/register_kube.go b/pkg/api/server/register_kube.go index 5291119dbf..85350fc774 100644 --- a/pkg/api/server/register_kube.go +++ b/pkg/api/server/register_kube.go @@ -17,31 +17,53 @@ func (s *APIServer) registerKubeHandlers(r *mux.Router) error { // description: Create and run pods based on a Kubernetes YAML file (pod or service kind). // parameters: // - in: query + // name: logDriver + // type: string + // description: Logging driver for the containers in the pod. + // - in: query + // name: logOptions + // type: array + // description: logging driver options + // items: + // type: string + // - in: query // name: network // type: array // description: USe the network mode or specify an array of networks. // items: // type: string // - in: query - // name: tlsVerify + // name: noHosts // type: boolean - // default: true - // description: Require HTTPS and verify signatures when contacting registries. + // default: false + // description: do not setup /etc/hosts file in container // - in: query - // name: logDriver - // type: string - // description: Logging driver for the containers in the pod. + // name: noTrunc + // type: boolean + // default: false + // description: use annotations that are not truncated to the Kubernetes maximum length of 63 characters // - in: query - // name: start + // name: publishPorts + // type: array + // description: publish a container's port, or a range of ports, to the host + // items: + // type: string + // - in: query + // name: replace // type: boolean - // default: true - // description: Start the pod after creating it. + // default: false + // description: replace existing pods and containers // - in: query // name: serviceContainer // type: boolean // default: false // description: Starts a service container before all pods. // - in: query + // name: start + // type: boolean + // default: true + // description: Start the pod after creating it. + // - in: query // name: staticIPs // type: array // description: Static IPs used for the pods. @@ -54,19 +76,19 @@ func (s *APIServer) registerKubeHandlers(r *mux.Router) error { // items: // type: string // - in: query - // name: wait - // type: boolean - // default: false - // description: Clean up all objects created when a SIGTERM is received or pods exit. - // - in: query - // name: noTrunc + // name: tlsVerify // type: boolean - // default: false - // description: use annotations that are not truncated to the Kubernetes maximum length of 63 characters + // default: true + // description: Require HTTPS and verify signatures when contacting registries. // - in: query // name: userns // type: string // description: Set the user namespace mode for the pods. + // - in: query + // name: wait + // type: boolean + // default: false + // description: Clean up all objects created when a SIGTERM is received or pods exit. // - in: body // name: request // description: Kubernetes YAML file. diff --git a/pkg/bindings/kube/types.go b/pkg/bindings/kube/types.go index 7dcc77dcea..3a798df3f3 100644 --- a/pkg/bindings/kube/types.go +++ b/pkg/bindings/kube/types.go @@ -42,6 +42,8 @@ type PlayOptions struct { LogDriver *string // LogOptions for the container. For example: journald LogOptions *[]string + // Replace - replace existing pods and containers + Replace *bool // Start - don't start the pod if false Start *bool // NoTrunc - use annotations that were not truncated to the diff --git a/pkg/bindings/kube/types_play_options.go b/pkg/bindings/kube/types_play_options.go index 49e6499ac8..6082799a69 100644 --- a/pkg/bindings/kube/types_play_options.go +++ b/pkg/bindings/kube/types_play_options.go @@ -258,6 +258,21 @@ func (o *PlayOptions) GetLogOptions() []string { return *o.LogOptions } +// WithReplace set field Replace to given value +func (o *PlayOptions) WithReplace(value bool) *PlayOptions { + o.Replace = &value + return o +} + +// GetReplace returns value of field Replace +func (o *PlayOptions) GetReplace() bool { + if o.Replace == nil { + var z bool + return z + } + return *o.Replace +} + // WithStart set field Start to given value func (o *PlayOptions) WithStart(value bool) *PlayOptions { o.Start = &value diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index cdf776596b..1d1f3a6407 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -109,6 +109,12 @@ func (ic *ContainerEngine) createServiceContainer(ctx context.Context, name stri // via the `sdNotifyAnnotation` annotation in the K8s YAML. opts = append(opts, libpod.WithSdNotifyMode(define.SdNotifyModeIgnore)) + if options.Replace { + if _, err := ic.ContainerRm(ctx, []string{spec.Name}, entities.RmOptions{Force: true, Ignore: true}); err != nil { + return nil, err + } + } + // Create a new libpod container based on the spec. ctr, err := ic.Libpod.NewContainer(ctx, runtimeSpec, spec, false, opts...) if err != nil { @@ -813,6 +819,12 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY return nil, nil, err } opts = append(opts, libpod.WithSdNotifyMode(define.SdNotifyModeIgnore)) + if options.Replace { + if _, err := ic.ContainerRm(ctx, []string{spec.Name}, entities.RmOptions{Force: true, Ignore: true}); err != nil { + return nil, nil, err + } + } + ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...) if err != nil { return nil, nil, err @@ -913,6 +925,12 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY opts = append(opts, libpod.WithSdNotifySocket(proxy.SocketPath())) } + if options.Replace { + if _, err := ic.ContainerRm(ctx, []string{spec.Name}, entities.RmOptions{Force: true, Ignore: true}); err != nil { + return nil, nil, err + } + } + ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...) if err != nil { return nil, nil, err @@ -1516,7 +1534,7 @@ func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, body io.Reader, opt return nil, err } - reports.RmReport, err = ic.PodRm(ctx, podNames, entities.PodRmOptions{Ignore: true}) + reports.RmReport, err = ic.PodRm(ctx, podNames, entities.PodRmOptions{Ignore: true, Force: true}) if err != nil { return nil, err } diff --git a/pkg/domain/infra/tunnel/kube.go b/pkg/domain/infra/tunnel/kube.go index e1e49d58df..d03d4ebc7c 100644 --- a/pkg/domain/infra/tunnel/kube.go +++ b/pkg/domain/infra/tunnel/kube.go @@ -58,7 +58,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, body io.Reader, opts en options := new(kube.PlayOptions).WithAuthfile(opts.Authfile).WithUsername(opts.Username).WithPassword(opts.Password) options.WithCertDir(opts.CertDir).WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithConfigMaps(opts.ConfigMaps) options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Networks).WithSeccompProfileRoot(opts.SeccompProfileRoot) - options.WithStaticIPs(opts.StaticIPs).WithStaticMACs(opts.StaticMACs).WithWait(opts.Wait).WithServiceContainer(opts.ServiceContainer) + options.WithStaticIPs(opts.StaticIPs).WithStaticMACs(opts.StaticMACs).WithWait(opts.Wait).WithServiceContainer(opts.ServiceContainer).WithReplace(opts.Replace) if len(opts.LogOptions) > 0 { options.WithLogOptions(opts.LogOptions) } diff --git a/test/system/700-play.bats b/test/system/700-play.bats index 66a0625999..a4ec319b68 100644 --- a/test/system/700-play.bats +++ b/test/system/700-play.bats @@ -411,6 +411,27 @@ _EOF run_podman rmi -f userimage:latest } +# Ocassionaly a remnant storage container is left behind which causes +# podman play kube --replace to fail. This tests created a conflicting +# storage container name using buildah to make sure --replace, still +# functions proplery by removing the storage container. +@test "podman kube play --replace external storage" { + TESTDIR=$PODMAN_TMPDIR/testdir + mkdir -p $TESTDIR + echo "$testYaml" | sed "s|TESTDIR|${TESTDIR}|g" > $PODMAN_TMPDIR/test.yaml + run_podman play kube $PODMAN_TMPDIR/test.yaml + # Force removal of container + run_podman rm --force -t0 test_pod-test + # Create external container using buildah with same name + buildah from --name test_pod-test $IMAGE + # --replace deletes the buildah container and replace it with new one + run_podman play kube --replace $PODMAN_TMPDIR/test.yaml + + run_podman stop -a -t 0 + run_podman pod rm -t 0 -f test_pod + run_podman rmi -f userimage:latest +} + @test "podman kube --annotation" { TESTDIR=$PODMAN_TMPDIR/testdir RANDOMSTRING=$(random_string 15)