Skip to content
This repository was archived by the owner on Apr 25, 2023. It is now read-only.

Remove all metadata fields but labels from targets of kf federate #1086

Merged
merged 1 commit into from
Aug 16, 2019
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# Unreleased
- [#1086](https://github.com/kubernetes-sigs/kubefed/pull/1086)
`kubefedctl federate` now removes all metadata fields except labels
from the template of federated resources created from a
non-federated resource. Previously `metadata.annotations` and
`metadata.finalizers` were not removed which could result in
propagation errors.
- [#1079](https://github.com/kubernetes-sigs/kubefed/issues/1079) The
spec field is now required in generated federated types. For types
generated previously, a check has been added so that a missing spec
Expand Down
21 changes: 18 additions & 3 deletions pkg/kubefedctl/federate/federate.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,10 @@ func FederatedResourceFromTargetResource(typeConfig typeconfig.Interface, resour
fedAPIResource := typeConfig.GetFederatedType()
targetResource := resource.DeepCopy()

targetKind := typeConfig.GetTargetType().Kind

// Special handling is needed for some controller set fields.
switch typeConfig.GetTargetType().Kind {
switch targetKind {
case ctlutil.NamespaceKind:
{
unstructured.RemoveNestedField(targetResource.Object, "spec", "finalizers")
Expand Down Expand Up @@ -397,9 +399,22 @@ func FederatedResourceFromTargetResource(typeConfig typeconfig.Interface, resour
resourceNamespace := getNamespace(typeConfig, qualifiedName)
fedResource := &unstructured.Unstructured{}
SetBasicMetaFields(fedResource, fedAPIResource, qualifiedName.Name, resourceNamespace, "")
RemoveUnwantedFields(targetResource)

err := unstructured.SetNestedField(fedResource.Object, targetResource.Object, ctlutil.SpecField, ctlutil.TemplateField)
// Warn if annotations are present in case the intention is to
// define annotations in the template of the federated resource.
annotations, _, err := unstructured.NestedMap(targetResource.Object, "metadata", "annotations")
if err != nil {
return nil, errors.Wrap(err, "Failed to retrieve metadata.annotations")
}
if len(annotations) > 0 {
klog.Warningf("Annotations defined for %s %q will not appear in the template of the federated resource: %v", targetKind, qualifiedName, annotations)
}

if err := RemoveUnwantedFields(targetResource); err != nil {
return nil, err
}

err = unstructured.SetNestedField(fedResource.Object, targetResource.Object, ctlutil.SpecField, ctlutil.TemplateField)
if err != nil {
return nil, err
}
Expand Down
28 changes: 18 additions & 10 deletions pkg/kubefedctl/federate/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,27 @@ import (
"sigs.k8s.io/kubefed/pkg/kubefedctl/util"
)

var systemMetadataFields = []string{"selfLink", "uid", "resourceVersion", "generation", "creationTimestamp", "deletionTimestamp", "deletionGracePeriodSeconds"}

func RemoveUnwantedFields(resource *unstructured.Unstructured) {
for _, field := range systemMetadataFields {
unstructured.RemoveNestedField(resource.Object, "metadata", field)
// For resources with pod template subresource (jobs, deployments, replicasets)
unstructured.RemoveNestedField(resource.Object, "spec", "template", "metadata", field)
}
unstructured.RemoveNestedField(resource.Object, "metadata", "name")
unstructured.RemoveNestedField(resource.Object, "metadata", "namespace")
func RemoveUnwantedFields(resource *unstructured.Unstructured) error {
unstructured.RemoveNestedField(resource.Object, "apiVersion")
unstructured.RemoveNestedField(resource.Object, "kind")
unstructured.RemoveNestedField(resource.Object, "status")

// All metadata fields save labels should be cleared. Other
// metadata fields will be set by the system on creation or
// subsequently by controllers.
labels, _, err := unstructured.NestedMap(resource.Object, "metadata", "labels")
if err != nil {
return errors.Wrap(err, "Failed to retrieve metadata.labels")
}
unstructured.RemoveNestedField(resource.Object, "metadata")
if len(labels) > 0 {
err := unstructured.SetNestedMap(resource.Object, labels, "metadata", "labels")
if err != nil {
return errors.Wrap(err, "Failed to set metadata.labels")
}
}

return nil
}

func SetBasicMetaFields(resource *unstructured.Unstructured, apiResource metav1.APIResource, name, namespace, generateName string) {
Expand Down
8 changes: 6 additions & 2 deletions test/e2e/federate.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,12 @@ func validateTemplateEquality(tl common.TestLogger, fedResource, targetResource

expectedResource := &unstructured.Unstructured{}
expectedResource.Object = templateMap.(map[string]interface{})
federate.RemoveUnwantedFields(expectedResource)
federate.RemoveUnwantedFields(targetResource)
if err := federate.RemoveUnwantedFields(expectedResource); err != nil {
tl.Fatalf("Failed to remove unwanted fields from expected resource: %v", err)
}
if err := federate.RemoveUnwantedFields(targetResource); err != nil {
tl.Fatalf("Failed to remove unwanted fields from target resource: %v", err)
}
if kind == util.NamespaceKind {
unstructured.RemoveNestedField(targetResource.Object, "spec", "finalizers")
}
Expand Down