diff --git a/federation/apis/federation/validation/validation.go b/federation/apis/federation/validation/validation.go index db5dcdbe580..be936f567fc 100644 --- a/federation/apis/federation/validation/validation.go +++ b/federation/apis/federation/validation/validation.go @@ -22,8 +22,6 @@ import ( "k8s.io/kubernetes/pkg/util/validation/field" ) -var ValidateClusterName = validation.NameIsDNS1035Label - func ValidateClusterSpec(spec *federation.ClusterSpec, fieldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} // address is required. @@ -34,7 +32,7 @@ func ValidateClusterSpec(spec *federation.ClusterSpec, fieldPath *field.Path) fi } func ValidateCluster(cluster *federation.Cluster) field.ErrorList { - allErrs := validation.ValidateObjectMeta(&cluster.ObjectMeta, false, ValidateClusterName, field.NewPath("metadata")) + allErrs := validation.ValidateObjectMeta(&cluster.ObjectMeta, false, validation.ValidateClusterName, field.NewPath("metadata")) allErrs = append(allErrs, ValidateClusterSpec(&cluster.Spec, field.NewPath("spec"))...) return allErrs } diff --git a/pkg/api/meta.go b/pkg/api/meta.go index 03d434e44d4..a05d694435b 100644 --- a/pkg/api/meta.go +++ b/pkg/api/meta.go @@ -131,3 +131,10 @@ func (meta *ObjectMeta) SetOwnerReferences(references []metatypes.OwnerReference } meta.OwnerReferences = newReferences } + +func (meta *ObjectMeta) GetClusterName() string { + return meta.ClusterName +} +func (meta *ObjectMeta) SetClusterName(clusterName string) { + meta.ClusterName = clusterName +} diff --git a/pkg/api/meta/interfaces.go b/pkg/api/meta/interfaces.go index f8179869d88..a12c7076146 100644 --- a/pkg/api/meta/interfaces.go +++ b/pkg/api/meta/interfaces.go @@ -62,6 +62,8 @@ type Object interface { SetFinalizers(finalizers []string) GetOwnerReferences() []metatypes.OwnerReference SetOwnerReferences([]metatypes.OwnerReference) + GetClusterName() string + SetClusterName(clusterName string) } var _ Object = &runtime.Unstructured{} diff --git a/pkg/api/types.go b/pkg/api/types.go index 1db2e50ecb0..bfd5b9535fe 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -149,6 +149,11 @@ type ObjectMeta struct { // from the list. If the deletionTimestamp of the object is non-nil, entries // in this list can only be removed. Finalizers []string `json:"finalizers,omitempty"` + + // The name of the cluster which the object belongs to. + // This is used to distinguish resources with same name and namespace in different clusters. + // This field is not set anywhere right now and apiserver is going to ignore it if set in create or update request. + ClusterName string `json:"clusterName,omitempty"` } const ( diff --git a/pkg/api/v1/meta.go b/pkg/api/v1/meta.go index d5ba042a200..6f95cf7bc73 100644 --- a/pkg/api/v1/meta.go +++ b/pkg/api/v1/meta.go @@ -83,3 +83,10 @@ func (meta *ObjectMeta) SetOwnerReferences(references []metatypes.OwnerReference } meta.OwnerReferences = newReferences } + +func (meta *ObjectMeta) GetClusterName() string { + return meta.ClusterName +} +func (meta *ObjectMeta) SetClusterName(clusterName string) { + meta.ClusterName = clusterName +} diff --git a/pkg/api/v1/types.go b/pkg/api/v1/types.go index 8b77739c181..00e47a961f5 100644 --- a/pkg/api/v1/types.go +++ b/pkg/api/v1/types.go @@ -186,6 +186,11 @@ type ObjectMeta struct { // from the list. If the deletionTimestamp of the object is non-nil, entries // in this list can only be removed. Finalizers []string `json:"finalizers,omitempty" patchStrategy:"merge" protobuf:"bytes,14,rep,name=finalizers"` + + // The name of the cluster which the object belongs to. + // This is used to distinguish resources with same name and namespace in different clusters. + // This field is not set anywhere right now and apiserver is going to ignore it if set in create or update request. + ClusterName string `json:"clusterName,omitempty"` } const ( diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index b754f39c5cb..9d4ac4bff03 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -279,6 +279,9 @@ var ValidateServiceAccountName = NameIsDNSSubdomain // trailing dashes are allowed. var ValidateEndpointsName = NameIsDNSSubdomain +// ValidateClusterName can be used to check whether the given cluster name is valid. +var ValidateClusterName = NameIsDNS1035Label + // NameIsDNSSubdomain is a ValidateNameFunc for names that must be a DNS subdomain. func NameIsDNSSubdomain(name string, prefix bool) []string { if prefix { @@ -364,6 +367,11 @@ func ValidateObjectMeta(meta *api.ObjectMeta, requiresNamespace bool, nameFn Val allErrs = append(allErrs, field.Forbidden(fldPath.Child("namespace"), "not allowed on this type")) } } + if len(meta.ClusterName) != 0 { + for _, msg := range ValidateClusterName(meta.ClusterName, false) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("clusterName"), meta.ClusterName, msg)) + } + } allErrs = append(allErrs, ValidateNonnegativeField(meta.Generation, fldPath.Child("generation"))...) allErrs = append(allErrs, unversionedvalidation.ValidateLabels(meta.Labels, fldPath.Child("labels"))...) allErrs = append(allErrs, ValidateAnnotations(meta.Annotations, fldPath.Child("annotations"))...) @@ -425,6 +433,7 @@ func ValidateObjectMetaUpdate(newMeta, oldMeta *api.ObjectMeta, fldPath *field.P allErrs = append(allErrs, ValidateImmutableField(newMeta.Namespace, oldMeta.Namespace, fldPath.Child("namespace"))...) allErrs = append(allErrs, ValidateImmutableField(newMeta.UID, oldMeta.UID, fldPath.Child("uid"))...) allErrs = append(allErrs, ValidateImmutableField(newMeta.CreationTimestamp, oldMeta.CreationTimestamp, fldPath.Child("creationTimestamp"))...) + allErrs = append(allErrs, ValidateImmutableField(newMeta.ClusterName, oldMeta.ClusterName, fldPath.Child("clusterName"))...) allErrs = append(allErrs, unversionedvalidation.ValidateLabels(newMeta.Labels, fldPath.Child("labels"))...) allErrs = append(allErrs, ValidateAnnotations(newMeta.Annotations, fldPath.Child("annotations"))...) diff --git a/pkg/runtime/types.go b/pkg/runtime/types.go index 239c65b9d87..960bbef92a2 100644 --- a/pkg/runtime/types.go +++ b/pkg/runtime/types.go @@ -456,6 +456,14 @@ func (u *Unstructured) SetFinalizers(finalizers []string) { u.setNestedSlice(finalizers, "metadata", "finalizers") } +func (u *Unstructured) GetClusterName() string { + return getNestedString(u.Object, "metadata", "clusterName") +} + +func (u *Unstructured) SetClusterName(clusterName string) { + u.setNestedField(clusterName, "metadata", "clusterName") +} + // UnstructuredList allows lists that do not have Golang structs // registered to be manipulated generically. This can be used to deal // with the API lists from a plug-in. diff --git a/pkg/runtime/unstructured_test.go b/pkg/runtime/unstructured_test.go index df0217aa7db..e47abf13294 100644 --- a/pkg/runtime/unstructured_test.go +++ b/pkg/runtime/unstructured_test.go @@ -160,6 +160,7 @@ func TestUnstructuredGetters(t *testing.T) { "finalizer.1", "finalizer.2", }, + "clusterName": "cluster123", }, }, } @@ -232,6 +233,9 @@ func TestUnstructuredGetters(t *testing.T) { if got, want := unstruct.GetFinalizers(), []string{"finalizer.1", "finalizer.2"}; !reflect.DeepEqual(got, want) { t.Errorf("GetFinalizers()=%v, want %v", got, want) } + if got, want := unstruct.GetClusterName(), "cluster123"; got != want { + t.Errorf("GetClusterName()=%v, want %v", got, want) + } } func TestUnstructuredSetters(t *testing.T) { @@ -277,6 +281,7 @@ func TestUnstructuredSetters(t *testing.T) { "finalizer.1", "finalizer.2", }, + "clusterName": "cluster123", }, }, } @@ -311,6 +316,7 @@ func TestUnstructuredSetters(t *testing.T) { } unstruct.SetOwnerReferences(newOwnerReferences) unstruct.SetFinalizers([]string{"finalizer.1", "finalizer.2"}) + unstruct.SetClusterName("cluster123") if !reflect.DeepEqual(unstruct, want) { t.Errorf("Wanted: \n%s\n Got:\n%s", want, unstruct)