Skip to content

Commit 33d925a

Browse files
committed
move high level logic to reconciler methods
1 parent 9c64f22 commit 33d925a

File tree

3 files changed

+71
-43
lines changed

3 files changed

+71
-43
lines changed

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ RUN go mod download
1313
# Copy the go source
1414
COPY cmd/ ./cmd/
1515
COPY api/ ./api/
16+
COPY pkg/ ./pkg/
1617
COPY internal/ ./internal/
1718

1819
# Build

internal/controller/etcdcluster_controller.go

Lines changed: 60 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ type EtcdClusterReconciler struct {
7575
// Reconcile checks CR and current cluster state and performs actions to transform current state to desired.
7676
func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
7777
log.Debug(ctx, "reconciling object")
78-
state := observables{}
78+
state := &observables{}
7979
state.instance = &etcdaenixiov1alpha1.EtcdCluster{}
8080
err := r.Get(ctx, req.NamespacedName, state.instance)
8181
if err != nil {
@@ -92,7 +92,7 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
9292
}
9393

9494
// create two services and the pdb
95-
err = r.ensureUnconditionalObjects(ctx, state.instance)
95+
err = r.ensureUnconditionalObjects(ctx, state)
9696
if err != nil {
9797
return ctrl.Result{}, err
9898
}
@@ -123,7 +123,7 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
123123

124124
if !state.endpointsFound {
125125
if !state.stsExists {
126-
return r.createClusterFromScratch(ctx, &state) // TODO: needs implementing
126+
return r.createClusterFromScratch(ctx, state) // TODO: needs implementing
127127
}
128128

129129
// update sts pod template (and only pod template) if it doesn't match desired state
@@ -146,7 +146,7 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
146146
return ctrl.Result{}, nil
147147
}
148148

149-
return r.scaleUpFromZero(ctx, &state) // TODO: needs implementing
149+
return ctrl.Result{}, r.scaleUpFromZero(ctx) // TODO: needs implementing
150150
}
151151

152152
// get status of every endpoint and member list from every endpoint
@@ -174,7 +174,7 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
174174
}
175175

176176
if !memberReached {
177-
return r.createOrUpdateStatefulSet(ctx, &state, state.instance)
177+
return ctrl.Result{}, r.createOrUpdateStatefulSet(ctx)
178178
}
179179

180180
state.setClusterID()
@@ -189,7 +189,7 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
189189
Message: string(etcdaenixiov1alpha1.EtcdErrorCondSplitbrainMessage),
190190
},
191191
)
192-
return r.updateStatus(ctx, state.instance)
192+
return r.updateStatus(ctx, state)
193193
}
194194

195195
if !state.clusterHasQuorum() {
@@ -198,19 +198,19 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
198198
}
199199

200200
if state.hasLearners() {
201-
return ctrl.Result{}, r.promoteLearners(ctx, &state)
201+
return ctrl.Result{}, r.promoteLearners(ctx)
202202
}
203203

204-
if err := r.createOrUpdateClusterStateConfigMap(ctx, &state); err != nil {
204+
if err := r.createOrUpdateClusterStateConfigMap(ctx); err != nil {
205205
return ctrl.Result{}, err
206206
}
207207

208208
if !state.statefulSetPodSpecCorrect() {
209-
return ctrl.Result{}, r.createOrUpdateStatefulSet(ctx, &state)
209+
return ctrl.Result{}, r.createOrUpdateStatefulSet(ctx)
210210
}
211211

212212
// if size is different we have to remove statefulset it will be recreated in the next step
213-
if err := r.checkAndDeleteStatefulSetIfNecessary(ctx, &state, state.instance); err != nil {
213+
if err := r.checkAndDeleteStatefulSetIfNecessary(ctx, state); err != nil {
214214
return ctrl.Result{}, err
215215
}
216216

@@ -226,17 +226,17 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
226226
},
227227
)
228228
*/
229-
return r.updateStatus(ctx, state.instance)
229+
return r.updateStatus(ctx, state)
230230
}
231231

232232
// checkAndDeleteStatefulSetIfNecessary deletes the StatefulSet if the specified storage size has changed.
233-
func (r *EtcdClusterReconciler) checkAndDeleteStatefulSetIfNecessary(ctx context.Context, state *observables, instance *etcdaenixiov1alpha1.EtcdCluster) error {
233+
func (r *EtcdClusterReconciler) checkAndDeleteStatefulSetIfNecessary(ctx context.Context, state *observables) error {
234234
for _, volumeClaimTemplate := range state.statefulSet.Spec.VolumeClaimTemplates {
235235
if volumeClaimTemplate.Name != "data" {
236236
continue
237237
}
238238
currentStorage := volumeClaimTemplate.Spec.Resources.Requests[corev1.ResourceStorage]
239-
desiredStorage := instance.Spec.Storage.VolumeClaimTemplate.Spec.Resources.Requests[corev1.ResourceStorage]
239+
desiredStorage := state.instance.Spec.Storage.VolumeClaimTemplate.Spec.Resources.Requests[corev1.ResourceStorage]
240240
if desiredStorage.Cmp(currentStorage) != 0 {
241241
deletePolicy := metav1.DeletePropagationOrphan
242242
log.Info(ctx, "Deleting StatefulSet due to storage change", "statefulSet", state.statefulSet.Name)
@@ -252,21 +252,20 @@ func (r *EtcdClusterReconciler) checkAndDeleteStatefulSetIfNecessary(ctx context
252252
}
253253

254254
// ensureConditionalClusterObjects creates or updates all objects owned by cluster CR
255-
func (r *EtcdClusterReconciler) ensureConditionalClusterObjects(
256-
ctx context.Context, cluster *etcdaenixiov1alpha1.EtcdCluster) error {
255+
func (r *EtcdClusterReconciler) ensureConditionalClusterObjects(ctx context.Context, state *observables) error {
257256

258-
if err := factory.CreateOrUpdateClusterStateConfigMap(ctx, cluster, r.Client); err != nil {
257+
if err := factory.CreateOrUpdateClusterStateConfigMap(ctx, state.instance, r.Client); err != nil {
259258
log.Error(ctx, err, "reconcile cluster state configmap failed")
260259
return err
261260
}
262261
log.Debug(ctx, "cluster state configmap reconciled")
263262

264-
if err := factory.CreateOrUpdateStatefulSet(ctx, cluster, r.Client); err != nil {
263+
if err := factory.CreateOrUpdateStatefulSet(ctx, state.instance, r.Client); err != nil {
265264
log.Error(ctx, err, "reconcile statefulset failed")
266265
return err
267266
}
268267

269-
if err := factory.UpdatePersistentVolumeClaims(ctx, cluster, r.Client); err != nil {
268+
if err := factory.UpdatePersistentVolumeClaims(ctx, state.instance, r.Client); err != nil {
270269
log.Error(ctx, err, "reconcile persistentVolumeClaims failed")
271270
return err
272271
}
@@ -276,20 +275,20 @@ func (r *EtcdClusterReconciler) ensureConditionalClusterObjects(
276275
}
277276

278277
// updateStatusOnErr wraps error and updates EtcdCluster status
279-
func (r *EtcdClusterReconciler) updateStatusOnErr(ctx context.Context, cluster *etcdaenixiov1alpha1.EtcdCluster, err error) (ctrl.Result, error) {
278+
func (r *EtcdClusterReconciler) updateStatusOnErr(ctx context.Context, state *observables, err error) (ctrl.Result, error) {
280279
// The function 'updateStatusOnErr' will always return non-nil error. Hence, the ctrl.Result will always be ignored.
281280
// Therefore, the ctrl.Result returned by 'updateStatus' function can be discarded.
282281
// REF: https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/[email protected]#Reconciler
283-
_, statusErr := r.updateStatus(ctx, cluster)
282+
_, statusErr := r.updateStatus(ctx, state)
284283
if statusErr != nil {
285284
return ctrl.Result{}, goerrors.Join(statusErr, err)
286285
}
287286
return ctrl.Result{}, err
288287
}
289288

290289
// updateStatus updates EtcdCluster status and returns error and requeue in case status could not be updated due to conflict
291-
func (r *EtcdClusterReconciler) updateStatus(ctx context.Context, cluster *etcdaenixiov1alpha1.EtcdCluster) (ctrl.Result, error) {
292-
err := r.Status().Update(ctx, cluster)
290+
func (r *EtcdClusterReconciler) updateStatus(ctx context.Context, state *observables) (ctrl.Result, error) {
291+
err := r.Status().Update(ctx, state.instance)
293292
if err == nil {
294293
return ctrl.Result{}, nil
295294
}
@@ -302,9 +301,9 @@ func (r *EtcdClusterReconciler) updateStatus(ctx context.Context, cluster *etcda
302301
}
303302

304303
// isStatefulSetReady gets managed StatefulSet and checks its readiness.
305-
func (r *EtcdClusterReconciler) isStatefulSetReady(ctx context.Context, c *etcdaenixiov1alpha1.EtcdCluster) (bool, error) {
304+
func (r *EtcdClusterReconciler) isStatefulSetReady(ctx context.Context, state *observables) (bool, error) {
306305
sts := &appsv1.StatefulSet{}
307-
err := r.Get(ctx, client.ObjectKeyFromObject(c), sts)
306+
err := r.Get(ctx, client.ObjectKeyFromObject(state.instance), sts)
308307
if err == nil {
309308
return sts.Status.ReadyReplicas == *sts.Spec.Replicas, nil
310309
}
@@ -322,11 +321,11 @@ func (r *EtcdClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
322321
Complete(r)
323322
}
324323

325-
func (r *EtcdClusterReconciler) configureAuth(ctx context.Context, cluster *etcdaenixiov1alpha1.EtcdCluster) error {
324+
func (r *EtcdClusterReconciler) configureAuth(ctx context.Context, state *observables) error {
326325

327326
var err error
328327

329-
cli, err := r.GetEtcdClient(ctx, cluster)
328+
cli, err := r.GetEtcdClient(ctx, state.instance)
330329
if err != nil {
331330
return err
332331
}
@@ -342,7 +341,7 @@ func (r *EtcdClusterReconciler) configureAuth(ctx context.Context, cluster *etcd
342341

343342
auth := clientv3.NewAuth(cli)
344343

345-
if cluster.Spec.Security != nil && cluster.Spec.Security.EnableAuth {
344+
if state.instance.Spec.Security != nil && state.instance.Spec.Security.EnableAuth {
346345

347346
if err := r.createRoleIfNotExists(ctx, auth, "root"); err != nil {
348347
return err
@@ -393,12 +392,12 @@ func testMemberList(ctx context.Context, cli *clientv3.Client) error {
393392
return err
394393
}
395394

396-
func (r *EtcdClusterReconciler) GetEtcdClient(ctx context.Context, cluster *etcdaenixiov1alpha1.EtcdCluster) (*clientv3.Client, error) {
395+
func (r *EtcdClusterReconciler) GetEtcdClient(ctx context.Context, instance *etcdaenixiov1alpha1.EtcdCluster) (*clientv3.Client, error) {
397396

398-
endpoints := getEndpointsSlice(cluster)
397+
endpoints := getEndpointsSlice(instance)
399398
log.Debug(ctx, "endpoints built", "endpoints", endpoints)
400399

401-
tlsConfig, err := r.getTLSConfig(ctx, cluster)
400+
tlsConfig, err := r.getTLSConfig(ctx, instance)
402401
if err != nil {
403402
log.Error(ctx, err, "failed to build tls config")
404403
return nil, err
@@ -421,17 +420,17 @@ func (r *EtcdClusterReconciler) GetEtcdClient(ctx context.Context, cluster *etcd
421420

422421
}
423422

424-
func (r *EtcdClusterReconciler) getTLSConfig(ctx context.Context, cluster *etcdaenixiov1alpha1.EtcdCluster) (*tls.Config, error) {
423+
func (r *EtcdClusterReconciler) getTLSConfig(ctx context.Context, instance *etcdaenixiov1alpha1.EtcdCluster) (*tls.Config, error) {
425424

426425
var err error
427426

428427
caCertPool := &x509.CertPool{}
429428

430-
if cluster.IsServerTrustedCADefined() {
429+
if instance.IsServerTrustedCADefined() {
431430

432431
serverCASecret := &corev1.Secret{}
433432

434-
if err = r.Get(ctx, client.ObjectKey{Namespace: cluster.Namespace, Name: cluster.Spec.Security.TLS.ServerTrustedCASecret}, serverCASecret); err != nil {
433+
if err = r.Get(ctx, client.ObjectKey{Namespace: instance.Namespace, Name: instance.Spec.Security.TLS.ServerTrustedCASecret}, serverCASecret); err != nil {
435434
log.Error(ctx, err, "failed to get server trusted CA secret")
436435
return nil, err
437436
}
@@ -448,10 +447,10 @@ func (r *EtcdClusterReconciler) getTLSConfig(ctx context.Context, cluster *etcda
448447

449448
cert := tls.Certificate{}
450449

451-
if cluster.IsClientSecurityEnabled() {
450+
if instance.IsClientSecurityEnabled() {
452451

453452
rootSecret := &corev1.Secret{}
454-
if err = r.Get(ctx, client.ObjectKey{Namespace: cluster.Namespace, Name: cluster.Spec.Security.TLS.ClientSecret}, rootSecret); err != nil {
453+
if err = r.Get(ctx, client.ObjectKey{Namespace: instance.Namespace, Name: instance.Spec.Security.TLS.ClientSecret}, rootSecret); err != nil {
455454
log.Error(ctx, err, "failed to get root client secret")
456455
return nil, err
457456
}
@@ -465,7 +464,7 @@ func (r *EtcdClusterReconciler) getTLSConfig(ctx context.Context, cluster *etcda
465464
}
466465

467466
tlsConfig := &tls.Config{
468-
InsecureSkipVerify: !cluster.IsServerTrustedCADefined(),
467+
InsecureSkipVerify: !instance.IsServerTrustedCADefined(),
469468
RootCAs: caCertPool,
470469
Certificates: []tls.Certificate{
471470
cert,
@@ -602,7 +601,7 @@ func (r *EtcdClusterReconciler) disableAuth(ctx context.Context, authClient clie
602601
// ensureUnconditionalObjects creates the two services and the PDB
603602
// which can be created at the start of the reconciliation loop
604603
// without any risk of disrupting the etcd cluster
605-
func (r *EtcdClusterReconciler) ensureUnconditionalObjects(ctx context.Context, instance *etcdaenixiov1alpha1.EtcdCluster) error {
604+
func (r *EtcdClusterReconciler) ensureUnconditionalObjects(ctx context.Context, state *observables) error {
606605
const concurrentOperations = 3
607606
c := make(chan error)
608607
defer close(c)
@@ -620,23 +619,23 @@ func (r *EtcdClusterReconciler) ensureUnconditionalObjects(ctx context.Context,
620619
defer wg.Done()
621620
select {
622621
case <-ctx.Done():
623-
case c <- wrapWithMsg(factory.CreateOrUpdateClientService(ctx, instance, r.Client),
622+
case c <- wrapWithMsg(factory.CreateOrUpdateClientService(ctx, state.instance, r.Client),
624623
"couldn't ensure client service"):
625624
}
626625
}(c)
627626
go func(chan<- error) {
628627
defer wg.Done()
629628
select {
630629
case <-ctx.Done():
631-
case c <- wrapWithMsg(factory.CreateOrUpdateHeadlessService(ctx, instance, r.Client),
630+
case c <- wrapWithMsg(factory.CreateOrUpdateHeadlessService(ctx, state.instance, r.Client),
632631
"couldn't ensure headless service"):
633632
}
634633
}(c)
635634
go func(chan<- error) {
636635
defer wg.Done()
637636
select {
638637
case <-ctx.Done():
639-
case c <- wrapWithMsg(factory.CreateOrUpdatePdb(ctx, instance, r.Client),
638+
case c <- wrapWithMsg(factory.CreateOrUpdatePdb(ctx, state.instance, r.Client),
640639
"couldn't ensure pod disruption budget"):
641640
}
642641
}(c)
@@ -698,14 +697,32 @@ func (r *EtcdClusterReconciler) createClusterFromScratch(ctx context.Context, st
698697
)
699698

700699
// ensure managed resources
701-
if err = r.ensureConditionalClusterObjects(ctx, state.instance); err != nil {
702-
return r.updateStatusOnErr(ctx, state.instance, fmt.Errorf("cannot create Cluster auxiliary objects: %w", err))
700+
if err = r.ensureConditionalClusterObjects(ctx, state); err != nil {
701+
return r.updateStatusOnErr(ctx, state, fmt.Errorf("cannot create Cluster auxiliary objects: %w", err))
703702
}
704703
panic("not yet implemented")
705704
}
706705

707706
// TODO!
708707
// nolint:unused
709-
func (r *EtcdClusterReconciler) scaleUpFromZero(ctx context.Context, state *observables) (ctrl.Result, error) {
708+
func (r *EtcdClusterReconciler) scaleUpFromZero(ctx context.Context) error {
709+
panic("not yet implemented")
710+
}
711+
712+
// TODO!
713+
// nolint:unused
714+
func (r *EtcdClusterReconciler) createOrUpdateClusterStateConfigMap(ctx context.Context) error {
715+
panic("not yet implemented")
716+
}
717+
718+
// TODO!
719+
// nolint:unused
720+
func (r *EtcdClusterReconciler) createOrUpdateStatefulSet(ctx context.Context) error {
721+
panic("not yet implemented")
722+
}
723+
724+
// TODO!
725+
// nolint:unused
726+
func (r *EtcdClusterReconciler) promoteLearners(ctx context.Context) error {
710727
panic("not yet implemented")
711728
}

internal/controller/observables.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,13 @@ func (o *observables) statefulSetPodSpecCorrect() bool {
183183
func (o *observables) statefulSetReady() bool {
184184
return o.statefulSet.Status.ReadyReplicas == *o.statefulSet.Spec.Replicas
185185
}
186+
187+
// TODO:
188+
func (o *observables) clusterHasQuorum() bool {
189+
return false
190+
}
191+
192+
// TODO:
193+
func (o *observables) hasLearners() bool {
194+
return false
195+
}

0 commit comments

Comments
 (0)