From 28477ea47dbcac8d959d719d817a57706dd4fb09 Mon Sep 17 00:00:00 2001 From: Sam Batschelet Date: Thu, 25 Apr 2019 16:27:46 -0400 Subject: [PATCH] *: add resource sync for etcd-quorum-guard This PR adds functionality which will sync ConfigMaps and Secrets from openshift-config namespace to openshift-etcd. The result will be etcd TLS resources available for etcd-quorum-guard to consume. Signed-off-by: Sam Batschelet --- lib/resourceapply/core.go | 91 +++++++++++++++++++++++++++++++++++++++ pkg/operator/operator.go | 1 + pkg/operator/sync.go | 29 +++++++++++++ 3 files changed, 121 insertions(+) diff --git a/lib/resourceapply/core.go b/lib/resourceapply/core.go index fb482296a7..4ef14aa10a 100644 --- a/lib/resourceapply/core.go +++ b/lib/resourceapply/core.go @@ -46,3 +46,94 @@ func ApplySecret(client coreclientv1.SecretsGetter, required *corev1.Secret) (*c actual, err := client.Secrets(required.Namespace).Update(existing) return actual, true, err } + +// ApplyConfigMap merges objectmeta, requires data +func ApplyConfigMap(client coreclientv1.ConfigMapsGetter, required *corev1.ConfigMap) (*corev1.ConfigMap, bool, error) { + existing, err := client.ConfigMaps(required.Namespace).Get(required.Name, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + actual, err := client.ConfigMaps(required.Namespace).Create(required) + return actual, true, err + } + if err != nil { + return nil, false, err + } + + modified := resourcemerge.BoolPtr(false) + existingCopy := existing.DeepCopy() + + resourcemerge.EnsureObjectMeta(modified, &existingCopy.ObjectMeta, required.ObjectMeta) + + var modifiedKeys []string + for existingCopyKey, existingCopyValue := range existingCopy.Data { + if requiredValue, ok := required.Data[existingCopyKey]; !ok || (existingCopyValue != requiredValue) { + modifiedKeys = append(modifiedKeys, "data."+existingCopyKey) + } + } + for requiredKey := range required.Data { + if _, ok := existingCopy.Data[requiredKey]; !ok { + modifiedKeys = append(modifiedKeys, "data."+requiredKey) + } + } + + dataSame := len(modifiedKeys) == 0 + if dataSame && !*modified { + return existingCopy, false, nil + } + existingCopy.Data = required.Data + + actual, err := client.ConfigMaps(required.Namespace).Update(existingCopy) + + return actual, true, err +} + +// SyncConfigMap syncs ConfigMap opjectmeta from source namespace to destination +func SyncConfigMap(client coreclientv1.ConfigMapsGetter, sourceNamespace, sourceName, targetNamespace, targetName string, ownerRefs []metav1.OwnerReference) (*corev1.ConfigMap, bool, error) { + source, err := client.ConfigMaps(sourceNamespace).Get(sourceName, metav1.GetOptions{}) + sourceCopy := source.DeepCopy() + + switch { + case apierrors.IsNotFound(err): + deleteErr := client.ConfigMaps(targetNamespace).Delete(targetName, nil) + if apierrors.IsNotFound(deleteErr) { + return nil, false, nil + } + if deleteErr == nil { + return nil, true, nil + } + return nil, false, deleteErr + case err != nil: + return nil, false, err + default: + sourceCopy.Namespace = targetNamespace + sourceCopy.Name = targetName + sourceCopy.ResourceVersion = "" + sourceCopy.OwnerReferences = ownerRefs + return ApplyConfigMap(client, sourceCopy) + } +} + +// SyncConfigMap syncs Secret opjectmeta from source namespace to destination +func SyncSecret(client coreclientv1.SecretsGetter, sourceNamespace, sourceName, targetNamespace, targetName string, ownerRefs []metav1.OwnerReference) (*corev1.Secret, bool, error) { + source, err := client.Secrets(sourceNamespace).Get(sourceName, metav1.GetOptions{}) + sourceCopy := source.DeepCopy() + + switch { + case apierrors.IsNotFound(err): + deleteErr := client.Secrets(targetNamespace).Delete(targetName, nil) + if apierrors.IsNotFound(deleteErr) { + return nil, false, nil + } + if deleteErr == nil { + return nil, true, nil + } + return nil, false, deleteErr + case err != nil: + return nil, false, err + default: + sourceCopy.Namespace = targetNamespace + sourceCopy.Name = targetName + sourceCopy.ResourceVersion = "" + sourceCopy.OwnerReferences = ownerRefs + return ApplySecret(client, sourceCopy) + } +} diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index 865599211a..faf53634f3 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -399,6 +399,7 @@ func (optr *Operator) sync(key string) error { {"mcs", optr.syncMachineConfigServer}, {"mcd", optr.syncMachineConfigDaemon}, {"required-pools", optr.syncRequiredMachineConfigPools}, + {"required-resources", optr.syncRequiredMachineConfigResources}, } return optr.syncAll(rc, syncFuncs) } diff --git a/pkg/operator/sync.go b/pkg/operator/sync.go index 29f7f52589..e30bc85e2b 100644 --- a/pkg/operator/sync.go +++ b/pkg/operator/sync.go @@ -345,6 +345,35 @@ func (optr *Operator) syncRequiredMachineConfigPools(config renderConfig) error return nil } +// syncRequiredMachineConfigResources ensures that the ConfigMap and Secret resources are synced from source namespace to destination. +func (optr *Operator) syncRequiredMachineConfigResources(config renderConfig) error { + sourceNamespace := "openshift-config" + destinationNamespace := "openshift-etcd" + + _, _, err := resourceapply.SyncConfigMap( + optr.kubeClient.CoreV1(), + sourceNamespace, + "etcd-metric-serving-ca", + destinationNamespace, + "etcd-metric-serving-ca", + []metav1.OwnerReference{}) + if err != nil { + return err + } + + _, _, errs := resourceapply.SyncSecret( + optr.kubeClient.CoreV1(), + sourceNamespace, + "etcd-metric-client", + destinationNamespace, + "etcd-metric-client", + []metav1.OwnerReference{}) + if errs != nil { + return errs + } + return nil +} + const ( deploymentRolloutPollInterval = time.Second deploymentRolloutTimeout = 10 * time.Minute