From 47c1017cf8b90909ea7245a110159cdecd2e6197 Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Tue, 16 Apr 2019 09:31:32 -0400 Subject: Clean up after play kube failure Before, we would half create a pod in play kube and error out if we fail. Rather, let's clean up after our failure so the user doesn't have to delete the pod themselves. Signed-off-by: Peter Hunt --- cmd/podman/play_kube.go | 79 +++++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go index d60c873f8..d15dd1393 100644 --- a/cmd/podman/play_kube.go +++ b/cmd/podman/play_kube.go @@ -45,7 +45,7 @@ var ( playKubeCommand.InputArgs = args playKubeCommand.GlobalFlags = MainGlobalOpts playKubeCommand.Remote = remoteclient - return playKubeYAMLCmd(&playKubeCommand) + return playKubeCmd(&playKubeCommand) }, Example: `podman play kube demo.yml podman play kube --cert-dir /mycertsdir --tls-verify=true --quiet myWebPod`, @@ -65,16 +65,7 @@ func init() { flags.BoolVar(&playKubeCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") } -func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error { - var ( - podOptions []libpod.PodCreateOption - podYAML v1.Pod - registryCreds *types.DockerAuthConfig - containers []*libpod.Container - writer io.Writer - ) - - ctx := getContext() +func playKubeCmd(c *cliconfig.KubePlayValues) error { args := c.InputArgs if len(args) > 1 { return errors.New("you can only play one kubernetes file at a time") @@ -83,19 +74,39 @@ func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error { return errors.New("you must supply at least one file") } + ctx := getContext() runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } defer runtime.Shutdown(false) - content, err := ioutil.ReadFile(args[0]) + pod, err := playKubeYAMLCmd(c, ctx, runtime, args[0]) + if err != nil && pod != nil { + if err2 := runtime.RemovePod(ctx, pod, true, true); err2 != nil { + logrus.Errorf("unable to remove pod %s after failing to play kube", pod.ID()) + } + } + return err +} + +func playKubeYAMLCmd(c *cliconfig.KubePlayValues, ctx context.Context, runtime *libpod.Runtime, yamlFile string) (*libpod.Pod, error) { + var ( + containers []*libpod.Container + pod *libpod.Pod + podOptions []libpod.PodCreateOption + podYAML v1.Pod + registryCreds *types.DockerAuthConfig + writer io.Writer + ) + + content, err := ioutil.ReadFile(yamlFile) if err != nil { - return err + return nil, err } if err := yaml.Unmarshal(content, &podYAML); err != nil { - return errors.Wrapf(err, "unable to read %s as YAML", args[0]) + return nil, errors.Wrapf(err, "unable to read %s as YAML", yamlFile) } // check for name collision between pod and container @@ -113,23 +124,21 @@ func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error { nsOptions, err := shared.GetNamespaceOptions(strings.Split(shared.DefaultKernelNamespaces, ",")) if err != nil { - return err + return nil, err } podOptions = append(podOptions, nsOptions...) podPorts := getPodPorts(podYAML.Spec.Containers) podOptions = append(podOptions, libpod.WithInfraContainerPorts(podPorts)) // Create the Pod - pod, err := runtime.NewPod(ctx, podOptions...) + pod, err = runtime.NewPod(ctx, podOptions...) if err != nil { - return err + return pod, err } - // Print the Pod's ID - fmt.Println(pod.ID()) podInfraID, err := pod.InfraContainerID() if err != nil { - return err + return pod, err } namespaces := map[string]string{ @@ -157,26 +166,26 @@ func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error { for _, volume := range podYAML.Spec.Volumes { hostPath := volume.VolumeSource.HostPath if hostPath == nil { - return errors.Errorf("HostPath is currently the only supported VolumeSource") + return pod, errors.Errorf("HostPath is currently the only supported VolumeSource") } if hostPath.Type != nil { switch *hostPath.Type { case v1.HostPathDirectoryOrCreate: if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) { if err := os.Mkdir(hostPath.Path, createDirectoryPermission); err != nil { - return errors.Errorf("Error creating HostPath %s at %s", volume.Name, hostPath.Path) + return pod, errors.Errorf("Error creating HostPath %s at %s", volume.Name, hostPath.Path) } } // unconditionally label a newly created volume as private if err := libpod.LabelVolumePath(hostPath.Path, false); err != nil { - return errors.Wrapf(err, "Error giving %s a label", hostPath.Path) + return pod, errors.Wrapf(err, "Error giving %s a label", hostPath.Path) } break case v1.HostPathFileOrCreate: if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) { f, err := os.OpenFile(hostPath.Path, os.O_RDONLY|os.O_CREATE, createFilePermission) if err != nil { - return errors.Errorf("Error creating HostPath %s at %s", volume.Name, hostPath.Path) + return pod, errors.Errorf("Error creating HostPath %s at %s", volume.Name, hostPath.Path) } if err := f.Close(); err != nil { logrus.Warnf("Error in closing newly created HostPath file: %v", err) @@ -184,7 +193,7 @@ func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error { } // unconditionally label a newly created volume as private if err := libpod.LabelVolumePath(hostPath.Path, false); err != nil { - return errors.Wrapf(err, "Error giving %s a label", hostPath.Path) + return pod, errors.Wrapf(err, "Error giving %s a label", hostPath.Path) } break case v1.HostPathDirectory: @@ -193,11 +202,11 @@ func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error { // do nothing here because we will verify the path exists in validateVolumeHostDir break default: - return errors.Errorf("Directories are the only supported HostPath type") + return pod, errors.Errorf("Directories are the only supported HostPath type") } } if err := shared.ValidateVolumeHostDir(hostPath.Path); err != nil { - return errors.Wrapf(err, "Error in parsing HostPath in YAML") + return pod, errors.Wrapf(err, "Error in parsing HostPath in YAML") } volumes[volume.Name] = hostPath.Path } @@ -205,15 +214,15 @@ func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error { for _, container := range podYAML.Spec.Containers { newImage, err := runtime.ImageRuntime().New(ctx, container.Image, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, false, nil) if err != nil { - return err + return pod, err } createConfig, err := kubeContainerToCreateConfig(ctx, container, runtime, newImage, namespaces, volumes) if err != nil { - return err + return pod, err } ctr, err := shared.CreateContainerFromCreateConfig(runtime, createConfig, ctx, pod) if err != nil { - return err + return pod, err } containers = append(containers, ctr) } @@ -223,12 +232,18 @@ func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error { if err := ctr.Start(ctx, true); err != nil { // Making this a hard failure here to avoid a mess // the other containers are in created status - return err + return pod, err } + } + + // We've now successfully converted this YAML into a pod + // print our pod and containers, signifying we succeeded + fmt.Println(pod.ID()) + for _, ctr := range containers { fmt.Println(ctr.ID()) } - return nil + return pod, nil } // getPodPorts converts a slice of kube container descriptions to an -- cgit v1.2.3-54-g00ecf