diff --git a/core/src/plugins/kubernetes/kubernetes-type/common.ts b/core/src/plugins/kubernetes/kubernetes-type/common.ts index cbb9f5ddd3..cfe2b2f73f 100644 --- a/core/src/plugins/kubernetes/kubernetes-type/common.ts +++ b/core/src/plugins/kubernetes/kubernetes-type/common.ts @@ -47,13 +47,32 @@ export async function getManifests({ defaultNamespace: string readFromSrcDir?: boolean }): Promise { - const manifests = await readManifests(ctx, action, log, readFromSrcDir) + const rawManifests = await readManifests(ctx, action, log, readFromSrcDir) as KubernetesResource[] + + // remove *List objects + const manifests = rawManifests.flatMap((manifest) => { + if (manifest.kind.endsWith("List")) { + if (!manifest.items || manifest.items.length === 0) { + // empty list + return [] + } else if (manifest.items.length > 0 && manifest.items[0].kind) { + // at least the first manifest has a kind: seems to be a valid List + return manifest.items as KubernetesResource[] + } else { + throw new PluginError("Failed to read Kubernetes manifest: Encountered an invalid List manifest", { + manifest + }) + } + } + return manifest + }) return Bluebird.map(manifests, async (manifest) => { // Ensure a namespace is set, if not already set, and if required by the resource type if (!manifest.metadata?.namespace) { if (!manifest.metadata) { - manifest.metadata = {} + // TODO: Type system complains that name is missing + (manifest as any).metadata = {} } const info = await api.getApiResourceInfo(log, manifest.apiVersion, manifest.kind) diff --git a/core/test/data/test-projects/kubernetes-module/config-map-list/garden.yml b/core/test/data/test-projects/kubernetes-module/config-map-list/garden.yml new file mode 100644 index 0000000000..ca100d9bcc --- /dev/null +++ b/core/test/data/test-projects/kubernetes-module/config-map-list/garden.yml @@ -0,0 +1,6 @@ +kind: "Deploy" +type: "kubernetes" +name: "config-map-list" +spec: + files: + - manifests.yaml diff --git a/core/test/data/test-projects/kubernetes-module/config-map-list/manifests.yaml b/core/test/data/test-projects/kubernetes-module/config-map-list/manifests.yaml new file mode 100644 index 0000000000..e09f886ec3 --- /dev/null +++ b/core/test/data/test-projects/kubernetes-module/config-map-list/manifests.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +items: +- apiVersion: v1 + data: + foo.json: test + kind: ConfigMap + metadata: + name: foo +- apiVersion: v1 + data: + bar.json: test + kind: ConfigMap + metadata: + name: bar +- apiVersion: v1 + data: + baz.json: test + kind: ConfigMap + metadata: + name: baz +kind: ConfigMapList diff --git a/core/test/integ/src/plugins/kubernetes/kubernetes-module/handlers.ts b/core/test/integ/src/plugins/kubernetes/kubernetes-module/handlers.ts index 995accb79d..d9cc7d1b20 100644 --- a/core/test/integ/src/plugins/kubernetes/kubernetes-module/handlers.ts +++ b/core/test/integ/src/plugins/kubernetes/kubernetes-module/handlers.ts @@ -332,6 +332,16 @@ describe("kubernetes-module handlers", () => { expect(ns1ResourceRefreshed, "originalNamespaceRefreshed").to.exist }) + + it("should successfully deploy List manifest kinds", async () => { + const configMapList = await getTestData("config-map-list", {}) + + // this should be 3, and not 1, as we transform *List objects to separate manifests + expect(configMapList.manifests.length).to.be.equal(3) + + // test successful deploy + await kubernetesDeploy(configMapList.deployParams) + }) }) describe("deleteService", () => {