sigs.k8s.io/cluster-api@v1.7.1/internal/contract/metadata.go (about) 1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package contract 18 19 import ( 20 "github.com/pkg/errors" 21 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 22 23 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 24 ) 25 26 // Metadata provides a helper struct for working with Metadata. 27 type Metadata struct { 28 path Path 29 } 30 31 // Path returns the path of the metadata. 32 func (m *Metadata) Path() Path { 33 return m.path 34 } 35 36 // Get gets the metadata object. 37 func (m *Metadata) Get(obj *unstructured.Unstructured) (*clusterv1.ObjectMeta, error) { 38 labelsPath := append(m.path, "labels") 39 labelsValue, ok, err := unstructured.NestedStringMap(obj.UnstructuredContent(), labelsPath...) 40 if err != nil { 41 return nil, errors.Wrap(err, "failed to retrieve control plane metadata.labels") 42 } 43 if !ok { 44 labelsValue = map[string]string{} 45 } 46 47 annotationsPath := append(m.path, "annotations") 48 annotationsValue, ok, err := unstructured.NestedStringMap(obj.UnstructuredContent(), annotationsPath...) 49 if err != nil { 50 return nil, errors.Wrap(err, "failed to retrieve control plane metadata.annotations") 51 } 52 if !ok { 53 annotationsValue = map[string]string{} 54 } 55 56 return &clusterv1.ObjectMeta{ 57 Labels: labelsValue, 58 Annotations: annotationsValue, 59 }, nil 60 } 61 62 // Set sets the metadata value. 63 // Note: We are blanking out empty label annotations, thus avoiding triggering infinite reconcile 64 // given that at json level label: {} or annotation: {} is different from no field, which is the 65 // corresponding value stored in etcd given that those fields are defined as omitempty. 66 func (m *Metadata) Set(obj *unstructured.Unstructured, metadata *clusterv1.ObjectMeta) error { 67 labelsPath := append(m.path, "labels") 68 unstructured.RemoveNestedField(obj.UnstructuredContent(), labelsPath...) 69 if len(metadata.Labels) > 0 { 70 if err := unstructured.SetNestedStringMap(obj.UnstructuredContent(), metadata.Labels, labelsPath...); err != nil { 71 return errors.Wrap(err, "failed to set control plane metadata.labels") 72 } 73 } 74 75 annotationsPath := append(m.path, "annotations") 76 unstructured.RemoveNestedField(obj.UnstructuredContent(), annotationsPath...) 77 if len(metadata.Annotations) > 0 { 78 if err := unstructured.SetNestedStringMap(obj.UnstructuredContent(), metadata.Annotations, annotationsPath...); err != nil { 79 return errors.Wrap(err, "failed to set control plane metadata.annotations") 80 } 81 } 82 return nil 83 }