From 17779d338026fc680d21432ee1994b34f83326d9 Mon Sep 17 00:00:00 2001 From: Aidan Macdonald Date: Fri, 6 Nov 2020 21:49:51 -0800 Subject: [PATCH 1/2] Adding support for podman play volumes per https://github.com/containers/podman/issues/5788 Signed-off-by: Aidan Macdonald --- pkg/domain/entities/play.go | 13 ++++- pkg/domain/infra/abi/play.go | 37 +++++++++++++ pkg/domain/infra/abi/play_test.go | 89 +++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 1 deletion(-) diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go index 356e6869df..a09bb4af72 100644 --- a/pkg/domain/entities/play.go +++ b/pkg/domain/entities/play.go @@ -38,8 +38,19 @@ type PlayKubePod struct { Logs []string } +// PlayKubeVolume represents a single named volume +type PlayKubeVolume struct { + // Name - Name of the volume created as a result of play kube. + Name string + // Labels - Volume Labels + Labels map[string]string + // MountPoint - Volume MountPoint + MountPoint string +} + // PlayKubeReport contains the results of running play kube. type PlayKubeReport struct { // Pods - pods created by play kube. - Pods []PlayKubePod + Pods []PlayKubePod + Volumes []PlayKubeVolume } diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index fbba00984a..dfe4e17505 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -7,6 +7,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strconv" "strings" "github.com/containers/buildah/pkg/parse" @@ -71,12 +72,48 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Deployment", path) } return ic.playKubeDeployment(ctx, &deploymentYAML, options) + case "PersistentVolume": + var volYAML v1.PersistentVolume + if err := yaml.Unmarshal(content, &volYAML); err != nil { + return nil, errors.Wrapf(err, "unable to read YAML %q as Kube PersistentVolume", path) + } + return ic.playKubePersistentVolume(ctx, &volYAML, options) default: return nil, errors.Errorf("invalid YAML kind: %q. [Pod|Deployment] are the only supported Kubernetes Kinds", kubeObject.Kind) } } +func (ic *ContainerEngine) playKubePersistentVolume(ctx context.Context, deploymentYAML *v1.PersistentVolume, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) { + var ( + report entities.PlayKubeReport + ) + + volOptions := []libpod.VolumeCreateOption{ + libpod.WithVolumeLabels(deploymentYAML.GetLabels()), + libpod.WithVolumeName(deploymentYAML.GetName()), + } + + uid, err := strconv.Atoi(string(deploymentYAML.GetUID())) + if err != nil { + return nil, errors.Errorf("Failed to parse UID for volume %s", err) + } + volOptions = append(volOptions, libpod.WithVolumeUID(uid)) + + vol, err := ic.Libpod.NewVolume(ctx, volOptions...) + if err != nil { + return nil, err + } + + report.Volumes = append(report.Volumes, entities.PlayKubeVolume{ + Name: vol.Name(), + Labels: vol.Labels(), + MountPoint: vol.MountPoint(), + }) + + return &report, nil +} + func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAML *v1apps.Deployment, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) { var ( deploymentName string diff --git a/pkg/domain/infra/abi/play_test.go b/pkg/domain/infra/abi/play_test.go index 5595476c31..32249f4eb9 100644 --- a/pkg/domain/infra/abi/play_test.go +++ b/pkg/domain/infra/abi/play_test.go @@ -2,8 +2,14 @@ package abi import ( "bytes" + "context" + "io/ioutil" + "os" + "reflect" "testing" + "github.com/containers/podman/v2/libpod" + "github.com/containers/podman/v2/pkg/domain/entities" "github.com/stretchr/testify/assert" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -252,3 +258,86 @@ func TestEnvVarValue(t *testing.T) { }) } } + +func TestContainerEngine_PlayKube(t *testing.T) { + type fields struct { + Libpod *libpod.Runtime + } + type args struct { + ctx context.Context + path string + options entities.PlayKubeOptions + } + type test struct { + name string + fields fields + args args + want *entities.PlayKubeReport + wantErr bool + } + + runtime, err := libpod.NewRuntime(context.TODO()) + if err != nil { + t.Error(err) + } + + contents := [][]string{ + {"PersistentVolume", ` +apiVersion: v1 +kind: PersistentVolume +metadata: + name: foo-pv +spec: + storageClassName: "" + claimRef: + name: foo-pvc + namespace: foo +`}, + } + + files := []*os.File{} + tests := []test{} + for _, content := range contents { + tmpfile, err := ioutil.TempFile("", "playfile") + if err != nil { + t.Error(err) + } + files = append(files, tmpfile) + + if _, err := tmpfile.Write([]byte(content[1])); err != nil { + t.Error(err) + } + + tests = append(tests, test{ + name: content[0], + fields: fields{Libpod: runtime}, + args: args{ + ctx: context.TODO(), + options: entities.PlayKubeOptions{}, + path: tmpfile.Name(), + }, + want: &entities.PlayKubeReport{ + Volumes: []entities.PlayKubeVolume{ + {Name: "foo-pvc"}, + }, + }, + wantErr: false, + }) + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ic := &ContainerEngine{ + Libpod: tt.fields.Libpod, + } + got, err := ic.PlayKube(tt.args.ctx, tt.args.path, tt.args.options) + if (err != nil) != tt.wantErr { + t.Errorf("ContainerEngine.PlayKube() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ContainerEngine.PlayKube() = %v, want %v", got, tt.want) + } + }) + } +} From 8774a791e99d9dd313f8c8a1f3c77eb468d6ee81 Mon Sep 17 00:00:00 2001 From: Aidan Macdonald Date: Sat, 7 Nov 2020 16:26:07 -0800 Subject: [PATCH 2/2] Using e2e test instead of unit --- pkg/domain/infra/abi/play_test.go | 89 ------------------------------- test/e2e/play_kube_test.go | 34 ++++++++++++ 2 files changed, 34 insertions(+), 89 deletions(-) diff --git a/pkg/domain/infra/abi/play_test.go b/pkg/domain/infra/abi/play_test.go index 32249f4eb9..5595476c31 100644 --- a/pkg/domain/infra/abi/play_test.go +++ b/pkg/domain/infra/abi/play_test.go @@ -2,14 +2,8 @@ package abi import ( "bytes" - "context" - "io/ioutil" - "os" - "reflect" "testing" - "github.com/containers/podman/v2/libpod" - "github.com/containers/podman/v2/pkg/domain/entities" "github.com/stretchr/testify/assert" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -258,86 +252,3 @@ func TestEnvVarValue(t *testing.T) { }) } } - -func TestContainerEngine_PlayKube(t *testing.T) { - type fields struct { - Libpod *libpod.Runtime - } - type args struct { - ctx context.Context - path string - options entities.PlayKubeOptions - } - type test struct { - name string - fields fields - args args - want *entities.PlayKubeReport - wantErr bool - } - - runtime, err := libpod.NewRuntime(context.TODO()) - if err != nil { - t.Error(err) - } - - contents := [][]string{ - {"PersistentVolume", ` -apiVersion: v1 -kind: PersistentVolume -metadata: - name: foo-pv -spec: - storageClassName: "" - claimRef: - name: foo-pvc - namespace: foo -`}, - } - - files := []*os.File{} - tests := []test{} - for _, content := range contents { - tmpfile, err := ioutil.TempFile("", "playfile") - if err != nil { - t.Error(err) - } - files = append(files, tmpfile) - - if _, err := tmpfile.Write([]byte(content[1])); err != nil { - t.Error(err) - } - - tests = append(tests, test{ - name: content[0], - fields: fields{Libpod: runtime}, - args: args{ - ctx: context.TODO(), - options: entities.PlayKubeOptions{}, - path: tmpfile.Name(), - }, - want: &entities.PlayKubeReport{ - Volumes: []entities.PlayKubeVolume{ - {Name: "foo-pvc"}, - }, - }, - wantErr: false, - }) - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ic := &ContainerEngine{ - Libpod: tt.fields.Libpod, - } - got, err := ic.PlayKube(tt.args.ctx, tt.args.path, tt.args.options) - if (err != nil) != tt.wantErr { - t.Errorf("ContainerEngine.PlayKube() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("ContainerEngine.PlayKube() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 1d683e9871..9f249c2603 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -172,6 +172,23 @@ spec: status: {} ` +var persistentVolumeYamlTemplate = ` +apiVersion: v1 +kind: PersistentVolume +metadata: + name: {{ .Name }} + labels: + type: {{ .Type }} +spec: + storageClassName: {{ .StorageClass }} + capacity: + storage: {{ .StorageCapacity }} + accessModes: + - {{ .AccessMode }} + hostPath: + path: "{{ .Path }} +` + var deploymentYamlTemplate = ` apiVersion: v1 kind: Deployment @@ -316,6 +333,8 @@ func generateKubeYaml(kind string, object interface{}, pathname string) error { yamlTemplate = podYamlTemplate case "deployment": yamlTemplate = deploymentYamlTemplate + case "persistentvolume": + yamlTemplate = persistentVolumeYamlTemplate default: return fmt.Errorf("unsupported kubernetes kind") } @@ -844,6 +863,21 @@ var _ = Describe("Podman play kube", func() { Expect(inspect.OutputToString()).To(ContainSubstring(`[echo hello world]`)) }) + It("podman play kube test volume correct command", func() { + vol := getVolume("type", "path") + err := generateKubeYaml("persistentvolume", vol, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"volume", "inspect", vol.Name, "--format", "'{{ .Name }}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(vol.Name)) + }) + It("podman play kube test restartPolicy", func() { // podName, set, expect testSli := [][]string{