Skip to content

Commit 580430b

Browse files
committed
Add a disable-default-addon-namespace flag
if the flag is set, default addon ns will not be created by the operator. Signed-off-by: Jian Qiu <[email protected]>
1 parent c61895c commit 580430b

File tree

6 files changed

+103
-31
lines changed

6 files changed

+103
-31
lines changed

pkg/cmd/spoke/operator.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,18 @@ func NewKlusterletOperatorCmd() *cobra.Command {
3131

3232
// add disable leader election flag
3333
flags := cmd.Flags()
34-
cmd.Flags().BoolVar(&klOptions.SkipPlaceholderHubSecret, "skip-placeholder-hub-secret", false,
34+
flags.BoolVar(&klOptions.SkipPlaceholderHubSecret, "skip-placeholder-hub-secret", false,
3535
"If set, will skip ensuring a placeholder hub secret which is originally intended for pulling "+
3636
"work image before approved")
37-
cmd.Flags().StringVar(&klOptions.ControlPlaneNodeLabelSelector, "control-plane-node-label-selector",
37+
flags.MarkDeprecated("skip-placeholder-hub-secret", "flag is not used in the operator.")
38+
flags.StringVar(&klOptions.ControlPlaneNodeLabelSelector, "control-plane-node-label-selector",
3839
"node-role.kubernetes.io/master=", "control plane node labels, "+
3940
"e.g. 'environment=production', 'tier notin (frontend,backend)'")
40-
cmd.Flags().Int32Var(&klOptions.DeploymentReplicas, "deployment-replicas", 0,
41+
flags.Int32Var(&klOptions.DeploymentReplicas, "deployment-replicas", 0,
4142
"Number of deployment replicas, operator will automatically determine replicas if not set")
43+
flags.BoolVar(&klOptions.DisableAddonNamespace, "disable-default-addon-namespace", false,
44+
"If set, will not create default open-cluster-management-agent-addon ns")
45+
4246
opts.AddFlags(flags)
4347

4448
return cmd

pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_cleanup_controller.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ type klusterletCleanupController struct {
4040
managedClusterClientsBuilder managedClusterClientsBuilderInterface
4141
controlPlaneNodeLabelSelector string
4242
deploymentReplicas int32
43+
disableAddonNamespace bool
4344
}
4445

4546
// NewKlusterletCleanupController construct klusterlet cleanup controller
@@ -55,6 +56,7 @@ func NewKlusterletCleanupController(
5556
operatorNamespace string,
5657
controlPlaneNodeLabelSelector string,
5758
deploymentReplicas int32,
59+
disableAddonNamespace bool,
5860
recorder events.Recorder) factory.Controller {
5961
controller := &klusterletCleanupController{
6062
kubeClient: kubeClient,
@@ -67,6 +69,7 @@ func NewKlusterletCleanupController(
6769
managedClusterClientsBuilder: newManagedClusterClientsBuilder(kubeClient, apiExtensionClient, appliedManifestWorkClient, recorder),
6870
controlPlaneNodeLabelSelector: controlPlaneNodeLabelSelector,
6971
deploymentReplicas: deploymentReplicas,
72+
disableAddonNamespace: disableAddonNamespace,
7073
}
7174

7275
return factory.New().WithSync(controller.sync).
@@ -122,6 +125,7 @@ func (n *klusterletCleanupController) sync(ctx context.Context, controllerContex
122125
ExternalManagedKubeConfigWorkSecret: helpers.ExternalManagedKubeConfigWork,
123126
InstallMode: klusterlet.Spec.DeployOption.Mode,
124127
HubApiServerHostAlias: klusterlet.Spec.HubApiServerHostAlias,
128+
DisableAddonNamespace: n.disableAddonNamespace,
125129

126130
RegistrationServiceAccount: serviceAccountName("registration-sa", klusterlet),
127131
WorkServiceAccount: serviceAccountName("work-sa", klusterlet),

pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ const (
4141
klusterletFinalizer = "operator.open-cluster-management.io/klusterlet-cleanup"
4242
managedResourcesEvictionTimestampAnno = "operator.open-cluster-management.io/managed-resources-eviction-timestamp"
4343
klusterletNamespaceLabelKey = "operator.open-cluster-management.io/klusterlet"
44-
hostedKlusterletLabelKey = "operator.open-cluster-management.io/hosted-klusterlet"
4544
)
4645

4746
type klusterletController struct {
@@ -50,11 +49,11 @@ type klusterletController struct {
5049
kubeClient kubernetes.Interface
5150
kubeVersion *version.Version
5251
operatorNamespace string
53-
skipHubSecretPlaceholder bool
5452
cache resourceapply.ResourceCache
5553
managedClusterClientsBuilder managedClusterClientsBuilderInterface
5654
controlPlaneNodeLabelSelector string
5755
deploymentReplicas int32
56+
disableAddonNamespace bool
5857
}
5958

6059
type klusterletReconcile interface {
@@ -82,20 +81,20 @@ func NewKlusterletController(
8281
operatorNamespace string,
8382
controlPlaneNodeLabelSelector string,
8483
deploymentReplicas int32,
85-
recorder events.Recorder,
86-
skipHubSecretPlaceholder bool) factory.Controller {
84+
disableAddonNamespace bool,
85+
recorder events.Recorder) factory.Controller {
8786
controller := &klusterletController{
8887
kubeClient: kubeClient,
8988
patcher: patcher.NewPatcher[
9089
*operatorapiv1.Klusterlet, operatorapiv1.KlusterletSpec, operatorapiv1.KlusterletStatus](klusterletClient),
9190
klusterletLister: klusterletInformer.Lister(),
9291
kubeVersion: kubeVersion,
9392
operatorNamespace: operatorNamespace,
94-
skipHubSecretPlaceholder: skipHubSecretPlaceholder,
9593
cache: resourceapply.NewResourceCache(),
9694
managedClusterClientsBuilder: newManagedClusterClientsBuilder(kubeClient, apiExtensionClient, appliedManifestWorkClient, recorder),
9795
controlPlaneNodeLabelSelector: controlPlaneNodeLabelSelector,
9896
deploymentReplicas: deploymentReplicas,
97+
disableAddonNamespace: disableAddonNamespace,
9998
}
10099

101100
return factory.New().WithSync(controller.sync).
@@ -164,6 +163,9 @@ type klusterletConfig struct {
164163
// ResourceRequirements is the resource requirements for the klusterlet managed containers.
165164
// The type has to be []byte to use "indent" template function.
166165
ResourceRequirements []byte
166+
167+
// DisableAddonNamespace is the flag to disable the creationg of default addon namespace.
168+
DisableAddonNamespace bool
167169
}
168170

169171
func (n *klusterletController) sync(ctx context.Context, controllerContext factory.SyncContext) error {
@@ -218,6 +220,7 @@ func (n *klusterletController) sync(ctx context.Context, controllerContext facto
218220
WorkServiceAccount: serviceAccountName("work-sa", klusterlet),
219221
ResourceRequirementResourceType: helpers.ResourceType(klusterlet),
220222
ResourceRequirements: resourceRequirements,
223+
DisableAddonNamespace: n.disableAddonNamespace,
221224
}
222225

223226
managedClusterClients, err := n.managedClusterClientsBuilder.

pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_controller_test.go

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,9 @@ func TestRemoveOldNamespace(t *testing.T) {
782782
Type: operatorapiv1.ConditionKlusterletApplied,
783783
Status: metav1.ConditionTrue,
784784
})
785-
controller.operatorStore.Update(klusterlet)
785+
if err := controller.operatorStore.Update(klusterlet); err != nil {
786+
t.Fatal(err)
787+
}
786788
err = controller.controller.sync(context.TODO(), syncContext)
787789
if err != nil {
788790
t.Errorf("Expected non error when sync, %v", err)
@@ -803,6 +805,53 @@ func TestRemoveOldNamespace(t *testing.T) {
803805
}
804806
}
805807

808+
// TestSyncDeploy test deployment of klusterlet components
809+
func TestSyncDisableAddonNamespace(t *testing.T) {
810+
klusterlet := newKlusterlet("klusterlet", "testns", "cluster1")
811+
bootStrapSecret := newSecret(helpers.BootstrapHubKubeConfig, "testns")
812+
hubKubeConfigSecret := newSecret(helpers.HubKubeConfig, "testns")
813+
hubKubeConfigSecret.Data["kubeconfig"] = []byte("dummuykubeconnfig")
814+
namespace := newNamespace("testns")
815+
syncContext := testingcommon.NewFakeSyncContext(t, "klusterlet")
816+
controller := newTestController(t, klusterlet, syncContext.Recorder(), nil, bootStrapSecret, hubKubeConfigSecret, namespace)
817+
controller.controller.disableAddonNamespace = true
818+
819+
err := controller.controller.sync(context.TODO(), syncContext)
820+
if err != nil {
821+
t.Errorf("Expected non error when sync, %v", err)
822+
}
823+
824+
var ns []runtime.Object
825+
kubeActions := controller.kubeClient.Actions()
826+
for _, action := range kubeActions {
827+
if action.GetVerb() == createVerb {
828+
object := action.(clienttesting.CreateActionImpl).Object
829+
if object.GetObjectKind().GroupVersionKind().Kind == "Namespace" {
830+
ns = append(ns, object)
831+
}
832+
}
833+
}
834+
835+
// Check if resources are created as expected, only 0 ns is created
836+
if len(ns) != 0 {
837+
t.Errorf("Expect 0 ns created in the sync loop, actual %d", len(ns))
838+
}
839+
840+
operatorAction := controller.operatorClient.Actions()
841+
testingcommon.AssertActions(t, operatorAction, "patch")
842+
klusterlet = &operatorapiv1.Klusterlet{}
843+
patchData := operatorAction[0].(clienttesting.PatchActionImpl).Patch
844+
err = json.Unmarshal(patchData, klusterlet)
845+
if err != nil {
846+
t.Fatal(err)
847+
}
848+
testinghelper.AssertOnlyConditions(
849+
t, klusterlet,
850+
testinghelper.NamedCondition(operatorapiv1.ConditionKlusterletApplied, "KlusterletApplied", metav1.ConditionTrue),
851+
testinghelper.NamedCondition(helpers.FeatureGatesTypeValid, helpers.FeatureGatesReasonAllValid, metav1.ConditionTrue),
852+
)
853+
}
854+
806855
// TestGetServersFromKlusterlet tests getServersFromKlusterlet func
807856
func TestGetServersFromKlusterlet(t *testing.T) {
808857
cases := []struct {

pkg/operator/operators/klusterlet/controllers/klusterletcontroller/klusterlet_managed_reconcile.go

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -63,29 +63,36 @@ type managedReconcile struct {
6363

6464
func (r *managedReconcile) reconcile(ctx context.Context, klusterlet *operatorapiv1.Klusterlet,
6565
config klusterletConfig) (*operatorapiv1.Klusterlet, reconcileState, error) {
66-
// For now, whether in Default or Hosted mode, the addons will be deployed on the managed cluster.
67-
// sync image pull secret from management cluster to managed cluster for addon namespace
68-
// TODO(zhujian7): In the future, we may consider deploy addons on the management cluster in Hosted mode.
69-
// Ensure the addon namespace on the managed cluster
70-
err := ensureNamespace(ctx, r.managedClusterClients.kubeClient, klusterlet, helpers.DefaultAddonNamespace, nil, r.recorder)
71-
if err != nil {
72-
return klusterlet, reconcileStop, err
73-
}
74-
// Sync pull secret to the klusterlet addon namespace
75-
// The reason we keep syncing secret instead of adding a label to trigger addonsecretcontroller to sync is:
76-
// addonsecretcontroller only watch namespaces in the same cluster klusterlet is running on.
77-
// And if addons are deployed in default mode on the managed cluster, but klusterlet is deployed in hosted
78-
// on management cluster, then we still need to sync the secret here in klusterlet-controller using `managedClusterClients.kubeClient`.
79-
err = syncPullSecret(ctx, r.kubeClient, r.managedClusterClients.kubeClient, klusterlet, r.operatorNamespace, helpers.DefaultAddonNamespace, r.recorder)
80-
if err != nil {
81-
return klusterlet, reconcileStop, err
66+
if !config.DisableAddonNamespace {
67+
// For now, whether in Default or Hosted mode, the addons will be deployed on the managed cluster.
68+
// sync image pull secret from management cluster to managed cluster for addon namespace
69+
// TODO(zhujian7): In the future, we may consider deploy addons on the management cluster in Hosted mode.
70+
// Ensure the addon namespace on the managed cluster
71+
if err := ensureNamespace(
72+
ctx,
73+
r.managedClusterClients.kubeClient,
74+
klusterlet, helpers.DefaultAddonNamespace, nil, r.recorder); err != nil {
75+
return klusterlet, reconcileStop, err
76+
}
77+
78+
// Sync pull secret to the klusterlet addon namespace
79+
// The reason we keep syncing secret instead of adding a label to trigger addonsecretcontroller to sync is:
80+
// addonsecretcontroller only watch namespaces in the same cluster klusterlet is running on.
81+
// And if addons are deployed in default mode on the managed cluster, but klusterlet is deployed in hosted
82+
// on management cluster, then we still need to sync the secret here in klusterlet-controller using `managedClusterClients.kubeClient`.
83+
if err := syncPullSecret(
84+
ctx,
85+
r.kubeClient,
86+
r.managedClusterClients.kubeClient,
87+
klusterlet, r.operatorNamespace, helpers.DefaultAddonNamespace, r.recorder); err != nil {
88+
return klusterlet, reconcileStop, err
89+
}
8290
}
8391

84-
err = ensureNamespace(
92+
if err := ensureNamespace(
8593
ctx, r.managedClusterClients.kubeClient, klusterlet, config.KlusterletNamespace, map[string]string{
8694
klusterletNamespaceLabelKey: klusterlet.Name,
87-
}, r.recorder)
88-
if err != nil {
95+
}, r.recorder); err != nil {
8996
return klusterlet, reconcileStop, err
9097
}
9198

@@ -197,7 +204,10 @@ func (r *managedReconcile) clean(ctx context.Context, klusterlet *operatorapiv1.
197204

198205
// remove the klusterlet namespace and klusterlet addon namespace on the managed cluster
199206
// For now, whether in Default or Hosted mode, the addons could be deployed on the managed cluster.
200-
namespaces := []string{config.KlusterletNamespace, fmt.Sprintf("%s-addon", config.KlusterletNamespace)}
207+
namespaces := []string{config.KlusterletNamespace}
208+
if !config.DisableAddonNamespace {
209+
namespaces = append(namespaces, helpers.DefaultAddonNamespace)
210+
}
201211
for _, namespace := range namespaces {
202212
if err := r.managedClusterClients.kubeClient.CoreV1().Namespaces().Delete(
203213
ctx, namespace, metav1.DeleteOptions{}); err != nil && !errors.IsNotFound(err) {

pkg/operator/operators/klusterlet/options.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type Options struct {
2828
SkipPlaceholderHubSecret bool
2929
ControlPlaneNodeLabelSelector string
3030
DeploymentReplicas int32
31+
DisableAddonNamespace bool
3132
}
3233

3334
// RunKlusterletOperator starts a new klusterlet operator
@@ -100,8 +101,8 @@ func (o *Options) RunKlusterletOperator(ctx context.Context, controllerContext *
100101
helpers.GetOperatorNamespace(),
101102
o.ControlPlaneNodeLabelSelector,
102103
o.DeploymentReplicas,
103-
controllerContext.EventRecorder,
104-
o.SkipPlaceholderHubSecret)
104+
o.DisableAddonNamespace,
105+
controllerContext.EventRecorder)
105106

106107
klusterletCleanupController := klusterletcontroller.NewKlusterletCleanupController(
107108
kubeClient,
@@ -115,6 +116,7 @@ func (o *Options) RunKlusterletOperator(ctx context.Context, controllerContext *
115116
helpers.GetOperatorNamespace(),
116117
o.ControlPlaneNodeLabelSelector,
117118
o.DeploymentReplicas,
119+
o.DisableAddonNamespace,
118120
controllerContext.EventRecorder)
119121

120122
ssarController := ssarcontroller.NewKlusterletSSARController(

0 commit comments

Comments
 (0)