mirror of
				https://github.com/1Password/onepassword-operator.git
				synced 2025-10-31 11:49:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			126 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package kube
 | ||
| 
 | ||
| import (
 | ||
| 	"context"
 | ||
| 	"time"
 | ||
| 
 | ||
| 	//nolint:staticcheck // ST1001
 | ||
| 	. "github.com/onsi/ginkgo/v2"
 | ||
| 	//nolint:staticcheck // ST1001
 | ||
| 	. "github.com/onsi/gomega"
 | ||
| 	appsv1 "k8s.io/api/apps/v1"
 | ||
| 	corev1 "k8s.io/api/core/v1"
 | ||
| 	"sigs.k8s.io/controller-runtime/pkg/client"
 | ||
| )
 | ||
| 
 | ||
| type Deployment struct {
 | ||
| 	client client.Client
 | ||
| 	config *Config
 | ||
| 	name   string
 | ||
| }
 | ||
| 
 | ||
| func (d *Deployment) Get(ctx context.Context) *appsv1.Deployment {
 | ||
| 	// Derive a short-lived context so this API call won't hang indefinitely.
 | ||
| 	c, cancel := context.WithTimeout(ctx, 10*time.Second)
 | ||
| 	defer cancel()
 | ||
| 
 | ||
| 	deployment := &appsv1.Deployment{}
 | ||
| 	err := d.client.Get(c, client.ObjectKey{Name: d.name, Namespace: d.config.Namespace}, deployment)
 | ||
| 	Expect(err).ToNot(HaveOccurred())
 | ||
| 
 | ||
| 	return deployment
 | ||
| }
 | ||
| 
 | ||
| func (d *Deployment) ReadEnvVar(ctx context.Context, envVarName string) string {
 | ||
| 	By("Reading " + envVarName + " value from deployment/" + d.name)
 | ||
| 	deployment := d.Get(ctx)
 | ||
| 
 | ||
| 	// Search env across all containers
 | ||
| 	found := ""
 | ||
| 	for _, container := range deployment.Spec.Template.Spec.Containers {
 | ||
| 		for _, env := range container.Env {
 | ||
| 			if env.Name == envVarName && env.Value != "" {
 | ||
| 				found = env.Value
 | ||
| 				break
 | ||
| 			}
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	Expect(found).NotTo(BeEmpty())
 | ||
| 	return found
 | ||
| }
 | ||
| 
 | ||
| func (d *Deployment) PatchEnvVars(ctx context.Context, upsert []corev1.EnvVar, remove []string) {
 | ||
| 	By("Patching env variables for deployment/" + d.name)
 | ||
| 	deployment := d.Get(ctx)
 | ||
| 	deploymentCopy := deployment.DeepCopy()
 | ||
| 	container := &deployment.Spec.Template.Spec.Containers[0]
 | ||
| 
 | ||
| 	// Build removal set for quick lookup
 | ||
| 	toRemove := make(map[string]struct{}, len(remove))
 | ||
| 	for _, n := range remove {
 | ||
| 		toRemove[n] = struct{}{}
 | ||
| 	}
 | ||
| 
 | ||
| 	// Build upsert map for quick lookup
 | ||
| 	upserts := make(map[string]corev1.EnvVar, len(upsert))
 | ||
| 	for _, e := range upsert {
 | ||
| 		upserts[e.Name] = e
 | ||
| 	}
 | ||
| 
 | ||
| 	// Filter existing envs: keep if not in remove and not being upserted
 | ||
| 	filtered := make([]corev1.EnvVar, 0, len(container.Env))
 | ||
| 	for _, e := range container.Env {
 | ||
| 		if _, ok := toRemove[e.Name]; ok {
 | ||
| 			continue
 | ||
| 		}
 | ||
| 		if newE, ok := upserts[e.Name]; ok {
 | ||
| 			filtered = append(filtered, newE) // replace existing
 | ||
| 			delete(upserts, e.Name)           // delete from map to not use once again
 | ||
| 		} else {
 | ||
| 			filtered = append(filtered, e)
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	// Append any new envs that weren’t already in the container
 | ||
| 	for _, e := range upserts {
 | ||
| 		filtered = append(filtered, e)
 | ||
| 	}
 | ||
| 
 | ||
| 	container.Env = filtered
 | ||
| 
 | ||
| 	// Derive a short-lived context so this API call won't hang indefinitely.
 | ||
| 	c, cancel := context.WithTimeout(ctx, 10*time.Second)
 | ||
| 	defer cancel()
 | ||
| 
 | ||
| 	err := d.client.Patch(c, deployment, client.MergeFrom(deploymentCopy))
 | ||
| 	Expect(err).ToNot(HaveOccurred())
 | ||
| 
 | ||
| 	// wait for new deployment to roll out
 | ||
| 	d.WaitDeploymentRolledOut(ctx)
 | ||
| }
 | ||
| 
 | ||
| // WaitDeploymentRolledOut waits for deployment to finish a rollout.
 | ||
| func (d *Deployment) WaitDeploymentRolledOut(ctx context.Context) {
 | ||
| 	By("Waiting for deployment/" + d.name + " to roll out")
 | ||
| 
 | ||
| 	deployment := d.Get(ctx)
 | ||
| 	targetGen := deployment.Generation
 | ||
| 
 | ||
| 	Eventually(func(g Gomega) error {
 | ||
| 		newDeployment := d.Get(ctx)
 | ||
| 		g.Expect(newDeployment.Status.ObservedGeneration).To(BeNumerically(">=", targetGen))
 | ||
| 
 | ||
| 		desired := int32(1)
 | ||
| 		if newDeployment.Spec.Replicas != nil {
 | ||
| 			desired = *newDeployment.Spec.Replicas
 | ||
| 		}
 | ||
| 
 | ||
| 		g.Expect(newDeployment.Status.UpdatedReplicas).To(Equal(desired))
 | ||
| 		g.Expect(newDeployment.Status.AvailableReplicas).To(Equal(desired))
 | ||
| 		g.Expect(newDeployment.Status.Replicas).To(Equal(desired))
 | ||
| 
 | ||
| 		return nil
 | ||
| 	}, d.config.TestConfig.Timeout, d.config.TestConfig.Interval).Should(Succeed())
 | ||
| }
 | 
