From 7ef97fa49ef8a38fc79a061dcb56a9405811302d Mon Sep 17 00:00:00 2001 From: Ygal Blum Date: Sun, 27 Aug 2023 15:52:32 +0300 Subject: [PATCH] Kube - support List documents Flatten List into documents Add List type to meta/v1 Add unittest Add e2e test Signed-off-by: Ygal Blum --- pkg/domain/infra/abi/play.go | 37 +++++++++++++--- pkg/domain/infra/abi/play_test.go | 17 ++++++++ .../apimachinery/pkg/apis/meta/v1/types.go | 12 ++++++ test/e2e/play_kube_test.go | 43 +++++++++++++++++++ 4 files changed, 103 insertions(+), 6 deletions(-) diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index edff325134..6f87ef4d0f 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -24,6 +24,7 @@ import ( "github.com/containers/podman/v4/pkg/domain/entities" v1apps "github.com/containers/podman/v4/pkg/k8s.io/api/apps/v1" v1 "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1" + metav1 "github.com/containers/podman/v4/pkg/k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/containers/podman/v4/pkg/specgen" "github.com/containers/podman/v4/pkg/specgen/generate" "github.com/containers/podman/v4/pkg/specgen/generate/kube" @@ -1261,13 +1262,37 @@ func splitMultiDocYAML(yamlContent []byte) ([][]byte, error) { return nil, fmt.Errorf("multi doc yaml could not be split: %w", err) } - if o != nil { - // back to bytes - document, err := yamlv3.Marshal(o) - if err != nil { - return nil, fmt.Errorf("individual doc yaml could not be marshalled: %w", err) - } + if o == nil { + continue + } + // back to bytes + document, err := yamlv3.Marshal(o) + if err != nil { + return nil, fmt.Errorf("individual doc yaml could not be marshalled: %w", err) + } + + kind, err := getKubeKind(document) + if err != nil { + return nil, fmt.Errorf("couldn't get object kind: %w", err) + } + + // The items in a document of kind "List" are fully qualified resources + // So, they can be treated as separate documents + if kind == "List" { + var kubeList metav1.List + if err := yaml.Unmarshal(document, &kubeList); err != nil { + return nil, err + } + for _, item := range kubeList.Items { + itemDocument, err := yamlv3.Marshal(item) + if err != nil { + return nil, fmt.Errorf("individual doc yaml could not be marshalled: %w", err) + } + + documentList = append(documentList, itemDocument) + } + } else { documentList = append(documentList, document) } } diff --git a/pkg/domain/infra/abi/play_test.go b/pkg/domain/infra/abi/play_test.go index 39b99f4633..37b5863f64 100644 --- a/pkg/domain/infra/abi/play_test.go +++ b/pkg/domain/infra/abi/play_test.go @@ -246,6 +246,23 @@ kind: Pod "multi doc yaml could not be split", 0, }, + { + "DocWithList", + ` +apiVersion: v1 +kind: List +items: +- apiVersion: v1 + kind: Pod +- apiVersion: v1 + kind: Pod +- apiVersion: v1 + kind: Pod +`, + false, + "", + 3, + }, } for _, test := range tests { diff --git a/pkg/k8s.io/apimachinery/pkg/apis/meta/v1/types.go b/pkg/k8s.io/apimachinery/pkg/apis/meta/v1/types.go index 7482266e7e..41053090f3 100644 --- a/pkg/k8s.io/apimachinery/pkg/apis/meta/v1/types.go +++ b/pkg/k8s.io/apimachinery/pkg/apis/meta/v1/types.go @@ -929,6 +929,18 @@ const ( CauseTypeResourceVersionTooLarge CauseType = "ResourceVersionTooLarge" ) +// List holds a list of objects, which may not be known by the server. +type List struct { + TypeMeta `json:",inline"` + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + // +optional + ListMeta `json:"metadata,omitempty"` + + // List of objects + Items []interface{} `json:"items"` +} + // APIVersions lists the versions that are available, to allow clients to // discover the API at /api, which is the root path of the legacy v1 API. // diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index f6a13cd1bf..8bb6f07c74 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -1190,6 +1190,34 @@ spec: - "sysctl kernel.msgmax" ` +var listPodAndConfigMap = ` +apiVersion: v1 +kind: List +items: +- apiVersion: v1 + kind: ConfigMap + metadata: + name: test-list-configmap + data: + foo: bar +- apiVersion: v1 + kind: Pod + metadata: + name: test-list-pod + spec: + containers: + - name: container + image: quay.io/libpod/alpine:latest + command: [ "/bin/sh", "-c", "env" ] + env: + - name: FOO + valueFrom: + configMapKeyRef: + name: test-list-configmap + key: foo + restartPolicy: Never +` + var ( defaultCtrName = "testCtr" defaultCtrCmd = []string{"top"} @@ -5955,4 +5983,19 @@ EXPOSE 2004-2005/tcp`, ALPINE) Expect(ps).Should(Exit(0)) Expect(ps.OutputToString()).To(ContainSubstring(podID[:12] + "-infra")) }) + + It("podman play kube support List kind", func() { + listYamlPathname := filepath.Join(podmanTest.TempDir, "list.yaml") + err = writeYaml(listPodAndConfigMap, listYamlPathname) + Expect(err).ToNot(HaveOccurred()) + + kube := podmanTest.Podman([]string{"play", "kube", listYamlPathname}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + inspect := podmanTest.Podman([]string{"inspect", "test-list-pod-container", "--format", "'{{ .Config.Env }}'"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(`FOO=bar`)) + }) })