From 32a6a5787ff0805874ba02b26c0efd54e7f2238d Mon Sep 17 00:00:00 2001 From: Andrea Decorte <104198+andreadecorte@users.noreply.github.com> Date: Wed, 16 Feb 2022 20:33:34 +0100 Subject: [PATCH] Add support for parsing manifests contained into List objects (#263) --- e2e/tests/00_static_files.yaml | 9 +++ ...loyment-deprecated-and-non-deprecated.yaml | 78 +++++++++++++++++++ .../list/list-deployment-non-deprecated.yaml | 42 ++++++++++ pkg/api/versions.go | 19 ++++- pkg/api/versions_test.go | 24 ++++++ 5 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 e2e/tests/assets/list/list-deployment-deprecated-and-non-deprecated.yaml create mode 100644 e2e/tests/assets/list/list-deployment-non-deprecated.yaml diff --git a/e2e/tests/00_static_files.yaml b/e2e/tests/00_static_files.yaml index c564fdf9..bf63c668 100644 --- a/e2e/tests/00_static_files.yaml +++ b/e2e/tests/00_static_files.yaml @@ -69,3 +69,12 @@ testcases: assertions: - result.code ShouldEqual 0 - result.systemout ShouldEqual "No output to display" + +- name: static files in a List + steps: + - script: pluto detect-files -d assets/list --target-versions k8s=v1.15.0 + assertions: + - result.code ShouldEqual 2 + - result.systemout ShouldContainSubstring "NAME KIND VERSION REPLACEMENT REMOVED DEPRECATED" + - result.systemout ShouldContainSubstring "utilities Deployment extensions/v1beta1 apps/v1 false true" + - result.systemout ShouldNotContainSubstring "utilities Deployment apps/v1 false false" \ No newline at end of file diff --git a/e2e/tests/assets/list/list-deployment-deprecated-and-non-deprecated.yaml b/e2e/tests/assets/list/list-deployment-deprecated-and-non-deprecated.yaml new file mode 100644 index 00000000..0e574239 --- /dev/null +++ b/e2e/tests/assets/list/list-deployment-deprecated-and-non-deprecated.yaml @@ -0,0 +1,78 @@ +apiVersion: v1 +items: +- apiVersion: extensions/v1beta1 + kind: Deployment + metadata: + name: utilities + labels: + app: utilities + spec: + replicas: 1 + selector: + matchLabels: + app: utilities + template: + metadata: + labels: + app: utilities + spec: + containers: + - name: utilities + image: quay.io/sudermanjr/utilities:latest + command: [ "/bin/bash", "-c", "--" ] + args: [ "while true; do sleep 30; done;" ] + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 10324 + capabilities: + drop: + - ALL + resources: + requests: + cpu: 30m + memory: 64Mi + limits: + cpu: 100m + memory: 128Mi +- apiVersion: apps/v1 + kind: Deployment + metadata: + name: utilities + labels: + app: utilities + spec: + replicas: 1 + selector: + matchLabels: + app: utilities + template: + metadata: + labels: + app: utilities + spec: + containers: + - name: utilities + image: quay.io/sudermanjr/utilities:latest + command: [ "/bin/bash", "-c", "--" ] + args: [ "while true; do sleep 30; done;" ] + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 10324 + capabilities: + drop: + - ALL + resources: + requests: + cpu: 30m + memory: 64Mi + limits: + cpu: 100m + memory: 128Mi +kind: List +metadata: + resourceVersion: '' + selfLink: '' \ No newline at end of file diff --git a/e2e/tests/assets/list/list-deployment-non-deprecated.yaml b/e2e/tests/assets/list/list-deployment-non-deprecated.yaml new file mode 100644 index 00000000..133c3644 --- /dev/null +++ b/e2e/tests/assets/list/list-deployment-non-deprecated.yaml @@ -0,0 +1,42 @@ +apiVersion: v1 +items: +- apiVersion: apps/v1 + kind: Deployment + metadata: + name: utilities + labels: + app: utilities + spec: + replicas: 1 + selector: + matchLabels: + app: utilities + template: + metadata: + labels: + app: utilities + spec: + containers: + - name: utilities + image: quay.io/sudermanjr/utilities:latest + command: [ "/bin/bash", "-c", "--" ] + args: [ "while true; do sleep 30; done;" ] + securityContext: + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 10324 + capabilities: + drop: + - ALL + resources: + requests: + cpu: 30m + memory: 64Mi + limits: + cpu: 100m + memory: 128Mi +kind: List +metadata: + resourceVersion: '' + selfLink: '' \ No newline at end of file diff --git a/pkg/api/versions.go b/pkg/api/versions.go index e56d5cef..18637e0c 100644 --- a/pkg/api/versions.go +++ b/pkg/api/versions.go @@ -33,6 +33,7 @@ type Stub struct { Kind string `json:"kind" yaml:"kind"` APIVersion string `json:"apiVersion" yaml:"apiVersion"` Metadata StubMeta `json:"metadata" yaml:"metadata"` + Items []Stub `json:"items" yaml:"items"` } // StubMeta will catch kube resource metadata @@ -132,7 +133,7 @@ func jsonToStub(data []byte) ([]*Stub, error) { if err != nil { return nil, err } - stubs = append(stubs, stub) + expandList(&stubs, stub) return stubs, nil } @@ -155,7 +156,7 @@ func yamlToStub(data []byte) ([]*Stub, error) { } return stubs, err } - stubs = append(stubs, stub) + expandList(&stubs, stub) } if stubs == nil && len(errs) > 0 { return nil, fmt.Errorf("one or more errors parsing yaml resulted in no versions found: %v", errs) @@ -163,6 +164,20 @@ func yamlToStub(data []byte) ([]*Stub, error) { return stubs, nil } +// expandList checks if we have a List manifest. +// If it is the case, the manifests inside are expanded, otherwise we just return the single manifest +func expandList(stubs *[]*Stub, currentStub *Stub) { + if currentStub.Items != nil { + klog.V(5).Infof("found a list with %d items, attempting to expand", len(currentStub.Items)) + for _, stub := range currentStub.Items { + currentItem := stub + *stubs = append(*stubs, ¤tItem) + } + } else { + *stubs = append(*stubs, currentStub) + } +} + // IsDeprecatedIn returns true if the version is deprecated in the applicable targetVersion // Will return false if the targetVersion passed is not a valid semver string func (v *Version) isDeprecatedIn(targetVersions map[string]string) bool { diff --git a/pkg/api/versions_test.go b/pkg/api/versions_test.go index 61649a79..5485fa5f 100644 --- a/pkg/api/versions_test.go +++ b/pkg/api/versions_test.go @@ -82,6 +82,12 @@ func Test_jsonToStub(t *testing.T) { want: []*Stub{{Kind: "foo", APIVersion: "bar"}}, wantErr: false, }, + { + name: "json list is multiple stubs", + data: []byte(`{"kind": "List", "apiVersion": "v1", "items": [{"kind": "foo", "apiVersion": "bar"},{"kind": "bar", "apiVersion": "foo"}]}`), + want: []*Stub{{Kind: "foo", APIVersion: "bar"},{Kind: "bar", APIVersion: "foo"}}, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -122,6 +128,12 @@ func Test_yamlToStub(t *testing.T) { want: []*Stub{{Kind: "foo", APIVersion: "bar"}}, wantErr: false, }, + { + name: "yaml list is multiple stubs", + data: []byte("kind: List\napiVersion: v1\nitems:\n- kind: foo\n apiVersion: bar\n- kind: bar\n apiVersion: foo"), + want: []*Stub{{Kind: "foo", APIVersion: "bar"},{Kind: "bar", APIVersion: "foo"}}, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -226,6 +238,12 @@ func Test_IsVersioned(t *testing.T) { want: []*Output{{APIVersion: &testVersionDeployment}}, wantErr: false, }, + { + name: "yaml list has version", + data: []byte("kind: List\napiVersion: v1\nitems:\n- kind: Deployment\n apiVersion: extensions/v1beta1"), + want: []*Output{{APIVersion: &testVersionDeployment}}, + wantErr: false, + }, { name: "json no version", data: []byte("{}"), @@ -250,6 +268,12 @@ func Test_IsVersioned(t *testing.T) { want: []*Output{{APIVersion: &testVersionDeployment}}, wantErr: false, }, + { + name: "json list has version", + data: []byte(`{"kind": "List", "apiVersion": "v1", "items": [{"kind": "Deployment", "apiVersion": "extensions/v1beta1"}]}`), + want: []*Output{{APIVersion: &testVersionDeployment}}, + wantErr: false, + }, { name: "not yaml", data: []byte("*."),