Skip to content

Commit f055448

Browse files
committed
Fix restarting the gatekeeper-constraint-sync
Previously, when Gatekeeper was uninstalled, the context for the gatekeeper sync manager was permanently cancelled. As a result, if Gatekeeper was re-installed, the manager would immediately stop again, and the constraint-sync controlelr would not be started properly. Refs: - https://issues.redhat.com/browse/ACM-21861 Signed-off-by: Justin Kulikauskas <[email protected]>
1 parent 358935e commit f055448

File tree

4 files changed

+64
-1
lines changed

4 files changed

+64
-1
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ CONTROLLER_NAME ?= $(shell cat COMPONENT_NAME 2> /dev/null)
4949
ifeq ($(KIND_VERSION), minimum)
5050
KIND_ARGS = --image kindest/node:v1.19.16
5151
E2E_FILTER = --label-filter="!skip-minimum"
52+
export DISABLE_GK_SYNC = true
5253
else ifneq ($(KIND_VERSION), latest)
5354
KIND_ARGS = --image kindest/node:$(KIND_VERSION)
5455
else

controllers/gatekeepersync/gatekeeper_constraint_sync.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,15 @@ var (
5050

5151
// SetupWithManager sets up the controller with the Manager.
5252
func (r *GatekeeperConstraintReconciler) SetupWithManager(mgr ctrl.Manager, constraintEvents source.Source) error {
53+
skipNameValidation := true // we need to be able to stop and restart this controller
54+
5355
return ctrl.NewControllerManagedBy(mgr).
5456
For(&policyv1.Policy{}).
5557
WithEventFilter(policyPredicates()).
56-
WithOptions(controller.Options{MaxConcurrentReconciles: r.ConcurrentReconciles}).
58+
WithOptions(controller.Options{
59+
SkipNameValidation: &skipNameValidation,
60+
MaxConcurrentReconciles: r.ConcurrentReconciles,
61+
}).
5762
WatchesRawSource(constraintEvents).
5863
Named(ControllerName).
5964
Complete(r)

main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,11 @@ func manageGatekeeperSyncManager(
955955
mgrRunning = false
956956

957957
mgrCtxCancel()
958+
959+
// Reset the context for later, otherwise the context is permanently cancelled,
960+
// and the manager won't start if Gatekeeper is reinstalled.
961+
//nolint:fatcontext
962+
mgrCtx, mgrCtxCancel = context.WithCancel(ctx)
958963
}
959964

960965
select {

test/e2e/e2e_suite_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"os/user"
1313
"path/filepath"
1414
"testing"
15+
"time"
1516

1617
. "github.com/onsi/ginkgo/v2"
1718
. "github.com/onsi/gomega"
@@ -45,6 +46,7 @@ var (
4546
gvrEvent schema.GroupVersionResource
4647
gvrConfigurationPolicy schema.GroupVersionResource
4748
gvrConstraintTemplate schema.GroupVersionResource
49+
gvrCRD schema.GroupVersionResource
4850
kubeconfigHub string
4951
kubeconfigManaged string
5052
defaultTimeoutSeconds int
@@ -106,6 +108,12 @@ var _ = BeforeSuite(func() {
106108
Version: "v1",
107109
Resource: "constrainttemplates",
108110
}
111+
gvrCRD = schema.GroupVersionResource{
112+
Group: "apiextensions.k8s.io",
113+
Version: "v1",
114+
Resource: "customresourcedefinitions",
115+
}
116+
109117
clientHub = NewKubeClient("", kubeconfigHub, "")
110118
clientHubDynamic = NewKubeClientDynamic("", kubeconfigHub, "")
111119
clientManaged = NewKubeClient("", kubeconfigManaged, "")
@@ -174,6 +182,50 @@ var _ = BeforeSuite(func() {
174182
ClientSet: kubernetes.NewForConfigOrDie(managedConfig),
175183
ControllerName: "status-sync-controller-test",
176184
}
185+
186+
if !gkSyncDisabled {
187+
// This section deletes and then re-creates the Gatekeeper ConstraintTemplate CRD, which
188+
// should cause the gatekeeper-sync controller to stop and then restart. Tests then verify
189+
// that gatekeeper-sync is running correctly, ensuring that there is not a bug in the
190+
// restart procedure.
191+
192+
// AI-ASSISTED: The code in this block was based on output from Cursor using claude-4-sonnet.
193+
194+
gkCRDName := "constrainttemplates.templates.gatekeeper.sh"
195+
196+
By("Deleting the constrainttemplate CRD to simulate uninstalling Gatekeeper")
197+
198+
originalCRD, err := clientManagedDynamic.Resource(gvrCRD).Get(context.TODO(), gkCRDName, metav1.GetOptions{})
199+
Expect(err).ToNot(HaveOccurred())
200+
201+
err = clientManagedDynamic.Resource(gvrCRD).Delete(context.TODO(), gkCRDName, metav1.DeleteOptions{})
202+
Expect(err).ToNot(HaveOccurred())
203+
204+
Eventually(func() bool {
205+
_, err := clientManagedDynamic.Resource(gvrCRD).Get(
206+
context.TODO(), gkCRDName, metav1.GetOptions{},
207+
)
208+
209+
return k8serrors.IsNotFound(err)
210+
}, defaultTimeoutSeconds, 1).Should(BeTrue())
211+
212+
By("Waiting 10 seconds for the manager to detect missing CRD")
213+
time.Sleep(10 * time.Second)
214+
215+
// Cleanup fields that would cause the Create to fail
216+
unstructured.RemoveNestedField(originalCRD.Object, "metadata", "resourceVersion")
217+
unstructured.RemoveNestedField(originalCRD.Object, "metadata", "uid")
218+
unstructured.RemoveNestedField(originalCRD.Object, "metadata", "generation")
219+
unstructured.RemoveNestedField(originalCRD.Object, "metadata", "creationTimestamp")
220+
unstructured.RemoveNestedField(originalCRD.Object, "status")
221+
222+
By("Re-creating the constrainttemplate CRD to simulate re-installing Gatekeeper")
223+
_, err = clientManagedDynamic.Resource(gvrCRD).Create(context.TODO(), originalCRD, metav1.CreateOptions{})
224+
Expect(err).ToNot(HaveOccurred())
225+
226+
By("Waiting 10 seconds for the manager to detect the fresh CRD")
227+
time.Sleep(10 * time.Second)
228+
}
177229
})
178230

179231
func NewKubeClient(url, kubeconfig, context string) kubernetes.Interface {

0 commit comments

Comments
 (0)