Skip to content

Commit f71c5ed

Browse files
authored
Merge pull request #4772 from nojnhuh/v2-kubeconfig
reconcile kubeconfig for AzureASOManagedControlPlane
2 parents 292d84c + dd11cff commit f71c5ed

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

exp/controllers/azureasomanagedcontrolplane_controller.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import (
2222
"fmt"
2323

2424
asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001"
25+
"github.com/Azure/azure-service-operator/v2/pkg/genruntime"
26+
corev1 "k8s.io/api/core/v1"
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2528
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2629
infracontroller "sigs.k8s.io/cluster-api-provider-azure/controllers"
2730
infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha1"
@@ -32,6 +35,7 @@ import (
3235
"sigs.k8s.io/cluster-api/util/annotations"
3336
"sigs.k8s.io/cluster-api/util/patch"
3437
"sigs.k8s.io/cluster-api/util/predicates"
38+
"sigs.k8s.io/cluster-api/util/secret"
3539
ctrl "sigs.k8s.io/controller-runtime"
3640
"sigs.k8s.io/controller-runtime/pkg/builder"
3741
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -68,6 +72,7 @@ func (r *AzureASOManagedControlPlaneReconciler) SetupWithManager(ctx context.Con
6872
infracontroller.ClusterPauseChangeAndInfrastructureReady(log),
6973
),
7074
).
75+
Owns(&corev1.Secret{}).
7176
Build(r)
7277
if err != nil {
7378
return err
@@ -210,9 +215,58 @@ func (r *AzureASOManagedControlPlaneReconciler) reconcileNormal(ctx context.Cont
210215
asoManagedControlPlane.Status.Version = "v" + *managedCluster.Status.CurrentKubernetesVersion
211216
}
212217

218+
err = r.reconcileKubeconfig(ctx, asoManagedControlPlane, cluster, managedCluster)
219+
if err != nil {
220+
return ctrl.Result{}, fmt.Errorf("failed to reconcile kubeconfig: %w", err)
221+
}
222+
213223
return ctrl.Result{}, nil
214224
}
215225

226+
func (r *AzureASOManagedControlPlaneReconciler) reconcileKubeconfig(ctx context.Context, asoManagedControlPlane *infrav1exp.AzureASOManagedControlPlane, cluster *clusterv1.Cluster, managedCluster *asocontainerservicev1.ManagedCluster) error {
227+
ctx, _, done := tele.StartSpanWithLogger(ctx,
228+
"controllers.AzureASOManagedControlPlaneReconciler.reconcileKubeconfig",
229+
)
230+
defer done()
231+
232+
var secretRef *genruntime.SecretDestination
233+
if managedCluster.Spec.OperatorSpec != nil &&
234+
managedCluster.Spec.OperatorSpec.Secrets != nil {
235+
secretRef = managedCluster.Spec.OperatorSpec.Secrets.UserCredentials
236+
if managedCluster.Spec.OperatorSpec.Secrets.AdminCredentials != nil {
237+
secretRef = managedCluster.Spec.OperatorSpec.Secrets.AdminCredentials
238+
}
239+
}
240+
if secretRef == nil {
241+
return reconcile.TerminalError(fmt.Errorf("ManagedCluster must define at least one of spec.operatorSpec.secrets.{userCredentials,adminCredentials}"))
242+
}
243+
asoKubeconfig := &corev1.Secret{}
244+
err := r.Get(ctx, client.ObjectKey{Namespace: cluster.Namespace, Name: secretRef.Name}, asoKubeconfig)
245+
if err != nil {
246+
return fmt.Errorf("failed to fetch secret created by ASO: %w", err)
247+
}
248+
249+
expectedSecret := &corev1.Secret{
250+
TypeMeta: metav1.TypeMeta{
251+
APIVersion: corev1.SchemeGroupVersion.Identifier(),
252+
Kind: "Secret",
253+
},
254+
ObjectMeta: metav1.ObjectMeta{
255+
Name: secret.Name(cluster.Name, secret.Kubeconfig),
256+
Namespace: cluster.Namespace,
257+
OwnerReferences: []metav1.OwnerReference{
258+
*metav1.NewControllerRef(asoManagedControlPlane, infrav1exp.GroupVersion.WithKind(infrav1exp.AzureASOManagedControlPlaneKind)),
259+
},
260+
Labels: map[string]string{clusterv1.ClusterNameLabel: cluster.Name},
261+
},
262+
Data: map[string][]byte{
263+
secret.KubeconfigDataName: asoKubeconfig.Data[secretRef.Key],
264+
},
265+
}
266+
267+
return r.Patch(ctx, expectedSecret, client.Apply, client.FieldOwner("capz-manager"), client.ForceOwnership)
268+
}
269+
216270
//nolint:unparam // these parameters will be used soon enough
217271
func (r *AzureASOManagedControlPlaneReconciler) reconcilePaused(ctx context.Context, asoManagedControlPlane *infrav1exp.AzureASOManagedControlPlane, cluster *clusterv1.Cluster) (ctrl.Result, error) {
218272
//nolint:all // ctx will be used soon

exp/controllers/azureasomanagedcontrolplane_controller_test.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"time"
2424

2525
asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001"
26+
"github.com/Azure/azure-service-operator/v2/pkg/genruntime"
2627
. "github.com/onsi/gomega"
2728
corev1 "k8s.io/api/core/v1"
2829
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -33,6 +34,7 @@ import (
3334
"k8s.io/utils/ptr"
3435
infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha1"
3536
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
37+
"sigs.k8s.io/cluster-api/util/secret"
3638
ctrl "sigs.k8s.io/controller-runtime"
3739
"sigs.k8s.io/controller-runtime/pkg/client"
3840
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
@@ -46,6 +48,7 @@ func TestAzureASOManagedControlPlaneReconcile(t *testing.T) {
4648
infrav1exp.AddToScheme,
4749
clusterv1.AddToScheme,
4850
asocontainerservicev1.AddToScheme,
51+
corev1.AddToScheme,
4952
)
5053
NewGomegaWithT(t).Expect(sb.AddToScheme(s)).To(Succeed())
5154
fakeClientBuilder := func() *fakeclient.ClientBuilder {
@@ -218,11 +221,30 @@ func TestAzureASOManagedControlPlaneReconcile(t *testing.T) {
218221
},
219222
},
220223
}
224+
kubeconfig := &corev1.Secret{
225+
ObjectMeta: metav1.ObjectMeta{
226+
Name: secret.Name(cluster.Name, secret.Kubeconfig),
227+
Namespace: cluster.Namespace,
228+
},
229+
Data: map[string][]byte{
230+
"some other key": []byte("some data"),
231+
},
232+
}
221233
managedCluster := &asocontainerservicev1.ManagedCluster{
222234
ObjectMeta: metav1.ObjectMeta{
223235
Name: "mc",
224236
Namespace: cluster.Namespace,
225237
},
238+
Spec: asocontainerservicev1.ManagedCluster_Spec{
239+
OperatorSpec: &asocontainerservicev1.ManagedClusterOperatorSpec{
240+
Secrets: &asocontainerservicev1.ManagedClusterOperatorSecrets{
241+
UserCredentials: &genruntime.SecretDestination{
242+
Name: secret.Name(cluster.Name, secret.Kubeconfig),
243+
Key: "some other key",
244+
},
245+
},
246+
},
247+
},
226248
Status: asocontainerservicev1.ManagedCluster_STATUS{
227249
Fqdn: ptr.To("endpoint"),
228250
CurrentKubernetesVersion: ptr.To("Current"),
@@ -258,10 +280,19 @@ func TestAzureASOManagedControlPlaneReconcile(t *testing.T) {
258280
},
259281
}
260282
c := fakeClientBuilder().
261-
WithObjects(cluster, asoManagedControlPlane, managedCluster).
283+
WithObjects(cluster, asoManagedControlPlane, managedCluster, kubeconfig).
262284
Build()
285+
kubeConfigPatched := false
263286
r := &AzureASOManagedControlPlaneReconciler{
264-
Client: c,
287+
Client: &FakeClient{
288+
Client: c,
289+
patchFunc: func(_ context.Context, obj client.Object, _ client.Patch, _ ...client.PatchOption) error {
290+
kubeconfig := obj.(*corev1.Secret)
291+
g.Expect(kubeconfig.Data[secret.KubeconfigDataName]).NotTo(BeEmpty())
292+
kubeConfigPatched = true
293+
return nil
294+
},
295+
},
265296
newResourceReconciler: func(_ *infrav1exp.AzureASOManagedControlPlane, _ []*unstructured.Unstructured) resourceReconciler {
266297
return &fakeResourceReconciler{
267298
reconcileFunc: func(ctx context.Context, o client.Object) error {
@@ -277,6 +308,7 @@ func TestAzureASOManagedControlPlaneReconcile(t *testing.T) {
277308
g.Expect(c.Get(ctx, client.ObjectKeyFromObject(asoManagedControlPlane), asoManagedControlPlane)).To(Succeed())
278309
g.Expect(asoManagedControlPlane.Status.ControlPlaneEndpoint.Host).To(Equal("endpoint"))
279310
g.Expect(asoManagedControlPlane.Status.Version).To(Equal("vCurrent"))
311+
g.Expect(kubeConfigPatched).To(BeTrue())
280312
})
281313

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

0 commit comments

Comments
 (0)