diff options
-rw-r--r-- | cmd/podman/common/volumes.go | 4 | ||||
-rw-r--r-- | libpod/network/files.go | 5 | ||||
-rw-r--r-- | libpod/network/network.go | 28 | ||||
-rw-r--r-- | libpod/runtime.go | 4 | ||||
-rw-r--r-- | pkg/api/handlers/compat/ping.go | 3 | ||||
-rw-r--r-- | pkg/api/server/register_ping.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play.go | 67 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/kube.go | 40 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/volume.go | 124 | ||||
-rw-r--r-- | pkg/specgen/volumes.go | 4 | ||||
-rw-r--r-- | test/apiv2/25-containersMore.at | 27 | ||||
-rw-r--r-- | test/e2e/network_test.go | 11 | ||||
-rw-r--r-- | test/e2e/play_kube_test.go | 89 |
13 files changed, 293 insertions, 115 deletions
diff --git a/cmd/podman/common/volumes.go b/cmd/podman/common/volumes.go index 0468f15e0..dfbb7b1b2 100644 --- a/cmd/podman/common/volumes.go +++ b/cmd/podman/common/volumes.go @@ -323,8 +323,8 @@ func getBindMount(args []string) (spec.Mount, error) { if len(kv) == 1 { return newMount, errors.Wrapf(optionArgError, kv[0]) } - if err := parse.ValidateVolumeHostDir(kv[1]); err != nil { - return newMount, err + if len(kv[1]) == 0 { + return newMount, errors.Wrapf(optionArgError, "host directory cannot be empty") } newMount.Source = kv[1] setSource = true diff --git a/libpod/network/files.go b/libpod/network/files.go index 846e5c62d..7f1e3ee18 100644 --- a/libpod/network/files.go +++ b/libpod/network/files.go @@ -14,6 +14,9 @@ import ( "github.com/pkg/errors" ) +// ErrNoSuchNetworkInterface indicates that no network interface exists +var ErrNoSuchNetworkInterface = errors.New("unable to find interface name for network") + // GetCNIConfDir get CNI configuration directory func GetCNIConfDir(configArg *config.Config) string { if len(configArg.Network.NetworkConfigDir) < 1 { @@ -142,7 +145,7 @@ func GetInterfaceNameFromConfig(path string) (string, error) { } } if len(name) == 0 { - return "", errors.New("unable to find interface name for network") + return "", ErrNoSuchNetworkInterface } return name, nil } diff --git a/libpod/network/network.go b/libpod/network/network.go index 7327a1a7d..0febb52f6 100644 --- a/libpod/network/network.go +++ b/libpod/network/network.go @@ -10,6 +10,7 @@ import ( "github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator" "github.com/containers/common/pkg/config" "github.com/containers/podman/v2/libpod/define" + "github.com/containers/podman/v2/pkg/rootless" "github.com/containers/podman/v2/pkg/util" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -181,21 +182,26 @@ func RemoveNetwork(config *config.Config, name string) error { // Before we delete the configuration file, we need to make sure we can read and parse // it to get the network interface name so we can remove that too interfaceName, err := GetInterfaceNameFromConfig(cniPath) - if err != nil { - return errors.Wrapf(err, "failed to find network interface name in %q", cniPath) - } - liveNetworkNames, err := GetLiveNetworkNames() - if err != nil { - return errors.Wrapf(err, "failed to get live network names") - } - if util.StringInSlice(interfaceName, liveNetworkNames) { - if err := RemoveInterface(interfaceName); err != nil { - return errors.Wrapf(err, "failed to delete the network interface %q", interfaceName) + if err == nil { + // Don't try to remove the network interface if we are not root + if !rootless.IsRootless() { + liveNetworkNames, err := GetLiveNetworkNames() + if err != nil { + return errors.Wrapf(err, "failed to get live network names") + } + if util.StringInSlice(interfaceName, liveNetworkNames) { + if err := RemoveInterface(interfaceName); err != nil { + return errors.Wrapf(err, "failed to delete the network interface %q", interfaceName) + } + } } + } else if err != ErrNoSuchNetworkInterface { + // Don't error if we couldn't find the network interface name + return err } // Remove the configuration file if err := os.Remove(cniPath); err != nil { - return errors.Wrapf(err, "failed to remove network configuration file %q", cniPath) + return errors.Wrap(err, "failed to remove network configuration") } return nil } diff --git a/libpod/runtime.go b/libpod/runtime.go index 792492db6..df3dfae2b 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -162,6 +162,10 @@ func newRuntimeFromConfig(ctx context.Context, conf *config.Config, options ...R runtime.config = conf + if err := SetXdgDirs(); err != nil { + return nil, err + } + storeOpts, err := storage.DefaultStoreOptions(rootless.IsRootless(), rootless.GetRootlessUID()) if err != nil { return nil, err diff --git a/pkg/api/handlers/compat/ping.go b/pkg/api/handlers/compat/ping.go index 06150bb63..9f6611b30 100644 --- a/pkg/api/handlers/compat/ping.go +++ b/pkg/api/handlers/compat/ping.go @@ -19,11 +19,10 @@ func Ping(w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Pragma", "no-cache") - w.Header().Set("Libpod-Buildha-Version", buildah.Version) + w.Header().Set("Libpod-Buildah-Version", buildah.Version) w.WriteHeader(http.StatusOK) if r.Method == http.MethodGet { fmt.Fprint(w, "OK") } - fmt.Fprint(w, "\n") } diff --git a/pkg/api/server/register_ping.go b/pkg/api/server/register_ping.go index 4e299008c..446a12a68 100644 --- a/pkg/api/server/register_ping.go +++ b/pkg/api/server/register_ping.go @@ -53,7 +53,7 @@ func (s *APIServer) registerPingHandlers(r *mux.Router) error { // Max Podman API Version the server supports. // Available if service is backed by Podman, therefore may be used to // determine if talking to Podman engine or another engine - // Libpod-Buildha-Version: + // Libpod-Buildah-Version: // type: string // description: | // Default version of libpod image builder. diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 4bcc6469c..3aeb6a2ee 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -8,7 +8,6 @@ import ( "os" "strings" - "github.com/containers/buildah/pkg/parse" "github.com/containers/image/v5/types" "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/image" @@ -24,13 +23,6 @@ import ( v1 "k8s.io/api/core/v1" ) -const ( - // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath - kubeDirectoryPermission = 0755 - // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath - kubeFilePermission = 0644 -) - func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) { var ( kubeObject v1.ObjectReference @@ -168,62 +160,9 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY DockerInsecureSkipTLSVerify: options.SkipTLSVerify, } - // 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 nil, 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, kubeDirectoryPermission); err != nil { - return nil, err - } - } - // Label a newly created volume - if err := libpod.LabelVolumePath(hostPath.Path); err != nil { - return nil, errors.Wrapf(err, "error giving %s a label", hostPath.Path) - } - case v1.HostPathFileOrCreate: - if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) { - f, err := os.OpenFile(hostPath.Path, os.O_RDONLY|os.O_CREATE, kubeFilePermission) - if err != nil { - return nil, errors.Wrap(err, "error creating HostPath") - } - if err := f.Close(); err != nil { - logrus.Warnf("Error in closing newly created HostPath file: %v", err) - } - } - // unconditionally label a newly created volume - if err := libpod.LabelVolumePath(hostPath.Path); err != nil { - return nil, errors.Wrapf(err, "error giving %s a label", hostPath.Path) - } - case v1.HostPathSocket: - st, err := os.Stat(hostPath.Path) - if err != nil { - return nil, errors.Wrap(err, "error checking HostPathSocket") - } - if st.Mode()&os.ModeSocket != os.ModeSocket { - return nil, errors.Errorf("error checking HostPathSocket: path %s is not a socket", hostPath.Path) - } - - case v1.HostPathDirectory: - case v1.HostPathFile: - case v1.HostPathUnset: - // do nothing here because we will verify the path exists in validateVolumeHostDir - break - default: - return nil, errors.Errorf("Invalid HostPath type %v", hostPath.Type) - } - } - - if err := parse.ValidateVolumeHostDir(hostPath.Path); err != nil { - return nil, errors.Wrapf(err, "error in parsing HostPath in YAML") - } - volumes[volume.Name] = hostPath.Path + volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes) + if err != nil { + return nil, err } seccompPaths, err := kube.InitializeSeccompPaths(podYAML.ObjectMeta.Annotations, options.SeccompProfileRoot) diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index e1202956c..5f72d28bb 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -47,7 +47,7 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec) return p, nil } -func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newImage *image.Image, volumes map[string]string, podID, podName, infraID string, configMaps []v1.ConfigMap, seccompPaths *KubeSeccompPaths, restartPolicy string) (*specgen.SpecGenerator, error) { +func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newImage *image.Image, volumes map[string]*KubeVolume, podID, podName, infraID string, configMaps []v1.ConfigMap, seccompPaths *KubeSeccompPaths, restartPolicy string) (*specgen.SpecGenerator, error) { s := specgen.NewSpecGenerator(iid, false) // podName should be non-empty for Deployment objects to be able to create @@ -163,22 +163,36 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI s.Env = envs for _, volume := range containerYAML.VolumeMounts { - hostPath, exists := volumes[volume.Name] + volumeSource, 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 := parse.ValidateVolumeCtrDir(volume.MountPath); err != nil { - return nil, errors.Wrapf(err, "error in parsing MountPath") - } - mount := spec.Mount{ - Destination: volume.MountPath, - Source: hostPath, - Type: "bind", - } - if volume.ReadOnly { - mount.Options = []string{"ro"} + switch volumeSource.Type { + case KubeVolumeTypeBindMount: + if err := parse.ValidateVolumeCtrDir(volume.MountPath); err != nil { + return nil, errors.Wrapf(err, "error in parsing MountPath") + } + mount := spec.Mount{ + Destination: volume.MountPath, + Source: volumeSource.Source, + Type: "bind", + } + if volume.ReadOnly { + mount.Options = []string{"ro"} + } + s.Mounts = append(s.Mounts, mount) + case KubeVolumeTypeNamed: + namedVolume := specgen.NamedVolume{ + Dest: volume.MountPath, + Name: volumeSource.Source, + } + if volume.ReadOnly { + namedVolume.Options = []string{"ro"} + } + s.Volumes = append(s.Volumes, &namedVolume) + default: + return nil, errors.Errorf("Unsupported volume source type") } - s.Mounts = append(s.Mounts, mount) } s.RestartPolicy = restartPolicy diff --git a/pkg/specgen/generate/kube/volume.go b/pkg/specgen/generate/kube/volume.go new file mode 100644 index 000000000..2ef0f4c23 --- /dev/null +++ b/pkg/specgen/generate/kube/volume.go @@ -0,0 +1,124 @@ +package kube + +import ( + "os" + + "github.com/containers/buildah/pkg/parse" + "github.com/containers/podman/v2/libpod" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + v1 "k8s.io/api/core/v1" +) + +const ( + // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath + kubeDirectoryPermission = 0755 + // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath + kubeFilePermission = 0644 +) + +type KubeVolumeType int + +const ( + KubeVolumeTypeBindMount KubeVolumeType = iota + KubeVolumeTypeNamed KubeVolumeType = iota +) + +type KubeVolume struct { + // Type of volume to create + Type KubeVolumeType + // Path for bind mount or volume name for named volume + Source string +} + +// Create a KubeVolume from an HostPathVolumeSource +func VolumeFromHostPath(hostPath *v1.HostPathVolumeSource) (*KubeVolume, error) { + 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, kubeDirectoryPermission); err != nil { + return nil, err + } + } + // Label a newly created volume + if err := libpod.LabelVolumePath(hostPath.Path); err != nil { + return nil, errors.Wrapf(err, "error giving %s a label", hostPath.Path) + } + case v1.HostPathFileOrCreate: + if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) { + f, err := os.OpenFile(hostPath.Path, os.O_RDONLY|os.O_CREATE, kubeFilePermission) + if err != nil { + return nil, errors.Wrap(err, "error creating HostPath") + } + if err := f.Close(); err != nil { + logrus.Warnf("Error in closing newly created HostPath file: %v", err) + } + } + // unconditionally label a newly created volume + if err := libpod.LabelVolumePath(hostPath.Path); err != nil { + return nil, errors.Wrapf(err, "error giving %s a label", hostPath.Path) + } + case v1.HostPathSocket: + st, err := os.Stat(hostPath.Path) + if err != nil { + return nil, errors.Wrap(err, "error checking HostPathSocket") + } + if st.Mode()&os.ModeSocket != os.ModeSocket { + return nil, errors.Errorf("error checking HostPathSocket: path %s is not a socket", hostPath.Path) + } + + case v1.HostPathDirectory: + case v1.HostPathFile: + case v1.HostPathUnset: + // do nothing here because we will verify the path exists in validateVolumeHostDir + break + default: + return nil, errors.Errorf("Invalid HostPath type %v", hostPath.Type) + } + } + + if err := parse.ValidateVolumeHostDir(hostPath.Path); err != nil { + return nil, errors.Wrapf(err, "error in parsing HostPath in YAML") + } + + return &KubeVolume{ + Type: KubeVolumeTypeBindMount, + Source: hostPath.Path, + }, nil +} + +// Create a KubeVolume from a PersistentVolumeClaimVolumeSource +func VolumeFromPersistentVolumeClaim(claim *v1.PersistentVolumeClaimVolumeSource) (*KubeVolume, error) { + return &KubeVolume{ + Type: KubeVolumeTypeNamed, + Source: claim.ClaimName, + }, nil +} + +// Create a KubeVolume from one of the supported VolumeSource +func VolumeFromSource(volumeSource v1.VolumeSource) (*KubeVolume, error) { + if volumeSource.HostPath != nil { + return VolumeFromHostPath(volumeSource.HostPath) + } else if volumeSource.PersistentVolumeClaim != nil { + return VolumeFromPersistentVolumeClaim(volumeSource.PersistentVolumeClaim) + } else { + return nil, errors.Errorf("HostPath and PersistentVolumeClaim are currently the conly supported VolumeSource") + } +} + +// Create a map of volume name to KubeVolume +func InitializeVolumes(specVolumes []v1.Volume) (map[string]*KubeVolume, error) { + volumes := make(map[string]*KubeVolume) + + for _, specVolume := range specVolumes { + volume, err := VolumeFromSource(specVolume.VolumeSource) + if err != nil { + return nil, err + } + + volumes[specVolume.Name] = volume + } + + return volumes, nil +} diff --git a/pkg/specgen/volumes.go b/pkg/specgen/volumes.go index 1178f9960..a4f42d715 100644 --- a/pkg/specgen/volumes.go +++ b/pkg/specgen/volumes.go @@ -87,8 +87,8 @@ func GenVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*Na // Do not check source dir for anonymous volumes if len(splitVol) > 1 { - if err := parse.ValidateVolumeHostDir(src); err != nil { - return nil, nil, nil, err + if len(src) == 0 { + return nil, nil, nil, errors.New("host directory cannot be empty") } } if err := parse.ValidateVolumeCtrDir(dest); err != nil { diff --git a/test/apiv2/25-containersMore.at b/test/apiv2/25-containersMore.at index e0e6f7222..4f6b80a5f 100644 --- a/test/apiv2/25-containersMore.at +++ b/test/apiv2/25-containersMore.at @@ -52,4 +52,31 @@ t POST libpod/containers/foo/unmount '' 204 t DELETE libpod/containers/foo?force=true 204 +podman run $IMAGE true + +t GET libpod/containers/json?last=1 200 \ + length=1 \ + .[0].Id~[0-9a-f]\\{64\\} \ + .[0].Image=$IMAGE \ + .[0].Command[0]="true" \ + .[0].State~\\\(exited\\\|stopped\\\) \ + .[0].ExitCode=0 \ + .[0].IsInfra=false + +cid=$(jq -r '.[0].Id' <<<"$output") + +t GET libpod/generate/$cid/kube 200 +like "$output" ".*apiVersion:.*" "Check generated kube yaml - apiVersion" +like "$output" ".*kind:\\sPod.*" "Check generated kube yaml - kind: Pod" +like "$output" ".*metadata:.*" "Check generated kube yaml - metadata" +like "$output" ".*spec:.*" "Check generated kube yaml - spec" + +t GET libpod/generate/$cid/kube?service=true 200 +like "$output" ".*apiVersion:.*" "Check generated kube yaml(service=true) - apiVersion" +like "$output" ".*kind:\\sPod.*" "Check generated kube yaml(service=true) - kind: Pod" +like "$output" ".*metadata:.*" "Check generated kube yaml(service=true) - metadata" +like "$output" ".*spec:.*" "Check generated kube yaml(service=true) - spec" +like "$output" ".*kind:\\sService.*" "Check generated kube yaml(service=true) - kind: Service" + +t DELETE libpod/containers/$cid 204 # vim: filetype=sh diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index 139a90ac7..adcf74f7e 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -499,4 +499,15 @@ var _ = Describe("Podman network", func() { exec.WaitWithDefaultTimeout() Expect(exec.ExitCode()).To(BeZero()) }) + + It("podman network create/remove macvlan", func() { + net := "macvlan" + stringid.GenerateNonCryptoID() + nc := podmanTest.Podman([]string{"network", "create", "--macvlan", "lo", net}) + nc.WaitWithDefaultTimeout() + Expect(nc.ExitCode()).To(Equal(0)) + + nc = podmanTest.Podman([]string{"network", "rm", net}) + nc.WaitWithDefaultTimeout() + Expect(nc.ExitCode()).To(Equal(0)) + }) }) diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 92e4544f9..5ecfdd6b5 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -164,9 +164,15 @@ spec: volumes: {{ range . }} - name: {{ .Name }} + {{- if (eq .VolumeType "HostPath") }} hostPath: - path: {{ .Path }} - type: {{ .Type }} + path: {{ .HostPath.Path }} + type: {{ .HostPath.Type }} + {{- end }} + {{- if (eq .VolumeType "PersistentVolumeClaim") }} + persistentVolumeClaim: + claimName: {{ .PersistentVolumeClaim.ClaimName }} + {{- end }} {{ end }} {{ end }} status: {} @@ -692,19 +698,44 @@ func getCtrNameInPod(pod *Pod) string { return fmt.Sprintf("%s-%s", pod.Name, defaultCtrName) } -type Volume struct { - Name string +type HostPath struct { Path string Type string } -// getVolume takes a type and a location for a volume -// giving it a default name of volName -func getVolume(vType, vPath string) *Volume { +type PersistentVolumeClaim struct { + ClaimName string +} + +type Volume struct { + VolumeType string + Name string + HostPath + PersistentVolumeClaim +} + +// getHostPathVolume takes a type and a location for a HostPath +// volume giving it a default name of volName +func getHostPathVolume(vType, vPath string) *Volume { + return &Volume{ + VolumeType: "HostPath", + Name: defaultVolName, + HostPath: HostPath{ + Path: vPath, + Type: vType, + }, + } +} + +// getHostPathVolume takes a name for a Persistentvolumeclaim +// volume giving it a default name of volName +func getPersistentVolumeClaimVolume(vName string) *Volume { return &Volume{ - Name: defaultVolName, - Path: vPath, - Type: vType, + VolumeType: "PersistentVolumeClaim", + Name: defaultVolName, + PersistentVolumeClaim: PersistentVolumeClaim{ + ClaimName: vName, + }, } } @@ -1257,7 +1288,7 @@ spec: It("podman play kube test with non-existent empty HostPath type volume", func() { hostPathLocation := filepath.Join(tempdir, "file") - pod := getPod(withVolume(getVolume(`""`, hostPathLocation))) + pod := getPod(withVolume(getHostPathVolume(`""`, hostPathLocation))) err := generateKubeYaml("pod", pod, kubeYaml) Expect(err).To(BeNil()) @@ -1272,7 +1303,7 @@ spec: Expect(err).To(BeNil()) f.Close() - pod := getPod(withVolume(getVolume(`""`, hostPathLocation))) + pod := getPod(withVolume(getHostPathVolume(`""`, hostPathLocation))) err = generateKubeYaml("pod", pod, kubeYaml) Expect(err).To(BeNil()) @@ -1284,7 +1315,7 @@ spec: It("podman play kube test with non-existent File HostPath type volume", func() { hostPathLocation := filepath.Join(tempdir, "file") - pod := getPod(withVolume(getVolume("File", hostPathLocation))) + pod := getPod(withVolume(getHostPathVolume("File", hostPathLocation))) err := generateKubeYaml("pod", pod, kubeYaml) Expect(err).To(BeNil()) @@ -1299,7 +1330,7 @@ spec: Expect(err).To(BeNil()) f.Close() - pod := getPod(withVolume(getVolume("File", hostPathLocation))) + pod := getPod(withVolume(getHostPathVolume("File", hostPathLocation))) err = generateKubeYaml("pod", pod, kubeYaml) Expect(err).To(BeNil()) @@ -1311,7 +1342,7 @@ spec: It("podman play kube test with FileOrCreate HostPath type volume", func() { hostPathLocation := filepath.Join(tempdir, "file") - pod := getPod(withVolume(getVolume("FileOrCreate", hostPathLocation))) + pod := getPod(withVolume(getHostPathVolume("FileOrCreate", hostPathLocation))) err := generateKubeYaml("pod", pod, kubeYaml) Expect(err).To(BeNil()) @@ -1327,7 +1358,7 @@ spec: It("podman play kube test with DirectoryOrCreate HostPath type volume", func() { hostPathLocation := filepath.Join(tempdir, "file") - pod := getPod(withVolume(getVolume("DirectoryOrCreate", hostPathLocation))) + pod := getPod(withVolume(getHostPathVolume("DirectoryOrCreate", hostPathLocation))) err := generateKubeYaml("pod", pod, kubeYaml) Expect(err).To(BeNil()) @@ -1347,7 +1378,7 @@ spec: Expect(err).To(BeNil()) f.Close() - pod := getPod(withVolume(getVolume("Socket", hostPathLocation))) + pod := getPod(withVolume(getHostPathVolume("Socket", hostPathLocation))) err = generateKubeYaml("pod", pod, kubeYaml) Expect(err).To(BeNil()) @@ -1356,14 +1387,14 @@ spec: Expect(kube.ExitCode()).NotTo(Equal(0)) }) - It("podman play kube test with read only volume", func() { + It("podman play kube test with read only HostPath volume", func() { hostPathLocation := filepath.Join(tempdir, "file") f, err := os.Create(hostPathLocation) Expect(err).To(BeNil()) f.Close() ctr := getCtr(withVolumeMount(hostPathLocation, true), withImage(BB)) - pod := getPod(withVolume(getVolume("File", hostPathLocation)), withCtr(ctr)) + pod := getPod(withVolume(getHostPathVolume("File", hostPathLocation)), withCtr(ctr)) err = generateKubeYaml("pod", pod, kubeYaml) Expect(err).To(BeNil()) @@ -1379,6 +1410,26 @@ spec: Expect(inspect.OutputToString()).To(ContainSubstring(correct)) }) + It("podman play kube test with PersistentVolumeClaim volume", func() { + volumeName := "namedVolume" + + ctr := getCtr(withVolumeMount("/test", false), withImage(BB)) + pod := getPod(withVolume(getPersistentVolumeClaimVolume(volumeName)), withCtr(ctr)) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", getCtrNameInPod(pod), "--format", "{{ (index .Mounts 0).Type }}:{{ (index .Mounts 0).Name }}"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + + correct := fmt.Sprintf("volume:%s", volumeName) + Expect(inspect.OutputToString()).To(Equal(correct)) + }) + It("podman play kube applies labels to pods", func() { var numReplicas int32 = 5 expectedLabelKey := "key1" |