Skip to content

Commit d8947cd

Browse files
Merge pull request #237 from appiepollo14/feat/allow-configure-replicas
RFE-6735: Allows for override replicas quantity to deploy a HA cert manager
2 parents 97ab881 + bc4ff39 commit d8947cd

File tree

9 files changed

+263
-0
lines changed

9 files changed

+263
-0
lines changed

api/operator/v1alpha1/certmanager_types.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ type DeploymentConfig struct {
8282
// +optional
8383
OverrideResources CertManagerResourceRequirements `json:"overrideResources,omitempty"`
8484

85+
// OverrideReplicas defines the number of replicas to run for an operand
86+
// +kubebuilder:validation:Optional
87+
// +kubebuilder:validation:Minimum=1
88+
// +optional
89+
OverrideReplicas *int32 `json:"overrideReplicas,omitempty"`
90+
8591
// +kubebuilder:validation:Optional
8692
// +optional
8793
OverrideScheduling CertManagerScheduling `json:"overrideScheduling,omitempty"`

api/operator/v1alpha1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bundle/manifests/operator.openshift.io_certmanagers.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ spec:
177177
additionalProperties:
178178
type: string
179179
type: object
180+
overrideReplicas:
181+
description: OverrideReplicas defines the number of replicas to
182+
run for an operand
183+
format: int32
184+
minimum: 1
185+
type: integer
180186
overrideResources:
181187
description: |-
182188
CertManagerResourceRequirements describes the compute resource requirements for the cert-manager operands,
@@ -413,6 +419,12 @@ spec:
413419
additionalProperties:
414420
type: string
415421
type: object
422+
overrideReplicas:
423+
description: OverrideReplicas defines the number of replicas to
424+
run for an operand
425+
format: int32
426+
minimum: 1
427+
type: integer
416428
overrideResources:
417429
description: |-
418430
CertManagerResourceRequirements describes the compute resource requirements for the cert-manager operands,
@@ -694,6 +706,12 @@ spec:
694706
additionalProperties:
695707
type: string
696708
type: object
709+
overrideReplicas:
710+
description: OverrideReplicas defines the number of replicas to
711+
run for an operand
712+
format: int32
713+
minimum: 1
714+
type: integer
697715
overrideResources:
698716
description: |-
699717
CertManagerResourceRequirements describes the compute resource requirements for the cert-manager operands,

config/crd/bases/operator.openshift.io_certmanagers.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ spec:
177177
additionalProperties:
178178
type: string
179179
type: object
180+
overrideReplicas:
181+
description: OverrideReplicas defines the number of replicas to
182+
run for an operand
183+
format: int32
184+
minimum: 1
185+
type: integer
180186
overrideResources:
181187
description: |-
182188
CertManagerResourceRequirements describes the compute resource requirements for the cert-manager operands,
@@ -413,6 +419,12 @@ spec:
413419
additionalProperties:
414420
type: string
415421
type: object
422+
overrideReplicas:
423+
description: OverrideReplicas defines the number of replicas to
424+
run for an operand
425+
format: int32
426+
minimum: 1
427+
type: integer
416428
overrideResources:
417429
description: |-
418430
CertManagerResourceRequirements describes the compute resource requirements for the cert-manager operands,
@@ -694,6 +706,12 @@ spec:
694706
additionalProperties:
695707
type: string
696708
type: object
709+
overrideReplicas:
710+
description: OverrideReplicas defines the number of replicas to
711+
run for an operand
712+
format: int32
713+
minimum: 1
714+
type: integer
697715
overrideResources:
698716
description: |-
699717
CertManagerResourceRequirements describes the compute resource requirements for the cert-manager operands,

pkg/controller/deployment/deployment_helper.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,33 @@ func getOverridePodLabelsFor(certmanagerinformer certmanagerinformer.CertManager
214214

215215
}
216216

217+
// getOverrideReplicasFor is a helper function that returns the OverrideReplicas provided
218+
// in the operator spec based on the deployment name.
219+
func getOverrideReplicasFor(certmanagerinformer certmanagerinformer.CertManagerInformer, deploymentName string) (*int32, error) {
220+
certmanager, err := certmanagerinformer.Lister().Get("cluster")
221+
if err != nil {
222+
return nil, fmt.Errorf("failed to get certmanager %q due to %v", "cluster", err)
223+
}
224+
225+
switch deploymentName {
226+
case certmanagerControllerDeployment:
227+
if certmanager.Spec.ControllerConfig != nil {
228+
return certmanager.Spec.ControllerConfig.OverrideReplicas, nil
229+
}
230+
case certmanagerWebhookDeployment:
231+
if certmanager.Spec.WebhookConfig != nil {
232+
return certmanager.Spec.WebhookConfig.OverrideReplicas, nil
233+
}
234+
case certmanagerCAinjectorDeployment:
235+
if certmanager.Spec.CAInjectorConfig != nil {
236+
return certmanager.Spec.CAInjectorConfig.OverrideReplicas, nil
237+
}
238+
default:
239+
return nil, fmt.Errorf("unsupported deployment name %q provided", deploymentName)
240+
}
241+
return nil, nil
242+
}
243+
217244
// getOverrideResourcesFor is a helper function that returns the OverrideResources provided
218245
// in the operator spec based on the deployment name.
219246
func getOverrideResourcesFor(certmanagerinformer certmanagerinformer.CertManagerInformer, deploymentName string) (v1alpha1.CertManagerResourceRequirements, error) {

pkg/controller/deployment/deployment_helper_test.go

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,3 +944,161 @@ func TestGetOverrideSchedulingFor(t *testing.T) {
944944
})
945945
}
946946
}
947+
948+
func TestGetOverrideReplicasFor(t *testing.T) {
949+
ptr := func(i int32) *int32 { return &i }
950+
951+
tests := []struct {
952+
name string
953+
certManagerObj v1alpha1.CertManager
954+
deploymentName string
955+
expectedOverrideReplicas *int32
956+
}{
957+
{
958+
name: "get override replicas of cert manager controller config",
959+
certManagerObj: v1alpha1.CertManager{
960+
ObjectMeta: metav1.ObjectMeta{
961+
Name: "cluster",
962+
},
963+
Spec: v1alpha1.CertManagerSpec{
964+
ControllerConfig: &v1alpha1.DeploymentConfig{
965+
OverrideReplicas: ptr(2),
966+
},
967+
},
968+
},
969+
deploymentName: certmanagerControllerDeployment,
970+
expectedOverrideReplicas: ptr(2),
971+
},
972+
{
973+
name: "get override scheduling of cert manager webhook config",
974+
certManagerObj: v1alpha1.CertManager{
975+
ObjectMeta: metav1.ObjectMeta{
976+
Name: "cluster",
977+
},
978+
Spec: v1alpha1.CertManagerSpec{
979+
WebhookConfig: &v1alpha1.DeploymentConfig{
980+
OverrideReplicas: ptr(0),
981+
},
982+
},
983+
},
984+
deploymentName: certmanagerWebhookDeployment,
985+
expectedOverrideReplicas: ptr(0),
986+
},
987+
{
988+
name: "get override replicas of cert manager cainjector config",
989+
certManagerObj: v1alpha1.CertManager{
990+
ObjectMeta: metav1.ObjectMeta{
991+
Name: "cluster",
992+
},
993+
Spec: v1alpha1.CertManagerSpec{
994+
CAInjectorConfig: &v1alpha1.DeploymentConfig{
995+
OverrideReplicas: ptr(2),
996+
},
997+
},
998+
},
999+
deploymentName: certmanagerCAinjectorDeployment,
1000+
expectedOverrideReplicas: ptr(2),
1001+
},
1002+
{
1003+
name: "no override replicas configured",
1004+
certManagerObj: v1alpha1.CertManager{
1005+
ObjectMeta: metav1.ObjectMeta{
1006+
Name: "cluster",
1007+
},
1008+
Spec: v1alpha1.CertManagerSpec{
1009+
// no configs set
1010+
},
1011+
},
1012+
deploymentName: certmanagerControllerDeployment,
1013+
expectedOverrideReplicas: nil,
1014+
},
1015+
}
1016+
1017+
ctx, cancel := context.WithCancel(context.Background())
1018+
defer cancel()
1019+
1020+
// Create channel to know when the watch has started.
1021+
watcherStarted := make(chan struct{})
1022+
// Create the fake client.
1023+
fakeClient := fake.NewSimpleClientset()
1024+
// A watch reactor for cert manager objects that allows the injection of the watcherStarted channel.
1025+
fakeClient.PrependWatchReactor("certmanagers", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
1026+
gvr := action.GetResource()
1027+
ns := action.GetNamespace()
1028+
watch, err := fakeClient.Tracker().Watch(gvr, ns)
1029+
if err != nil {
1030+
return false, nil, err
1031+
}
1032+
close(watcherStarted)
1033+
return true, watch, nil
1034+
})
1035+
1036+
// Create cert manager informers using the fake client.
1037+
certManagerInformers := certmanoperatorinformer.NewSharedInformerFactory(fakeClient, 0).Operator().V1alpha1().CertManagers()
1038+
1039+
// Create a channel to receive the cert manager objects from the informer.
1040+
certManagerChan := make(chan *v1alpha1.CertManager, 1)
1041+
1042+
// Add event handlers to the informer to write the cert manager objects to
1043+
// the channel received during the add and the delete events.
1044+
certManagerInformers.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
1045+
AddFunc: func(obj interface{}) {
1046+
certManagerObj := obj.(*v1alpha1.CertManager)
1047+
t.Logf("cert manager obj added: %s", certManagerObj.Name)
1048+
certManagerChan <- certManagerObj
1049+
},
1050+
DeleteFunc: func(obj interface{}) {
1051+
certManagerObj := obj.(*v1alpha1.CertManager)
1052+
t.Logf("cert manager obj deleted: %s", certManagerObj.Name)
1053+
certManagerChan <- certManagerObj
1054+
},
1055+
})
1056+
1057+
// Make sure informer is running.
1058+
go certManagerInformers.Informer().Run(ctx.Done())
1059+
1060+
// This is not required in tests, but it serves as a proof-of-concept by
1061+
// ensuring that the informer goroutine have warmed up and called List before
1062+
// we send any events to it.
1063+
cache.WaitForCacheSync(ctx.Done(), certManagerInformers.Informer().HasSynced)
1064+
1065+
// The fake client doesn't support resource version. Any writes to the client
1066+
// after the informer's initial LIST and before the informer establishing the
1067+
// watcher will be missed by the informer. Therefore we wait until the watcher
1068+
// starts.
1069+
<-watcherStarted
1070+
1071+
for _, tc := range tests {
1072+
t.Run(tc.name, func(t *testing.T) {
1073+
// Create the cert manager object using the fake client.
1074+
_, err := fakeClient.OperatorV1alpha1().CertManagers().Create(ctx, &tc.certManagerObj, metav1.CreateOptions{})
1075+
if err != nil {
1076+
t.Fatalf("error injecting cert manager add: %v", err)
1077+
}
1078+
1079+
// Wait for the informer to get the event.
1080+
select {
1081+
case <-certManagerChan:
1082+
case <-time.After(wait.ForeverTestTimeout):
1083+
t.Fatal("Informer did not get the added cert manager object")
1084+
}
1085+
1086+
actualOverrideReplicas, err := getOverrideReplicasFor(certManagerInformers, tc.deploymentName)
1087+
assert.NoError(t, err)
1088+
require.Equal(t, tc.expectedOverrideReplicas, actualOverrideReplicas)
1089+
1090+
// Delete the cert manager object using the fake client.
1091+
err = fakeClient.OperatorV1alpha1().CertManagers().Delete(ctx, tc.certManagerObj.Name, metav1.DeleteOptions{})
1092+
if err != nil {
1093+
t.Fatalf("error deleting cert manager add: %v", err)
1094+
}
1095+
1096+
// Wait for the informer to get the event.
1097+
select {
1098+
case <-certManagerChan:
1099+
case <-time.After(wait.ForeverTestTimeout):
1100+
t.Fatal("Informer did not get the deleted cert manager")
1101+
}
1102+
})
1103+
}
1104+
}

pkg/controller/deployment/deployment_overrides.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ type overrideEnvFunc func(certmanagerinformer.CertManagerInformer, string) ([]co
5757
// to cert-manager-operator spec.
5858
type overrideLabelsFunc func(certmanagerinformer.CertManagerInformer, string) (map[string]string, error)
5959

60+
// overrideReplicasFunc defines a function signature that is accepted by
61+
// withDeploymentReplicasOverrideHook(). This function returns the override
62+
// replicas provided to cert-manager-operator spec.
63+
type overrideReplicasFunc func(certmanagerinformer.CertManagerInformer, string) (*int32, error)
64+
6065
// overrideResourcesFunc defines a function signature that is accepted by
6166
// withContainerResourcesOverrideHook(). This function returns the override
6267
// resources provided to cert-manager-operator spec.
@@ -137,6 +142,22 @@ func withContainerResourcesOverrideHook(certmanagerinformer certmanagerinformer.
137142
}
138143
}
139144

145+
// withDeploymentReplicasOverrideHook overrides the deployment replicas with those provided by
146+
// the overrideReplicasFunc function.
147+
func withDeploymentReplicasOverrideHook(certmanagerinformer certmanagerinformer.CertManagerInformer, deploymentName string, fn overrideReplicasFunc) func(operatorSpec *operatorv1.OperatorSpec, deployment *appsv1.Deployment) error {
148+
return func(operatorSpec *operatorv1.OperatorSpec, deployment *appsv1.Deployment) error {
149+
overrideReplicas, err := fn(certmanagerinformer, deploymentName)
150+
if err != nil {
151+
return err
152+
}
153+
154+
if overrideReplicas != nil && deployment.Name == deploymentName {
155+
deployment.Spec.Replicas = ptr.To(*overrideReplicas)
156+
}
157+
return nil
158+
}
159+
}
160+
140161
// withPodSchedulingOverrideHook overrides the pod scheduling with those provided by
141162
// the overrideSchedulingFunc function.
142163
func withPodSchedulingOverrideHook(certmanagerinformer certmanagerinformer.CertManagerInformer, deploymentName string, fn overrideSchedulingFunc) func(operatorSpec *operatorv1.OperatorSpec, deployment *appsv1.Deployment) error {

pkg/controller/deployment/generic_deployment_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func newGenericDeploymentController(
4040
withContainerArgsValidateHook(certManagerOperatorInformers.Operator().V1alpha1().CertManagers(), deployment.Name),
4141
withContainerEnvOverrideHook(certManagerOperatorInformers.Operator().V1alpha1().CertManagers(), deployment.Name, getOverrideEnvFor),
4242
withContainerEnvValidateHook(certManagerOperatorInformers.Operator().V1alpha1().CertManagers(), deployment.Name),
43+
withDeploymentReplicasOverrideHook(certManagerOperatorInformers.Operator().V1alpha1().CertManagers(), deployment.Name, getOverrideReplicasFor),
4344
withContainerResourcesOverrideHook(certManagerOperatorInformers.Operator().V1alpha1().CertManagers(), deployment.Name, getOverrideResourcesFor),
4445
withContainerResourcesValidateHook(certManagerOperatorInformers.Operator().V1alpha1().CertManagers(), deployment.Name),
4546
withPodSchedulingOverrideHook(certManagerOperatorInformers.Operator().V1alpha1().CertManagers(), deployment.Name, getOverrideSchedulingFor),

pkg/operator/applyconfigurations/operator/v1alpha1/deploymentconfig.go

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)