From 816233f5893b9fcf69b0a6a024efa06e929fa179 Mon Sep 17 00:00:00 2001 From: Tim Schrodi Date: Fri, 25 Sep 2020 14:55:59 +0200 Subject: [PATCH] Fix overwritten changes --- bindings-go/apis/v2/componentdescriptor.go | 77 ++++++++++- bindings-go/apis/v2/validation/validation.go | 125 ++++++++++++++---- .../apis/v2/validation/validation_test.go | 82 +++++------- 3 files changed, 209 insertions(+), 75 deletions(-) diff --git a/bindings-go/apis/v2/componentdescriptor.go b/bindings-go/apis/v2/componentdescriptor.go index f1f72f50..2deb9389 100644 --- a/bindings-go/apis/v2/componentdescriptor.go +++ b/bindings-go/apis/v2/componentdescriptor.go @@ -64,7 +64,7 @@ type ComponentSpec struct { // Sources defines sources that produced the component Sources []Source `json:"sources"` // ComponentReferences references component dependencies that can be resolved in the current context. - ComponentReferences []ObjectMeta `json:"componentReferences"` + ComponentReferences []ComponentReference `json:"componentReferences"` // LocalResources defines internal resources that are created by the component LocalResources []Resource `json:"localResources"` // ExternalResources defines external resources that are not produced by a third party. @@ -85,6 +85,10 @@ type ObjectMeta struct { Name string `json:"name"` // Version is the semver version of the object. Version string `json:"version"` + // Labels defines an optional set of additional labels + // describing the object. + // +optional + Labels []Label `json:"labels,omitempty"` } // GetName returns the name of the object. @@ -107,6 +111,16 @@ func (o *ObjectMeta) SetVersion(version string) { o.Version = version } +// GetLabels returns the label of the object. +func (o ObjectMeta) GetLabels() []Label { + return o.Labels +} + +// SetLabels sets the labels of the object. +func (o *ObjectMeta) SetLabels(labels []Label) { + o.Labels = labels +} + // ObjectType describes the type of a object type ObjectType struct { // Type describes the type of the object. @@ -123,6 +137,58 @@ func (t *ObjectType) SetType(ttype string) { t.Type = ttype } +// Label is a label that can be set on objects. +type Label struct { + // Name is the unique name of the label. + Name string `json:"name"` + // Value is the json/yaml data of the label + Value json.RawMessage `json:"value"` +} + +// ComponentReference describes the reference to another component in the registry. // Source is the definition of a component's source. +type ComponentReference struct { + // Name is the context unique name of the object. + Name string `json:"name"` + // ComponentName describes the remote name of the referenced object + ComponentName string `json:"componentName"` + // Version is the semver version of the object. + Version string `json:"version"` + // Labels defines an optional set of additional labels + // describing the object. + // +optional + Labels []Label `json:"labels,omitempty"` +} + +// GetName returns the name of the object. +func (o ComponentReference) GetName() string { + return o.Name +} + +// SetName sets the name of the object. +func (o *ComponentReference) SetName(name string) { + o.Name = name +} + +// GetVersion returns the version of the object. +func (o ComponentReference) GetVersion() string { + return o.Version +} + +// SetVersion sets the version of the object. +func (o *ComponentReference) SetVersion(version string) { + o.Version = version +} + +// GetLabels returns the label of the object. +func (o ComponentReference) GetLabels() []Label { + return o.Labels +} + +// SetLabels sets the labels of the object. +func (o *ComponentReference) SetLabels(labels []Label) { + o.Labels = labels +} + // NameAccessor describes a accessor for a named object. type NameAccessor interface { // GetName returns the name of the object. @@ -139,10 +205,19 @@ type VersionAccessor interface { SetVersion(version string) } +// LabelsAccessor describes a accessor for a labeled object. +type LabelsAccessor interface { + // GetLabels returns the labels of the object. + GetLabels() []Label + // SetLabels sets the labels of the object. + SetLabels(labels []Label) +} + // ObjectMetaAccessor describes a accessor for named and versioned object. type ObjectMetaAccessor interface { NameAccessor VersionAccessor + LabelsAccessor } // TypedObjectAccessor defines the accessor for a typed component with additional data. diff --git a/bindings-go/apis/v2/validation/validation.go b/bindings-go/apis/v2/validation/validation.go index a1441244..e8edf5fb 100644 --- a/bindings-go/apis/v2/validation/validation.go +++ b/bindings-go/apis/v2/validation/validation.go @@ -51,63 +51,69 @@ func validate(fldPath *field.Path, component *v2.ComponentDescriptor) field.Erro allErrs = append(allErrs, err) } - allErrs = append(allErrs, validateObjectMeta(compPath, component.ObjectMeta)...) + allErrs = append(allErrs, validateObjectMeta(compPath, component)...) srcPath := compPath.Child("sources") - for i, src := range component.Sources { - allErrs = append(allErrs, validateSource(srcPath.Index(i), src)...) - } + allErrs = append(allErrs, validateSources(srcPath, component.Sources)...) refPath := compPath.Child("componentReferences") - for i, ref := range component.ComponentReferences { - allErrs = append(allErrs, validateObjectMeta(refPath.Index(i), ref)...) - } + allErrs = append(allErrs, validateComponentReferences(refPath, component.ComponentReferences)...) localPath := compPath.Child("localResources") - for i, res := range component.LocalResources { - allErrs = append(allErrs, validateResource(localPath.Index(i), res)...) - if res.GetVersion() != component.GetVersion() { - allErrs = append(allErrs, field.Invalid(localPath.Index(i).Child("version"), "invalid version", - "version of local resources must match the component version")) - } - } + allErrs = append(allErrs, validateResources(localPath, component.LocalResources, component.GetVersion())...) extPath := compPath.Child("externalResources") - for i, res := range component.ExternalResources { - allErrs = append(allErrs, validateResource(extPath.Index(i), res)...) - } + allErrs = append(allErrs, validateResources(extPath, component.ExternalResources, "")...) return allErrs } -func validateObjectMeta(fldPath *field.Path, om v2.ObjectMeta) field.ErrorList { +func validateObjectMeta(fldPath *field.Path, om v2.ObjectMetaAccessor) field.ErrorList { allErrs := field.ErrorList{} - if len(om.Name) == 0 { + if len(om.GetName()) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("name"), "must specify a name")) } - if len(om.Version) == 0 { + if len(om.GetVersion()) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("version"), "must specify a version")) } + if len(om.GetLabels()) != 0 { + allErrs = append(allErrs, validateLabels(fldPath.Child("labels"), om.GetLabels())...) + } + return allErrs +} + +func validateSources(fldPath *field.Path, sources []v2.Source) field.ErrorList { + allErrs := field.ErrorList{} + srcNames := make(map[string]struct{}) + for i, src := range sources { + srcPath := fldPath.Index(i) + allErrs = append(allErrs, validateSource(srcPath, src)...) + + if _, ok := srcNames[src.Name]; ok { + allErrs = append(allErrs, field.Duplicate(srcPath, "duplicate source")) + continue + } + srcNames[src.Name] = struct{}{} + } return allErrs } -func validateSource(fldPath *field.Path, res v2.Source) field.ErrorList { +func validateSource(fldPath *field.Path, src v2.Source) field.ErrorList { allErrs := field.ErrorList{} - if len(res.GetName()) == 0 { + if len(src.GetName()) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("name"), "must specify a name")) } - if len(res.GetType()) == 0 { + if len(src.GetType()) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("type"), "must specify a type")) } - return allErrs } func validateResource(fldPath *field.Path, res v2.Resource) field.ErrorList { allErrs := field.ErrorList{} - allErrs = append(allErrs, validateObjectMeta(fldPath, res.ObjectMeta)...) + allErrs = append(allErrs, validateObjectMeta(fldPath, &res)...) - if len(res.GetType()) == 0 { + if res.TypedObjectAccessor == nil || len(res.GetType()) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("type"), "must specify a type")) } @@ -123,3 +129,70 @@ func validateProvider(fldPath *field.Path, provider v2.ProviderType) *field.Erro } return nil } + +func validateLabels(fldPath *field.Path, labels []v2.Label) field.ErrorList { + allErrs := field.ErrorList{} + labelNames := make(map[string]struct{}) + for i, label := range labels { + labelPath := fldPath.Index(i) + if len(label.Name) == 0 { + allErrs = append(allErrs, field.Required(labelPath.Child("name"), "must specify a name")) + continue + } + + if _, ok := labelNames[label.Name]; ok { + allErrs = append(allErrs, field.Duplicate(labelPath, "duplicate label name")) + continue + } + labelNames[label.Name] = struct{}{} + } + return allErrs +} + +func validateComponentReference(fldPath *field.Path, cr v2.ComponentReference) field.ErrorList { + allErrs := field.ErrorList{} + if len(cr.ComponentName) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("componentName"), "must specify a component name")) + } + allErrs = append(allErrs, validateObjectMeta(fldPath, &cr)...) + return allErrs +} + +func validateComponentReferences(fldPath *field.Path, refs []v2.ComponentReference) field.ErrorList { + allErrs := field.ErrorList{} + refNames := make(map[string]struct{}) + for i, ref := range refs { + refPath := fldPath.Index(i) + allErrs = append(allErrs, validateComponentReference(refPath, ref)...) + + if _, ok := refNames[ref.Name]; ok { + allErrs = append(allErrs, field.Duplicate(refPath, "duplicate component reference name")) + continue + } + refNames[ref.Name] = struct{}{} + } + return allErrs +} + +func validateResources(fldPath *field.Path, resources []v2.Resource, componentVersion string) field.ErrorList { + allErrs := field.ErrorList{} + resourceNames := make(map[string]struct{}) + for i, res := range resources { + localPath := fldPath.Index(i) + allErrs = append(allErrs, validateResource(localPath, res)...) + + // only validate the component version if it is defined + if len(componentVersion) != 0 { + if res.GetVersion() != componentVersion { + allErrs = append(allErrs, field.Invalid(localPath.Child("version"), "invalid version", + "version of local resources must match the component version")) + } + } + if _, ok := resourceNames[res.Name]; ok { + allErrs = append(allErrs, field.Duplicate(localPath, "duplicated local resource")) + continue + } + resourceNames[res.Name] = struct{}{} + } + return allErrs +} diff --git a/bindings-go/apis/v2/validation/validation_test.go b/bindings-go/apis/v2/validation/validation_test.go index 0a041007..59d82bcd 100644 --- a/bindings-go/apis/v2/validation/validation_test.go +++ b/bindings-go/apis/v2/validation/validation_test.go @@ -152,12 +152,14 @@ var _ = Describe("Validation", func() { Context("#Sources", func() { It("should forbid if a duplicated component's source is defined", func() { - comp.Sources = []v2.Resource{ + comp.Sources = []v2.Source{ { - ObjectMeta: v2.ObjectMeta{Name: "a"}, + Name: "a", + TypedObjectAccessor: v2.NewCustomType("custom", nil), }, { - ObjectMeta: v2.ObjectMeta{Name: "a"}, + Name: "a", + TypedObjectAccessor: v2.NewCustomType("custom", nil), }, } errList := validate(nil, comp) @@ -172,11 +174,9 @@ var _ = Describe("Validation", func() { It("should pass if a reference is set", func() { comp.ComponentReferences = []v2.ComponentReference{ { + Name: "test", ComponentName: "test", - ObjectMeta: v2.ObjectMeta{ - Name: "test", - Version: "1.2.3", - }, + Version: "1.2.3", }, } errList := validate(nil, comp) @@ -194,9 +194,7 @@ var _ = Describe("Validation", func() { comp.ComponentReferences = []v2.ComponentReference{ { ComponentName: "test", - ObjectMeta: v2.ObjectMeta{ - Version: "1.2.3", - }, + Version: "1.2.3", }, } errList := validate(nil, comp) @@ -209,10 +207,8 @@ var _ = Describe("Validation", func() { It("should forbid if a reference's component name is missing", func() { comp.ComponentReferences = []v2.ComponentReference{ { - ObjectMeta: v2.ObjectMeta{ - Name: "test", - Version: "1.2.3", - }, + Name: "test", + Version: "1.2.3", }, } errList := validate(nil, comp) @@ -226,9 +222,7 @@ var _ = Describe("Validation", func() { comp.ComponentReferences = []v2.ComponentReference{ { ComponentName: "test", - ObjectMeta: v2.ObjectMeta{ - Name: "test", - }, + Name: "test", }, } errList := validate(nil, comp) @@ -241,14 +235,10 @@ var _ = Describe("Validation", func() { It("should forbid if a duplicated component reference is defined", func() { comp.ComponentReferences = []v2.ComponentReference{ { - ObjectMeta: v2.ObjectMeta{ - Name: "test", - }, + Name: "test", }, { - ObjectMeta: v2.ObjectMeta{ - Name: "test", - }, + Name: "test", }, } errList := validate(nil, comp) @@ -299,7 +289,7 @@ var _ = Describe("Validation", func() { }) Context("#ExternalResources", func() { - It("should forbid if a duplicated local resource is defined", func() { + It("should forbid if a duplicated external resource is defined", func() { comp.ExternalResources = []v2.Resource{ { ObjectMeta: v2.ObjectMeta{ @@ -326,18 +316,16 @@ var _ = Describe("Validation", func() { comp.ComponentReferences = []v2.ComponentReference{ { ComponentName: "test", - ObjectMeta: v2.ObjectMeta{ - Name: "test", - Version: "1.2.3", - Labels: []v2.Label{ - { - Name: "l1", - Value: []byte{}, - }, - { - Name: "l1", - Value: []byte{}, - }, + Name: "test", + Version: "1.2.3", + Labels: []v2.Label{ + { + Name: "l1", + Value: []byte{}, + }, + { + Name: "l1", + Value: []byte{}, }, }, }, @@ -354,18 +342,16 @@ var _ = Describe("Validation", func() { comp.ComponentReferences = []v2.ComponentReference{ { ComponentName: "test", - ObjectMeta: v2.ObjectMeta{ - Name: "test", - Version: "1.2.3", - Labels: []v2.Label{ - { - Name: "l1", - Value: []byte{}, - }, - { - Name: "l2", - Value: []byte{}, - }, + Name: "test", + Version: "1.2.3", + Labels: []v2.Label{ + { + Name: "l1", + Value: []byte{}, + }, + { + Name: "l2", + Value: []byte{}, }, }, },