From 8d30f365e93dd92a6d744d1007a589c6e7578a40 Mon Sep 17 00:00:00 2001 From: Timofei Larkin Date: Tue, 30 Jul 2024 23:21:27 +0300 Subject: [PATCH] outline some of the subroutines of the non-happy path for cluster reconciliation --- internal/controller/etcdcluster_controller.go | 49 +++++++++++++++---- internal/controller/factory/configmap.go | 31 ++---------- internal/controller/factory/statefulset.go | 5 ++ 3 files changed, 49 insertions(+), 36 deletions(-) diff --git a/internal/controller/etcdcluster_controller.go b/internal/controller/etcdcluster_controller.go index 2cb13a8..156cd25 100644 --- a/internal/controller/etcdcluster_controller.go +++ b/internal/controller/etcdcluster_controller.go @@ -125,16 +125,28 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) if !state.endpointsFound { if !state.stsExists { - cm := factory.TemplateClusterStateConfigMap(instance, "new", state.desiredReplicas()) - err := ctrl.SetControllerReference(instance, cm, r.Scheme) - if err != nil { - return ctrl.Result{}, err - } - err = r.patchOrCreateObject(ctx, cm) - if err != nil { - return ctrl.Result{}, err - } + return r.createClusterFromScratch(ctx, &state) // TODO: needs implementing + } + // else try reconciling the sts + existingSts := state.statefulSet.DeepCopy() + desiredSts := factory.TemplateStatefulSet() // TODO: needs implementing + existingSts.Spec.Template.Spec = desiredSts.Spec.Template.Spec + err := r.patchOrCreateObject(ctx, existingSts) + if err != nil { + return ctrl.Result{}, err + } + state.statefulSet = *existingSts + if existingSts.Status.ReadyReplicas != *existingSts.Spec.Replicas { // TODO: this check might not be the best to check for a ready sts + return ctrl.Result{}, fmt.Errorf("waiting for statefulset to become ready") + } + if *existingSts.Spec.Replicas > 0 { + return ctrl.Result{}, fmt.Errorf("reached an impossible state (no endpoints, but active pods)") + } + if *instance.Spec.Replicas == 0 { + // cluster successfully scaled down to zero + return ctrl.Result{}, nil } + return r.scaleUpFromZero(ctx, &state) // TODO: needs implementing } // get status of every endpoint and member list from every endpoint @@ -690,3 +702,22 @@ func (r *EtcdClusterReconciler) patchOrCreateObject(ctx context.Context, obj cli } return err } + +// TODO! +func (r *EtcdClusterReconciler) createClusterFromScratch(ctx context.Context, state *observables) (ctrl.Result, error) { + cm := factory.TemplateClusterStateConfigMap(state.instance, "new", state.desiredReplicas()) + err := ctrl.SetControllerReference(state.instance, cm, r.Scheme) + if err != nil { + return ctrl.Result{}, err + } + err = r.patchOrCreateObject(ctx, cm) + if err != nil { + return ctrl.Result{}, err + } + panic("not yet implemented") +} + +// TODO! +func (r *EtcdClusterReconciler) scaleUpFromZero(ctx context.Context, state *observables) (ctrl.Result, error) { + panic("not yet implemented") +} diff --git a/internal/controller/factory/configmap.go b/internal/controller/factory/configmap.go index 7a06e47..7081b06 100644 --- a/internal/controller/factory/configmap.go +++ b/internal/controller/factory/configmap.go @@ -70,39 +70,16 @@ func CreateOrUpdateClusterStateConfigMap( rclient client.Client, ) error { var err error - initialCluster := "" - clusterService := fmt.Sprintf("%s.%s.svc:2380", GetHeadlessServiceName(cluster), cluster.Namespace) - for i := int32(0); i < *cluster.Spec.Replicas; i++ { - if i > 0 { - initialCluster += "," - } - podName := fmt.Sprintf("%s-%d", cluster.Name, i) - initialCluster += fmt.Sprintf("%s=https://%s.%s", - podName, podName, clusterService, - ) - } - - configMap := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: cluster.Namespace, - Name: GetClusterStateConfigMapName(cluster), - }, - Data: map[string]string{ - "ETCD_INITIAL_CLUSTER_STATE": "new", - "ETCD_INITIAL_CLUSTER": initialCluster, - "ETCD_INITIAL_CLUSTER_TOKEN": cluster.Name + "-" + cluster.Namespace, - }, + state := "new" + if isEtcdClusterReady(cluster) { + state = "existing" } + configMap := TemplateClusterStateConfigMap(cluster, state, int(*cluster.Spec.Replicas)) ctx, err = contextWithGVK(ctx, configMap, rclient.Scheme()) if err != nil { return err } - if isEtcdClusterReady(cluster) { - // update cluster state to existing - log.Debug(ctx, "updating cluster state") - configMap.Data["ETCD_INITIAL_CLUSTER_STATE"] = "existing" - } log.Debug(ctx, "configmap data generated", "data", configMap.Data) if err := ctrl.SetControllerReference(cluster, configMap, rclient.Scheme()); err != nil { diff --git a/internal/controller/factory/statefulset.go b/internal/controller/factory/statefulset.go index 859fd80..93e1266 100644 --- a/internal/controller/factory/statefulset.go +++ b/internal/controller/factory/statefulset.go @@ -41,6 +41,11 @@ const ( defaultBackendQuotaBytesFraction = 0.95 ) +// TODO! +func TemplateStatefulSet() *appsv1.StatefulSet { + panic("not yet implemented") +} + func PodLabels(cluster *etcdaenixiov1alpha1.EtcdCluster) map[string]string { labels := NewLabelsBuilder().WithName().WithInstance(cluster.Name).WithManagedBy()