Skip to content

Commit e37260a

Browse files
author
Arka Saha
committed
Update reconciler logic for server,peer certificate
Signed-off-by: Arka Saha <[email protected]>
1 parent eba6759 commit e37260a

File tree

4 files changed

+84
-51
lines changed

4 files changed

+84
-51
lines changed

config/samples/operator_v1alpha1_etcdcluster.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ spec:
1515
commonName: "etcd-operator-system"
1616
validityDuration: "90h"
1717
issuerName: "selfsigned"
18-
issuerKind: "ClusterIssuer"
18+
issuerKind: "ClusterIssuer"

internal/controller/etcdcluster_controller.go

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,13 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
8787

8888
// Create Client Certificate for etcd-operator to communicate with the etcdCluster
8989
if etcdCluster.Spec.TLS != nil {
90-
clientCertErr := r.checkClientCertificate(etcdCluster, ctx)
90+
clientCertErr := createClientCertificate(etcdCluster, ctx, r.Client)
9191
if clientCertErr != nil {
9292
logger.Error(clientCertErr, "Failed to create Client Certificate.")
9393
}
9494
} else {
9595
// TODO: instead of logging error, set default autoConfig
96-
logger.Error(fmt.Errorf("missing TLS config for %s", etcdCluster.Name), "certificates cannot be created")
96+
logger.Error(nil, fmt.Sprintf("missing TLS config for %s", etcdCluster.Name))
9797
}
9898

9999
logger.Info("Reconciling EtcdCluster", "spec", etcdCluster.Spec)
@@ -105,7 +105,7 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
105105
logger.Info("Creating StatefulSet with 0 replica", "expectedSize", etcdCluster.Spec.Size)
106106
// Create a new StatefulSet
107107

108-
sts, err = reconcileStatefulSet(ctx, logger, etcdCluster, r.Client, 0, r.Scheme)
108+
sts, err = reconcileStatefulSet(ctx, logger, etcdCluster, r.Client, 0, r.Scheme, true)
109109
if err != nil {
110110
return ctrl.Result{}, err
111111
}
@@ -118,17 +118,6 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
118118
}
119119
}
120120

121-
// Create Server and Peer Certificate for etcd-operator to communicate within the members
122-
if etcdCluster.Spec.TLS != nil {
123-
createServerPeerCertErr := r.checkServerPeerCertificate(etcdCluster, sts, ctx)
124-
if createServerPeerCertErr != nil {
125-
logger.Error(createServerPeerCertErr, "Error creating Server or Peer Certificate")
126-
}
127-
} else {
128-
// TODO: instead of logging error, set default autoConfig
129-
logger.Error(fmt.Errorf("missing TLS config for %s", etcdCluster.Name), "certificates cannot be created")
130-
}
131-
132121
// If the Statefulsets is not controlled by this EtcdCluster resource, we should log
133122
// a warning to the event recorder and return error msg.
134123
err = checkStatefulSetControlledByEtcdOperator(etcdCluster, sts)
@@ -141,7 +130,7 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
141130
if sts.Spec.Replicas != nil && *sts.Spec.Replicas == 0 {
142131
logger.Info("StatefulSet has 0 replicas. Trying to create a new cluster with 1 member")
143132

144-
sts, err = reconcileStatefulSet(ctx, logger, etcdCluster, r.Client, 1, r.Scheme)
133+
sts, err = reconcileStatefulSet(ctx, logger, etcdCluster, r.Client, 1, r.Scheme, true)
145134
if err != nil {
146135
return ctrl.Result{}, err
147136
}
@@ -171,15 +160,15 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
171160
logger.Info("An etcd member was added into the cluster, but the StatefulSet hasn't scaled out yet")
172161
newReplicaCount := targetReplica + 1
173162
logger.Info("Increasing StatefulSet replicas to match the etcd cluster member count", "oldReplicaCount", targetReplica, "newReplicaCount", newReplicaCount)
174-
_, err = reconcileStatefulSet(ctx, logger, etcdCluster, r.Client, newReplicaCount, r.Scheme)
163+
_, err = reconcileStatefulSet(ctx, logger, etcdCluster, r.Client, newReplicaCount, r.Scheme, true)
175164
if err != nil {
176165
return ctrl.Result{}, err
177166
}
178167
} else {
179168
logger.Info("An etcd member was removed from the cluster, but the StatefulSet hasn't scaled in yet")
180169
newReplicaCount := targetReplica - 1
181170
logger.Info("Decreasing StatefulSet replicas to remove the unneeded Pod.", "oldReplicaCount", targetReplica, "newReplicaCount", newReplicaCount)
182-
_, err = reconcileStatefulSet(ctx, logger, etcdCluster, r.Client, newReplicaCount, r.Scheme)
171+
_, err = reconcileStatefulSet(ctx, logger, etcdCluster, r.Client, newReplicaCount, r.Scheme, false)
183172
if err != nil {
184173
return ctrl.Result{}, err
185174
}
@@ -244,6 +233,11 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
244233
}
245234

246235
logger.Info("Learner member added successfully", "peerURLs", peerURL)
236+
237+
sts, err = reconcileStatefulSet(ctx, logger, etcdCluster, r.Client, targetReplica, r.Scheme, true)
238+
if err != nil {
239+
return ctrl.Result{}, err
240+
}
247241
} else {
248242
// scale in
249243
targetReplica--
@@ -256,11 +250,11 @@ func (r *EtcdClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request)
256250
if err := etcdutils.RemoveMember(eps, memberID); err != nil {
257251
return ctrl.Result{}, err
258252
}
259-
}
260253

261-
sts, err = reconcileStatefulSet(ctx, logger, etcdCluster, r.Client, targetReplica, r.Scheme)
262-
if err != nil {
263-
return ctrl.Result{}, err
254+
sts, err = reconcileStatefulSet(ctx, logger, etcdCluster, r.Client, targetReplica, r.Scheme, false)
255+
if err != nil {
256+
return ctrl.Result{}, err
257+
}
264258
}
265259

266260
allMembersHealthy, err := areAllMembersHealthy(sts, logger)

internal/controller/utils.go

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func prepareOwnerReference(ec *ecv1alpha1.EtcdCluster, scheme *runtime.Scheme) (
6565
return owners, nil
6666
}
6767

68-
func reconcileStatefulSet(ctx context.Context, logger logr.Logger, ec *ecv1alpha1.EtcdCluster, c client.Client, replicas int32, scheme *runtime.Scheme) (*appsv1.StatefulSet, error) {
68+
func reconcileStatefulSet(ctx context.Context, logger logr.Logger, ec *ecv1alpha1.EtcdCluster, c client.Client, replicas int32, scheme *runtime.Scheme, addMember bool) (*appsv1.StatefulSet, error) {
6969

7070
// prepare/update configmap for StatefulSet
7171
err := applyEtcdClusterState(ctx, ec, int(replicas), c, scheme, logger)
@@ -85,6 +85,26 @@ func reconcileStatefulSet(ctx context.Context, logger logr.Logger, ec *ecv1alpha
8585
return nil, err
8686
}
8787

88+
// Add or remove server and peer certificate
89+
if addMember {
90+
if replicas > 0 {
91+
if ec.Spec.TLS != nil {
92+
createServerPeerCertErr := createServerPeerCertificate(ec, replicas, ctx, c)
93+
if createServerPeerCertErr != nil {
94+
logger.Error(createServerPeerCertErr, "Error creating Server or Peer Certificate")
95+
}
96+
} else {
97+
// TODO: instead of logging error, set default autoConfig
98+
logger.Error(nil, fmt.Sprintf("missing TLS config for %s", ec.Name))
99+
}
100+
}
101+
} else {
102+
deleteServerPeerCertErr := deleteServerPeerCertificate(ec, replicas, ctx, c)
103+
if deleteServerPeerCertErr != nil {
104+
logger.Error(deleteServerPeerCertErr, "Error deleting Server or Peer Certificate")
105+
}
106+
}
107+
88108
// Return latest Stateful set. (This is to ensure that we return the latest statefulset for next operation to act on)
89109
return getStatefulSet(ctx, c, ec.Name, ec.Namespace)
90110
}
@@ -528,15 +548,6 @@ func healthCheck(sts *appsv1.StatefulSet, lg klog.Logger) (*clientv3.MemberListR
528548
return memberlistResp, healthInfos, nil
529549
}
530550

531-
func (r *EtcdClusterReconciler) getStatefulSetPods(sts *appsv1.StatefulSet, ctx context.Context) (*corev1.PodList, error) {
532-
podList := corev1.PodList{}
533-
err := r.Client.List(ctx, &podList, client.InNamespace(sts.Namespace), client.MatchingLabels(sts.Spec.Selector.MatchLabels))
534-
if err != nil {
535-
return nil, err
536-
}
537-
return &podList, nil
538-
}
539-
540551
func createCMCertificateConfig(ec *ecv1alpha1.ProviderCertManagerConfig) *certInterface.Config {
541552
duration, err := time.ParseDuration(ec.ValidityDuration)
542553
if err != nil {
@@ -564,8 +575,8 @@ func createAutoCertificateConfig(ec *ecv1alpha1.ProviderAutoConfig) *certInterfa
564575
return config
565576
}
566577

567-
func (r *EtcdClusterReconciler) createCertificate(ec *ecv1alpha1.EtcdCluster, ctx context.Context, certName string) error {
568-
cert, certErr := certificate.NewProvider(certificate.ProviderType(ec.Spec.TLS.Provider), r.Client)
578+
func createCertificate(ec *ecv1alpha1.EtcdCluster, ctx context.Context, c client.Client, certName string) error {
579+
cert, certErr := certificate.NewProvider(certificate.ProviderType(ec.Spec.TLS.Provider), c)
569580
if certErr != nil {
570581
// TODO: instead of error, set default autoConfig
571582
return certErr
@@ -608,24 +619,51 @@ func (r *EtcdClusterReconciler) createCertificate(ec *ecv1alpha1.EtcdCluster, ct
608619
return nil
609620
}
610621

611-
func (r *EtcdClusterReconciler) checkClientCertificate(ec *ecv1alpha1.EtcdCluster, ctx context.Context) error {
622+
func deleteCertificate(ec *ecv1alpha1.EtcdCluster, ctx context.Context, c client.Client, certName string) error {
623+
cert, certErr := certificate.NewProvider(certificate.ProviderType(ec.Spec.TLS.Provider), c)
624+
if certErr != nil {
625+
// TODO: instead of error, set default autoConfig
626+
return certErr
627+
}
628+
deleteCertErr := cert.DeleteCertificateSecret(ctx, certName, ec.Namespace)
629+
if deleteCertErr != nil {
630+
log.Printf("Error deleting certificate with name %s: %s", certName, deleteCertErr)
631+
return deleteCertErr
632+
}
633+
log.Printf("Successfully deleted certificate with name %s", certName)
634+
return nil
635+
}
636+
637+
func createClientCertificate(ec *ecv1alpha1.EtcdCluster, ctx context.Context, c client.Client) error {
612638
certName := fmt.Sprintf("%s-%s-tls", ec.Name, "client")
613-
createClientCertErr := r.createCertificate(ec, ctx, certName)
639+
createClientCertErr := createCertificate(ec, ctx, c, certName)
614640
return createClientCertErr
615641
}
616642

617-
func (r *EtcdClusterReconciler) checkServerPeerCertificate(ec *ecv1alpha1.EtcdCluster, sts *appsv1.StatefulSet, ctx context.Context) error {
618-
podList, podListErr := r.getStatefulSetPods(sts, ctx)
619-
if podListErr != nil {
620-
return podListErr
621-
}
622-
for _, pod := range podList.Items {
623-
serverCertName := fmt.Sprintf("%s-%s-tls", pod.Name, "server")
624-
peerCertName := fmt.Sprintf("%s-%s-tls", pod.Name, "peer")
625-
createServerCertErr := r.createCertificate(ec, ctx, serverCertName)
626-
log.Println(createServerCertErr)
627-
createPeerCertErr := r.createCertificate(ec, ctx, peerCertName)
628-
log.Println(createPeerCertErr)
643+
func createServerPeerCertificate(ec *ecv1alpha1.EtcdCluster, replicas int32, ctx context.Context, c client.Client) error {
644+
serverCertName := fmt.Sprintf("%s-%s-%s-tls", ec.Name, string(replicas-1), "server")
645+
peerCertName := fmt.Sprintf("%s-%s-%s-tls", ec.Name, string(replicas-1), "peer")
646+
createServerCertErr := createCertificate(ec, ctx, c, serverCertName)
647+
if createServerCertErr != nil {
648+
return createServerCertErr
649+
}
650+
createPeerCertErr := createCertificate(ec, ctx, c, peerCertName)
651+
if createPeerCertErr != nil {
652+
return createPeerCertErr
653+
}
654+
return nil
655+
}
656+
657+
func deleteServerPeerCertificate(ec *ecv1alpha1.EtcdCluster, replicas int32, ctx context.Context, c client.Client) error {
658+
serverCertName := fmt.Sprintf("%s-%s-%s-tls", ec.Name, string(replicas), "server")
659+
peerCertName := fmt.Sprintf("%s-%s-%s-tls", ec.Name, string(replicas), "peer")
660+
deleteServerCertErr := deleteCertificate(ec, ctx, c, serverCertName)
661+
if deleteServerCertErr != nil {
662+
return deleteServerCertErr
663+
}
664+
deletePeerCertErr := deleteCertificate(ec, ctx, c, peerCertName)
665+
if deletePeerCertErr != nil {
666+
return deletePeerCertErr
629667
}
630668
return nil
631669
}

internal/controller/utils_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ import (
1616
"sigs.k8s.io/controller-runtime/pkg/client/fake"
1717
"sigs.k8s.io/controller-runtime/pkg/log"
1818

19-
ecv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1"
20-
"go.etcd.io/etcd-operator/internal/etcdutils"
2119
"go.etcd.io/etcd/api/v3/etcdserverpb"
2220
clientv3 "go.etcd.io/etcd/client/v3"
21+
22+
ecv1alpha1 "go.etcd.io/etcd-operator/api/v1alpha1"
23+
"go.etcd.io/etcd-operator/internal/etcdutils"
2324
)
2425

2526
func TestPrepareOwnerReference(t *testing.T) {
@@ -67,7 +68,7 @@ func TestReconcileStatefulSet(t *testing.T) {
6768
},
6869
}
6970

70-
_, _ = reconcileStatefulSet(t.Context(), logger, ec, fakeClient, 3, scheme)
71+
_, _ = reconcileStatefulSet(t.Context(), logger, ec, fakeClient, 3, scheme, true)
7172

7273
sts := &appsv1.StatefulSet{}
7374
err := fakeClient.Get(t.Context(), client.ObjectKey{Name: "test-etcd", Namespace: "default"}, sts)

0 commit comments

Comments
 (0)