diff --git a/internal/controller/etcdcluster_controller.go b/internal/controller/etcdcluster_controller.go index f4ec6eca..d9e47ad7 100644 --- a/internal/controller/etcdcluster_controller.go +++ b/internal/controller/etcdcluster_controller.go @@ -91,6 +91,7 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) } state := observables{} + state.instance = instance // create two services and the pdb err = r.ensureUnconditionalObjects(ctx, instance) @@ -661,3 +662,37 @@ func (r *EtcdClusterReconciler) ensureUnconditionalObjects(ctx context.Context, } return nil } + +// TODO! +// nolint:unused +func (r *EtcdClusterReconciler) patchOrCreateObject(ctx context.Context, obj client.Object) error { + err := r.Patch(ctx, obj, client.Apply, &client.PatchOptions{FieldManager: "etcd-operator"}, client.ForceOwnership) + if err == nil { + return nil + } + if client.IgnoreNotFound(err) == nil { + err = r.Create(ctx, obj) + } + return err +} + +// TODO! +// nolint:unparam,unused +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! +// nolint:unused +func (r *EtcdClusterReconciler) scaleUpFromZero(ctx context.Context, state *observables) (ctrl.Result, error) { + panic("not yet implemented") +} diff --git a/internal/controller/factory/pvc.go b/internal/controller/factory/pvc.go index 1b49d2cd..60d2d513 100644 --- a/internal/controller/factory/pvc.go +++ b/internal/controller/factory/pvc.go @@ -30,6 +30,14 @@ import ( "k8s.io/apimachinery/pkg/types" ) +func PVCLabels(cluster *etcdaenixiov1alpha1.EtcdCluster) map[string]string { + labels := PodLabels(cluster) + for key, value := range cluster.Spec.Storage.VolumeClaimTemplate.Labels { + labels[key] = value + } + return labels +} + func GetPVCName(cluster *etcdaenixiov1alpha1.EtcdCluster) string { if len(cluster.Spec.Storage.VolumeClaimTemplate.Name) > 0 { return cluster.Spec.Storage.VolumeClaimTemplate.Name @@ -38,6 +46,16 @@ func GetPVCName(cluster *etcdaenixiov1alpha1.EtcdCluster) string { return "data" } +func PVCs(ctx context.Context, cluster *etcdaenixiov1alpha1.EtcdCluster, cli client.Client) ([]corev1.PersistentVolumeClaim, error) { + labels := PVCLabels(cluster) + pvcs := corev1.PersistentVolumeClaimList{} + err := cli.List(ctx, &pvcs, client.MatchingLabels(labels)) + if err != nil { + return nil, err + } + return pvcs.Items, nil +} + // UpdatePersistentVolumeClaims checks and updates the sizes of PVCs in an EtcdCluster if the specified storage size is larger than the current. func UpdatePersistentVolumeClaims(ctx context.Context, cluster *etcdaenixiov1alpha1.EtcdCluster, rclient client.Client) error { labelSelector := labels.SelectorFromSet(labels.Set{ diff --git a/internal/controller/factory/statefulset.go b/internal/controller/factory/statefulset.go index e8d48362..202419b2 100644 --- a/internal/controller/factory/statefulset.go +++ b/internal/controller/factory/statefulset.go @@ -41,19 +41,30 @@ 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() + + if cluster.Spec.PodTemplate.Labels != nil { + for key, value := range cluster.Spec.PodTemplate.Labels { + labels[key] = value + } + } + + return labels +} + func CreateOrUpdateStatefulSet( ctx context.Context, cluster *etcdaenixiov1alpha1.EtcdCluster, rclient client.Client, ) error { podMetadata := metav1.ObjectMeta{ - Labels: NewLabelsBuilder().WithName().WithInstance(cluster.Name).WithManagedBy(), - } - - if cluster.Spec.PodTemplate.Labels != nil { - for key, value := range cluster.Spec.PodTemplate.Labels { - podMetadata.Labels[key] = value - } + Labels: PodLabels(cluster), } if cluster.Spec.PodTemplate.Annotations != nil { diff --git a/internal/controller/observables.go b/internal/controller/observables.go index adbaba3f..4d080f4c 100644 --- a/internal/controller/observables.go +++ b/internal/controller/observables.go @@ -2,8 +2,12 @@ package controller import ( "context" + // "strconv" + // "strings" "sync" + "github.com/aenix-io/etcd-operator/api/v1alpha1" + // "github.com/aenix-io/etcd-operator/pkg/set" clientv3 "go.etcd.io/etcd/client/v3" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -19,16 +23,18 @@ type etcdStatus struct { memberListError error } +// TODO: nolint // observables stores observations that the operator can make about // states of objects in kubernetes type observables struct { + instance *v1alpha1.EtcdCluster statefulSet appsv1.StatefulSet stsExists bool + endpoints []string //nolint:unused endpointsFound bool etcdStatuses []etcdStatus clusterID uint64 - _ int - _ []corev1.PersistentVolumeClaim + pvcs []corev1.PersistentVolumeClaim //nolint:unused } // setClusterID populates the clusterID field based on etcdStatuses @@ -68,7 +74,8 @@ func (s *etcdStatus) fill(ctx context.Context, c *clientv3.Client) { } // TODO: make a real function -func (o *observables) _() int { +// nolint:unused +func (o *observables) desiredReplicas() int { if o.etcdStatuses != nil { for i := range o.etcdStatuses { if o.etcdStatuses[i].memberList != nil {