Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ssa: Add read function that validates resources #228

Merged
merged 1 commit into from
Jan 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions ssa/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ func ReadObject(r io.Reader) (*unstructured.Unstructured, error) {
}

// ReadObjects decodes the YAML or JSON documents from the given reader into unstructured Kubernetes API objects.
// The documents which do not subscribe to the Kubernetes Object interface, are silently dropped from the result.
func ReadObjects(r io.Reader) ([]*unstructured.Unstructured, error) {
reader := yamlutil.NewYAMLOrJSONDecoder(r, 2048)
objects := make([]*unstructured.Unstructured, 0)
Expand Down Expand Up @@ -175,6 +176,50 @@ func ReadObjects(r io.Reader) ([]*unstructured.Unstructured, error) {
return objects, nil
}

// ReadKubernetesObjects decodes the YAML or JSON documents from the given reader into unstructured Kubernetes API objects.
// If any of the given resources do not subscribe to the Kubernetes Object interface, an error is returned.
func ReadKubernetesObjects(r io.Reader) ([]*unstructured.Unstructured, error) {
reader := yamlutil.NewYAMLOrJSONDecoder(r, 2048)
objects := make([]*unstructured.Unstructured, 0)

for {
obj := &unstructured.Unstructured{}
err := reader.Decode(obj)
if err != nil {
if err == io.EOF {
err = nil
break
}
return objects, err
}

if obj.Object == nil {
continue
}

if obj.IsList() {
err = obj.EachListItem(func(item runtime.Object) error {
obj := item.(*unstructured.Unstructured)
if !IsKubernetesObject(obj) {
return fmt.Errorf("failed to decode Kubernetes object from: %v", obj)
}
objects = append(objects, obj)
return nil
})
if err != nil {
return objects, err
}
continue
}

if !IsKubernetesObject(obj) {
return objects, fmt.Errorf("failed to decode Kubernetes object from: %v", obj)
}
}

return objects, nil
}

// ObjectToYAML encodes the given Kubernetes API object to YAML.
func ObjectToYAML(object *unstructured.Unstructured) string {
var builder strings.Builder
Expand Down
77 changes: 77 additions & 0 deletions ssa/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,80 @@ func TestCmpMaskData(t *testing.T) {
}

}

func TestReadKubernetesObjects(t *testing.T) {
testCases := []struct {
name string
resources string
expectError bool
}{
{
name: "valid resources",
resources: `
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: crossplane-provider-aws1
spec:
package: crossplane/provider-aws:v0.23.0
controllerConfigRef:
name: provider-aws
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: crossplane-provider-aws2
spec:
package: crossplane/provider-aws:v0.23.0
controllerConfigRef:
name: provider-aws
`,
expectError: false,
},
{
name: "some invalid resources",
resources: `
---
piVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: crossplane-provider-aws1
spec:
package: crossplane/provider-aws:v0.23.0
controllerConfigRef:
name: provider-aws
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: crossplane-provider-aws2
spec:
package: crossplane/provider-aws:v0.23.0
controllerConfigRef:
name: provider-aws
`,
expectError: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
_, err := ReadKubernetesObjects(strings.NewReader(tc.resources))
if err != nil && !tc.expectError {
t.Errorf("unexpected error: %v", err)
}

if err != nil && tc.expectError {
validObj, readErr := ReadObjects(strings.NewReader(tc.resources))
if readErr != nil {
t.Errorf("unexpected error: %v", readErr)
}

if len(validObj) != 1 {
t.Errorf("unexpected objects: %v", validObj)
}
}
})
}
}