diff options
Diffstat (limited to 'cmd/podman/play_kube.go')
-rw-r--r-- | cmd/podman/play_kube.go | 104 |
1 files changed, 87 insertions, 17 deletions
diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go index 6f23e340e..10221a339 100644 --- a/cmd/podman/play_kube.go +++ b/cmd/podman/play_kube.go @@ -1,6 +1,7 @@ package main import ( + "context" "fmt" "io" "io/ioutil" @@ -25,10 +26,17 @@ import ( "k8s.io/api/core/v1" ) +const ( + // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath + createDirectoryPermission = 0755 +) + var ( playKubeCommand cliconfig.KubePlayValues - playKubeDescription = "Play a Pod and its containers based on a Kubrernetes YAML" - _playKubeCommand = &cobra.Command{ + playKubeDescription = `Command reads in a structured file of Kubernetes YAML. + + It creates the pod and containers described in the YAML. The containers within the pod are then started and the ID of the new Pod is output.` + _playKubeCommand = &cobra.Command{ Use: "kube [flags] KUBEFILE", Short: "Play a pod based on Kubernetes YAML", Long: playKubeDescription, @@ -44,6 +52,7 @@ var ( func init() { playKubeCommand.Command = _playKubeCommand + playKubeCommand.SetHelpTemplate(HelpTemplate()) playKubeCommand.SetUsageTemplate(UsageTemplate()) flags := playKubeCommand.Flags() flags.StringVar(&playKubeCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override") @@ -51,7 +60,7 @@ func init() { flags.StringVar(&playKubeCommand.Creds, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") flags.BoolVarP(&playKubeCommand.Quiet, "quiet", "q", false, "Suppress output information when pulling images") flags.StringVar(&playKubeCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)") - flags.BoolVar(&playKubeCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)") + flags.BoolVar(&playKubeCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") } func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error { @@ -90,11 +99,20 @@ func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error { return errors.Wrapf(err, "unable to read %s as YAML", args[0]) } + // check for name collision between pod and container + podName := podYAML.ObjectMeta.Name + for _, n := range podYAML.Spec.Containers { + if n.Name == podName { + fmt.Printf("a container exists with the same name (%s) as the pod in your YAML file; changing pod name to %s_pod\n", podName, podName) + podName = fmt.Sprintf("%s_pod", podName) + } + } + podOptions = append(podOptions, libpod.WithInfraContainer()) - podOptions = append(podOptions, libpod.WithPodName(podYAML.ObjectMeta.Name)) + podOptions = append(podOptions, libpod.WithPodName(podName)) // TODO for now we just used the default kernel namespaces; we need to add/subtract this from yaml - nsOptions, err := shared.GetNamespaceOptions(strings.Split(DefaultKernelNamespaces, ",")) + nsOptions, err := shared.GetNamespaceOptions(strings.Split(shared.DefaultKernelNamespaces, ",")) if err != nil { return err } @@ -135,16 +153,45 @@ func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error { dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify) } + // map from name to mount point + volumes := make(map[string]string) + for _, volume := range podYAML.Spec.Volumes { + hostPath := volume.VolumeSource.HostPath + if hostPath == nil { + return 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) + } + } + case v1.HostPathDirectory: + // do nothing here because we will verify the path exists in validateVolumeHostDir + break + default: + return 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") + } + fmt.Println(volume.Name) + volumes[volume.Name] = hostPath.Path + } + for _, container := range podYAML.Spec.Containers { newImage, err := runtime.ImageRuntime().New(ctx, container.Image, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, false, nil) if err != nil { return err } - createConfig := kubeContainerToCreateConfig(container, runtime, newImage, namespaces) + createConfig, err := kubeContainerToCreateConfig(ctx, container, runtime, newImage, namespaces, volumes) if err != nil { return err } - ctr, err := createContainerFromCreateConfig(runtime, createConfig, ctx, pod) + ctr, err := shared.CreateContainerFromCreateConfig(runtime, createConfig, ctx, pod) if err != nil { return err } @@ -185,7 +232,7 @@ func getPodPorts(containers []v1.Container) []ocicni.PortMapping { } // kubeContainerToCreateConfig takes a v1.Container and returns a createconfig describing a container -func kubeContainerToCreateConfig(containerYAML v1.Container, runtime *libpod.Runtime, newImage *image2.Image, namespaces map[string]string) *createconfig.CreateConfig { +func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, runtime *libpod.Runtime, newImage *image2.Image, namespaces map[string]string, volumes map[string]string) (*createconfig.CreateConfig, error) { var ( containerConfig createconfig.CreateConfig envs map[string]string @@ -197,15 +244,25 @@ func kubeContainerToCreateConfig(containerYAML v1.Container, runtime *libpod.Run containerConfig.Name = containerYAML.Name containerConfig.Tty = containerYAML.TTY containerConfig.WorkDir = containerYAML.WorkingDir - if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil { - containerConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem - } - if containerYAML.SecurityContext.Privileged != nil { - containerConfig.Privileged = *containerYAML.SecurityContext.Privileged + + imageData, _ := newImage.Inspect(ctx) + + containerConfig.User = "0" + if imageData != nil { + containerConfig.User = imageData.Config.User } - if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil { - containerConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation + if containerConfig.SecurityOpts != nil { + if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil { + containerConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem + } + if containerYAML.SecurityContext.Privileged != nil { + containerConfig.Privileged = *containerYAML.SecurityContext.Privileged + } + + if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil { + containerConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation + } } containerConfig.Command = containerYAML.Command @@ -222,7 +279,9 @@ func kubeContainerToCreateConfig(containerYAML v1.Container, runtime *libpod.Run // disabled in code review per mheon //containerConfig.PidMode = ns.PidMode(namespaces["pid"]) containerConfig.UsernsMode = ns.UsernsMode(namespaces["user"]) - + if len(containerConfig.WorkDir) == 0 { + containerConfig.WorkDir = "/" + } if len(containerYAML.Env) > 0 { envs = make(map[string]string) } @@ -231,5 +290,16 @@ func kubeContainerToCreateConfig(containerYAML v1.Container, runtime *libpod.Run envs[e.Name] = e.Value } containerConfig.Env = envs - return &containerConfig + + for _, volume := range containerYAML.VolumeMounts { + host_path, exists := volumes[volume.Name] + if !exists { + return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name) + } + if err := shared.ValidateVolumeCtrDir(volume.MountPath); err != nil { + return nil, errors.Wrapf(err, "error in parsing MountPath") + } + containerConfig.Volumes = append(containerConfig.Volumes, fmt.Sprintf("%s:%s", host_path, volume.MountPath)) + } + return &containerConfig, nil } |