Skip to content

Commit 55b2514

Browse files
authored
fix: set hcp initialized earlier (#139)
Otherwise it gets stuck as no workload resources will get ready.
1 parent 863507e commit 55b2514

11 files changed

Lines changed: 612 additions & 501 deletions

File tree

go.mod

Lines changed: 124 additions & 125 deletions
Large diffs are not rendered by default.

go.sum

Lines changed: 224 additions & 273 deletions
Large diffs are not rendered by default.

pkg/hostedcontrolplane/controller.go

Lines changed: 112 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -373,13 +373,6 @@ func (r *hostedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
373373
return reconcile.Result{}, fmt.Errorf("failed to get HostedControlPlane: %w", err)
374374
}
375375

376-
patchHelper, err := patch.NewHelper(hostedControlPlane, r.client)
377-
if err != nil {
378-
return ctrl.Result{}, fmt.Errorf("failed to create patch helper for HostedControlPlane: %w", err)
379-
}
380-
381-
hostedControlPlane.Status.ExternalManagedControlPlane = new(true)
382-
383376
ctx = recorder.IntoContext(ctx, recorder.New(r.recorder, hostedControlPlane))
384377

385378
cluster, err := util.GetOwnerCluster(ctx, r.client, hostedControlPlane.ObjectMeta)
@@ -421,13 +414,33 @@ func (r *hostedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
421414
}
422415

423416
isPaused, requeue, err := paused.EnsurePausedCondition(ctx, r.client, cluster, hostedControlPlane)
424-
if err != nil || isPaused || requeue {
425-
if err != nil {
426-
return ctrl.Result{}, fmt.Errorf("failed to verify paused condition: %w", err)
427-
}
417+
if err != nil {
418+
return ctrl.Result{}, fmt.Errorf("failed to verify paused condition: %w", err)
419+
} else if isPaused || requeue {
428420
return ctrl.Result{RequeueAfter: 10 * time.Second}, retErr
429421
}
430422

423+
if hostedControlPlane.DeletionTimestamp.IsZero() {
424+
if finalizerAdded, err := finalizers.EnsureFinalizer(ctx, r.client,
425+
hostedControlPlane, r.finalizer,
426+
); err != nil {
427+
return ctrl.Result{}, errorsUtil.IfErrErrorf("failed to ensure finalizer: %w", err)
428+
} else if finalizerAdded {
429+
emit.Info(ctx, emit.SinkSpanEvent, hostedControlPlane,
430+
"FinalizerMissing", "FinalizerAdded",
431+
"Added missing finalizer",
432+
)
433+
return ctrl.Result{}, nil
434+
}
435+
}
436+
437+
patchHelper, err := patch.NewHelper(hostedControlPlane, r.client)
438+
if err != nil {
439+
return ctrl.Result{}, fmt.Errorf("failed to create patch helper for HostedControlPlane: %w", err)
440+
}
441+
442+
hostedControlPlane.Status.ExternalManagedControlPlane = new(true)
443+
431444
defer func() {
432445
hostedControlPlane.Status.ObservedGeneration = hostedControlPlane.Generation
433446
if err := r.patch(ctx, patchHelper, hostedControlPlane); err != nil {
@@ -436,10 +449,10 @@ func (r *hostedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.R
436449
}()
437450

438451
if !hostedControlPlane.DeletionTimestamp.IsZero() {
439-
return r.reconcileDelete(ctx, patchHelper, hostedControlPlane)
452+
return r.reconcileDelete(ctx, hostedControlPlane)
440453
}
441454

442-
return r.reconcileNormal(ctx, patchHelper, hostedControlPlane, cluster)
455+
return r.reconcileNormal(ctx, hostedControlPlane, cluster)
443456
},
444457
)
445458
}
@@ -498,80 +511,103 @@ func (r *hostedControlPlaneReconciler) patch(
498511
//nolint:funlen // this function is not really complex
499512
func (r *hostedControlPlaneReconciler) reconcileNormal(
500513
ctx context.Context,
501-
_ *patch.Helper,
502514
hostedControlPlane *v1alpha1.HostedControlPlane,
503515
cluster *capiv2.Cluster,
504516
) (ctrl.Result, error) {
505517
return tracing.WithSpan(ctx, r.tracer, "ReconcileNormal",
506518
func(ctx context.Context, span trace.Span) (ctrl.Result, error) {
507-
if finalizerAdded, err := finalizers.EnsureFinalizer(ctx, r.client,
508-
hostedControlPlane, r.finalizer,
509-
); err != nil || finalizerAdded {
510-
return ctrl.Result{}, errorsUtil.IfErrErrorf("failed to ensure finalizer: %w", err)
511-
}
512519
span.SetAttributes(
513520
attribute.String("hostedcontrolplane.version", hostedControlPlane.Spec.Version),
514521
attribute.Int("hostedcontrolplane.replicas", int(hostedControlPlane.Spec.ReplicasOrDefault())),
515522
)
516523

517524
type Phase struct {
518525
Reconcile func(context.Context, *v1alpha1.HostedControlPlane, *capiv2.Cluster) (string, error)
519-
Condition capiv2.ConditionType
526+
Condition string
520527
FailedReason string
521528
Name string
522529
}
523530

524531
serviceDomain := "cluster.local"
525-
serviceCIDR := "10.96.0.0/12"
526-
podCIDR := "10.0.0.0/16"
527-
528-
if clusterSpecServiceDomain := cluster.Spec.ClusterNetwork.ServiceDomain; clusterSpecServiceDomain != "" {
529-
serviceDomain = clusterSpecServiceDomain
532+
serviceCIDR := net.IPNet{
533+
IP: net.IPv4(10, 96, 0, 0),
534+
Mask: net.CIDRMask(12, 32),
530535
}
531-
532-
if clusterServiceCIDR := cluster.Spec.ClusterNetwork.Services.String(); clusterServiceCIDR != "" {
533-
serviceCIDR = clusterServiceCIDR
536+
podCIDR := net.IPNet{
537+
IP: net.IPv4(10, 0, 0, 0),
538+
Mask: net.CIDRMask(16, 32),
534539
}
535540

536-
if clusterPodCIDR := cluster.Spec.ClusterNetwork.Pods.String(); clusterPodCIDR != "" {
537-
podCIDR = clusterPodCIDR
541+
if clusterSpecServiceDomain := cluster.Spec.ClusterNetwork.ServiceDomain; clusterSpecServiceDomain != "" {
542+
serviceDomain = clusterSpecServiceDomain
538543
}
539544

540-
var dnsIP net.IP
541-
var kubernetesServiceIP net.IP
542-
if _, serviceNet, err := net.ParseCIDR(strings.Split(serviceCIDR, ",")[0]); err != nil {
543-
conditions.Set(hostedControlPlane, metav1.Condition{
544-
Type: v1alpha1.WorkloadClusterResourcesReadyCondition,
545-
Status: metav1.ConditionFalse,
546-
Reason: v1alpha1.WorkloadClusterResourcesFailedReason,
547-
Message: fmt.Sprintf("Failed to parse Service CIDR %q: %v", serviceCIDR, err),
548-
})
549-
return ctrl.Result{}, errorsUtil.IfErrErrorf("failed to parse Service CIDR %q: %w", serviceCIDR, err)
550-
} else {
551-
dnsIP, err = utilNet.GetIndexedIP(serviceNet, 10)
552-
if err != nil {
545+
if clusterNetwork := cluster.Spec.ClusterNetwork.Services.String(); clusterNetwork != "" {
546+
if _, clusterServiceCIDR, err := net.ParseCIDR(clusterNetwork); err != nil {
553547
conditions.Set(hostedControlPlane, metav1.Condition{
554548
Type: v1alpha1.WorkloadClusterResourcesReadyCondition,
555549
Status: metav1.ConditionFalse,
556550
Reason: v1alpha1.WorkloadClusterResourcesFailedReason,
557-
Message: fmt.Sprintf("Failed to calculate DNS IP from Service CIDR %q: %v", serviceCIDR, err),
551+
Message: fmt.Sprintf("Failed to parse Service CIDR %q: %v", clusterNetwork, err),
558552
})
559-
return ctrl.Result{}, errorsUtil.IfErrErrorf("failed to calculate DNS IP from Service CIDR %q: %w",
560-
serviceCIDR, err)
553+
return ctrl.Result{}, errorsUtil.IfErrErrorf(
554+
"failed to parse Service CIDR %q: %w",
555+
clusterNetwork,
556+
err,
557+
)
558+
} else {
559+
serviceCIDR = *clusterServiceCIDR
561560
}
562-
kubernetesServiceIP, err = utilNet.GetIndexedIP(serviceNet, 1)
563-
if err != nil {
561+
}
562+
563+
if clusterPodNetwork := cluster.Spec.ClusterNetwork.Pods.String(); clusterPodNetwork != "" {
564+
if _, clusterPodCIDR, err := net.ParseCIDR(clusterPodNetwork); err != nil {
564565
conditions.Set(hostedControlPlane, metav1.Condition{
565566
Type: v1alpha1.WorkloadClusterResourcesReadyCondition,
566567
Status: metav1.ConditionFalse,
567568
Reason: v1alpha1.WorkloadClusterResourcesFailedReason,
568-
Message: fmt.Sprintf("Failed to calculate Kubernetes Service IP from Service CIDR %q: %v", serviceCIDR, err),
569+
Message: fmt.Sprintf("Failed to parse Pod CIDR %q: %v", clusterPodNetwork, err),
569570
})
570-
return ctrl.Result{}, errorsUtil.IfErrErrorf("failed to calculate Kubernetes Service IP from Service CIDR %q: %w",
571-
serviceCIDR, err)
571+
return ctrl.Result{}, errorsUtil.IfErrErrorf(
572+
"failed to parse Pod CIDR %q: %w",
573+
clusterPodNetwork,
574+
err,
575+
)
576+
} else {
577+
podCIDR = *clusterPodCIDR
572578
}
573579
}
574580

581+
dnsIP, err := utilNet.GetIndexedIP(&serviceCIDR, 10)
582+
if err != nil {
583+
conditions.Set(hostedControlPlane, metav1.Condition{
584+
Type: v1alpha1.WorkloadClusterResourcesReadyCondition,
585+
Status: metav1.ConditionFalse,
586+
Reason: v1alpha1.WorkloadClusterResourcesFailedReason,
587+
Message: fmt.Sprintf("Failed to calculate DNS IP from Service CIDR %q: %v", serviceCIDR, err),
588+
})
589+
return ctrl.Result{}, errorsUtil.IfErrErrorf("failed to calculate DNS IP from Service CIDR %q: %w",
590+
serviceCIDR, err)
591+
}
592+
kubernetesServiceIP, err := utilNet.GetIndexedIP(&serviceCIDR, 1)
593+
if err != nil {
594+
conditions.Set(hostedControlPlane, metav1.Condition{
595+
Type: v1alpha1.WorkloadClusterResourcesReadyCondition,
596+
Status: metav1.ConditionFalse,
597+
Reason: v1alpha1.WorkloadClusterResourcesFailedReason,
598+
Message: fmt.Sprintf(
599+
"Failed to calculate Kubernetes Service IP from Service CIDR %q: %v",
600+
serviceCIDR,
601+
err,
602+
),
603+
})
604+
return ctrl.Result{}, errorsUtil.IfErrErrorf(
605+
"failed to calculate Kubernetes Service IP from Service CIDR %q: %w",
606+
serviceCIDR,
607+
err,
608+
)
609+
}
610+
575611
var ciliumClient ciliumclient.Interface
576612

577613
groups, err := r.managementClusterClient.Discovery().ServerGroups()
@@ -714,8 +750,28 @@ func (r *hostedControlPlaneReconciler) reconcileNormal(
714750
FailedReason: v1alpha1.EtcdClusterFailedReason,
715751
},
716752
{
717-
Name: "apiserver deployments",
718-
Reconcile: apiServerResourcesReconciler.ReconcileApiServerDeployments,
753+
Name: "apiserver deployments",
754+
Reconcile: func(
755+
ctx context.Context,
756+
hostedControlPlane *v1alpha1.HostedControlPlane,
757+
cluster *capiv2.Cluster,
758+
) (string, error) {
759+
notReady, err := apiServerResourcesReconciler.ReconcileApiServerDeployments(
760+
ctx,
761+
hostedControlPlane,
762+
cluster,
763+
)
764+
if err != nil {
765+
return "", fmt.Errorf("reconcile api server deployments: %w", err)
766+
}
767+
if notReady != "" {
768+
return notReady, nil
769+
}
770+
771+
hostedControlPlane.Status.Initialization.ControlPlaneInitialized = new(true)
772+
773+
return "", nil
774+
},
719775
Condition: v1alpha1.APIServerDeploymentsReadyCondition,
720776
FailedReason: v1alpha1.APIServerDeploymentsFailedReason,
721777
},
@@ -751,23 +807,23 @@ func (r *hostedControlPlaneReconciler) reconcileNormal(
751807
); {
752808
case err != nil:
753809
conditions.Set(hostedControlPlane, metav1.Condition{
754-
Type: string(phase.Condition),
810+
Type: phase.Condition,
755811
Status: metav1.ConditionFalse,
756812
Reason: phase.FailedReason,
757813
Message: fmt.Sprintf("Reconciling phase %s failed: %v", phase.Name, err),
758814
})
759815
return reconcile.Result{}, err
760816
case notReadyReason != "":
761817
conditions.Set(hostedControlPlane, metav1.Condition{
762-
Type: string(phase.Condition),
818+
Type: phase.Condition,
763819
Status: metav1.ConditionFalse,
764820
Reason: notReadyReason,
765821
Message: fmt.Sprintf("phase %s not ready", phase.Name),
766822
})
767823
return reconcile.Result{RequeueAfter: 10 * time.Second}, nil
768824
default:
769825
conditions.Set(hostedControlPlane, metav1.Condition{
770-
Type: string(phase.Condition),
826+
Type: phase.Condition,
771827
Status: metav1.ConditionTrue,
772828
Reason: "ReconcileSucceeded",
773829
Message: fmt.Sprintf("Management phase %s reconciled successfully", phase.Name),
@@ -784,7 +840,6 @@ func (r *hostedControlPlaneReconciler) reconcileNormal(
784840

785841
func (r *hostedControlPlaneReconciler) reconcileDelete(
786842
ctx context.Context,
787-
_ *patch.Helper,
788843
hostedControlPlane *v1alpha1.HostedControlPlane,
789844
) (ctrl.Result, error) {
790845
return tracing.WithSpan(ctx, r.tracer, "ReconcileDelete",

pkg/hostedcontrolplane/controller_test.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"testing"
77
"time"
88

9+
certmanagerfake "github.com/cert-manager/cert-manager/pkg/client/clientset/versioned/fake"
910
ciliumclient "github.com/cilium/cilium/pkg/k8s/client/clientset/versioned"
1011
. "github.com/onsi/gomega"
1112
"github.com/teutonet/cluster-api-provider-hosted-control-plane/api/v1alpha1"
@@ -63,7 +64,7 @@ func createTestReconcilerWithFilter(client client.Client, reconcileFilter string
6364
return NewHostedControlPlaneReconciler(
6465
client,
6566
&alias.ManagementClusterClient{Interface: fake.NewClientset()},
66-
nil,
67+
&certmanagerfake.Clientset{},
6768
nil,
6869
func(ctx context.Context) (ciliumclient.Interface, error) {
6970
return nil, nil
@@ -177,6 +178,12 @@ func withGeneration(hcp *v1alpha1.HostedControlPlane, generation int64) *v1alpha
177178
return newHCP
178179
}
179180

181+
func withFinalizer(hcp *v1alpha1.HostedControlPlane) *v1alpha1.HostedControlPlane {
182+
newHCP := hcp.DeepCopy()
183+
newHCP.Finalizers = []string{"hcp.controlplane.cluster.x-k8s.io"}
184+
return newHCP
185+
}
186+
180187
func TestHostedControlPlaneReconciler_ReconcileWorkflow(t *testing.T) {
181188
cluster := createTestCluster("test-cluster", "default")
182189
tests := []struct {
@@ -501,7 +508,7 @@ func TestHostedControlPlaneReconciler_ObservedGeneration(t *testing.T) {
501508
}{
502509
{
503510
name: "normal reconciliation should set observedGeneration",
504-
hostedControlPlane: withGeneration(
511+
hostedControlPlane: withFinalizer(withGeneration(
505512
withConditions(
506513
withReplicas(
507514
withOwnerReference(
@@ -517,7 +524,7 @@ func TestHostedControlPlaneReconciler_ObservedGeneration(t *testing.T) {
517524
}},
518525
),
519526
2,
520-
),
527+
)),
521528
cluster: withEndpoint(
522529
createTestClusterWithPausedCondition("test-cluster", "default", false),
523530
createTestHostedControlPlane("test-hcp", "default"),

pkg/hostedcontrolplane/lifecycle_phases_test.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,15 +296,16 @@ func TestHostedControlPlane_FullLifecycle(t *testing.T) {
296296
},
297297
},
298298
{
299-
name: "Verify ExternalManagedControlPlane Status",
299+
name: "Add Finalizer",
300300
verifyResources: func(ctx context.Context, g Gomega) {
301-
g.Expect(hcp.Status.ExternalManagedControlPlane).To(PointTo(BeTrue()))
301+
g.Expect(hcp.Finalizers).To(ContainElement("hcp.controlplane.cluster.x-k8s.io"))
302302
},
303+
expectNoGenerationBump: true,
303304
},
304305
{
305-
name: "Add Finalizer",
306+
name: "Verify ExternalManagedControlPlane Status",
306307
verifyResources: func(ctx context.Context, g Gomega) {
307-
g.Expect(hcp.Finalizers).To(ContainElement("hcp.controlplane.cluster.x-k8s.io"))
308+
g.Expect(hcp.Status.ExternalManagedControlPlane).To(PointTo(BeTrue()))
308309
},
309310
},
310311
{
@@ -794,6 +795,9 @@ func TestHostedControlPlane_FullLifecycle(t *testing.T) {
794795
),
795796
},
796797
},
798+
verifyResources: func(ctx context.Context, g Gomega) {
799+
g.Expect(*hcp.Status.Initialization.ControlPlaneInitialized).To(BeTrue())
800+
},
797801
},
798802
{
799803
name: "Make Api Server TLS Route Ready",
@@ -1469,8 +1473,8 @@ func simulateK8sAPI(ctx context.Context, kubernetesClient kubernetes.Interface,
14691473
}
14701474
}
14711475

1472-
func verifyConditions(after map[bool][]types2.GomegaMatcher, hcp *v1alpha1.HostedControlPlane, g Gomega) {
1473-
for status, matchers := range after {
1476+
func verifyConditions(conditionMatchers map[bool][]types2.GomegaMatcher, hcp *v1alpha1.HostedControlPlane, g Gomega) {
1477+
for status, matchers := range conditionMatchers {
14741478
conditionStatus := slices.Ternary(status, metav1.ConditionTrue, metav1.ConditionFalse)
14751479
partitionedConditions := slices.GroupBy(hcp.Status.Conditions,
14761480
func(condition metav1.Condition) bool {

0 commit comments

Comments
 (0)