Skip to content

Commit 2dcb600

Browse files
committed
fix: address Lytol review nits
- Add BatchDelete helper to internal; use in Chronicle, Connect, Package Manager, and Workbench cleanup/suspend functions - Rename isProductEnabled to checkBool(ptr *bool, defaultVal bool) and apply consistently for both enabled and teardown patterns across site_controller.go and site_controller_networkpolicies.go
1 parent ad41280 commit 2dcb600

8 files changed

Lines changed: 75 additions & 154 deletions

File tree

docs/guides/upgrading.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,15 @@ If you are upgrading an existing installation that has already run the operator
174174
1. Identify the components with existing DB password secrets:
175175

176176
```bash
177-
kubectl get secrets -n posit-team -o name | grep -v db-password
177+
for comp in workbench connect packagemanager; do
178+
kubectl get secret "${comp}" -n posit-team --ignore-not-found -o name
179+
done
178180
```
179181

180182
2. For each component (workbench, connect, packagemanager), rename the secret:
181183

184+
> **Warning:** If `${NEW_NAME}` already exists in the cluster, do not apply this migration — the operator has already generated a new password and you must re-synchronize the database password manually.
185+
182186
```bash
183187
# Get the old secret data
184188
OLD_NAME=<component-name>
@@ -187,7 +191,7 @@ If you are upgrading an existing installation that has already run the operator
187191

188192
# Create new secret with old data
189193
kubectl get secret "${OLD_NAME}" -n "${NAMESPACE}" -o json \
190-
| python3 -c "import json,sys; d=json.load(sys.stdin); d['metadata']['name']='${NEW_NAME}'; [d['metadata'].pop(k,None) for k in ['resourceVersion','uid','creationTimestamp','ownerReferences']]; print(json.dumps(d))" \
194+
| python3 -c "import json,sys; d=json.load(sys.stdin); d['metadata']['name']='${NEW_NAME}'; [d['metadata'].pop(k,None) for k in ['resourceVersion','uid','creationTimestamp','managedFields','ownerReferences']]; print(json.dumps(d))" \
191195
| kubectl apply -f -
192196

193197
# Delete old secret

internal/controller/core/chronicle_controller.go

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -340,26 +340,15 @@ func (r *ChronicleReconciler) CleanupChronicle(ctx context.Context, req ctrl.Req
340340

341341
key := client.ObjectKey{Name: c.ComponentName(), Namespace: req.Namespace}
342342

343-
// SERVICE
344-
if err := internal.BasicDelete(ctx, r, l, key, &corev1.Service{}); err != nil {
345-
return ctrl.Result{}, err
346-
}
347-
348-
// STATEFULSET
349-
if err := internal.BasicDelete(ctx, r, l, key, &v1.StatefulSet{}); err != nil {
350-
return ctrl.Result{}, err
351-
}
352343
// NOTE: Chronicle's StatefulSet does not use VolumeClaimTemplates (it uses EmptyDir or S3).
353344
// If VolumeClaimTemplates are added in the future, their PVCs must be deleted explicitly
354345
// here because Kubernetes does not garbage-collect StatefulSet PVCs automatically.
355-
356-
// CONFIGMAP
357-
if err := internal.BasicDelete(ctx, r, l, key, &corev1.ConfigMap{}); err != nil {
358-
return ctrl.Result{}, err
359-
}
360-
361-
// SERVICE ACCOUNTS
362-
if err := internal.BasicDelete(ctx, r, l, key, &corev1.ServiceAccount{}); err != nil {
346+
if err := internal.BatchDelete(ctx, r, l, key,
347+
&corev1.Service{},
348+
&v1.StatefulSet{},
349+
&corev1.ConfigMap{},
350+
&corev1.ServiceAccount{},
351+
); err != nil {
363352
return ctrl.Result{}, err
364353
}
365354

@@ -383,13 +372,10 @@ func (r *ChronicleReconciler) suspendDeployedService(ctx context.Context, req ct
383372

384373
key := client.ObjectKey{Name: c.ComponentName(), Namespace: req.Namespace}
385374

386-
// SERVICE
387-
if err := internal.BasicDelete(ctx, r, l, key, &corev1.Service{}); err != nil {
388-
return ctrl.Result{}, err
389-
}
390-
391-
// STATEFULSET (Chronicle uses StatefulSet, not Deployment)
392-
if err := internal.BasicDelete(ctx, r, l, key, &v1.StatefulSet{}); err != nil {
375+
if err := internal.BatchDelete(ctx, r, l, key,
376+
&corev1.Service{},
377+
&v1.StatefulSet{}, // Chronicle uses StatefulSet, not Deployment
378+
); err != nil {
393379
return ctrl.Result{}, err
394380
}
395381

internal/controller/core/connect.go

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -886,13 +886,11 @@ func (r *ConnectReconciler) suspendDeployedService(ctx context.Context, req ctrl
886886

887887
key := client.ObjectKey{Name: c.ComponentName(), Namespace: req.Namespace}
888888

889-
if err := internal.BasicDelete(ctx, r, l, key, &networkingv1.Ingress{}); err != nil {
890-
return ctrl.Result{}, err
891-
}
892-
if err := internal.BasicDelete(ctx, r, l, key, &corev1.Service{}); err != nil {
893-
return ctrl.Result{}, err
894-
}
895-
if err := internal.BasicDelete(ctx, r, l, key, &v1.Deployment{}); err != nil {
889+
if err := internal.BatchDelete(ctx, r, l, key,
890+
&networkingv1.Ingress{},
891+
&corev1.Service{},
892+
&v1.Deployment{},
893+
); err != nil {
896894
return ctrl.Result{}, err
897895
}
898896

@@ -912,48 +910,17 @@ func (r *ConnectReconciler) cleanupDeployedService(ctx context.Context, req ctrl
912910
Namespace: req.Namespace,
913911
}
914912

915-
// INGRESS
916-
917-
existingIngress := &networkingv1.Ingress{}
918-
if err := internal.BasicDelete(ctx, r, l, key, existingIngress); err != nil {
919-
return err
920-
}
921-
922-
// SERVICE
923-
924-
existingService := &corev1.Service{}
925-
if err := internal.BasicDelete(ctx, r, l, key, existingService); err != nil {
926-
return err
927-
}
928-
929-
// DEPLOYMENT
930-
931-
existingDeployment := &v1.Deployment{}
932-
if err := internal.BasicDelete(ctx, r, l, key, existingDeployment); err != nil {
933-
return err
934-
}
935-
936-
// VOLUME
937913
// NOTE: we delete the volume universally, even if create was false...
938914
// this ensures that we have the resource completely removed, whether it
939915
// was created, forgotten, or never created.
940-
941-
existingPvc := &corev1.PersistentVolumeClaim{}
942-
if err := internal.BasicDelete(ctx, r, l, key, existingPvc); err != nil {
943-
return err
944-
}
945-
946-
// SERVICE ACCOUNT
947-
948-
existingServiceAccount := &corev1.ServiceAccount{}
949-
if err := internal.BasicDelete(ctx, r, l, key, existingServiceAccount); err != nil {
950-
return err
951-
}
952-
953-
// CONFIGMAP
954-
955-
existingConfigmap := &corev1.ConfigMap{}
956-
if err := internal.BasicDelete(ctx, r, l, key, existingConfigmap); err != nil {
916+
if err := internal.BatchDelete(ctx, r, l, key,
917+
&networkingv1.Ingress{},
918+
&corev1.Service{},
919+
&v1.Deployment{},
920+
&corev1.PersistentVolumeClaim{},
921+
&corev1.ServiceAccount{},
922+
&corev1.ConfigMap{},
923+
); err != nil {
957924
return err
958925
}
959926

internal/controller/core/package_manager.go

Lines changed: 13 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,11 @@ func (r *PackageManagerReconciler) suspendDeployedService(ctx context.Context, r
5252

5353
key := client.ObjectKey{Name: pm.ComponentName(), Namespace: req.Namespace}
5454

55-
// INGRESS
56-
if err := internal.BasicDelete(ctx, r, l, key, &networkingv1.Ingress{}); err != nil {
57-
return ctrl.Result{}, err
58-
}
59-
60-
// SERVICE
61-
if err := internal.BasicDelete(ctx, r, l, key, &corev1.Service{}); err != nil {
62-
return ctrl.Result{}, err
63-
}
64-
65-
// DEPLOYMENT
66-
if err := internal.BasicDelete(ctx, r, l, key, &v1.Deployment{}); err != nil {
55+
if err := internal.BatchDelete(ctx, r, l, key,
56+
&networkingv1.Ingress{},
57+
&corev1.Service{},
58+
&v1.Deployment{},
59+
); err != nil {
6760
return ctrl.Result{}, err
6861
}
6962

@@ -83,48 +76,17 @@ func (r *PackageManagerReconciler) cleanupDeployedService(ctx context.Context, r
8376
Namespace: req.Namespace,
8477
}
8578

86-
// INGRESS
87-
88-
existingIngress := &networkingv1.Ingress{}
89-
if err := internal.BasicDelete(ctx, r, l, key, existingIngress); err != nil {
90-
return err
91-
}
92-
93-
// SERVICE
94-
95-
existingService := &corev1.Service{}
96-
if err := internal.BasicDelete(ctx, r, l, key, existingService); err != nil {
97-
return err
98-
}
99-
100-
// DEPLOYMENT
101-
102-
existingDeployment := &v1.Deployment{}
103-
if err := internal.BasicDelete(ctx, r, l, key, existingDeployment); err != nil {
104-
return err
105-
}
106-
107-
// VOLUME
10879
// NOTE: we delete the volume universally, even if create was false...
10980
// this ensures that we have the resource completely removed, whether it
11081
// was created, forgotten, or never created.
111-
112-
existingPvc := &corev1.PersistentVolumeClaim{}
113-
if err := internal.BasicDelete(ctx, r, l, key, existingPvc); err != nil {
114-
return err
115-
}
116-
117-
// SERVICE ACCOUNT
118-
119-
existingServiceAccount := &corev1.ServiceAccount{}
120-
if err := internal.BasicDelete(ctx, r, l, key, existingServiceAccount); err != nil {
121-
return err
122-
}
123-
124-
// CONFIGMAP
125-
126-
existingConfigmap := &corev1.ConfigMap{}
127-
if err := internal.BasicDelete(ctx, r, l, key, existingConfigmap); err != nil {
82+
if err := internal.BatchDelete(ctx, r, l, key,
83+
&networkingv1.Ingress{},
84+
&corev1.Service{},
85+
&v1.Deployment{},
86+
&corev1.PersistentVolumeClaim{},
87+
&corev1.ServiceAccount{},
88+
&corev1.ConfigMap{},
89+
); err != nil {
12890
return err
12991
}
13092

internal/controller/core/site_controller.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@ import (
2424
"sigs.k8s.io/controller-runtime/pkg/log"
2525
)
2626

27-
// isProductEnabled returns true if the product is enabled (nil defaults to enabled).
28-
func isProductEnabled(b *bool) bool {
29-
return b == nil || *b
27+
// checkBool dereferences a bool pointer, returning defaultVal if nil.
28+
func checkBool(b *bool, defaultVal bool) bool {
29+
if b == nil {
30+
return defaultVal
31+
}
32+
return *b
3033
}
3134

3235
// SiteReconciler reconciles a Site object
@@ -161,26 +164,26 @@ func (r *SiteReconciler) reconcileResources(ctx context.Context, req ctrl.Reques
161164
// VOLUMES
162165

163166
// Determine if Connect is enabled (used for volume provisioning and later for reconciliation)
164-
connectEnabled := site.Spec.Connect.Enabled == nil || *site.Spec.Connect.Enabled
165-
connectTeardown := site.Spec.Connect.Teardown != nil && *site.Spec.Connect.Teardown
167+
connectEnabled := checkBool(site.Spec.Connect.Enabled, true)
168+
connectTeardown := checkBool(site.Spec.Connect.Teardown, false)
166169
if connectTeardown && connectEnabled {
167170
l.Info("connect.teardown is set but connect.enabled is not false; teardown has no effect until enabled=false")
168171
}
169172

170-
workbenchEnabled := isProductEnabled(site.Spec.Workbench.Enabled)
171-
workbenchTeardown := site.Spec.Workbench.Teardown != nil && *site.Spec.Workbench.Teardown
173+
workbenchEnabled := checkBool(site.Spec.Workbench.Enabled, true)
174+
workbenchTeardown := checkBool(site.Spec.Workbench.Teardown, false)
172175
if workbenchTeardown && workbenchEnabled {
173176
l.Info("workbench.teardown is set but workbench.enabled is not false; teardown has no effect until enabled=false")
174177
}
175178

176-
pmEnabled := isProductEnabled(site.Spec.PackageManager.Enabled)
177-
pmTeardown := site.Spec.PackageManager.Teardown != nil && *site.Spec.PackageManager.Teardown
179+
pmEnabled := checkBool(site.Spec.PackageManager.Enabled, true)
180+
pmTeardown := checkBool(site.Spec.PackageManager.Teardown, false)
178181
if pmTeardown && pmEnabled {
179182
l.Info("packageManager.teardown is set but packageManager.enabled is not false; teardown has no effect until enabled=false")
180183
}
181184

182-
chronicleEnabled := isProductEnabled(site.Spec.Chronicle.Enabled)
183-
chronicleTeardown := site.Spec.Chronicle.Teardown != nil && *site.Spec.Chronicle.Teardown
185+
chronicleEnabled := checkBool(site.Spec.Chronicle.Enabled, true)
186+
chronicleTeardown := checkBool(site.Spec.Chronicle.Teardown, false)
184187
if chronicleTeardown && chronicleEnabled {
185188
l.Info("chronicle.teardown is set but chronicle.enabled is not false; teardown has no effect until enabled=false")
186189
}

internal/controller/core/site_controller_networkpolicies.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func (r *SiteReconciler) reconcileNetworkPolicies(ctx context.Context, req ctrl.
3939
}
4040

4141
// Chronicle network policy
42-
chronicleEnabled := isProductEnabled(site.Spec.Chronicle.Enabled)
42+
chronicleEnabled := checkBool(site.Spec.Chronicle.Enabled, true)
4343
if chronicleEnabled {
4444
if err := r.reconcileChronicleNetworkPolicy(ctx, req.Namespace, l, site); err != nil {
4545
l.Error(err, "error ensuring chronicle network policy")
@@ -53,7 +53,7 @@ func (r *SiteReconciler) reconcileNetworkPolicies(ctx context.Context, req ctrl.
5353
}
5454

5555
// Connect network policies
56-
connectEnabled := site.Spec.Connect.Enabled == nil || *site.Spec.Connect.Enabled
56+
connectEnabled := checkBool(site.Spec.Connect.Enabled, true)
5757
if connectEnabled {
5858
if err := r.reconcileConnectNetworkPolicy(ctx, req.Namespace, l, site); err != nil {
5959
l.Error(err, "error ensuring connect network policy")
@@ -82,7 +82,7 @@ func (r *SiteReconciler) reconcileNetworkPolicies(ctx context.Context, req ctrl.
8282
}
8383

8484
// Package Manager network policy
85-
pmEnabled := isProductEnabled(site.Spec.PackageManager.Enabled)
85+
pmEnabled := checkBool(site.Spec.PackageManager.Enabled, true)
8686
if pmEnabled {
8787
if err := r.reconcilePackageManagerNetworkPolicy(ctx, req.Namespace, l, site); err != nil {
8888
l.Error(err, "error ensuring package manager network policy")
@@ -96,7 +96,7 @@ func (r *SiteReconciler) reconcileNetworkPolicies(ctx context.Context, req ctrl.
9696
}
9797

9898
// Workbench network policies
99-
workbenchEnabled := isProductEnabled(site.Spec.Workbench.Enabled)
99+
workbenchEnabled := checkBool(site.Spec.Workbench.Enabled, true)
100100
if workbenchEnabled {
101101
if err := r.reconcileWorkbenchNetworkPolicy(ctx, req.Namespace, l, site); err != nil {
102102
l.Error(err, "error ensuring workbench network policy")

internal/controller/core/workbench.go

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,22 +1034,11 @@ func (r *WorkbenchReconciler) CleanupWorkbench(ctx context.Context, req ctrl.Req
10341034
func (r *WorkbenchReconciler) deleteServingResources(ctx context.Context, req ctrl.Request, w *positcov1beta1.Workbench, l logr.Logger) error {
10351035
key := client.ObjectKey{Name: w.ComponentName(), Namespace: req.Namespace}
10361036

1037-
// INGRESS
1038-
if err := internal.BasicDelete(ctx, r, l, key, &networkingv1.Ingress{}); err != nil {
1039-
return err
1040-
}
1041-
1042-
// SERVICE
1043-
if err := internal.BasicDelete(ctx, r, l, key, &corev1.Service{}); err != nil {
1044-
return err
1045-
}
1046-
1047-
// DEPLOYMENT
1048-
if err := internal.BasicDelete(ctx, r, l, key, &appsv1.Deployment{}); err != nil {
1049-
return err
1050-
}
1051-
1052-
return nil
1037+
return internal.BatchDelete(ctx, r, l, key,
1038+
&networkingv1.Ingress{},
1039+
&corev1.Service{},
1040+
&appsv1.Deployment{},
1041+
)
10531042
}
10541043

10551044
// suspendDeployedService removes serving resources (Deployment, Service, Ingress)

internal/kubernetes_crudding.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,16 @@ func BasicDelete(ctx context.Context, r product.SomeReconciler, l logr.Logger, k
7777
return nil
7878
}
7979

80+
// BatchDelete calls BasicDelete for each object in objects using the same key. Returns on the first error.
81+
func BatchDelete(ctx context.Context, r product.SomeReconciler, l logr.Logger, key client.ObjectKey, objects ...client.Object) error {
82+
for _, obj := range objects {
83+
if err := BasicDelete(ctx, r, l, key, obj); err != nil {
84+
return err
85+
}
86+
}
87+
return nil
88+
}
89+
8090
// PvcCreateOrUpdate is careful only to patch valid fields _if they have changed_. Otherwise, leave things
8191
// alone! In particular, StorageClassName will throw a diff every time if we leave it as blank (the default), because
8292
// Kubernetes fills in the StorageClassName

0 commit comments

Comments
 (0)