Skip to content

Commit

Permalink
fix(kubernetes): do not fail to deploy List kinds (e.g. ConfigMapList) (
Browse files Browse the repository at this point in the history
#4501)

* fix(kubernetes): do not fail to deploy List kinds (e.g. configMapList)

Fixes #4500

Co-authored-by: Srihas Konduru <srihas-g@users.noreply.github.com>

* improvement: slightly increase defensiveness

Maybe the List is actually a CRD? Seems to be unlikely as other tools like Kustomize also treat kinds matching `*List` as lists.
But add a better error message here if items contains something unexpected just in case.

This logic is more or less equivalent to https://github.com/kubernetes-sigs/kustomize/blob/cf3e81b590ab1fd7fc8f50849535f44bfea0d355/api/resource/factory.go#L550

---------

Co-authored-by: Srihas Konduru <srihas-g@users.noreply.github.com>
  • Loading branch information
stefreak and Srihas Konduru committed Jun 1, 2023
1 parent a0d79f7 commit 25e1637
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 2 deletions.
23 changes: 21 additions & 2 deletions core/src/plugins/kubernetes/kubernetes-type/common.ts
Expand Up @@ -47,13 +47,32 @@ export async function getManifests({
defaultNamespace: string
readFromSrcDir?: boolean
}): Promise<KubernetesResource[]> {
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)
Expand Down
@@ -0,0 +1,6 @@
kind: "Deploy"
type: "kubernetes"
name: "config-map-list"
spec:
files:
- 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
Expand Up @@ -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", () => {
Expand Down

0 comments on commit 25e1637

Please sign in to comment.