Merge pull request #202 from 1Password/vzt/fix-context

Pass context given in `Reconcile` function down to Connect/SDK requests
This commit is contained in:
Volodymyr Zotov
2025-06-24 14:21:29 -05:00
committed by GitHub
17 changed files with 150 additions and 136 deletions

View File

@@ -25,6 +25,7 @@ SOFTWARE.
package main package main
import ( import (
"context"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
@@ -112,6 +113,9 @@ func main() {
printVersion() printVersion()
// Create a root context that will be cancelled on termination signals
ctx := ctrl.SetupSignalHandler()
watchNamespace, err := getWatchNamespace() watchNamespace, err := getWatchNamespace()
if err != nil { if err != nil {
setupLog.Error(err, "unable to get WatchNamespace, "+ setupLog.Error(err, "unable to get WatchNamespace, "+
@@ -152,7 +156,7 @@ func main() {
} }
// Setup One Password Client // Setup One Password Client
opClient, err := opclient.NewFromEnvironment(opclient.Config{ opClient, err := opclient.NewFromEnvironment(ctx, opclient.Config{
Logger: setupLog, Logger: setupLog,
Version: version.OperatorVersion, Version: version.OperatorVersion,
}) })
@@ -185,10 +189,10 @@ func main() {
//Setup 1PasswordConnect //Setup 1PasswordConnect
if shouldManageConnect() { if shouldManageConnect() {
setupLog.Info("Automated Connect Management Enabled") setupLog.Info("Automated Connect Management Enabled")
go func() { go func(ctx context.Context) {
connectStarted := false connectStarted := false
for connectStarted == false { for connectStarted == false {
err := op.SetupConnect(mgr.GetClient(), deploymentNamespace) err := op.SetupConnect(ctx, mgr.GetClient(), deploymentNamespace)
// Cache Not Started is an acceptable error. Retry until cache is started. // Cache Not Started is an acceptable error. Retry until cache is started.
if err != nil && !errors.Is(err, &cache.ErrCacheNotStarted{}) { if err != nil && !errors.Is(err, &cache.ErrCacheNotStarted{}) {
setupLog.Error(err, "") setupLog.Error(err, "")
@@ -198,7 +202,7 @@ func main() {
connectStarted = true connectStarted = true
} }
} }
}() }(ctx)
} else { } else {
setupLog.Info("Automated Connect Management Disabled") setupLog.Info("Automated Connect Management Disabled")
} }
@@ -207,20 +211,20 @@ func main() {
updatedSecretsPoller := op.NewManager(mgr.GetClient(), opClient, shouldAutoRestartDeployments()) updatedSecretsPoller := op.NewManager(mgr.GetClient(), opClient, shouldAutoRestartDeployments())
done := make(chan bool) done := make(chan bool)
ticker := time.NewTicker(getPollingIntervalForUpdatingSecrets()) ticker := time.NewTicker(getPollingIntervalForUpdatingSecrets())
go func() { go func(ctx context.Context) {
for { for {
select { select {
case <-done: case <-done:
ticker.Stop() ticker.Stop()
return return
case <-ticker.C: case <-ticker.C:
err := updatedSecretsPoller.UpdateKubernetesSecretsTask() err := updatedSecretsPoller.UpdateKubernetesSecretsTask(ctx)
if err != nil { if err != nil {
setupLog.Error(err, "error running update kubernetes secret task") setupLog.Error(err, "error running update kubernetes secret task")
} }
} }
} }
}() }(ctx)
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to set up health check") setupLog.Error(err, "unable to set up health check")
@@ -232,7 +236,7 @@ func main() {
} }
setupLog.Info("starting manager") setupLog.Info("starting manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { if err := mgr.Start(ctx); err != nil {
setupLog.Error(err, "problem running manager") setupLog.Error(err, "problem running manager")
os.Exit(1) os.Exit(1)
} }

View File

@@ -77,7 +77,7 @@ func (r *DeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request)
reqLogger.V(logs.DebugLevel).Info("Reconciling Deployment") reqLogger.V(logs.DebugLevel).Info("Reconciling Deployment")
deployment := &appsv1.Deployment{} deployment := &appsv1.Deployment{}
err := r.Get(context.Background(), req.NamespacedName, deployment) err := r.Get(ctx, req.NamespacedName, deployment)
if err != nil { if err != nil {
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
return reconcile.Result{}, nil return reconcile.Result{}, nil
@@ -97,12 +97,12 @@ func (r *DeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request)
// This is so we can handle cleanup of associated secrets properly // This is so we can handle cleanup of associated secrets properly
if !utils.ContainsString(deployment.ObjectMeta.Finalizers, finalizer) { if !utils.ContainsString(deployment.ObjectMeta.Finalizers, finalizer) {
deployment.ObjectMeta.Finalizers = append(deployment.ObjectMeta.Finalizers, finalizer) deployment.ObjectMeta.Finalizers = append(deployment.ObjectMeta.Finalizers, finalizer)
if err = r.Update(context.Background(), deployment); err != nil { if err = r.Update(ctx, deployment); err != nil {
return reconcile.Result{}, err return reconcile.Result{}, err
} }
} }
// Handles creation or updating secrets for deployment if needed // Handles creation or updating secrets for deployment if needed
if err = r.handleApplyingDeployment(deployment, deployment.Namespace, annotations, req); err != nil { if err = r.handleApplyingDeployment(ctx, deployment, deployment.Namespace, annotations, req); err != nil {
if strings.Contains(err.Error(), "rate limit") { if strings.Contains(err.Error(), "rate limit") {
reqLogger.V(logs.InfoLevel).Info("1Password rate limit hit. Requeuing after 15 minutes.") reqLogger.V(logs.InfoLevel).Info("1Password rate limit hit. Requeuing after 15 minutes.")
return ctrl.Result{RequeueAfter: 15 * time.Minute}, nil return ctrl.Result{RequeueAfter: 15 * time.Minute}, nil
@@ -117,12 +117,12 @@ func (r *DeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request)
if utils.ContainsString(deployment.ObjectMeta.Finalizers, finalizer) { if utils.ContainsString(deployment.ObjectMeta.Finalizers, finalizer) {
secretName := annotations[op.NameAnnotation] secretName := annotations[op.NameAnnotation]
if err = r.cleanupKubernetesSecretForDeployment(secretName, deployment); err != nil { if err = r.cleanupKubernetesSecretForDeployment(ctx, secretName, deployment); err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
// Remove the finalizer from the deployment so deletion of deployment can be completed // Remove the finalizer from the deployment so deletion of deployment can be completed
if err = r.removeOnePasswordFinalizerFromDeployment(deployment); err != nil { if err = r.removeOnePasswordFinalizerFromDeployment(ctx, deployment); err != nil {
return reconcile.Result{}, err return reconcile.Result{}, err
} }
} }
@@ -136,7 +136,7 @@ func (r *DeploymentReconciler) SetupWithManager(mgr ctrl.Manager) error {
Complete(r) Complete(r)
} }
func (r *DeploymentReconciler) cleanupKubernetesSecretForDeployment(secretName string, deletedDeployment *appsv1.Deployment) error { func (r *DeploymentReconciler) cleanupKubernetesSecretForDeployment(ctx context.Context, secretName string, deletedDeployment *appsv1.Deployment) error {
kubernetesSecret := &corev1.Secret{} kubernetesSecret := &corev1.Secret{}
kubernetesSecret.ObjectMeta.Name = secretName kubernetesSecret.ObjectMeta.Name = secretName
kubernetesSecret.ObjectMeta.Namespace = deletedDeployment.Namespace kubernetesSecret.ObjectMeta.Namespace = deletedDeployment.Namespace
@@ -146,14 +146,14 @@ func (r *DeploymentReconciler) cleanupKubernetesSecretForDeployment(secretName s
} }
updatedSecrets := map[string]*corev1.Secret{secretName: kubernetesSecret} updatedSecrets := map[string]*corev1.Secret{secretName: kubernetesSecret}
multipleDeploymentsUsingSecret, err := r.areMultipleDeploymentsUsingSecret(updatedSecrets, *deletedDeployment) multipleDeploymentsUsingSecret, err := r.areMultipleDeploymentsUsingSecret(ctx, updatedSecrets, *deletedDeployment)
if err != nil { if err != nil {
return err return err
} }
// Only delete the associated kubernetes secret if it is not being used by other deployments // Only delete the associated kubernetes secret if it is not being used by other deployments
if !multipleDeploymentsUsingSecret { if !multipleDeploymentsUsingSecret {
if err = r.Delete(context.Background(), kubernetesSecret); err != nil { if err = r.Delete(ctx, kubernetesSecret); err != nil {
if !errors.IsNotFound(err) { if !errors.IsNotFound(err) {
return err return err
} }
@@ -162,13 +162,13 @@ func (r *DeploymentReconciler) cleanupKubernetesSecretForDeployment(secretName s
return nil return nil
} }
func (r *DeploymentReconciler) areMultipleDeploymentsUsingSecret(updatedSecrets map[string]*corev1.Secret, deletedDeployment appsv1.Deployment) (bool, error) { func (r *DeploymentReconciler) areMultipleDeploymentsUsingSecret(ctx context.Context, updatedSecrets map[string]*corev1.Secret, deletedDeployment appsv1.Deployment) (bool, error) {
deployments := &appsv1.DeploymentList{} deployments := &appsv1.DeploymentList{}
opts := []client.ListOption{ opts := []client.ListOption{
client.InNamespace(deletedDeployment.Namespace), client.InNamespace(deletedDeployment.Namespace),
} }
err := r.List(context.Background(), deployments, opts...) err := r.List(ctx, deployments, opts...)
if err != nil { if err != nil {
logDeployment.Error(err, "Failed to list kubernetes deployments") logDeployment.Error(err, "Failed to list kubernetes deployments")
return false, err return false, err
@@ -184,12 +184,12 @@ func (r *DeploymentReconciler) areMultipleDeploymentsUsingSecret(updatedSecrets
return false, nil return false, nil
} }
func (r *DeploymentReconciler) removeOnePasswordFinalizerFromDeployment(deployment *appsv1.Deployment) error { func (r *DeploymentReconciler) removeOnePasswordFinalizerFromDeployment(ctx context.Context, deployment *appsv1.Deployment) error {
deployment.ObjectMeta.Finalizers = utils.RemoveString(deployment.ObjectMeta.Finalizers, finalizer) deployment.ObjectMeta.Finalizers = utils.RemoveString(deployment.ObjectMeta.Finalizers, finalizer)
return r.Update(context.Background(), deployment) return r.Update(ctx, deployment)
} }
func (r *DeploymentReconciler) handleApplyingDeployment(deployment *appsv1.Deployment, namespace string, annotations map[string]string, request reconcile.Request) error { func (r *DeploymentReconciler) handleApplyingDeployment(ctx context.Context, deployment *appsv1.Deployment, namespace string, annotations map[string]string, request reconcile.Request) error {
reqLog := logDeployment.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) reqLog := logDeployment.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
secretName := annotations[op.NameAnnotation] secretName := annotations[op.NameAnnotation]
@@ -201,7 +201,7 @@ func (r *DeploymentReconciler) handleApplyingDeployment(deployment *appsv1.Deplo
return nil return nil
} }
item, err := op.GetOnePasswordItemByPath(r.OpClient, annotations[op.ItemPathAnnotation]) item, err := op.GetOnePasswordItemByPath(ctx, r.OpClient, annotations[op.ItemPathAnnotation])
if err != nil { if err != nil {
return fmt.Errorf("Failed to retrieve item: %v", err) return fmt.Errorf("Failed to retrieve item: %v", err)
} }
@@ -218,5 +218,5 @@ func (r *DeploymentReconciler) handleApplyingDeployment(deployment *appsv1.Deplo
UID: deployment.GetUID(), UID: deployment.GetUID(),
} }
return kubeSecrets.CreateKubernetesSecretFromItem(r.Client, secretName, namespace, item, annotations[op.RestartDeploymentsAnnotation], secretLabels, secretType, ownerRef) return kubeSecrets.CreateKubernetesSecretFromItem(ctx, r.Client, secretName, namespace, item, annotations[op.RestartDeploymentsAnnotation], secretLabels, secretType, ownerRef)
} }

View File

@@ -24,14 +24,13 @@ const (
) )
var _ = Describe("Deployment controller", func() { var _ = Describe("Deployment controller", func() {
var ctx context.Context ctx := context.Background()
var deploymentKey types.NamespacedName var deploymentKey types.NamespacedName
var secretKey types.NamespacedName var secretKey types.NamespacedName
var deploymentResource *appsv1.Deployment var deploymentResource *appsv1.Deployment
createdSecret := &v1.Secret{} createdSecret := &v1.Secret{}
makeDeployment := func() { makeDeployment := func() {
ctx = context.Background()
deploymentKey = types.NamespacedName{ deploymentKey = types.NamespacedName{
Name: deploymentName, Name: deploymentName,
@@ -93,13 +92,13 @@ var _ = Describe("Deployment controller", func() {
cleanK8sResources := func() { cleanK8sResources := func() {
// failed test runs that don't clean up leave resources behind. // failed test runs that don't clean up leave resources behind.
err := k8sClient.DeleteAllOf(context.Background(), &onepasswordv1.OnePasswordItem{}, client.InNamespace(namespace)) err := k8sClient.DeleteAllOf(ctx, &onepasswordv1.OnePasswordItem{}, client.InNamespace(namespace))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
err = k8sClient.DeleteAllOf(context.Background(), &v1.Secret{}, client.InNamespace(namespace)) err = k8sClient.DeleteAllOf(ctx, &v1.Secret{}, client.InNamespace(namespace))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
err = k8sClient.DeleteAllOf(context.Background(), &appsv1.Deployment{}, client.InNamespace(namespace)) err = k8sClient.DeleteAllOf(ctx, &appsv1.Deployment{}, client.InNamespace(namespace))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
} }

View File

@@ -84,7 +84,7 @@ func (r *OnePasswordItemReconciler) Reconcile(ctx context.Context, req ctrl.Requ
reqLogger.V(logs.DebugLevel).Info("Reconciling OnePasswordItem") reqLogger.V(logs.DebugLevel).Info("Reconciling OnePasswordItem")
onepassworditem := &onepasswordv1.OnePasswordItem{} onepassworditem := &onepasswordv1.OnePasswordItem{}
err := r.Get(context.Background(), req.NamespacedName, onepassworditem) err := r.Get(ctx, req.NamespacedName, onepassworditem)
if err != nil { if err != nil {
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
return ctrl.Result{}, nil return ctrl.Result{}, nil
@@ -98,20 +98,20 @@ func (r *OnePasswordItemReconciler) Reconcile(ctx context.Context, req ctrl.Requ
// This is so we can handle cleanup of associated secrets properly // This is so we can handle cleanup of associated secrets properly
if !utils.ContainsString(onepassworditem.ObjectMeta.Finalizers, finalizer) { if !utils.ContainsString(onepassworditem.ObjectMeta.Finalizers, finalizer) {
onepassworditem.ObjectMeta.Finalizers = append(onepassworditem.ObjectMeta.Finalizers, finalizer) onepassworditem.ObjectMeta.Finalizers = append(onepassworditem.ObjectMeta.Finalizers, finalizer)
if err = r.Update(context.Background(), onepassworditem); err != nil { if err = r.Update(ctx, onepassworditem); err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
} }
// Handles creation or updating secrets for deployment if needed // Handles creation or updating secrets for deployment if needed
err = r.handleOnePasswordItem(onepassworditem, req) err = r.handleOnePasswordItem(ctx, onepassworditem, req)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "rate limit") { if strings.Contains(err.Error(), "rate limit") {
reqLogger.V(logs.InfoLevel).Info("1Password rate limit hit. Requeuing after 15 minutes.") reqLogger.V(logs.InfoLevel).Info("1Password rate limit hit. Requeuing after 15 minutes.")
return ctrl.Result{RequeueAfter: 15 * time.Minute}, nil return ctrl.Result{RequeueAfter: 15 * time.Minute}, nil
} }
} }
if updateStatusErr := r.updateStatus(onepassworditem, err); updateStatusErr != nil { if updateStatusErr := r.updateStatus(ctx, onepassworditem, err); updateStatusErr != nil {
return ctrl.Result{}, fmt.Errorf("cannot update status: %s", updateStatusErr) return ctrl.Result{}, fmt.Errorf("cannot update status: %s", updateStatusErr)
} }
return ctrl.Result{}, err return ctrl.Result{}, err
@@ -120,12 +120,12 @@ func (r *OnePasswordItemReconciler) Reconcile(ctx context.Context, req ctrl.Requ
if utils.ContainsString(onepassworditem.ObjectMeta.Finalizers, finalizer) { if utils.ContainsString(onepassworditem.ObjectMeta.Finalizers, finalizer) {
// Delete associated kubernetes secret // Delete associated kubernetes secret
if err = r.cleanupKubernetesSecret(onepassworditem); err != nil { if err = r.cleanupKubernetesSecret(ctx, onepassworditem); err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
// Remove finalizer now that cleanup is complete // Remove finalizer now that cleanup is complete
if err = r.removeFinalizer(onepassworditem); err != nil { if err = r.removeFinalizer(ctx, onepassworditem); err != nil {
return ctrl.Result{}, err return ctrl.Result{}, err
} }
} }
@@ -139,20 +139,20 @@ func (r *OnePasswordItemReconciler) SetupWithManager(mgr ctrl.Manager) error {
Complete(r) Complete(r)
} }
func (r *OnePasswordItemReconciler) removeFinalizer(onePasswordItem *onepasswordv1.OnePasswordItem) error { func (r *OnePasswordItemReconciler) removeFinalizer(ctx context.Context, onePasswordItem *onepasswordv1.OnePasswordItem) error {
onePasswordItem.ObjectMeta.Finalizers = utils.RemoveString(onePasswordItem.ObjectMeta.Finalizers, finalizer) onePasswordItem.ObjectMeta.Finalizers = utils.RemoveString(onePasswordItem.ObjectMeta.Finalizers, finalizer)
if err := r.Update(context.Background(), onePasswordItem); err != nil { if err := r.Update(ctx, onePasswordItem); err != nil {
return err return err
} }
return nil return nil
} }
func (r *OnePasswordItemReconciler) cleanupKubernetesSecret(onePasswordItem *onepasswordv1.OnePasswordItem) error { func (r *OnePasswordItemReconciler) cleanupKubernetesSecret(ctx context.Context, onePasswordItem *onepasswordv1.OnePasswordItem) error {
kubernetesSecret := &corev1.Secret{} kubernetesSecret := &corev1.Secret{}
kubernetesSecret.ObjectMeta.Name = onePasswordItem.Name kubernetesSecret.ObjectMeta.Name = onePasswordItem.Name
kubernetesSecret.ObjectMeta.Namespace = onePasswordItem.Namespace kubernetesSecret.ObjectMeta.Namespace = onePasswordItem.Namespace
if err := r.Delete(context.Background(), kubernetesSecret); err != nil { if err := r.Delete(ctx, kubernetesSecret); err != nil {
if !errors.IsNotFound(err) { if !errors.IsNotFound(err) {
return err return err
} }
@@ -160,18 +160,18 @@ func (r *OnePasswordItemReconciler) cleanupKubernetesSecret(onePasswordItem *one
return nil return nil
} }
func (r *OnePasswordItemReconciler) removeOnePasswordFinalizerFromOnePasswordItem(opSecret *onepasswordv1.OnePasswordItem) error { func (r *OnePasswordItemReconciler) removeOnePasswordFinalizerFromOnePasswordItem(ctx context.Context, opSecret *onepasswordv1.OnePasswordItem) error {
opSecret.ObjectMeta.Finalizers = utils.RemoveString(opSecret.ObjectMeta.Finalizers, finalizer) opSecret.ObjectMeta.Finalizers = utils.RemoveString(opSecret.ObjectMeta.Finalizers, finalizer)
return r.Update(context.Background(), opSecret) return r.Update(ctx, opSecret)
} }
func (r *OnePasswordItemReconciler) handleOnePasswordItem(resource *onepasswordv1.OnePasswordItem, req ctrl.Request) error { func (r *OnePasswordItemReconciler) handleOnePasswordItem(ctx context.Context, resource *onepasswordv1.OnePasswordItem, req ctrl.Request) error {
secretName := resource.GetName() secretName := resource.GetName()
labels := resource.Labels labels := resource.Labels
secretType := resource.Type secretType := resource.Type
autoRestart := resource.Annotations[op.RestartDeploymentsAnnotation] autoRestart := resource.Annotations[op.RestartDeploymentsAnnotation]
item, err := op.GetOnePasswordItemByPath(r.OpClient, resource.Spec.ItemPath) item, err := op.GetOnePasswordItemByPath(ctx, r.OpClient, resource.Spec.ItemPath)
if err != nil { if err != nil {
return fmt.Errorf("Failed to retrieve item: %v", err) return fmt.Errorf("Failed to retrieve item: %v", err)
} }
@@ -188,10 +188,10 @@ func (r *OnePasswordItemReconciler) handleOnePasswordItem(resource *onepasswordv
UID: resource.GetUID(), UID: resource.GetUID(),
} }
return kubeSecrets.CreateKubernetesSecretFromItem(r.Client, secretName, resource.Namespace, item, autoRestart, labels, secretType, ownerRef) return kubeSecrets.CreateKubernetesSecretFromItem(ctx, r.Client, secretName, resource.Namespace, item, autoRestart, labels, secretType, ownerRef)
} }
func (r *OnePasswordItemReconciler) updateStatus(resource *onepasswordv1.OnePasswordItem, err error) error { func (r *OnePasswordItemReconciler) updateStatus(ctx context.Context, resource *onepasswordv1.OnePasswordItem, err error) error {
existingCondition := findCondition(resource.Status.Conditions, onepasswordv1.OnePasswordItemReady) existingCondition := findCondition(resource.Status.Conditions, onepasswordv1.OnePasswordItemReady)
updatedCondition := existingCondition updatedCondition := existingCondition
if err != nil { if err != nil {
@@ -207,7 +207,7 @@ func (r *OnePasswordItemReconciler) updateStatus(resource *onepasswordv1.OnePass
} }
resource.Status.Conditions = []onepasswordv1.OnePasswordItemCondition{updatedCondition} resource.Status.Conditions = []onepasswordv1.OnePasswordItemCondition{updatedCondition}
return r.Status().Update(context.Background(), resource) return r.Status().Update(ctx, resource)
} }
func findCondition(conditions []onepasswordv1.OnePasswordItemCondition, t onepasswordv1.OnePasswordItemConditionType) onepasswordv1.OnePasswordItemCondition { func findCondition(conditions []onepasswordv1.OnePasswordItemCondition, t onepasswordv1.OnePasswordItemConditionType) onepasswordv1.OnePasswordItemCondition {

View File

@@ -30,7 +30,7 @@ var ErrCannotUpdateSecretType = errs.New("Cannot change secret type. Secret type
var log = logf.Log var log = logf.Log
func CreateKubernetesSecretFromItem(kubeClient kubernetesClient.Client, secretName, namespace string, item *model.Item, autoRestart string, labels map[string]string, secretType string, ownerRef *metav1.OwnerReference) error { func CreateKubernetesSecretFromItem(ctx context.Context, kubeClient kubernetesClient.Client, secretName, namespace string, item *model.Item, autoRestart string, labels map[string]string, secretType string, ownerRef *metav1.OwnerReference) error {
itemVersion := fmt.Sprint(item.Version) itemVersion := fmt.Sprint(item.Version)
secretAnnotations := map[string]string{ secretAnnotations := map[string]string{
VersionAnnotation: itemVersion, VersionAnnotation: itemVersion,
@@ -49,10 +49,10 @@ func CreateKubernetesSecretFromItem(kubeClient kubernetesClient.Client, secretNa
secret := BuildKubernetesSecretFromOnePasswordItem(secretName, namespace, secretAnnotations, labels, secretType, *item, ownerRef) secret := BuildKubernetesSecretFromOnePasswordItem(secretName, namespace, secretAnnotations, labels, secretType, *item, ownerRef)
currentSecret := &corev1.Secret{} currentSecret := &corev1.Secret{}
err := kubeClient.Get(context.Background(), types.NamespacedName{Name: secret.Name, Namespace: secret.Namespace}, currentSecret) err := kubeClient.Get(ctx, types.NamespacedName{Name: secret.Name, Namespace: secret.Namespace}, currentSecret)
if err != nil && errors.IsNotFound(err) { if err != nil && errors.IsNotFound(err) {
log.Info(fmt.Sprintf("Creating Secret %v at namespace '%v'", secret.Name, secret.Namespace)) log.Info(fmt.Sprintf("Creating Secret %v at namespace '%v'", secret.Name, secret.Namespace))
return kubeClient.Create(context.Background(), secret) return kubeClient.Create(ctx, secret)
} else if err != nil { } else if err != nil {
return err return err
} }
@@ -78,7 +78,7 @@ func CreateKubernetesSecretFromItem(kubeClient kubernetesClient.Client, secretNa
currentSecret.ObjectMeta.Annotations = secretAnnotations currentSecret.ObjectMeta.Annotations = secretAnnotations
currentSecret.ObjectMeta.Labels = labels currentSecret.ObjectMeta.Labels = labels
currentSecret.Data = secret.Data currentSecret.Data = secret.Data
if err := kubeClient.Update(context.Background(), currentSecret); err != nil { if err := kubeClient.Update(ctx, currentSecret); err != nil {
return fmt.Errorf("Kubernetes secret update failed: %w", err) return fmt.Errorf("Kubernetes secret update failed: %w", err)
} }
return nil return nil

View File

@@ -17,6 +17,7 @@ import (
const restartDeploymentAnnotation = "false" const restartDeploymentAnnotation = "false"
func TestCreateKubernetesSecretFromOnePasswordItem(t *testing.T) { func TestCreateKubernetesSecretFromOnePasswordItem(t *testing.T) {
ctx := context.Background()
secretName := "test-secret-name" secretName := "test-secret-name"
namespace := "test" namespace := "test"
@@ -30,12 +31,12 @@ func TestCreateKubernetesSecretFromOnePasswordItem(t *testing.T) {
secretLabels := map[string]string{} secretLabels := map[string]string{}
secretType := "" secretType := ""
err := CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &item, restartDeploymentAnnotation, secretLabels, secretType, nil) err := CreateKubernetesSecretFromItem(ctx, kubeClient, secretName, namespace, &item, restartDeploymentAnnotation, secretLabels, secretType, nil)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
createdSecret := &corev1.Secret{} createdSecret := &corev1.Secret{}
err = kubeClient.Get(context.Background(), types.NamespacedName{Name: secretName, Namespace: namespace}, createdSecret) err = kubeClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, createdSecret)
if err != nil { if err != nil {
t.Errorf("Secret was not created: %v", err) t.Errorf("Secret was not created: %v", err)
@@ -45,6 +46,7 @@ func TestCreateKubernetesSecretFromOnePasswordItem(t *testing.T) {
} }
func TestKubernetesSecretFromOnePasswordItemOwnerReferences(t *testing.T) { func TestKubernetesSecretFromOnePasswordItemOwnerReferences(t *testing.T) {
ctx := context.Background()
secretName := "test-secret-name" secretName := "test-secret-name"
namespace := "test" namespace := "test"
@@ -64,12 +66,12 @@ func TestKubernetesSecretFromOnePasswordItemOwnerReferences(t *testing.T) {
Name: "test-deployment", Name: "test-deployment",
UID: types.UID("test-uid"), UID: types.UID("test-uid"),
} }
err := CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &item, restartDeploymentAnnotation, secretLabels, secretType, ownerRef) err := CreateKubernetesSecretFromItem(ctx, kubeClient, secretName, namespace, &item, restartDeploymentAnnotation, secretLabels, secretType, ownerRef)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
createdSecret := &corev1.Secret{} createdSecret := &corev1.Secret{}
err = kubeClient.Get(context.Background(), types.NamespacedName{Name: secretName, Namespace: namespace}, createdSecret) err = kubeClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, createdSecret)
// Check owner references. // Check owner references.
gotOwnerRefs := createdSecret.ObjectMeta.OwnerReferences gotOwnerRefs := createdSecret.ObjectMeta.OwnerReferences
@@ -90,6 +92,7 @@ func TestKubernetesSecretFromOnePasswordItemOwnerReferences(t *testing.T) {
} }
func TestUpdateKubernetesSecretFromOnePasswordItem(t *testing.T) { func TestUpdateKubernetesSecretFromOnePasswordItem(t *testing.T) {
ctx := context.Background()
secretName := "test-secret-update" secretName := "test-secret-update"
namespace := "test" namespace := "test"
@@ -103,7 +106,7 @@ func TestUpdateKubernetesSecretFromOnePasswordItem(t *testing.T) {
secretLabels := map[string]string{} secretLabels := map[string]string{}
secretType := "" secretType := ""
err := CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &item, restartDeploymentAnnotation, secretLabels, secretType, nil) err := CreateKubernetesSecretFromItem(ctx, kubeClient, secretName, namespace, &item, restartDeploymentAnnotation, secretLabels, secretType, nil)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
@@ -115,12 +118,12 @@ func TestUpdateKubernetesSecretFromOnePasswordItem(t *testing.T) {
newItem.Version = 456 newItem.Version = 456
newItem.VaultID = "hfnjvi6aymbsnfc2xeeoheizda" newItem.VaultID = "hfnjvi6aymbsnfc2xeeoheizda"
newItem.ID = "h46bb3jddvay7nxopfhvlwg35q" newItem.ID = "h46bb3jddvay7nxopfhvlwg35q"
err = CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &newItem, restartDeploymentAnnotation, secretLabels, secretType, nil) err = CreateKubernetesSecretFromItem(ctx, kubeClient, secretName, namespace, &newItem, restartDeploymentAnnotation, secretLabels, secretType, nil)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
updatedSecret := &corev1.Secret{} updatedSecret := &corev1.Secret{}
err = kubeClient.Get(context.Background(), types.NamespacedName{Name: secretName, Namespace: namespace}, updatedSecret) err = kubeClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, updatedSecret)
if err != nil { if err != nil {
t.Errorf("Secret was not found: %v", err) t.Errorf("Secret was not found: %v", err)
@@ -205,6 +208,7 @@ func TestBuildKubernetesSecretFixesInvalidLabels(t *testing.T) {
} }
func TestCreateKubernetesTLSSecretFromOnePasswordItem(t *testing.T) { func TestCreateKubernetesTLSSecretFromOnePasswordItem(t *testing.T) {
ctx := context.Background()
secretName := "tls-test-secret-name" secretName := "tls-test-secret-name"
namespace := "test" namespace := "test"
@@ -218,12 +222,12 @@ func TestCreateKubernetesTLSSecretFromOnePasswordItem(t *testing.T) {
secretLabels := map[string]string{} secretLabels := map[string]string{}
secretType := "kubernetes.io/tls" secretType := "kubernetes.io/tls"
err := CreateKubernetesSecretFromItem(kubeClient, secretName, namespace, &item, restartDeploymentAnnotation, secretLabels, secretType, nil) err := CreateKubernetesSecretFromItem(ctx, kubeClient, secretName, namespace, &item, restartDeploymentAnnotation, secretLabels, secretType, nil)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
createdSecret := &corev1.Secret{} createdSecret := &corev1.Secret{}
err = kubeClient.Get(context.Background(), types.NamespacedName{Name: secretName, Namespace: namespace}, createdSecret) err = kubeClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, createdSecret)
if err != nil { if err != nil {
t.Errorf("Secret was not created: %v", err) t.Errorf("Secret was not created: %v", err)

View File

@@ -1,6 +1,7 @@
package mocks package mocks
import ( import (
"context"
"github.com/stretchr/testify/mock" "github.com/stretchr/testify/mock"
"github.com/1Password/onepassword-operator/pkg/onepassword/model" "github.com/1Password/onepassword-operator/pkg/onepassword/model"
@@ -10,7 +11,7 @@ type TestClient struct {
mock.Mock mock.Mock
} }
func (tc *TestClient) GetItemByID(vaultID, itemID string) (*model.Item, error) { func (tc *TestClient) GetItemByID(ctx context.Context, vaultID, itemID string) (*model.Item, error) {
args := tc.Called(vaultID, itemID) args := tc.Called(vaultID, itemID)
if args.Get(0) == nil { if args.Get(0) == nil {
return nil, args.Error(1) return nil, args.Error(1)
@@ -18,12 +19,12 @@ func (tc *TestClient) GetItemByID(vaultID, itemID string) (*model.Item, error) {
return args.Get(0).(*model.Item), args.Error(1) return args.Get(0).(*model.Item), args.Error(1)
} }
func (tc *TestClient) GetItemsByTitle(vaultID, itemTitle string) ([]model.Item, error) { func (tc *TestClient) GetItemsByTitle(ctx context.Context, vaultID, itemTitle string) ([]model.Item, error) {
args := tc.Called(vaultID, itemTitle) args := tc.Called(vaultID, itemTitle)
return args.Get(0).([]model.Item), args.Error(1) return args.Get(0).([]model.Item), args.Error(1)
} }
func (tc *TestClient) GetFileContent(vaultID, itemID, fileID string) ([]byte, error) { func (tc *TestClient) GetFileContent(ctx context.Context, vaultID, itemID, fileID string) ([]byte, error) {
args := tc.Called(vaultID, itemID, fileID) args := tc.Called(vaultID, itemID, fileID)
if args.Get(0) == nil { if args.Get(0) == nil {
return nil, args.Error(1) return nil, args.Error(1)
@@ -31,7 +32,7 @@ func (tc *TestClient) GetFileContent(vaultID, itemID, fileID string) ([]byte, er
return args.Get(0).([]byte), args.Error(1) return args.Get(0).([]byte), args.Error(1)
} }
func (tc *TestClient) GetVaultsByTitle(title string) ([]model.Vault, error) { func (tc *TestClient) GetVaultsByTitle(ctx context.Context, title string) ([]model.Vault, error) {
args := tc.Called(title) args := tc.Called(title)
return args.Get(0).([]model.Vault), args.Error(1) return args.Get(0).([]model.Vault), args.Error(1)
} }

View File

@@ -1,6 +1,7 @@
package client package client
import ( import (
"context"
"errors" "errors"
"os" "os"
@@ -13,10 +14,10 @@ import (
// Client is an interface for interacting with 1Password items and vaults. // Client is an interface for interacting with 1Password items and vaults.
type Client interface { type Client interface {
GetItemByID(vaultID, itemID string) (*model.Item, error) GetItemByID(ctx context.Context, vaultID, itemID string) (*model.Item, error)
GetItemsByTitle(vaultID, itemTitle string) ([]model.Item, error) GetItemsByTitle(ctx context.Context, vaultID, itemTitle string) ([]model.Item, error)
GetFileContent(vaultID, itemID, fileID string) ([]byte, error) GetFileContent(ctx context.Context, vaultID, itemID, fileID string) ([]byte, error)
GetVaultsByTitle(title string) ([]model.Vault, error) GetVaultsByTitle(ctx context.Context, title string) ([]model.Vault, error)
} }
type Config struct { type Config struct {
@@ -25,7 +26,7 @@ type Config struct {
} }
// NewFromEnvironment creates a new 1Password client based on the provided configuration. // NewFromEnvironment creates a new 1Password client based on the provided configuration.
func NewFromEnvironment(cfg Config) (Client, error) { func NewFromEnvironment(ctx context.Context, cfg Config) (Client, error) {
connectHost, _ := os.LookupEnv("OP_CONNECT_HOST") connectHost, _ := os.LookupEnv("OP_CONNECT_HOST")
connectToken, _ := os.LookupEnv("OP_CONNECT_TOKEN") connectToken, _ := os.LookupEnv("OP_CONNECT_TOKEN")
serviceAccountToken, _ := os.LookupEnv("OP_SERVICE_ACCOUNT_TOKEN") serviceAccountToken, _ := os.LookupEnv("OP_SERVICE_ACCOUNT_TOKEN")
@@ -36,7 +37,7 @@ func NewFromEnvironment(cfg Config) (Client, error) {
if serviceAccountToken != "" { if serviceAccountToken != "" {
cfg.Logger.Info("Using Service Account Token") cfg.Logger.Info("Using Service Account Token")
return sdk.NewClient(sdk.Config{ return sdk.NewClient(ctx, sdk.Config{
ServiceAccountToken: serviceAccountToken, ServiceAccountToken: serviceAccountToken,
IntegrationName: "1password-operator", IntegrationName: "1password-operator",
IntegrationVersion: cfg.Version, IntegrationVersion: cfg.Version,

View File

@@ -1,6 +1,7 @@
package connect package connect
import ( import (
"context"
"fmt" "fmt"
"github.com/1Password/connect-sdk-go/connect" "github.com/1Password/connect-sdk-go/connect"
@@ -26,7 +27,7 @@ func NewClient(config Config) *Connect {
} }
} }
func (c *Connect) GetItemByID(vaultID, itemID string) (*model.Item, error) { func (c *Connect) GetItemByID(ctx context.Context, vaultID, itemID string) (*model.Item, error) {
connectItem, err := c.client.GetItemByUUID(itemID, vaultID) connectItem, err := c.client.GetItemByUUID(itemID, vaultID)
if err != nil { if err != nil {
return nil, fmt.Errorf("1Password Connect error: %w", err) return nil, fmt.Errorf("1Password Connect error: %w", err)
@@ -37,7 +38,7 @@ func (c *Connect) GetItemByID(vaultID, itemID string) (*model.Item, error) {
return &item, nil return &item, nil
} }
func (c *Connect) GetItemsByTitle(vaultID, itemTitle string) ([]model.Item, error) { func (c *Connect) GetItemsByTitle(ctx context.Context, vaultID, itemTitle string) ([]model.Item, error) {
// Get all items in the vault with the specified title // Get all items in the vault with the specified title
connectItems, err := c.client.GetItemsByTitle(itemTitle, vaultID) connectItems, err := c.client.GetItemsByTitle(itemTitle, vaultID)
if err != nil { if err != nil {
@@ -54,7 +55,7 @@ func (c *Connect) GetItemsByTitle(vaultID, itemTitle string) ([]model.Item, erro
return items, nil return items, nil
} }
func (c *Connect) GetFileContent(vaultID, itemID, fileID string) ([]byte, error) { func (c *Connect) GetFileContent(ctx context.Context, vaultID, itemID, fileID string) ([]byte, error) {
bytes, err := c.client.GetFileContent(&onepassword.File{ bytes, err := c.client.GetFileContent(&onepassword.File{
ContentPath: fmt.Sprintf("/v1/vaults/%s/items/%s/files/%s/content", vaultID, itemID, fileID), ContentPath: fmt.Sprintf("/v1/vaults/%s/items/%s/files/%s/content", vaultID, itemID, fileID),
}) })
@@ -65,7 +66,7 @@ func (c *Connect) GetFileContent(vaultID, itemID, fileID string) ([]byte, error)
return bytes, nil return bytes, nil
} }
func (c *Connect) GetVaultsByTitle(vaultQuery string) ([]model.Vault, error) { func (c *Connect) GetVaultsByTitle(ctx context.Context, vaultQuery string) ([]model.Vault, error) {
connectVaults, err := c.client.GetVaultsByTitle(vaultQuery) connectVaults, err := c.client.GetVaultsByTitle(vaultQuery)
if err != nil { if err != nil {
return nil, fmt.Errorf("1Password Connect error: %w", err) return nil, fmt.Errorf("1Password Connect error: %w", err)

View File

@@ -1,6 +1,7 @@
package connect package connect
import ( import (
"context"
"errors" "errors"
"testing" "testing"
"time" "time"
@@ -49,7 +50,7 @@ func TestConnect_GetItemByID(t *testing.T) {
for description, tc := range testCases { for description, tc := range testCases {
t.Run(description, func(t *testing.T) { t.Run(description, func(t *testing.T) {
client := &Connect{client: tc.mockClient()} client := &Connect{client: tc.mockClient()}
item, err := client.GetItemByID("vault-id", "item-id") item, err := client.GetItemByID(context.Background(), "vault-id", "item-id")
tc.check(t, item, err) tc.check(t, item, err)
}) })
} }
@@ -111,7 +112,7 @@ func TestConnect_GetItemsByTitle(t *testing.T) {
for description, tc := range testCases { for description, tc := range testCases {
t.Run(description, func(t *testing.T) { t.Run(description, func(t *testing.T) {
client := &Connect{client: tc.mockClient()} client := &Connect{client: tc.mockClient()}
items, err := client.GetItemsByTitle("vault-id", "item-title") items, err := client.GetItemsByTitle(context.Background(), "vault-id", "item-title")
tc.check(t, items, err) tc.check(t, items, err)
}) })
} }
@@ -153,7 +154,7 @@ func TestConnect_GetFileContent(t *testing.T) {
for description, tc := range testCases { for description, tc := range testCases {
t.Run(description, func(t *testing.T) { t.Run(description, func(t *testing.T) {
client := &Connect{client: tc.mockClient()} client := &Connect{client: tc.mockClient()}
content, err := client.GetFileContent("vault-id", "item-id", "file-id") content, err := client.GetFileContent(context.Background(), "vault-id", "item-id", "file-id")
tc.check(t, content, err) tc.check(t, content, err)
}) })
} }
@@ -233,7 +234,7 @@ func TestConnect_GetVaultsByTitle(t *testing.T) {
for description, tc := range testCases { for description, tc := range testCases {
t.Run(description, func(t *testing.T) { t.Run(description, func(t *testing.T) {
client := &Connect{client: tc.mockClient()} client := &Connect{client: tc.mockClient()}
vault, err := client.GetVaultsByTitle(VaultTitleEmployee) vault, err := client.GetVaultsByTitle(context.Background(), VaultTitleEmployee)
tc.check(t, vault, err) tc.check(t, vault, err)
}) })
} }

View File

@@ -20,8 +20,8 @@ type SDK struct {
client *sdk.Client client *sdk.Client
} }
func NewClient(config Config) (*SDK, error) { func NewClient(ctx context.Context, config Config) (*SDK, error) {
client, err := sdk.NewClient(context.Background(), client, err := sdk.NewClient(ctx,
sdk.WithServiceAccountToken(config.ServiceAccountToken), sdk.WithServiceAccountToken(config.ServiceAccountToken),
sdk.WithIntegrationInfo(config.IntegrationName, config.IntegrationVersion), sdk.WithIntegrationInfo(config.IntegrationName, config.IntegrationVersion),
) )
@@ -34,8 +34,8 @@ func NewClient(config Config) (*SDK, error) {
}, nil }, nil
} }
func (s *SDK) GetItemByID(vaultID, itemID string) (*model.Item, error) { func (s *SDK) GetItemByID(ctx context.Context, vaultID, itemID string) (*model.Item, error) {
sdkItem, err := s.client.Items().Get(context.Background(), vaultID, itemID) sdkItem, err := s.client.Items().Get(ctx, vaultID, itemID)
if err != nil { if err != nil {
return nil, fmt.Errorf("1Password sdk error: %w", err) return nil, fmt.Errorf("1Password sdk error: %w", err)
} }
@@ -45,9 +45,9 @@ func (s *SDK) GetItemByID(vaultID, itemID string) (*model.Item, error) {
return &item, nil return &item, nil
} }
func (s *SDK) GetItemsByTitle(vaultID, itemTitle string) ([]model.Item, error) { func (s *SDK) GetItemsByTitle(ctx context.Context, vaultID, itemTitle string) ([]model.Item, error) {
// Get all items in the vault // Get all items in the vault
sdkItems, err := s.client.Items().List(context.Background(), vaultID) sdkItems, err := s.client.Items().List(ctx, vaultID)
if err != nil { if err != nil {
return nil, fmt.Errorf("1Password sdk error: %w", err) return nil, fmt.Errorf("1Password sdk error: %w", err)
} }
@@ -65,8 +65,8 @@ func (s *SDK) GetItemsByTitle(vaultID, itemTitle string) ([]model.Item, error) {
return items, nil return items, nil
} }
func (s *SDK) GetFileContent(vaultID, itemID, fileID string) ([]byte, error) { func (s *SDK) GetFileContent(ctx context.Context, vaultID, itemID, fileID string) ([]byte, error) {
bytes, err := s.client.Items().Files().Read(context.Background(), vaultID, itemID, sdk.FileAttributes{ bytes, err := s.client.Items().Files().Read(ctx, vaultID, itemID, sdk.FileAttributes{
ID: fileID, ID: fileID,
}) })
if err != nil { if err != nil {
@@ -76,9 +76,9 @@ func (s *SDK) GetFileContent(vaultID, itemID, fileID string) ([]byte, error) {
return bytes, nil return bytes, nil
} }
func (s *SDK) GetVaultsByTitle(title string) ([]model.Vault, error) { func (s *SDK) GetVaultsByTitle(ctx context.Context, title string) ([]model.Vault, error) {
// List all vaults // List all vaults
sdkVaults, err := s.client.Vaults().List(context.Background()) sdkVaults, err := s.client.Vaults().List(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("1Password sdk error: %w", err) return nil, fmt.Errorf("1Password sdk error: %w", err)
} }

View File

@@ -55,7 +55,7 @@ func TestSDK_GetItemByID(t *testing.T) {
ItemsAPI: tc.mockItemAPI(), ItemsAPI: tc.mockItemAPI(),
}, },
} }
item, err := client.GetItemByID("vault-id", "item-id") item, err := client.GetItemByID(context.Background(), "vault-id", "item-id")
tc.check(t, item, err) tc.check(t, item, err)
}) })
} }
@@ -135,7 +135,7 @@ func TestSDK_GetItemsByTitle(t *testing.T) {
ItemsAPI: tc.mockItemAPI(), ItemsAPI: tc.mockItemAPI(),
}, },
} }
items, err := client.GetItemsByTitle("vault-id", "item-title") items, err := client.GetItemsByTitle(context.Background(), "vault-id", "item-title")
tc.check(t, items, err) tc.check(t, items, err)
}) })
} }
@@ -197,7 +197,7 @@ func TestSDK_GetFileContent(t *testing.T) {
ItemsAPI: tc.mockItemAPI(), ItemsAPI: tc.mockItemAPI(),
}, },
} }
content, err := client.GetFileContent("vault-id", "item-id", "file-id") content, err := client.GetFileContent(context.Background(), "vault-id", "item-id", "file-id")
tc.check(t, content, err) tc.check(t, content, err)
}) })
} }
@@ -281,7 +281,7 @@ func TestSDK_GetVaultsByTitle(t *testing.T) {
VaultsAPI: tc.mockVaultAPI(), VaultsAPI: tc.mockVaultAPI(),
}, },
} }
vault, err := client.GetVaultsByTitle(VaultTitleEmployee) vault, err := client.GetVaultsByTitle(context.Background(), VaultTitleEmployee)
tc.check(t, vault, err) tc.check(t, vault, err)
}) })
} }

View File

@@ -18,13 +18,13 @@ var logConnectSetup = logf.Log.WithName("ConnectSetup")
var deploymentPath = "../config/connect/deployment.yaml" var deploymentPath = "../config/connect/deployment.yaml"
var servicePath = "../config/connect/service.yaml" var servicePath = "../config/connect/service.yaml"
func SetupConnect(kubeClient client.Client, deploymentNamespace string) error { func SetupConnect(ctx context.Context, kubeClient client.Client, deploymentNamespace string) error {
err := setupService(kubeClient, servicePath, deploymentNamespace) err := setupService(ctx, kubeClient, servicePath, deploymentNamespace)
if err != nil { if err != nil {
return err return err
} }
err = setupDeployment(kubeClient, deploymentPath, deploymentNamespace) err = setupDeployment(ctx, kubeClient, deploymentPath, deploymentNamespace)
if err != nil { if err != nil {
return err return err
} }
@@ -32,27 +32,27 @@ func SetupConnect(kubeClient client.Client, deploymentNamespace string) error {
return nil return nil
} }
func setupDeployment(kubeClient client.Client, deploymentPath string, deploymentNamespace string) error { func setupDeployment(ctx context.Context, kubeClient client.Client, deploymentPath string, deploymentNamespace string) error {
existingDeployment := &appsv1.Deployment{} existingDeployment := &appsv1.Deployment{}
// check if deployment has already been created // check if deployment has already been created
err := kubeClient.Get(context.Background(), types.NamespacedName{Name: "onepassword-connect", Namespace: deploymentNamespace}, existingDeployment) err := kubeClient.Get(ctx, types.NamespacedName{Name: "onepassword-connect", Namespace: deploymentNamespace}, existingDeployment)
if err != nil { if err != nil {
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
logConnectSetup.Info("No existing Connect deployment found. Creating Deployment") logConnectSetup.Info("No existing Connect deployment found. Creating Deployment")
return createDeployment(kubeClient, deploymentPath, deploymentNamespace) return createDeployment(ctx, kubeClient, deploymentPath, deploymentNamespace)
} }
} }
return err return err
} }
func createDeployment(kubeClient client.Client, deploymentPath string, deploymentNamespace string) error { func createDeployment(ctx context.Context, kubeClient client.Client, deploymentPath string, deploymentNamespace string) error {
deployment, err := getDeploymentToCreate(deploymentPath, deploymentNamespace) deployment, err := getDeploymentToCreate(deploymentPath, deploymentNamespace)
if err != nil { if err != nil {
return err return err
} }
err = kubeClient.Create(context.Background(), deployment) err = kubeClient.Create(ctx, deployment)
if err != nil { if err != nil {
return err return err
} }
@@ -78,21 +78,21 @@ func getDeploymentToCreate(deploymentPath string, deploymentNamespace string) (*
return deployment, nil return deployment, nil
} }
func setupService(kubeClient client.Client, servicePath string, deploymentNamespace string) error { func setupService(ctx context.Context, kubeClient client.Client, servicePath string, deploymentNamespace string) error {
existingService := &corev1.Service{} existingService := &corev1.Service{}
//check if service has already been created //check if service has already been created
err := kubeClient.Get(context.Background(), types.NamespacedName{Name: "onepassword-connect", Namespace: deploymentNamespace}, existingService) err := kubeClient.Get(ctx, types.NamespacedName{Name: "onepassword-connect", Namespace: deploymentNamespace}, existingService)
if err != nil { if err != nil {
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
logConnectSetup.Info("No existing Connect service found. Creating Service") logConnectSetup.Info("No existing Connect service found. Creating Service")
return createService(kubeClient, servicePath, deploymentNamespace) return createService(ctx, kubeClient, servicePath, deploymentNamespace)
} }
} }
return err return err
} }
func createService(kubeClient client.Client, servicePath string, deploymentNamespace string) error { func createService(ctx context.Context, kubeClient client.Client, servicePath string, deploymentNamespace string) error {
f, err := os.Open(servicePath) f, err := os.Open(servicePath)
if err != nil { if err != nil {
return err return err
@@ -108,7 +108,7 @@ func createService(kubeClient client.Client, servicePath string, deploymentNames
return err return err
} }
err = kubeClient.Create(context.Background(), service) err = kubeClient.Create(ctx, service)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -15,6 +15,7 @@ import (
var defaultNamespacedName = types.NamespacedName{Name: "onepassword-connect", Namespace: "default"} var defaultNamespacedName = types.NamespacedName{Name: "onepassword-connect", Namespace: "default"}
func TestServiceSetup(t *testing.T) { func TestServiceSetup(t *testing.T) {
ctx := context.Background()
// Register operator types with the runtime scheme. // Register operator types with the runtime scheme.
s := scheme.Scheme s := scheme.Scheme
@@ -25,7 +26,7 @@ func TestServiceSetup(t *testing.T) {
// Create a fake client to mock API calls. // Create a fake client to mock API calls.
client := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(objs...).Build() client := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(objs...).Build()
err := setupService(client, "../../config/connect/service.yaml", defaultNamespacedName.Namespace) err := setupService(ctx, client, "../../config/connect/service.yaml", defaultNamespacedName.Namespace)
if err != nil { if err != nil {
t.Errorf("Error Setting Up Connect: %v", err) t.Errorf("Error Setting Up Connect: %v", err)
@@ -33,13 +34,14 @@ func TestServiceSetup(t *testing.T) {
// check that service was created // check that service was created
service := &corev1.Service{} service := &corev1.Service{}
err = client.Get(context.TODO(), defaultNamespacedName, service) err = client.Get(ctx, defaultNamespacedName, service)
if err != nil { if err != nil {
t.Errorf("Error Setting Up Connect service: %v", err) t.Errorf("Error Setting Up Connect service: %v", err)
} }
} }
func TestDeploymentSetup(t *testing.T) { func TestDeploymentSetup(t *testing.T) {
ctx := context.Background()
// Register operator types with the runtime scheme. // Register operator types with the runtime scheme.
s := scheme.Scheme s := scheme.Scheme
@@ -50,7 +52,7 @@ func TestDeploymentSetup(t *testing.T) {
// Create a fake client to mock API calls. // Create a fake client to mock API calls.
client := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(objs...).Build() client := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(objs...).Build()
err := setupDeployment(client, "../../config/connect/deployment.yaml", defaultNamespacedName.Namespace) err := setupDeployment(ctx, client, "../../config/connect/deployment.yaml", defaultNamespacedName.Namespace)
if err != nil { if err != nil {
t.Errorf("Error Setting Up Connect: %v", err) t.Errorf("Error Setting Up Connect: %v", err)
@@ -58,7 +60,7 @@ func TestDeploymentSetup(t *testing.T) {
// check that deployment was created // check that deployment was created
deployment := &appsv1.Deployment{} deployment := &appsv1.Deployment{}
err = client.Get(context.TODO(), defaultNamespacedName, deployment) err = client.Get(ctx, defaultNamespacedName, deployment)
if err != nil { if err != nil {
t.Errorf("Error Setting Up Connect deployment: %v", err) t.Errorf("Error Setting Up Connect deployment: %v", err)
} }

View File

@@ -1,6 +1,7 @@
package onepassword package onepassword
import ( import (
"context"
"fmt" "fmt"
"strings" "strings"
@@ -12,28 +13,28 @@ import (
var logger = logf.Log.WithName("retrieve_item") var logger = logf.Log.WithName("retrieve_item")
func GetOnePasswordItemByPath(opClient opclient.Client, path string) (*model.Item, error) { func GetOnePasswordItemByPath(ctx context.Context, opClient opclient.Client, path string) (*model.Item, error) {
vaultNameOrID, itemNameOrID, err := ParseVaultAndItemFromPath(path) vaultNameOrID, itemNameOrID, err := ParseVaultAndItemFromPath(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
vaultID, err := getVaultID(opClient, vaultNameOrID) vaultID, err := getVaultID(ctx, opClient, vaultNameOrID)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to 'getVaultID' for vaultNameOrID='%s': %w", vaultNameOrID, err) return nil, fmt.Errorf("failed to 'getVaultID' for vaultNameOrID='%s': %w", vaultNameOrID, err)
} }
itemID, err := getItemID(opClient, vaultID, itemNameOrID) itemID, err := getItemID(ctx, opClient, vaultID, itemNameOrID)
if err != nil { if err != nil {
return nil, fmt.Errorf("faild to 'getItemID' for vaultID='%s' and itemNameOrID='%s': %w", vaultID, itemNameOrID, err) return nil, fmt.Errorf("faild to 'getItemID' for vaultID='%s' and itemNameOrID='%s': %w", vaultID, itemNameOrID, err)
} }
item, err := opClient.GetItemByID(vaultID, itemID) item, err := opClient.GetItemByID(ctx, vaultID, itemID)
if err != nil { if err != nil {
return nil, fmt.Errorf("faield to 'GetItemByID' for vaultID='%s' and itemID='%s': %w", vaultID, itemID, err) return nil, fmt.Errorf("faield to 'GetItemByID' for vaultID='%s' and itemID='%s': %w", vaultID, itemID, err)
} }
for _, file := range item.Files { for _, file := range item.Files {
_, err := opClient.GetFileContent(vaultID, itemID, file.ID) _, err := opClient.GetFileContent(ctx, vaultID, itemID, file.ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -50,9 +51,9 @@ func ParseVaultAndItemFromPath(path string) (string, string, error) {
return "", "", fmt.Errorf("%q is not an acceptable path for One Password item. Must be of the format: `vaults/{vault_id}/items/{item_id}`", path) return "", "", fmt.Errorf("%q is not an acceptable path for One Password item. Must be of the format: `vaults/{vault_id}/items/{item_id}`", path)
} }
func getVaultID(client opclient.Client, vaultNameOrID string) (string, error) { func getVaultID(ctx context.Context, client opclient.Client, vaultNameOrID string) (string, error) {
if !IsValidClientUUID(vaultNameOrID) { if !IsValidClientUUID(vaultNameOrID) {
vaults, err := client.GetVaultsByTitle(vaultNameOrID) vaults, err := client.GetVaultsByTitle(ctx, vaultNameOrID)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -75,9 +76,9 @@ func getVaultID(client opclient.Client, vaultNameOrID string) (string, error) {
return vaultNameOrID, nil return vaultNameOrID, nil
} }
func getItemID(client opclient.Client, vaultId, itemNameOrID string) (string, error) { func getItemID(ctx context.Context, client opclient.Client, vaultId, itemNameOrID string) (string, error) {
if !IsValidClientUUID(itemNameOrID) { if !IsValidClientUUID(itemNameOrID) {
items, err := client.GetItemsByTitle(vaultId, itemNameOrID) items, err := client.GetItemsByTitle(ctx, vaultId, itemNameOrID)
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@@ -37,23 +37,23 @@ type SecretUpdateHandler struct {
shouldAutoRestartDeploymentsGlobal bool shouldAutoRestartDeploymentsGlobal bool
} }
func (h *SecretUpdateHandler) UpdateKubernetesSecretsTask() error { func (h *SecretUpdateHandler) UpdateKubernetesSecretsTask(ctx context.Context) error {
updatedKubernetesSecrets, err := h.updateKubernetesSecrets() updatedKubernetesSecrets, err := h.updateKubernetesSecrets(ctx)
if err != nil { if err != nil {
return err return err
} }
return h.restartDeploymentsWithUpdatedSecrets(updatedKubernetesSecrets) return h.restartDeploymentsWithUpdatedSecrets(ctx, updatedKubernetesSecrets)
} }
func (h *SecretUpdateHandler) restartDeploymentsWithUpdatedSecrets(updatedSecretsByNamespace map[string]map[string]*corev1.Secret) error { func (h *SecretUpdateHandler) restartDeploymentsWithUpdatedSecrets(ctx context.Context, updatedSecretsByNamespace map[string]map[string]*corev1.Secret) error {
// No secrets to update. Exit // No secrets to update. Exit
if len(updatedSecretsByNamespace) == 0 || updatedSecretsByNamespace == nil { if len(updatedSecretsByNamespace) == 0 || updatedSecretsByNamespace == nil {
return nil return nil
} }
deployments := &appsv1.DeploymentList{} deployments := &appsv1.DeploymentList{}
err := h.client.List(context.Background(), deployments) err := h.client.List(ctx, deployments)
if err != nil { if err != nil {
log.Error(err, "Failed to list kubernetes deployments") log.Error(err, "Failed to list kubernetes deployments")
return err return err
@@ -63,7 +63,7 @@ func (h *SecretUpdateHandler) restartDeploymentsWithUpdatedSecrets(updatedSecret
return nil return nil
} }
setForAutoRestartByNamespaceMap, err := h.getIsSetForAutoRestartByNamespaceMap() setForAutoRestartByNamespaceMap, err := h.getIsSetForAutoRestartByNamespaceMap(ctx)
if err != nil { if err != nil {
return err return err
} }
@@ -78,7 +78,7 @@ func (h *SecretUpdateHandler) restartDeploymentsWithUpdatedSecrets(updatedSecret
} }
for _, secret := range updatedDeploymentSecrets { for _, secret := range updatedDeploymentSecrets {
if isSecretSetForAutoRestart(secret, deployment, setForAutoRestartByNamespaceMap) { if isSecretSetForAutoRestart(secret, deployment, setForAutoRestartByNamespaceMap) {
h.restartDeployment(deployment) h.restartDeployment(ctx, deployment)
continue continue
} }
} }
@@ -89,21 +89,21 @@ func (h *SecretUpdateHandler) restartDeploymentsWithUpdatedSecrets(updatedSecret
return nil return nil
} }
func (h *SecretUpdateHandler) restartDeployment(deployment *appsv1.Deployment) { func (h *SecretUpdateHandler) restartDeployment(ctx context.Context, deployment *appsv1.Deployment) {
log.Info(fmt.Sprintf("Deployment %q at namespace %q references an updated secret. Restarting", deployment.GetName(), deployment.Namespace)) log.Info(fmt.Sprintf("Deployment %q at namespace %q references an updated secret. Restarting", deployment.GetName(), deployment.Namespace))
if deployment.Spec.Template.Annotations == nil { if deployment.Spec.Template.Annotations == nil {
deployment.Spec.Template.Annotations = map[string]string{} deployment.Spec.Template.Annotations = map[string]string{}
} }
deployment.Spec.Template.Annotations[RestartAnnotation] = time.Now().String() deployment.Spec.Template.Annotations[RestartAnnotation] = time.Now().String()
err := h.client.Update(context.Background(), deployment) err := h.client.Update(ctx, deployment)
if err != nil { if err != nil {
log.Error(err, "Problem restarting deployment") log.Error(err, "Problem restarting deployment")
} }
} }
func (h *SecretUpdateHandler) updateKubernetesSecrets() (map[string]map[string]*corev1.Secret, error) { func (h *SecretUpdateHandler) updateKubernetesSecrets(ctx context.Context) (map[string]map[string]*corev1.Secret, error) {
secrets := &corev1.SecretList{} secrets := &corev1.SecretList{}
err := h.client.List(context.Background(), secrets) err := h.client.List(ctx, secrets)
if err != nil { if err != nil {
log.Error(err, "Failed to list kubernetes secrets") log.Error(err, "Failed to list kubernetes secrets")
return nil, err return nil, err
@@ -121,7 +121,7 @@ func (h *SecretUpdateHandler) updateKubernetesSecrets() (map[string]map[string]*
OnePasswordItemPath := h.getPathFromOnePasswordItem(secret) OnePasswordItemPath := h.getPathFromOnePasswordItem(secret)
item, err := GetOnePasswordItemByPath(h.opClient, OnePasswordItemPath) item, err := GetOnePasswordItemByPath(ctx, h.opClient, OnePasswordItemPath)
if err != nil { if err != nil {
log.Error(err, "failed to retrieve 1Password item at path \"%s\" for secret \"%s\"", secret.Annotations[ItemPathAnnotation], secret.Name) log.Error(err, "failed to retrieve 1Password item at path \"%s\" for secret \"%s\"", secret.Annotations[ItemPathAnnotation], secret.Name)
continue continue
@@ -135,7 +135,7 @@ func (h *SecretUpdateHandler) updateKubernetesSecrets() (map[string]map[string]*
log.V(logs.DebugLevel).Info(fmt.Sprintf("Secret '%v' has been updated in 1Password but is set to be ignored. Updates to an ignored secret will not trigger an update to a kubernetes secret or a rolling restart.", secret.GetName())) log.V(logs.DebugLevel).Info(fmt.Sprintf("Secret '%v' has been updated in 1Password but is set to be ignored. Updates to an ignored secret will not trigger an update to a kubernetes secret or a rolling restart.", secret.GetName()))
secret.Annotations[VersionAnnotation] = itemVersion secret.Annotations[VersionAnnotation] = itemVersion
secret.Annotations[ItemPathAnnotation] = itemPathString secret.Annotations[ItemPathAnnotation] = itemPathString
if err := h.client.Update(context.Background(), &secret); err != nil { if err := h.client.Update(ctx, &secret); err != nil {
log.Error(err, "failed to update secret %s annotations to version %d: %s", secret.Name, itemVersion, err) log.Error(err, "failed to update secret %s annotations to version %d: %s", secret.Name, itemVersion, err)
continue continue
} }
@@ -146,7 +146,7 @@ func (h *SecretUpdateHandler) updateKubernetesSecrets() (map[string]map[string]*
secret.Annotations[ItemPathAnnotation] = itemPathString secret.Annotations[ItemPathAnnotation] = itemPathString
secret.Data = kubeSecrets.BuildKubernetesSecretData(item.Fields, item.Files) secret.Data = kubeSecrets.BuildKubernetesSecretData(item.Fields, item.Files)
log.V(logs.DebugLevel).Info(fmt.Sprintf("New secret path: %v and version: %v", secret.Annotations[ItemPathAnnotation], secret.Annotations[VersionAnnotation])) log.V(logs.DebugLevel).Info(fmt.Sprintf("New secret path: %v and version: %v", secret.Annotations[ItemPathAnnotation], secret.Annotations[VersionAnnotation]))
if err := h.client.Update(context.Background(), &secret); err != nil { if err := h.client.Update(ctx, &secret); err != nil {
log.Error(err, "failed to update secret %s to version %d: %s", secret.Name, itemVersion, err) log.Error(err, "failed to update secret %s to version %d: %s", secret.Name, itemVersion, err)
continue continue
} }
@@ -177,9 +177,9 @@ func isUpdatedSecret(secretName string, updatedSecrets map[string]*corev1.Secret
return false return false
} }
func (h *SecretUpdateHandler) getIsSetForAutoRestartByNamespaceMap() (map[string]bool, error) { func (h *SecretUpdateHandler) getIsSetForAutoRestartByNamespaceMap(ctx context.Context) (map[string]bool, error) {
namespaces := &corev1.NamespaceList{} namespaces := &corev1.NamespaceList{}
err := h.client.List(context.Background(), namespaces) err := h.client.List(ctx, namespaces)
if err != nil { if err != nil {
log.Error(err, "Failed to list kubernetes namespaces") log.Error(err, "Failed to list kubernetes namespaces")
return nil, err return nil, err

View File

@@ -787,7 +787,7 @@ var tests = []testUpdateSecretTask{
func TestUpdateSecretHandler(t *testing.T) { func TestUpdateSecretHandler(t *testing.T) {
for _, testData := range tests { for _, testData := range tests {
t.Run(testData.testName, func(t *testing.T) { t.Run(testData.testName, func(t *testing.T) {
ctx := context.Background()
// Register operator types with the runtime scheme. // Register operator types with the runtime scheme.
s := scheme.Scheme s := scheme.Scheme
s.AddKnownTypes(appsv1.SchemeGroupVersion, testData.existingDeployment) s.AddKnownTypes(appsv1.SchemeGroupVersion, testData.existingDeployment)
@@ -813,7 +813,7 @@ func TestUpdateSecretHandler(t *testing.T) {
shouldAutoRestartDeploymentsGlobal: testData.globalAutoRestartEnabled, shouldAutoRestartDeploymentsGlobal: testData.globalAutoRestartEnabled,
} }
err := h.UpdateKubernetesSecretsTask() err := h.UpdateKubernetesSecretsTask(ctx)
assert.Equal(t, testData.expectedError, err) assert.Equal(t, testData.expectedError, err)
@@ -826,7 +826,7 @@ func TestUpdateSecretHandler(t *testing.T) {
// Check if Secret has been created and has the correct data // Check if Secret has been created and has the correct data
secret := &corev1.Secret{} secret := &corev1.Secret{}
err = cl.Get(context.TODO(), types.NamespacedName{Name: expectedSecretName, Namespace: namespace}, secret) err = cl.Get(ctx, types.NamespacedName{Name: expectedSecretName, Namespace: namespace}, secret)
if testData.expectedResultSecret == nil { if testData.expectedResultSecret == nil {
assert.Error(t, err) assert.Error(t, err)
@@ -840,7 +840,7 @@ func TestUpdateSecretHandler(t *testing.T) {
//check if deployment has been restarted //check if deployment has been restarted
deployment := &appsv1.Deployment{} deployment := &appsv1.Deployment{}
err = cl.Get(context.TODO(), types.NamespacedName{Name: testData.existingDeployment.Name, Namespace: namespace}, deployment) err = cl.Get(ctx, types.NamespacedName{Name: testData.existingDeployment.Name, Namespace: namespace}, deployment)
_, ok := deployment.Spec.Template.Annotations[RestartAnnotation] _, ok := deployment.Spec.Template.Annotations[RestartAnnotation]
if ok { if ok {