From d98f9172a0a84fbb09bdff022a9712cd91ccf849 Mon Sep 17 00:00:00 2001 From: jillianwilson Date: Tue, 2 Mar 2021 16:59:21 -0400 Subject: [PATCH] Auto restart one password custom resource will be be added to converted kubernetes secret --- README.md | 12 ++++++++++ ...onepassword.com_v1_onepassworditem_cr.yaml | 1 - .../deployment/deployment_controller.go | 2 +- .../onepassworditem_controller.go | 4 +++- .../kubernetes_secrets_builder.go | 22 ++++++++++++++----- .../kubernetes_secrets_builder_test.go | 12 +++++++--- pkg/onepassword/secret_update_handler.go | 19 +++++----------- pkg/utils/string.go | 13 +++++++++++ 8 files changed, 59 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 6d7f0b0..2710620 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,18 @@ metadata: ``` If the value is not set, the auto reset settings on the namespace will be used. +**Per OnePasswordItem Custom Resource** +This method allows for managing auto restarts on a given OnePasswordItem custom resource. Auto restarts can by managed by setting the annotation `onepasswordoperator/auto_restart` to either `true` or `false` on the desired OnePasswordItem. An example of this is shown below: +```yaml +# enabled auto restarts for the OnePasswordItem +apiVersion: onepassword.com/v1 +kind: OnePasswordItem +metadata: + name: example + onepasswordoperator/auto_restart: "true" +``` +If the value is not set, the auto reset settings on the deployment will be used. + ## Development ### Creating a Docker image diff --git a/deploy/crds/onepassword.com_v1_onepassworditem_cr.yaml b/deploy/crds/onepassword.com_v1_onepassworditem_cr.yaml index d0a94dd..8afe8fc 100644 --- a/deploy/crds/onepassword.com_v1_onepassworditem_cr.yaml +++ b/deploy/crds/onepassword.com_v1_onepassworditem_cr.yaml @@ -2,6 +2,5 @@ apiVersion: onepassword.com/v1 kind: OnePasswordItem metadata: name: example - onepasswordoperator/auto_restart: "true" spec: itemPath: "vaults//items/" diff --git a/pkg/controller/deployment/deployment_controller.go b/pkg/controller/deployment/deployment_controller.go index d1fc744..500f60d 100644 --- a/pkg/controller/deployment/deployment_controller.go +++ b/pkg/controller/deployment/deployment_controller.go @@ -201,5 +201,5 @@ func (r *ReconcileDeployment) HandleApplyingDeployment(namespace string, annotat return fmt.Errorf("Failed to retrieve item: %v", err) } - return kubeSecrets.CreateKubernetesSecretFromItem(r.kubeClient, secretName, namespace, item) + return kubeSecrets.CreateKubernetesSecretFromItem(r.kubeClient, secretName, namespace, item, annotations[op.RestartDeploymentsAnnotation]) } diff --git a/pkg/controller/onepassworditem/onepassworditem_controller.go b/pkg/controller/onepassworditem/onepassworditem_controller.go index cfc8ab7..3c808bd 100644 --- a/pkg/controller/onepassworditem/onepassworditem_controller.go +++ b/pkg/controller/onepassworditem/onepassworditem_controller.go @@ -7,6 +7,7 @@ import ( onepasswordv1 "github.com/1Password/onepassword-operator/pkg/apis/onepassword/v1" kubeSecrets "github.com/1Password/onepassword-operator/pkg/kubernetessecrets" "github.com/1Password/onepassword-operator/pkg/onepassword" + op "github.com/1Password/onepassword-operator/pkg/onepassword" "github.com/1Password/onepassword-operator/pkg/utils" "github.com/1Password/connect-sdk-go/connect" @@ -143,11 +144,12 @@ func (r *ReconcileOnePasswordItem) removeOnePasswordFinalizerFromOnePasswordItem func (r *ReconcileOnePasswordItem) HandleOnePasswordItem(resource *onepasswordv1.OnePasswordItem, request reconcile.Request) error { secretName := resource.GetName() + autoRestart := resource.Annotations[op.RestartDeploymentsAnnotation] item, err := onepassword.GetOnePasswordItemByPath(r.opConnectClient, resource.Spec.ItemPath) if err != nil { return fmt.Errorf("Failed to retrieve item: %v", err) } - return kubeSecrets.CreateKubernetesSecretFromItem(r.kubeClient, secretName, resource.Namespace, item) + return kubeSecrets.CreateKubernetesSecretFromItem(r.kubeClient, secretName, resource.Namespace, item, autoRestart) } diff --git a/pkg/kubernetessecrets/kubernetes_secrets_builder.go b/pkg/kubernetessecrets/kubernetes_secrets_builder.go index 5f250b1..ebcf221 100644 --- a/pkg/kubernetessecrets/kubernetes_secrets_builder.go +++ b/pkg/kubernetessecrets/kubernetes_secrets_builder.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/1Password/connect-sdk-go/onepassword" + "github.com/1Password/onepassword-operator/pkg/utils" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -13,21 +14,30 @@ import ( logf "sigs.k8s.io/controller-runtime/pkg/log" ) -const onepasswordPrefix = "onepasswordoperator" -const NameAnnotation = onepasswordPrefix + "/item-name" -const VersionAnnotation = onepasswordPrefix + "/item-version" -const restartAnnotation = onepasswordPrefix + "/lastRestarted" -const ItemPathAnnotation = onepasswordPrefix + "/item-path" +const OnepasswordPrefix = "onepasswordoperator" +const NameAnnotation = OnepasswordPrefix + "/item-name" +const VersionAnnotation = OnepasswordPrefix + "/item-version" +const restartAnnotation = OnepasswordPrefix + "/lastRestarted" +const ItemPathAnnotation = OnepasswordPrefix + "/item-path" +const RestartDeploymentsAnnotation = OnepasswordPrefix + "/auto_restart" var log = logf.Log -func CreateKubernetesSecretFromItem(kubeClient kubernetesClient.Client, secretName, namespace string, item *onepassword.Item) error { +func CreateKubernetesSecretFromItem(kubeClient kubernetesClient.Client, secretName, namespace string, item *onepassword.Item, autoRestart string) error { itemVersion := fmt.Sprint(item.Version) annotations := map[string]string{ VersionAnnotation: itemVersion, ItemPathAnnotation: fmt.Sprintf("vaults/%v/items/%v", item.Vault.ID, item.ID), } + if autoRestart != "" { + _, err := utils.StringToBool(autoRestart) + if err != nil { + log.Error(err, "Error parsing %v annotation on Secret %v. Must be true or false. Defaulting to false.", RestartDeploymentsAnnotation, secretName) + return err + } + annotations[RestartDeploymentsAnnotation] = autoRestart + } secret := BuildKubernetesSecretFromOnePasswordItem(secretName, namespace, annotations, *item) currentSecret := &corev1.Secret{} diff --git a/pkg/kubernetessecrets/kubernetes_secrets_builder_test.go b/pkg/kubernetessecrets/kubernetes_secrets_builder_test.go index 8a706ec..cb331c6 100644 --- a/pkg/kubernetessecrets/kubernetes_secrets_builder_test.go +++ b/pkg/kubernetessecrets/kubernetes_secrets_builder_test.go @@ -13,6 +13,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" ) +const restartDeploymentAnnotation = "false" + type k8s struct { clientset kubernetes.Interface } @@ -28,7 +30,7 @@ func TestCreateKubernetesSecretFromOnePasswordItem(t *testing.T) { item.ID = "h46bb3jddvay7nxopfhvlwg35q" kubeClient := fake.NewFakeClient() - err := CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &item) + err := CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &item, restartDeploymentAnnotation) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -53,7 +55,7 @@ func TestUpdateKubernetesSecretFromOnePasswordItem(t *testing.T) { item.ID = "h46bb3jddvay7nxopfhvlwg35q" kubeClient := fake.NewFakeClient() - err := CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &item) + err := CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &item, restartDeploymentAnnotation) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -64,7 +66,7 @@ func TestUpdateKubernetesSecretFromOnePasswordItem(t *testing.T) { newItem.Version = 456 newItem.Vault.ID = "hfnjvi6aymbsnfc2xeeoheizda" newItem.ID = "h46bb3jddvay7nxopfhvlwg35q" - err = CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &newItem) + err = CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &newItem, restartDeploymentAnnotation) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -125,6 +127,10 @@ func compareAnnotationsToItem(annotations map[string]string, item onepassword.It if annotations[VersionAnnotation] != fmt.Sprint(item.Version) { t.Errorf("Expected annotation version to be %v but was %v", item.Version, annotations[VersionAnnotation]) } + + if annotations[RestartDeploymentsAnnotation] != "false" { + t.Errorf("Expected restart deployments annotation to be %v but was %v", restartDeploymentAnnotation, RestartDeploymentsAnnotation) + } } func compareFields(actualFields []*onepassword.ItemField, secretData map[string][]byte, t *testing.T) { diff --git a/pkg/onepassword/secret_update_handler.go b/pkg/onepassword/secret_update_handler.go index c898dda..7b38a7c 100644 --- a/pkg/onepassword/secret_update_handler.go +++ b/pkg/onepassword/secret_update_handler.go @@ -3,11 +3,10 @@ package onepassword import ( "context" "fmt" - "strconv" - "strings" "time" kubeSecrets "github.com/1Password/onepassword-operator/pkg/kubernetessecrets" + "github.com/1Password/onepassword-operator/pkg/utils" "github.com/1Password/connect-sdk-go/connect" "github.com/1Password/connect-sdk-go/onepassword" @@ -184,9 +183,9 @@ func isSecretSetForAutoRestart(secret *corev1.Secret, deployment *appsv1.Deploym return isDeploymentSetForAutoRestart(deployment, setForAutoRestartByNamespace) } - restartDeploymentBool, err := stringToBool(restartDeployment) + restartDeploymentBool, err := utils.StringToBool(restartDeployment) if err != nil { - log.Error(err, "Error parsing %v annotation on Deployment %v. Must be true or false. Defaulting to false.", RestartDeploymentsAnnotation, deployment.Name) + log.Error(err, "Error parsing %v annotation on Secret %v. Must be true or false. Defaulting to false.", RestartDeploymentsAnnotation, secret.Name) return false } return restartDeploymentBool @@ -199,7 +198,7 @@ func isDeploymentSetForAutoRestart(deployment *appsv1.Deployment, setForAutoRest return setForAutoRestartByNamespace[deployment.Namespace] } - restartDeploymentBool, err := stringToBool(restartDeployment) + restartDeploymentBool, err := utils.StringToBool(restartDeployment) if err != nil { log.Error(err, "Error parsing %v annotation on Deployment %v. Must be true or false. Defaulting to false.", RestartDeploymentsAnnotation, deployment.Name) return false @@ -214,18 +213,10 @@ func (h *SecretUpdateHandler) isNamespaceSetToAutoRestart(namespace *corev1.Name return h.shouldAutoRestartDeploymentsGlobal } - restartDeploymentBool, err := stringToBool(restartDeployment) + restartDeploymentBool, err := utils.StringToBool(restartDeployment) if err != nil { log.Error(err, "Error parsing %v annotation on Namespace %v. Must be true or false. Defaulting to false.", RestartDeploymentsAnnotation, namespace.Name) return false } return restartDeploymentBool } - -func stringToBool(str string) (bool, error) { - restartDeploymentBool, err := strconv.ParseBool(strings.ToLower(str)) - if err != nil { - return false, err - } - return restartDeploymentBool, nil -} diff --git a/pkg/utils/string.go b/pkg/utils/string.go index 09862e6..ffe2871 100644 --- a/pkg/utils/string.go +++ b/pkg/utils/string.go @@ -1,5 +1,10 @@ package utils +import ( + "strconv" + "strings" +) + func ContainsString(slice []string, s string) bool { for _, item := range slice { if item == s { @@ -18,3 +23,11 @@ func RemoveString(slice []string, s string) (result []string) { } return } + +func StringToBool(str string) (bool, error) { + restartDeploymentBool, err := strconv.ParseBool(strings.ToLower(str)) + if err != nil { + return false, err + } + return restartDeploymentBool, nil +}