Skip to content

Commit 9ea0b39

Browse files
committed
set AzureASOManagedCluster spec.controlPlaneEndpoint
1 parent f8d26c6 commit 9ea0b39

11 files changed

+274
-2
lines changed

api/v1beta1/azuremanagedcluster_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
type AzureManagedClusterSpec struct {
2626
// ControlPlaneEndpoint represents the endpoint used to communicate with the control plane.
2727
// Immutable, populated by the AKS API at create.
28+
// Because this field is programmatically set by CAPZ after resource creation, we define it as +optional
29+
// in the API schema to permit resource admission.
2830
// +optional
2931
ControlPlaneEndpoint clusterv1.APIEndpoint `json:"controlPlaneEndpoint"`
3032
}

config/crd/bases/infrastructure.cluster.x-k8s.io_azureasomanagedclusters.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,24 @@ spec:
4040
spec:
4141
description: AzureASOManagedClusterSpec defines the desired state of AzureASOManagedCluster.
4242
properties:
43+
controlPlaneEndpoint:
44+
description: |-
45+
ControlPlaneEndpoint is the location of the API server within the control plane. CAPZ manages this field
46+
and it should not be set by the user. It fulfills Cluster API's cluster infrastructure provider contract.
47+
Because this field is programmatically set by CAPZ after resource creation, we define it as +optional
48+
in the API schema to permit resource admission.
49+
properties:
50+
host:
51+
description: The hostname on which the API server is serving.
52+
type: string
53+
port:
54+
description: The port on which the API server is serving.
55+
format: int32
56+
type: integer
57+
required:
58+
- host
59+
- port
60+
type: object
4361
resources:
4462
description: Resources are embedded ASO resources to be managed by
4563
this resource.

config/crd/bases/infrastructure.cluster.x-k8s.io_azureasomanagedcontrolplanes.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,21 @@ spec:
5353
description: AzureASOManagedControlPlaneStatus defines the observed state
5454
of AzureASOManagedControlPlane.
5555
properties:
56+
controlPlaneEndpoint:
57+
description: ControlPlaneEndpoint represents the endpoint for the
58+
cluster's API server.
59+
properties:
60+
host:
61+
description: The hostname on which the API server is serving.
62+
type: string
63+
port:
64+
description: The port on which the API server is serving.
65+
format: int32
66+
type: integer
67+
required:
68+
- host
69+
- port
70+
type: object
5671
resources:
5772
items:
5873
description: ResourceStatus represents the status of a resource.

config/crd/bases/infrastructure.cluster.x-k8s.io_azuremanagedclusters.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ spec:
6060
description: |-
6161
ControlPlaneEndpoint represents the endpoint used to communicate with the control plane.
6262
Immutable, populated by the AKS API at create.
63+
Because this field is programmatically set by CAPZ after resource creation, we define it as +optional
64+
in the API schema to permit resource admission.
6365
properties:
6466
host:
6567
description: The hostname on which the API server is serving.

exp/api/v1alpha1/azureasomanagedcluster_types.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package v1alpha1
1818

1919
import (
2020
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2122
)
2223

2324
const (
@@ -31,6 +32,13 @@ const (
3132
// AzureASOManagedClusterSpec defines the desired state of AzureASOManagedCluster.
3233
type AzureASOManagedClusterSpec struct {
3334
AzureASOManagedClusterTemplateResourceSpec `json:",inline"`
35+
36+
// ControlPlaneEndpoint is the location of the API server within the control plane. CAPZ manages this field
37+
// and it should not be set by the user. It fulfills Cluster API's cluster infrastructure provider contract.
38+
// Because this field is programmatically set by CAPZ after resource creation, we define it as +optional
39+
// in the API schema to permit resource admission.
40+
//+optional
41+
ControlPlaneEndpoint clusterv1.APIEndpoint `json:"controlPlaneEndpoint"`
3442
}
3543

3644
// AzureASOManagedClusterStatus defines the observed state of AzureASOManagedCluster.

exp/api/v1alpha1/azureasomanagedcontrolplane_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package v1alpha1
1818

1919
import (
2020
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2122
)
2223

2324
// AzureASOManagedControlPlaneKind is the kind for AzureASOManagedControlPlane.
@@ -32,6 +33,10 @@ type AzureASOManagedControlPlaneSpec struct {
3233
type AzureASOManagedControlPlaneStatus struct {
3334
//+optional
3435
Resources []ResourceStatus `json:"resources,omitempty"`
36+
37+
// ControlPlaneEndpoint represents the endpoint for the cluster's API server.
38+
//+optional
39+
ControlPlaneEndpoint clusterv1.APIEndpoint `json:"controlPlaneEndpoint"`
3540
}
3641

3742
//+kubebuilder:object:root=true

exp/api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

exp/controllers/azureasomanagedcluster_controller.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"errors"
2222
"fmt"
2323

24+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2425
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2526
"k8s.io/apimachinery/pkg/runtime"
2627
infracontroller "sigs.k8s.io/cluster-api-provider-azure/controllers"
@@ -36,7 +37,9 @@ import (
3637
"sigs.k8s.io/controller-runtime/pkg/builder"
3738
"sigs.k8s.io/controller-runtime/pkg/client"
3839
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
40+
"sigs.k8s.io/controller-runtime/pkg/event"
3941
"sigs.k8s.io/controller-runtime/pkg/handler"
42+
"sigs.k8s.io/controller-runtime/pkg/predicate"
4043
"sigs.k8s.io/controller-runtime/pkg/reconcile"
4144
)
4245

@@ -83,6 +86,25 @@ func (r *AzureASOManagedClusterReconciler) SetupWithManager(ctx context.Context,
8386
infracontroller.ClusterUpdatePauseChange(log),
8487
),
8588
).
89+
Watches(
90+
&infrav1exp.AzureASOManagedControlPlane{},
91+
handler.EnqueueRequestsFromMapFunc(asoManagedControlPlaneToManagedClusterMap(r.Client)),
92+
builder.WithPredicates(
93+
predicates.ResourceHasFilterLabel(log, r.WatchFilterValue),
94+
predicate.Funcs{
95+
CreateFunc: func(ev event.CreateEvent) bool {
96+
controlPlane := ev.Object.(*infrav1exp.AzureASOManagedControlPlane)
97+
return !controlPlane.Status.ControlPlaneEndpoint.IsZero()
98+
},
99+
UpdateFunc: func(ev event.UpdateEvent) bool {
100+
oldControlPlane := ev.ObjectOld.(*infrav1exp.AzureASOManagedControlPlane)
101+
newControlPlane := ev.ObjectNew.(*infrav1exp.AzureASOManagedControlPlane)
102+
return oldControlPlane.Status.ControlPlaneEndpoint !=
103+
newControlPlane.Status.ControlPlaneEndpoint
104+
},
105+
},
106+
),
107+
).
86108
Build(r)
87109
if err != nil {
88110
return err
@@ -105,6 +127,33 @@ func (r *AzureASOManagedClusterReconciler) SetupWithManager(ctx context.Context,
105127
return nil
106128
}
107129

130+
func asoManagedControlPlaneToManagedClusterMap(c client.Client) handler.MapFunc {
131+
return func(ctx context.Context, o client.Object) []reconcile.Request {
132+
asoManagedControlPlane := o.(*infrav1exp.AzureASOManagedControlPlane)
133+
134+
cluster, err := util.GetOwnerCluster(ctx, c, asoManagedControlPlane.ObjectMeta)
135+
if err != nil {
136+
return nil
137+
}
138+
139+
if cluster == nil ||
140+
cluster.Spec.InfrastructureRef == nil ||
141+
cluster.Spec.InfrastructureRef.APIVersion != infrav1exp.GroupVersion.Identifier() ||
142+
cluster.Spec.InfrastructureRef.Kind != infrav1exp.AzureASOManagedClusterKind {
143+
return nil
144+
}
145+
146+
return []reconcile.Request{
147+
{
148+
NamespacedName: client.ObjectKey{
149+
Namespace: cluster.Spec.InfrastructureRef.Namespace,
150+
Name: cluster.Spec.InfrastructureRef.Name,
151+
},
152+
},
153+
}
154+
}
155+
}
156+
108157
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azureasomanagedclusters,verbs=get;list;watch;create;update;patch;delete
109158
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azureasomanagedclusters/status,verbs=get;update;patch
110159
//+kubebuilder:rbac:groups=infrastructure.cluster.x-k8s.io,resources=azureasomanagedclusters/finalizers,verbs=update
@@ -191,6 +240,18 @@ func (r *AzureASOManagedClusterReconciler) reconcileNormal(ctx context.Context,
191240
}
192241
}
193242

243+
asoManagedControlPlane := &infrav1exp.AzureASOManagedControlPlane{
244+
ObjectMeta: metav1.ObjectMeta{
245+
Namespace: cluster.Spec.ControlPlaneRef.Namespace,
246+
Name: cluster.Spec.ControlPlaneRef.Name,
247+
},
248+
}
249+
err = r.Get(ctx, client.ObjectKeyFromObject(asoManagedControlPlane), asoManagedControlPlane)
250+
if client.IgnoreNotFound(err) != nil {
251+
return ctrl.Result{}, fmt.Errorf("failed to get AzureASOManagedControlPlane %s/%s: %w", asoManagedControlPlane.Namespace, asoManagedControlPlane.Name, err)
252+
}
253+
asoManagedCluster.Spec.ControlPlaneEndpoint = asoManagedControlPlane.Status.ControlPlaneEndpoint
254+
194255
return ctrl.Result{}, nil
195256
}
196257

exp/controllers/azureasomanagedcluster_controller_test.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ func TestAzureASOManagedClusterReconcile(t *testing.T) {
219219
ControlPlaneRef: &corev1.ObjectReference{
220220
APIVersion: infrav1exp.GroupVersion.Identifier(),
221221
Kind: infrav1exp.AzureASOManagedControlPlaneKind,
222+
Name: "amcp",
223+
Namespace: "ns",
222224
},
223225
},
224226
}
@@ -238,8 +240,17 @@ func TestAzureASOManagedClusterReconcile(t *testing.T) {
238240
},
239241
},
240242
}
243+
asoManagedControlPlane := &infrav1exp.AzureASOManagedControlPlane{
244+
ObjectMeta: metav1.ObjectMeta{
245+
Name: "amcp",
246+
Namespace: cluster.Namespace,
247+
},
248+
Status: infrav1exp.AzureASOManagedControlPlaneStatus{
249+
ControlPlaneEndpoint: clusterv1.APIEndpoint{Host: "endpoint"},
250+
},
251+
}
241252
c := fakeClientBuilder().
242-
WithObjects(cluster, asoManagedCluster).
253+
WithObjects(cluster, asoManagedCluster, asoManagedControlPlane).
243254
Build()
244255
r := &AzureASOManagedClusterReconciler{
245256
Client: c,
@@ -254,6 +265,9 @@ func TestAzureASOManagedClusterReconcile(t *testing.T) {
254265
result, err := r.Reconcile(ctx, ctrl.Request{NamespacedName: client.ObjectKeyFromObject(asoManagedCluster)})
255266
g.Expect(err).NotTo(HaveOccurred())
256267
g.Expect(result).To(Equal(ctrl.Result{}))
268+
269+
g.Expect(c.Get(ctx, client.ObjectKeyFromObject(asoManagedCluster), asoManagedCluster)).To(Succeed())
270+
g.Expect(asoManagedCluster.Spec.ControlPlaneEndpoint.Host).To(Equal("endpoint"))
257271
})
258272

259273
t.Run("successfully reconciles pause", func(t *testing.T) {

exp/controllers/azureasomanagedcontrolplane_controller.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"errors"
2222
"fmt"
2323

24+
asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001"
2425
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2526
infracontroller "sigs.k8s.io/cluster-api-provider-azure/controllers"
2627
infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha1"
@@ -174,6 +175,19 @@ func (r *AzureASOManagedControlPlaneReconciler) reconcileNormal(ctx context.Cont
174175
if err != nil {
175176
return ctrl.Result{}, err
176177
}
178+
179+
var managedClusterName string
180+
for _, resource := range us {
181+
if resource.GroupVersionKind().Group == asocontainerservicev1.GroupVersion.Group &&
182+
resource.GroupVersionKind().Kind == "ManagedCluster" {
183+
managedClusterName = resource.GetName()
184+
break
185+
}
186+
}
187+
if managedClusterName == "" {
188+
return ctrl.Result{}, reconcile.TerminalError(fmt.Errorf("no %s ManagedCluster defined in AzureASOManagedControlPlane spec.resources", asocontainerservicev1.GroupVersion.Group))
189+
}
190+
177191
resourceReconciler := r.newResourceReconciler(asoManagedControlPlane, us)
178192
err = resourceReconciler.Reconcile(ctx)
179193
if err != nil {
@@ -185,6 +199,14 @@ func (r *AzureASOManagedControlPlaneReconciler) reconcileNormal(ctx context.Cont
185199
}
186200
}
187201

202+
managedCluster := &asocontainerservicev1.ManagedCluster{}
203+
err = r.Get(ctx, client.ObjectKey{Namespace: asoManagedControlPlane.Namespace, Name: managedClusterName}, managedCluster)
204+
if err != nil {
205+
return ctrl.Result{}, fmt.Errorf("error getting ManagedCluster: %w", err)
206+
}
207+
208+
asoManagedControlPlane.Status.ControlPlaneEndpoint = getControlPlaneEndpoint(managedCluster)
209+
188210
return ctrl.Result{}, nil
189211
}
190212

@@ -224,3 +246,19 @@ func (r *AzureASOManagedControlPlaneReconciler) reconcileDelete(ctx context.Cont
224246
controllerutil.RemoveFinalizer(asoManagedControlPlane, infrav1exp.AzureASOManagedControlPlaneFinalizer)
225247
return ctrl.Result{}, nil
226248
}
249+
250+
func getControlPlaneEndpoint(managedCluster *asocontainerservicev1.ManagedCluster) clusterv1.APIEndpoint {
251+
if managedCluster.Status.PrivateFQDN != nil {
252+
return clusterv1.APIEndpoint{
253+
Host: *managedCluster.Status.PrivateFQDN,
254+
Port: 443,
255+
}
256+
}
257+
if managedCluster.Status.Fqdn != nil {
258+
return clusterv1.APIEndpoint{
259+
Host: *managedCluster.Status.Fqdn,
260+
Port: 443,
261+
}
262+
}
263+
return clusterv1.APIEndpoint{}
264+
}

0 commit comments

Comments
 (0)