diff --git a/pkg/clients/compute/aks.go b/pkg/clients/compute/aks.go index 4971fbaa..78cd28ec 100644 --- a/pkg/clients/compute/aks.go +++ b/pkg/clients/compute/aks.go @@ -189,7 +189,7 @@ func (c AggregateClient) ensureApplication(ctx context.Context, name, secret str return l.Value(), nil // nolint:staticcheck } - url := fmt.Sprintf("https://%s.aks.crossplane.io", name) + url := fmt.Sprintf("api://%s.aks.crossplane.io", name) p := graphrbac.ApplicationCreateParameters{ AvailableToOtherTenants: to.BoolPtr(false), DisplayName: to.StringPtr(name), diff --git a/pkg/controller/compute/managed.go b/pkg/controller/compute/managed.go index 94b1146a..9547aaaa 100644 --- a/pkg/controller/compute/managed.go +++ b/pkg/controller/compute/managed.go @@ -22,6 +22,8 @@ import ( "github.com/Azure/go-autorest/autorest/to" "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/util/workqueue" ctrl "sigs.k8s.io/controller-runtime" @@ -50,6 +52,7 @@ const ( errGetAKSCluster = "cannot get AKSCluster" errGetKubeConfig = "cannot get AKSCluster kubeconfig" errDeleteAKSCluster = "cannot delete AKSCluster" + errGetConnSecret = "cannot get connection secret" ) // SetupAKSCluster adds a controller that reconciles AKSClusters. @@ -143,14 +146,42 @@ func (e *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext return managed.ExternalCreation{}, errors.New(errNotAKSCluster) } cr.SetConditions(xpv1.Creating()) - secret, err := e.newPasswordFn() + + pw, err := e.getPassword(ctx, cr) if err != nil { - return managed.ExternalCreation{}, errors.Wrap(err, errGenPassword) + return managed.ExternalCreation{}, err + } + if pw == "" { + pw, err = e.newPasswordFn() + if err != nil { + return managed.ExternalCreation{}, errors.Wrap(err, errGenPassword) + } + } + return managed.ExternalCreation{ + ConnectionDetails: managed.ConnectionDetails{ + xpv1.ResourceCredentialsSecretPasswordKey: []byte(pw), + }, + }, errors.Wrap(e.client.EnsureManagedCluster(ctx, cr, pw), errCreateAKSCluster) +} + +func (e *external) getPassword(ctx context.Context, cr *v1alpha3.AKSCluster) (string, error) { + if cr.Spec.WriteConnectionSecretToReference == nil || + cr.Spec.WriteConnectionSecretToReference.Name == "" || cr.Spec.WriteConnectionSecretToReference.Namespace == "" { + return "", nil } - return managed.ExternalCreation{}, errors.Wrap(e.client.EnsureManagedCluster(ctx, cr, secret), errCreateAKSCluster) + + s := &v1.Secret{} + if err := e.kube.Get(ctx, types.NamespacedName{ + Namespace: cr.Spec.WriteConnectionSecretToReference.Namespace, + Name: cr.Spec.WriteConnectionSecretToReference.Name, + }, s); err != nil { + return "", errors.Wrap(err, errGetConnSecret) + } + + return string(s.Data[xpv1.ResourceCredentialsSecretPasswordKey]), nil } -func (e *external) Update(ctx context.Context, mg resource.Managed) (managed.ExternalUpdate, error) { +func (e *external) Update(_ context.Context, _ resource.Managed) (managed.ExternalUpdate, error) { // TODO(negz): Support updates. return managed.ExternalUpdate{}, nil } diff --git a/pkg/controller/compute/managed_test.go b/pkg/controller/compute/managed_test.go index 16e884c0..21427a6b 100644 --- a/pkg/controller/compute/managed_test.go +++ b/pkg/controller/compute/managed_test.go @@ -24,8 +24,11 @@ import ( "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2018-03-31/containerservice" "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/to" + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" "github.com/google/go-cmp/cmp" "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource" @@ -35,6 +38,11 @@ import ( "github.com/crossplane/provider-azure/pkg/clients/compute/fake" ) +const ( + testPasswd = "pass123" + testExistingSecret = "existingSecret" +) + type modifier func(*v1alpha3.AKSCluster) func withState(state string) modifier { @@ -55,6 +63,12 @@ func withEndpoint(ep string) modifier { } } +func withConnectionSecretRef(ref *xpv1.SecretReference) modifier { + return func(c *v1alpha3.AKSCluster) { + c.Spec.WriteConnectionSecretToReference = ref + } +} + func aksCluster(m ...modifier) *v1alpha3.AKSCluster { ac := &v1alpha3.AKSCluster{} @@ -254,6 +268,123 @@ func TestCreate(t *testing.T) { }, want: want{ err: errors.Wrap(errBoom, errCreateAKSCluster), + ec: managed.ExternalCreation{ + ConnectionDetails: map[string][]byte{ + "password": {}, + }, + }, + }, + }, + "SuccessEnsureCluster": { + e: &external{ + newPasswordFn: func() (string, error) { return testPasswd, nil }, + client: fake.AKSClient{ + MockEnsureManagedCluster: func(_ context.Context, _ *v1alpha3.AKSCluster, _ string) error { + return nil + }, + }, + }, + args: args{ + ctx: context.Background(), + mg: aksCluster(), + }, + want: want{ + ec: managed.ExternalCreation{ + ConnectionDetails: map[string][]byte{ + "password": []byte(testPasswd), + }, + }, + }, + }, + "SuccessExistingEmptyAppSecret": { + e: &external{ + newPasswordFn: func() (string, error) { return testPasswd, nil }, + client: fake.AKSClient{ + MockEnsureManagedCluster: func(_ context.Context, _ *v1alpha3.AKSCluster, _ string) error { + return nil + }, + }, + kube: &test.MockClient{ + MockGet: func(_ context.Context, _ client.ObjectKey, o client.Object) error { + s, ok := o.(*v1.Secret) + if !ok { + t.Fatalf("not a *v1.Secret") + } + s.Data = map[string][]byte{"password": {}} + return nil + }, + }, + }, + args: args{ + ctx: context.Background(), + mg: aksCluster(withConnectionSecretRef(&xpv1.SecretReference{ + Name: "test-secret", + Namespace: "test-ns", + })), + }, + want: want{ + ec: managed.ExternalCreation{ + ConnectionDetails: map[string][]byte{ + "password": []byte(testPasswd), + }, + }, + }, + }, + "SuccessExistingNonEmptyAppSecret": { + e: &external{ + newPasswordFn: func() (string, error) { return testPasswd, nil }, + client: fake.AKSClient{ + MockEnsureManagedCluster: func(_ context.Context, _ *v1alpha3.AKSCluster, _ string) error { + return nil + }, + }, + kube: &test.MockClient{ + MockGet: func(_ context.Context, _ client.ObjectKey, o client.Object) error { + s, ok := o.(*v1.Secret) + if !ok { + t.Fatalf("not a *v1.Secret") + } + s.Data = map[string][]byte{"password": []byte(testExistingSecret)} + return nil + }, + }, + }, + args: args{ + ctx: context.Background(), + mg: aksCluster(withConnectionSecretRef(&xpv1.SecretReference{ + Name: "test-secret", + Namespace: "test-ns", + })), + }, + want: want{ + ec: managed.ExternalCreation{ + ConnectionDetails: map[string][]byte{ + "password": []byte(testExistingSecret), + }, + }, + }, + }, + "ErrExistingAppSecret": { + e: &external{ + newPasswordFn: func() (string, error) { return testPasswd, nil }, + client: fake.AKSClient{ + MockEnsureManagedCluster: func(_ context.Context, _ *v1alpha3.AKSCluster, _ string) error { + return nil + }, + }, + kube: &test.MockClient{ + MockGet: test.NewMockGetFn(errBoom), + }, + }, + args: args{ + ctx: context.Background(), + mg: aksCluster(withConnectionSecretRef(&xpv1.SecretReference{ + Name: "test-secret", + Namespace: "test-ns", + })), + }, + want: want{ + err: errors.Wrap(errBoom, errGetConnSecret), }, }, }