diff --git a/pkg/restore/merge_service_account.go b/pkg/restore/merge_service_account.go index 53b05ab75..8bd3d8c9c 100644 --- a/pkg/restore/merge_service_account.go +++ b/pkg/restore/merge_service_account.go @@ -24,8 +24,6 @@ import ( "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" - - "github.com/heptio/velero/pkg/util/collections" ) // mergeServiceAccount takes a backed up serviceaccount and merges attributes into the current in-cluster service account. @@ -46,9 +44,9 @@ func mergeServiceAccounts(fromCluster, fromBackup *unstructured.Unstructured) (* desired.ImagePullSecrets = mergeLocalObjectReferenceSlices(desired.ImagePullSecrets, backupSA.ImagePullSecrets) - desired.Labels = collections.MergeMaps(desired.Labels, backupSA.Labels) + desired.Labels = mergeMaps(desired.Labels, backupSA.Labels) - desired.Annotations = collections.MergeMaps(desired.Annotations, backupSA.Annotations) + desired.Annotations = mergeMaps(desired.Annotations, backupSA.Annotations) desiredUnstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(desired) if err != nil { @@ -95,6 +93,24 @@ func mergeLocalObjectReferenceSlices(first, second []corev1api.LocalObjectRefere return first } +// mergeMaps takes two map[string]string and merges missing keys from the second into the first. +// If a key already exists, its value is not overwritten. +func mergeMaps(first, second map[string]string) map[string]string { + // If the first map passed in is empty, just use all of the second map's data + if first == nil { + first = map[string]string{} + } + + for k, v := range second { + _, ok := first[k] + if !ok { + first[k] = v + } + } + + return first +} + // generatePatch will calculate a JSON merge patch for an object's desired state. // If the passed in objects are already equal, nil is returned. func generatePatch(fromCluster, desired *unstructured.Unstructured) ([]byte, error) { diff --git a/pkg/restore/merge_service_account_test.go b/pkg/restore/merge_service_account_test.go index 0e5a04452..038fdf9d2 100644 --- a/pkg/restore/merge_service_account_test.go +++ b/pkg/restore/merge_service_account_test.go @@ -315,6 +315,60 @@ func stripWhitespace(s string) string { }, s) } +func TestMergeMaps(t *testing.T) { + var testCases = []struct { + name string + source map[string]string + destination map[string]string + expected map[string]string + }{ + { + name: "nil destination should result in source being copied", + destination: nil, + source: map[string]string{ + "k1": "v1", + }, + expected: map[string]string{ + "k1": "v1", + }, + }, + { + name: "keys missing from destination should be copied from source", + destination: map[string]string{ + "k2": "v2", + }, + source: map[string]string{ + "k1": "v1", + }, + expected: map[string]string{ + "k1": "v1", + "k2": "v2", + }, + }, + { + name: "matching key should not have value copied from source", + destination: map[string]string{ + "k1": "v1", + }, + source: map[string]string{ + "k1": "v2", + }, + expected: map[string]string{ + "k1": "v1", + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + + result := mergeMaps(tc.destination, tc.source) + + assert.Equal(t, tc.expected, result) + }) + } +} + func TestGeneratePatch(t *testing.T) { tests := []struct { name string