diff --git a/api/v1beta1/azuremanagedmachinepool_webhook_test.go b/api/v1beta1/azuremanagedmachinepool_webhook_test.go index bcbed6a3f53..0dae9bf34ac 100644 --- a/api/v1beta1/azuremanagedmachinepool_webhook_test.go +++ b/api/v1beta1/azuremanagedmachinepool_webhook_test.go @@ -20,7 +20,7 @@ import ( "context" "testing" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -289,7 +289,7 @@ func TestAzureManagedMachinePoolUpdatingWebhook(t *testing.T) { SKU: "StandardD2S_V3", OSDiskSizeGB: ptr.To[int32](512), MaxPods: ptr.To[int32](24), - OsDiskType: ptr.To(string(containerservice.OSDiskTypeEphemeral)), + OsDiskType: ptr.To(string(armcontainerservice.OSDiskTypeEphemeral)), }, }, old: &AzureManagedMachinePool{ @@ -298,7 +298,7 @@ func TestAzureManagedMachinePoolUpdatingWebhook(t *testing.T) { SKU: "StandardD2S_V3", OSDiskSizeGB: ptr.To[int32](512), MaxPods: ptr.To[int32](24), - OsDiskType: ptr.To(string(containerservice.OSDiskTypeManaged)), + OsDiskType: ptr.To(string(armcontainerservice.OSDiskTypeManaged)), }, }, wantErr: true, @@ -392,7 +392,7 @@ func TestAzureManagedMachinePoolUpdatingWebhook(t *testing.T) { SKU: "StandardD2S_V3", OSDiskSizeGB: ptr.To[int32](512), MaxPods: ptr.To[int32](30), - OsDiskType: ptr.To(string(containerservice.OSDiskTypeManaged)), + OsDiskType: ptr.To(string(armcontainerservice.OSDiskTypeManaged)), }, }, old: &AzureManagedMachinePool{ @@ -401,7 +401,7 @@ func TestAzureManagedMachinePoolUpdatingWebhook(t *testing.T) { SKU: "StandardD2S_V3", OSDiskSizeGB: ptr.To[int32](512), MaxPods: ptr.To[int32](30), - OsDiskType: ptr.To(string(containerservice.OSDiskTypeManaged)), + OsDiskType: ptr.To(string(armcontainerservice.OSDiskTypeManaged)), }, }, wantErr: false, @@ -638,7 +638,7 @@ func TestAzureManagedMachinePool_ValidateCreate(t *testing.T) { ammp: &AzureManagedMachinePool{ Spec: AzureManagedMachinePoolSpec{ MaxPods: ptr.To[int32](249), - OsDiskType: ptr.To(string(containerservice.OSDiskTypeManaged)), + OsDiskType: ptr.To(string(armcontainerservice.OSDiskTypeManaged)), }, }, wantErr: false, @@ -1292,7 +1292,7 @@ func getKnownValidAzureManagedMachinePool() *AzureManagedMachinePool { return &AzureManagedMachinePool{ Spec: AzureManagedMachinePoolSpec{ MaxPods: ptr.To[int32](30), - OsDiskType: ptr.To(string(containerservice.OSDiskTypeEphemeral)), + OsDiskType: ptr.To(string(armcontainerservice.OSDiskTypeEphemeral)), }, } } diff --git a/azure/converters/managedagentpool.go b/azure/converters/managedagentpool.go index 9792e64a930..9808ef46c90 100644 --- a/azure/converters/managedagentpool.go +++ b/azure/converters/managedagentpool.go @@ -17,17 +17,17 @@ limitations under the License. package converters import ( - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" ) // AgentPoolToManagedClusterAgentPoolProfile converts a AgentPoolSpec to an Azure SDK ManagedClusterAgentPoolProfile used in managedcluster reconcile. -func AgentPoolToManagedClusterAgentPoolProfile(pool containerservice.AgentPool) containerservice.ManagedClusterAgentPoolProfile { - properties := pool.ManagedClusterAgentPoolProfileProperties - agentPool := containerservice.ManagedClusterAgentPoolProfile{ +func AgentPoolToManagedClusterAgentPoolProfile(pool armcontainerservice.AgentPool) armcontainerservice.ManagedClusterAgentPoolProfile { + properties := pool.Properties + agentPool := armcontainerservice.ManagedClusterAgentPoolProfile{ Name: pool.Name, // Note: if converting from agentPoolSpec.Parameters(), this field will not be set VMSize: properties.VMSize, - OsType: properties.OsType, - OsDiskSizeGB: properties.OsDiskSizeGB, + OSType: properties.OSType, + OSDiskSizeGB: properties.OSDiskSizeGB, Count: properties.Count, Type: properties.Type, OrchestratorVersion: properties.OrchestratorVersion, @@ -39,7 +39,7 @@ func AgentPoolToManagedClusterAgentPoolProfile(pool containerservice.AgentPool) NodeTaints: properties.NodeTaints, AvailabilityZones: properties.AvailabilityZones, MaxPods: properties.MaxPods, - OsDiskType: properties.OsDiskType, + OSDiskType: properties.OSDiskType, NodeLabels: properties.NodeLabels, EnableUltraSSD: properties.EnableUltraSSD, EnableNodePublicIP: properties.EnableNodePublicIP, diff --git a/azure/converters/managedagentpool_test.go b/azure/converters/managedagentpool_test.go index 8095a095ede..2cbdd181286 100644 --- a/azure/converters/managedagentpool_test.go +++ b/azure/converters/managedagentpool_test.go @@ -19,38 +19,37 @@ package converters import ( "testing" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" . "github.com/onsi/gomega" "k8s.io/utils/ptr" - "sigs.k8s.io/cluster-api-provider-azure/azure" ) func Test_AgentPoolToManagedClusterAgentPoolProfile(t *testing.T) { cases := []struct { name string - pool containerservice.AgentPool - expect func(*GomegaWithT, containerservice.ManagedClusterAgentPoolProfile) + pool armcontainerservice.AgentPool + expect func(*GomegaWithT, armcontainerservice.ManagedClusterAgentPoolProfile) }{ { name: "Should set all values correctly", - pool: containerservice.AgentPool{ + pool: armcontainerservice.AgentPool{ Name: ptr.To("agentpool1"), - ManagedClusterAgentPoolProfileProperties: &containerservice.ManagedClusterAgentPoolProfileProperties{ + Properties: &armcontainerservice.ManagedClusterAgentPoolProfileProperties{ VMSize: ptr.To("Standard_D2s_v3"), - OsType: azure.LinuxOS, - OsDiskSizeGB: ptr.To[int32](100), + OSType: ptr.To(armcontainerservice.OSTypeLinux), + OSDiskSizeGB: ptr.To[int32](100), Count: ptr.To[int32](2), - Type: containerservice.AgentPoolTypeVirtualMachineScaleSets, + Type: ptr.To(armcontainerservice.AgentPoolTypeVirtualMachineScaleSets), OrchestratorVersion: ptr.To("1.22.6"), VnetSubnetID: ptr.To("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-123/providers/Microsoft.Network/virtualNetworks/vnet-123/subnets/subnet-123"), - Mode: containerservice.AgentPoolModeUser, + Mode: ptr.To(armcontainerservice.AgentPoolModeUser), EnableAutoScaling: ptr.To(true), MaxCount: ptr.To[int32](5), MinCount: ptr.To[int32](2), - NodeTaints: &[]string{"key1=value1:NoSchedule"}, - AvailabilityZones: &[]string{"zone1"}, + NodeTaints: []*string{ptr.To("key1=value1:NoSchedule")}, + AvailabilityZones: []*string{ptr.To("zone1")}, MaxPods: ptr.To[int32](60), - OsDiskType: containerservice.OSDiskTypeManaged, + OSDiskType: ptr.To(armcontainerservice.OSDiskTypeManaged), NodeLabels: map[string]*string{ "custom": ptr.To("default"), }, @@ -61,24 +60,24 @@ func Test_AgentPoolToManagedClusterAgentPoolProfile(t *testing.T) { }, }, - expect: func(g *GomegaWithT, result containerservice.ManagedClusterAgentPoolProfile) { - g.Expect(result).To(Equal(containerservice.ManagedClusterAgentPoolProfile{ + expect: func(g *GomegaWithT, result armcontainerservice.ManagedClusterAgentPoolProfile) { + g.Expect(result).To(Equal(armcontainerservice.ManagedClusterAgentPoolProfile{ Name: ptr.To("agentpool1"), VMSize: ptr.To("Standard_D2s_v3"), - OsType: azure.LinuxOS, - OsDiskSizeGB: ptr.To[int32](100), + OSType: ptr.To(armcontainerservice.OSTypeLinux), + OSDiskSizeGB: ptr.To[int32](100), Count: ptr.To[int32](2), - Type: containerservice.AgentPoolTypeVirtualMachineScaleSets, + Type: ptr.To(armcontainerservice.AgentPoolTypeVirtualMachineScaleSets), OrchestratorVersion: ptr.To("1.22.6"), VnetSubnetID: ptr.To("/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-123/providers/Microsoft.Network/virtualNetworks/vnet-123/subnets/subnet-123"), - Mode: containerservice.AgentPoolModeUser, + Mode: ptr.To(armcontainerservice.AgentPoolModeUser), EnableAutoScaling: ptr.To(true), MaxCount: ptr.To[int32](5), MinCount: ptr.To[int32](2), - NodeTaints: &[]string{"key1=value1:NoSchedule"}, - AvailabilityZones: &[]string{"zone1"}, + NodeTaints: []*string{ptr.To("key1=value1:NoSchedule")}, + AvailabilityZones: []*string{ptr.To("zone1")}, MaxPods: ptr.To[int32](60), - OsDiskType: containerservice.OSDiskTypeManaged, + OSDiskType: ptr.To(armcontainerservice.OSDiskTypeManaged), NodeLabels: map[string]*string{ "custom": ptr.To("default"), }, diff --git a/azure/defaults.go b/azure/defaults.go index 6dab387adf3..86d7d249774 100644 --- a/azure/defaults.go +++ b/azure/defaults.go @@ -338,7 +338,7 @@ func UserAgent() string { } // ARMClientOptions returns default ARM client options for CAPZ SDK v2 requests. -func ARMClientOptions(azureEnvironment string) (*arm.ClientOptions, error) { +func ARMClientOptions(azureEnvironment string, extraPolicies ...policy.Policy) (*arm.ClientOptions, error) { opts := &arm.ClientOptions{} switch azureEnvironment { @@ -357,6 +357,7 @@ func ARMClientOptions(azureEnvironment string) (*arm.ClientOptions, error) { correlationIDPolicy{}, userAgentPolicy{}, } + opts.PerCallPolicies = append(opts.PerCallPolicies, extraPolicies...) opts.Retry.MaxRetries = -1 // Less than zero means one try and no retries. return opts, nil @@ -384,6 +385,26 @@ func (p userAgentPolicy) Do(req *policy.Request) (*http.Response, error) { return req.Next() } +// CustomPutPatchHeaderPolicy adds custom headers to a PUT or PATCH request. +// It implements the policy.Policy interface. +type CustomPutPatchHeaderPolicy struct { + Getter ResourceSpecGetter +} + +// Do adds any custom headers to a PUT or PATCH request. +func (p CustomPutPatchHeaderPolicy) Do(req *policy.Request) (*http.Response, error) { + if req.Raw().Method == http.MethodPut || req.Raw().Method == http.MethodPatch { + headerSpec, ok := p.Getter.(ResourceSpecGetterWithHeaders) + if ok { + for key, element := range headerSpec.CustomHeaders() { + req.Raw().Header.Set(key, element) + } + } + } + + return req.Next() +} + // SetAutoRestClientDefaults set authorizer and user agent for autorest client. func SetAutoRestClientDefaults(c *autorest.Client, auth autorest.Authorizer) { c.Authorizer = auth diff --git a/azure/defaults_test.go b/azure/defaults_test.go index 3b1e96ac4e2..855bf20b3b1 100644 --- a/azure/defaults_test.go +++ b/azure/defaults_test.go @@ -29,6 +29,8 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/go-autorest/autorest" . "github.com/onsi/gomega" + "go.uber.org/mock/gomock" + "sigs.k8s.io/cluster-api-provider-azure/azure/mock_azure" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -118,6 +120,90 @@ func TestPerCallPolicies(t *testing.T) { g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) } +func TestCustomPutPatchHeaderPolicy(t *testing.T) { + testHeaders := map[string]string{ + "X-Test-Header": "test-value", + "X-Test-Header2": "test-value2", + } + testcases := []struct { + name string + method string + headers map[string]string + expected map[string]string + }{ + { + name: "should add custom headers to PUT request", + method: http.MethodPut, + headers: testHeaders, + expected: testHeaders, + }, + { + name: "should add custom headers to PATCH request", + method: http.MethodPatch, + headers: testHeaders, + expected: testHeaders, + }, + { + name: "should skip empty custom headers for PUT request", + method: http.MethodPut, + }, + { + name: "should skip empty custom headers for PATCH request", + method: http.MethodPatch, + }, + { + name: "should skip empty custom headers for GET request", + method: http.MethodGet, + }, + { + name: "should not add custom headers to GET request", + method: http.MethodGet, + headers: testHeaders, + }, + { + name: "should not add custom headers to POST request", + method: http.MethodPost, + headers: testHeaders, + }, + } + for _, tc := range testcases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + g := NewWithT(t) + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + + // This server will check that custom headers are set correctly. + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + for k, v := range tc.expected { + g.Expect(r.Header.Get(k)).To(Equal(v)) + } + fmt.Fprintf(w, "Hello, %s", r.Proto) + })) + defer server.Close() + + // Create options with a custom PUT/PATCH header per-call policy + getterMock := mock_azure.NewMockResourceSpecGetterWithHeaders(mockCtrl) + getterMock.EXPECT().CustomHeaders().Return(tc.headers).AnyTimes() + opts, err := ARMClientOptions("", CustomPutPatchHeaderPolicy{Getter: getterMock}) + g.Expect(err).NotTo(HaveOccurred()) + + // Create a request + req, err := runtime.NewRequest(context.Background(), tc.method, server.URL) + g.Expect(err).NotTo(HaveOccurred()) + + // Create a pipeline and send the request to the test server for validation. + pipeline := defaultTestPipeline(opts.PerCallPolicies) + resp, err := pipeline.Do(req) + g.Expect(err).NotTo(HaveOccurred()) + defer resp.Body.Close() + g.Expect(resp.StatusCode).To(Equal(http.StatusOK)) + }) + } +} + func defaultTestPipeline(policies []policy.Policy) runtime.Pipeline { return runtime.NewPipeline( "testmodule", diff --git a/azure/pointers.go b/azure/pointers.go index 5bbad4151da..e5a4ddafe44 100644 --- a/azure/pointers.go +++ b/azure/pointers.go @@ -27,6 +27,28 @@ func StringSlice(s *[]string) []string { return nil } +// PtrSlice returns a slice of pointers from a pointer to a slice. It returns nil if the +// pointer is nil or the slice pointed to is empty. +func PtrSlice[T any](p *[]T) []*T { + if p == nil || len(*p) == 0 { + return nil + } + s := make([]*T, 0, len(*p)) + for _, v := range *p { + s = append(s, ptr.To(v)) + } + return s +} + +// AliasOrNil returns a pointer to a string-derived type from a passed string pointer, +// or nil if the pointer is nil or an empty string. +func AliasOrNil[T ~string](s *string) *T { + if s == nil || *s == "" { + return nil + } + return ptr.To(T(*s)) +} + // StringMapPtr converts a map[string]string into a map[string]*string. It returns nil if the map is nil. func StringMapPtr(m map[string]string) map[string]*string { if m == nil { diff --git a/azure/pointers_test.go b/azure/pointers_test.go index 9b983e9bf8d..5412a29f924 100644 --- a/azure/pointers_test.go +++ b/azure/pointers_test.go @@ -76,3 +76,73 @@ func TestStringMapPtr(t *testing.T) { }) } } + +func TestPtrSlice(t *testing.T) { + cases := []struct { + Name string + Arg *[]string + Expected []*string + }{ + { + Name: "Should return nil if the pointer is nil", + Arg: nil, + Expected: nil, + }, + { + Name: "Should return nil if the slice pointed to is empty", + Arg: &[]string{}, + Expected: nil, + }, + { + Name: "Should return slice of pointers from a pointer to a slice", + Arg: &[]string{"foo", "bar"}, + Expected: []*string{ptr.To("foo"), ptr.To("bar")}, + }, + } + for _, tc := range cases { + t.Run(tc.Name, func(t *testing.T) { + g := NewWithT(t) + actual := PtrSlice(tc.Arg) + g.Expect(tc.Expected).To(Equal(actual)) + }) + } +} + +func TestAliasOrNil(t *testing.T) { + type TestAlias string + cases := []struct { + Name string + Arg *string + Expected *string + }{ + { + Name: "Should return nil if the pointer is nil", + }, + { + Name: "Should return nil for an empty string pointer", + Arg: ptr.To(""), + }, + { + Name: "Should return a string pointer", + Arg: ptr.To("foo"), + Expected: ptr.To("foo"), + }, + } + for _, tc := range cases { + t.Run(tc.Name, func(t *testing.T) { + g := NewWithT(t) + + // Test with string + actual := AliasOrNil[string](tc.Arg) + g.Expect(tc.Expected).To(Equal(actual)) + + // Test with type alias + aliasActual := AliasOrNil[TestAlias](tc.Arg) + if tc.Expected == nil { + g.Expect(aliasActual).To(BeNil()) + } else { + g.Expect(aliasActual).To(Equal(ptr.To(TestAlias(*tc.Expected)))) + } + }) + } +} diff --git a/azure/scope/managedmachinepool_test.go b/azure/scope/managedmachinepool_test.go index 6fd53aa29ff..59f912feda2 100644 --- a/azure/scope/managedmachinepool_test.go +++ b/azure/scope/managedmachinepool_test.go @@ -21,7 +21,7 @@ import ( "reflect" "testing" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" "github.com/google/go-cmp/cmp" . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -591,7 +591,7 @@ func TestManagedMachinePoolScope_OSDiskType(t *testing.T) { }, ManagedMachinePool: ManagedMachinePool{ MachinePool: getMachinePool("pool1"), - InfraMachinePool: getAzureMachinePoolWithOsDiskType("pool1", string(containerservice.OSDiskTypeEphemeral)), + InfraMachinePool: getAzureMachinePoolWithOsDiskType("pool1", string(armcontainerservice.OSDiskTypeEphemeral)), }, }, Expected: &agentpools.AgentPoolSpec{ @@ -600,7 +600,7 @@ func TestManagedMachinePoolScope_OSDiskType(t *testing.T) { Mode: "User", Cluster: "cluster1", Replicas: 1, - OsDiskType: ptr.To(string(containerservice.OSDiskTypeEphemeral)), + OsDiskType: ptr.To(string(armcontainerservice.OSDiskTypeEphemeral)), VnetSubnetID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups//providers/Microsoft.Network/virtualNetworks//subnets/", Headers: map[string]string{}, }, diff --git a/azure/services/agentpools/agentpools.go b/azure/services/agentpools/agentpools.go index 6b0e7a8d4fd..cc7d7c70474 100644 --- a/azure/services/agentpools/agentpools.go +++ b/azure/services/agentpools/agentpools.go @@ -19,12 +19,12 @@ package agentpools import ( "context" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" "github.com/pkg/errors" "k8s.io/utils/ptr" infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" "sigs.k8s.io/cluster-api-provider-azure/azure" - "sigs.k8s.io/cluster-api-provider-azure/azure/services/async" + "sigs.k8s.io/cluster-api-provider-azure/azure/services/asyncpoller" "sigs.k8s.io/cluster-api-provider-azure/util/tele" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ) @@ -52,16 +52,20 @@ type AgentPoolScope interface { // Service provides operations on Azure resources. type Service struct { scope AgentPoolScope - async.Reconciler + asyncpoller.Reconciler } // New creates a new service. -func New(scope AgentPoolScope) *Service { - client := newClient(scope) - return &Service{ - scope: scope, - Reconciler: async.New(scope, client, client), +func New(scope AgentPoolScope) (*Service, error) { + client, err := newClient(scope) + if err != nil { + return nil, err } + return &Service{ + scope: scope, + Reconciler: asyncpoller.New[armcontainerservice.AgentPoolsClientCreateOrUpdateResponse, + armcontainerservice.AgentPoolsClientDeleteResponse](scope, client, client), + }, nil } // Name returns the service name. @@ -80,14 +84,14 @@ func (s *Service) Reconcile(ctx context.Context) error { if err != nil { resultingErr = err } else { - agentPool, ok := result.(containerservice.AgentPool) + agentPool, ok := result.(armcontainerservice.AgentPool) if !ok { - return errors.Errorf("%T is not a containerservice.AgentPool", result) + return errors.Errorf("%T is not an armcontainerservice.AgentPool", result) } // When autoscaling is set, add the annotation to the machine pool and update the replica count. - if ptr.Deref(agentPool.EnableAutoScaling, false) { + if ptr.Deref(agentPool.Properties.EnableAutoScaling, false) { s.scope.SetCAPIMachinePoolAnnotation(clusterv1.ReplicasManagedByAnnotation, "true") - s.scope.SetCAPIMachinePoolReplicas(agentPool.Count) + s.scope.SetCAPIMachinePoolReplicas(agentPool.Properties.Count) } else { // Otherwise, remove the annotation. s.scope.RemoveCAPIMachinePoolAnnotation(clusterv1.ReplicasManagedByAnnotation) } diff --git a/azure/services/agentpools/client.go b/azure/services/agentpools/client.go index 647de5499bf..b5d2f80f947 100644 --- a/azure/services/agentpools/client.go +++ b/azure/services/agentpools/client.go @@ -18,34 +18,32 @@ package agentpools import ( "context" - "encoding/json" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" - "github.com/Azure/go-autorest/autorest" - azureautorest "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" "github.com/pkg/errors" - infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" "sigs.k8s.io/cluster-api-provider-azure/azure" + "sigs.k8s.io/cluster-api-provider-azure/azure/services/asyncpoller" "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) // azureClient contains the Azure go-sdk Client. type azureClient struct { - agentpools containerservice.AgentPoolsClient + agentpools *armcontainerservice.AgentPoolsClient } -// newClient creates a new agent pools client from subscription ID. -func newClient(auth azure.Authorizer) *azureClient { - c := newAgentPoolsClient(auth.SubscriptionID(), auth.BaseURI(), auth.Authorizer()) - return &azureClient{c} -} - -// newAgentPoolsClient creates a new agent pool client from subscription ID. -func newAgentPoolsClient(subscriptionID string, baseURI string, authorizer autorest.Authorizer) containerservice.AgentPoolsClient { - agentPoolsClient := containerservice.NewAgentPoolsClientWithBaseURI(baseURI, subscriptionID) - azure.SetAutoRestClientDefaults(&agentPoolsClient.Client, authorizer) - return agentPoolsClient +// newClient creates a new agentpools client from an authorizer. +func newClient(scope AgentPoolScope) (*azureClient, error) { + opts, err := azure.ARMClientOptions(scope.CloudEnvironment(), azure.CustomPutPatchHeaderPolicy{Getter: scope.AgentPoolSpec()}) + if err != nil { + return nil, errors.Wrap(err, "failed to create agentpools client options") + } + factory, err := armcontainerservice.NewClientFactory(scope.SubscriptionID(), scope.Token(), opts) + if err != nil { + return nil, errors.Wrap(err, "failed to create armcontainerservice client factory") + } + return &azureClient{factory.NewAgentPoolsClient()}, nil } // Get gets an agent pool. @@ -53,61 +51,62 @@ func (ac *azureClient) Get(ctx context.Context, spec azure.ResourceSpecGetter) ( ctx, _, done := tele.StartSpanWithLogger(ctx, "agentpools.azureClient.Get") defer done() - return ac.agentpools.Get(ctx, spec.ResourceGroupName(), spec.OwnerResourceName(), spec.ResourceName()) + resp, err := ac.agentpools.Get(ctx, spec.ResourceGroupName(), spec.OwnerResourceName(), spec.ResourceName(), nil) + if err != nil { + return nil, err + } + return resp.AgentPool, nil } // CreateOrUpdateAsync creates or updates an agent pool asynchronously. -// It sends a PUT request to Azure and if accepted without error, the func will return a Future which can be used to track the ongoing +// It sends a PUT request to Azure and if accepted without error, the func will return a Poller which can be used to track the ongoing // progress of the operation. -func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.ResourceSpecGetter, parameters interface{}) (result interface{}, future azureautorest.FutureAPI, err error) { - ctx, _, done := tele.StartSpanWithLogger(ctx, "agentpools.azureClient.CreateOrUpdate") +func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string, parameters interface{}) ( + result interface{}, poller *runtime.Poller[armcontainerservice.AgentPoolsClientCreateOrUpdateResponse], err error) { + ctx, log, done := tele.StartSpanWithLogger(ctx, "agentpools.azureClient.CreateOrUpdate") defer done() - agentPool, ok := parameters.(containerservice.AgentPool) - if !ok { - return nil, nil, errors.Errorf("%T is not a containerservice.AgentPool", parameters) - } - - preparer, err := ac.agentpools.CreateOrUpdatePreparer(ctx, spec.ResourceGroupName(), spec.OwnerResourceName(), spec.ResourceName(), agentPool) - if err != nil { - return nil, nil, errors.Wrap(err, "failed to prepare operation") - } - - headerSpec, ok := spec.(azure.ResourceSpecGetterWithHeaders) - if !ok { - return nil, nil, errors.Errorf("%T is not a azure.ResourceSpecGetterWithHeaders", spec) - } - for key, element := range headerSpec.CustomHeaders() { - preparer.Header.Add(key, element) + var agentPool armcontainerservice.AgentPool + if parameters != nil { + ap, ok := parameters.(armcontainerservice.AgentPool) + if !ok { + return nil, nil, errors.Errorf("%T is not an armcontainerservice.AgentPool", parameters) + } + agentPool = ap } - createFuture, err := ac.agentpools.CreateOrUpdateSender(preparer) + opts := &armcontainerservice.AgentPoolsClientBeginCreateOrUpdateOptions{ResumeToken: resumeToken} + log.V(4).Info("sending request", "resumeToken", resumeToken) + poller, err = ac.agentpools.BeginCreateOrUpdate(ctx, spec.ResourceGroupName(), spec.OwnerResourceName(), spec.ResourceName(), agentPool, opts) if err != nil { - return nil, nil, errors.Wrap(err, "failed to begin operation") + return nil, nil, err } ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) defer cancel() - err = createFuture.WaitForCompletionRef(ctx, ac.agentpools.Client) + pollOpts := &runtime.PollUntilDoneOptions{Frequency: asyncpoller.DefaultPollerFrequency} + resp, err := poller.PollUntilDone(ctx, pollOpts) if err != nil { - // if an error occurs, return the future. - // this means the long-running operation didn't finish in the specified timeout. - return nil, &createFuture, err + // If an error occurs, return the poller. + return nil, poller, err } - result, err = createFuture.Result(ac.agentpools) - // if the operation completed, return a nil future - return result, nil, err + + // if the operation completed, return a nil poller + return resp.AgentPool, nil, err } // DeleteAsync deletes an agent pool asynchronously. DeleteAsync sends a DELETE -// request to Azure and if accepted without error, the func will return a Future which can be used to track the ongoing +// request to Azure and if accepted without error, the func will return a Poller which can be used to track the ongoing // progress of the operation. -func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecGetter) (future azureautorest.FutureAPI, err error) { - ctx, _, done := tele.StartSpanWithLogger(ctx, "agentpools.azureClient.Delete") +func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string) ( + poller *runtime.Poller[armcontainerservice.AgentPoolsClientDeleteResponse], err error) { + ctx, log, done := tele.StartSpanWithLogger(ctx, "agentpools.azureClient.DeleteAsync") defer done() - deleteFuture, err := ac.agentpools.Delete(ctx, spec.ResourceGroupName(), spec.OwnerResourceName(), spec.ResourceName()) + opts := &armcontainerservice.AgentPoolsClientBeginDeleteOptions{ResumeToken: resumeToken} + log.V(4).Info("sending request", "resumeToken", resumeToken) + poller, err = ac.agentpools.BeginDelete(ctx, spec.ResourceGroupName(), spec.OwnerResourceName(), spec.ResourceName(), opts) if err != nil { return nil, err } @@ -115,54 +114,14 @@ func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) defer cancel() - err = deleteFuture.WaitForCompletionRef(ctx, ac.agentpools.Client) + pollOpts := &runtime.PollUntilDoneOptions{Frequency: asyncpoller.DefaultPollerFrequency} + _, err = poller.PollUntilDone(ctx, pollOpts) if err != nil { - // if an error occurs, return the future. - // this means the long-running operation didn't finish in the specified timeout. - return &deleteFuture, err + // If an error occurs, return the poller. + // This means the long-running operation didn't finish in the specified timeout. + return poller, err } - _, err = deleteFuture.Result(ac.agentpools) - // if the operation completed, return a nil future. - return nil, err -} - -// IsDone returns true if the long-running operation has completed. -func (ac *azureClient) IsDone(ctx context.Context, future azureautorest.FutureAPI) (isDone bool, err error) { - ctx, _, done := tele.StartSpanWithLogger(ctx, "agentpools.azureClient.IsDone") - defer done() - - return future.DoneWithContext(ctx, ac.agentpools) -} - -// Result fetches the result of a long-running operation future. -func (ac *azureClient) Result(ctx context.Context, future azureautorest.FutureAPI, futureType string) (result interface{}, err error) { - _, _, done := tele.StartSpanWithLogger(ctx, "agentpools.azureClient.Result") - defer done() - if future == nil { - return nil, errors.Errorf("cannot get result from nil future") - } - - switch futureType { - case infrav1.PutFuture: - // Marshal and Unmarshal the future to put it into the correct future type so we can access the Result function. - // Unfortunately the FutureAPI can't be casted directly to AgentPoolsCreateOrUpdateFuture because it is a azureautorest.Future, which doesn't implement the Result function. See PR #1686 for discussion on alternatives. - // It was converted back to a generic azureautorest.Future from the CAPZ infrav1.Future type stored in Status: https://github.com/kubernetes-sigs/cluster-api-provider-azure/blob/main/azure/converters/futures.go#L49. - var createFuture *containerservice.AgentPoolsCreateOrUpdateFuture - jsonData, err := future.MarshalJSON() - if err != nil { - return nil, errors.Wrap(err, "failed to marshal future") - } - if err := json.Unmarshal(jsonData, &createFuture); err != nil { - return nil, errors.Wrap(err, "failed to unmarshal future data") - } - return createFuture.Result(ac.agentpools) - - case infrav1.DeleteFuture: - // Delete does not return a result agentPool. - return nil, nil - - default: - return nil, errors.Errorf("unknown future type %q", futureType) - } + // if the operation completed, return a nil poller. + return nil, err } diff --git a/azure/services/agentpools/spec.go b/azure/services/agentpools/spec.go index 2e11f4f676e..a52b06535c5 100644 --- a/azure/services/agentpools/spec.go +++ b/azure/services/agentpools/spec.go @@ -21,7 +21,7 @@ import ( "fmt" "time" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" "github.com/google/go-cmp/cmp" "github.com/pkg/errors" "k8s.io/apimachinery/pkg/api/resource" @@ -179,60 +179,60 @@ func (s *AgentPoolSpec) Parameters(ctx context.Context, existing interface{}) (p nodeLabels := s.NodeLabels if existing != nil { - existingPool, ok := existing.(containerservice.AgentPool) + existingPool, ok := existing.(armcontainerservice.AgentPool) if !ok { - return nil, errors.Errorf("%T is not a containerservice.AgentPool", existing) + return nil, errors.Errorf("%T is not an armcontainerservice.AgentPool", existing) } // agent pool already exists - ps := *existingPool.ManagedClusterAgentPoolProfileProperties.ProvisioningState + ps := *existingPool.Properties.ProvisioningState if ps != string(infrav1.Canceled) && ps != string(infrav1.Failed) && ps != string(infrav1.Succeeded) { msg := fmt.Sprintf("Unable to update existing agent pool in non terminal state. Agent pool must be in one of the following provisioning states: Canceled, Failed, or Succeeded. Actual state: %s", ps) return nil, azure.WithTransientError(errors.New(msg), 20*time.Second) } // Normalize individual agent pools to diff in case we need to update - existingProfile := containerservice.AgentPool{ - ManagedClusterAgentPoolProfileProperties: &containerservice.ManagedClusterAgentPoolProfileProperties{ - Count: existingPool.Count, - OrchestratorVersion: existingPool.OrchestratorVersion, - Mode: existingPool.Mode, - EnableAutoScaling: existingPool.EnableAutoScaling, - MinCount: existingPool.MinCount, - MaxCount: existingPool.MaxCount, - NodeLabels: existingPool.NodeLabels, - NodeTaints: existingPool.NodeTaints, - Tags: existingPool.Tags, - ScaleDownMode: existingPool.ScaleDownMode, - SpotMaxPrice: existingPool.SpotMaxPrice, - KubeletConfig: existingPool.KubeletConfig, + existingProfile := armcontainerservice.AgentPool{ + Properties: &armcontainerservice.ManagedClusterAgentPoolProfileProperties{ + Count: existingPool.Properties.Count, + OrchestratorVersion: existingPool.Properties.OrchestratorVersion, + Mode: existingPool.Properties.Mode, + EnableAutoScaling: existingPool.Properties.EnableAutoScaling, + MinCount: existingPool.Properties.MinCount, + MaxCount: existingPool.Properties.MaxCount, + NodeLabels: existingPool.Properties.NodeLabels, + NodeTaints: existingPool.Properties.NodeTaints, + Tags: existingPool.Properties.Tags, + ScaleDownMode: existingPool.Properties.ScaleDownMode, + SpotMaxPrice: existingPool.Properties.SpotMaxPrice, + KubeletConfig: existingPool.Properties.KubeletConfig, }, } - normalizedProfile := containerservice.AgentPool{ - ManagedClusterAgentPoolProfileProperties: &containerservice.ManagedClusterAgentPoolProfileProperties{ + normalizedProfile := armcontainerservice.AgentPool{ + Properties: &armcontainerservice.ManagedClusterAgentPoolProfileProperties{ Count: &s.Replicas, OrchestratorVersion: s.Version, - Mode: containerservice.AgentPoolMode(s.Mode), + Mode: azure.AliasOrNil[armcontainerservice.AgentPoolMode](&s.Mode), EnableAutoScaling: ptr.To(s.EnableAutoScaling), MinCount: s.MinCount, MaxCount: s.MaxCount, NodeLabels: s.NodeLabels, - NodeTaints: &s.NodeTaints, - ScaleDownMode: containerservice.ScaleDownMode(ptr.Deref(s.ScaleDownMode, "")), + NodeTaints: azure.PtrSlice(&s.NodeTaints), + ScaleDownMode: azure.AliasOrNil[armcontainerservice.ScaleDownMode](s.ScaleDownMode), Tags: converters.TagsToMap(s.AdditionalTags), }, } - if len(*normalizedProfile.NodeTaints) == 0 { - normalizedProfile.NodeTaints = nil + if len(normalizedProfile.Properties.NodeTaints) == 0 { + normalizedProfile.Properties.NodeTaints = nil } if s.SpotMaxPrice != nil { - normalizedProfile.SpotMaxPrice = ptr.To[float64](s.SpotMaxPrice.AsApproximateFloat64()) + normalizedProfile.Properties.SpotMaxPrice = ptr.To[float32](float32(s.SpotMaxPrice.AsApproximateFloat64())) } if s.KubeletConfig != nil { - normalizedProfile.KubeletConfig = &containerservice.KubeletConfig{ + normalizedProfile.Properties.KubeletConfig = &armcontainerservice.KubeletConfig{ CPUManagerPolicy: s.KubeletConfig.CPUManagerPolicy, CPUCfsQuota: s.KubeletConfig.CPUCfsQuota, CPUCfsQuotaPeriod: s.KubeletConfig.CPUCfsQuotaPeriod, @@ -243,7 +243,7 @@ func (s *AgentPoolSpec) Parameters(ctx context.Context, existing interface{}) (p ContainerLogMaxSizeMB: s.KubeletConfig.ContainerLogMaxSizeMB, ContainerLogMaxFiles: s.KubeletConfig.ContainerLogMaxFiles, PodMaxPids: s.KubeletConfig.PodMaxPids, - AllowedUnsafeSysctls: s.KubeletConfig.AllowedUnsafeSysctls, + AllowedUnsafeSysctls: azure.PtrSlice(s.KubeletConfig.AllowedUnsafeSysctls), } } @@ -251,15 +251,15 @@ func (s *AgentPoolSpec) Parameters(ctx context.Context, existing interface{}) (p // count present in MachinePool or AzureManagedMachinePool, hence we should not make an update API call based // on difference in count. if s.EnableAutoScaling { - normalizedProfile.Count = existingProfile.Count + normalizedProfile.Properties.Count = existingProfile.Properties.Count } // We do a just-in-time merge of existent kubernetes.azure.com-prefixed labels // So that we don't unintentionally delete them // See https://github.com/Azure/AKS/issues/3152 - if normalizedProfile.NodeLabels != nil { - nodeLabels = mergeSystemNodeLabels(normalizedProfile.NodeLabels, existingPool.NodeLabels) - normalizedProfile.NodeLabels = nodeLabels + if normalizedProfile.Properties.NodeLabels != nil { + nodeLabels = mergeSystemNodeLabels(normalizedProfile.Properties.NodeLabels, existingPool.Properties.NodeLabels) + normalizedProfile.Properties.NodeLabels = nodeLabels } // Compute a diff to check if we require an update @@ -272,21 +272,15 @@ func (s *AgentPoolSpec) Parameters(ctx context.Context, existing interface{}) (p log.V(4).Info("found a diff between the desired spec and the existing agentpool", "difference", diff) } - var availabilityZones *[]string - if len(s.AvailabilityZones) > 0 { - availabilityZones = &s.AvailabilityZones - } - var nodeTaints *[]string - if len(s.NodeTaints) > 0 { - nodeTaints = &s.NodeTaints - } + availabilityZones := azure.PtrSlice(&s.AvailabilityZones) + nodeTaints := azure.PtrSlice(&s.NodeTaints) var sku *string if s.SKU != "" { sku = &s.SKU } - var spotMaxPrice *float64 + var spotMaxPrice *float32 if s.SpotMaxPrice != nil { - spotMaxPrice = ptr.To[float64](s.SpotMaxPrice.AsApproximateFloat64()) + spotMaxPrice = ptr.To[float32](float32(s.SpotMaxPrice.AsApproximateFloat64())) } tags := converters.TagsToMap(s.AdditionalTags) if tags == nil { @@ -298,9 +292,9 @@ func (s *AgentPoolSpec) Parameters(ctx context.Context, existing interface{}) (p vnetSubnetID = &s.VnetSubnetID } - var kubeletConfig *containerservice.KubeletConfig + var kubeletConfig *armcontainerservice.KubeletConfig if s.KubeletConfig != nil { - kubeletConfig = &containerservice.KubeletConfig{ + kubeletConfig = &armcontainerservice.KubeletConfig{ CPUManagerPolicy: s.KubeletConfig.CPUManagerPolicy, CPUCfsQuota: s.KubeletConfig.CPUCfsQuota, CPUCfsQuotaPeriod: s.KubeletConfig.CPUCfsQuotaPeriod, @@ -311,19 +305,19 @@ func (s *AgentPoolSpec) Parameters(ctx context.Context, existing interface{}) (p ContainerLogMaxSizeMB: s.KubeletConfig.ContainerLogMaxSizeMB, ContainerLogMaxFiles: s.KubeletConfig.ContainerLogMaxFiles, PodMaxPids: s.KubeletConfig.PodMaxPids, - AllowedUnsafeSysctls: s.KubeletConfig.AllowedUnsafeSysctls, + AllowedUnsafeSysctls: azure.PtrSlice(s.KubeletConfig.AllowedUnsafeSysctls), } } - var linuxOSConfig *containerservice.LinuxOSConfig + var linuxOSConfig *armcontainerservice.LinuxOSConfig if s.LinuxOSConfig != nil { - linuxOSConfig = &containerservice.LinuxOSConfig{ + linuxOSConfig = &armcontainerservice.LinuxOSConfig{ SwapFileSizeMB: s.LinuxOSConfig.SwapFileSizeMB, TransparentHugePageEnabled: (*string)(s.LinuxOSConfig.TransparentHugePageEnabled), TransparentHugePageDefrag: (*string)(s.LinuxOSConfig.TransparentHugePageDefrag), } if s.LinuxOSConfig.Sysctls != nil { - linuxOSConfig.Sysctls = &containerservice.SysctlConfig{ + linuxOSConfig.Sysctls = &armcontainerservice.SysctlConfig{ FsAioMaxNr: s.LinuxOSConfig.Sysctls.FsAioMaxNr, FsFileMax: s.LinuxOSConfig.Sysctls.FsFileMax, FsInotifyMaxUserWatches: s.LinuxOSConfig.Sysctls.FsInotifyMaxUserWatches, @@ -336,17 +330,17 @@ func (s *AgentPoolSpec) Parameters(ctx context.Context, existing interface{}) (p NetCoreSomaxconn: s.LinuxOSConfig.Sysctls.NetCoreSomaxconn, NetCoreWmemDefault: s.LinuxOSConfig.Sysctls.NetCoreWmemDefault, NetCoreWmemMax: s.LinuxOSConfig.Sysctls.NetCoreWmemMax, - NetIpv4IPLocalPortRange: s.LinuxOSConfig.Sysctls.NetIpv4IPLocalPortRange, - NetIpv4NeighDefaultGcThresh1: s.LinuxOSConfig.Sysctls.NetIpv4NeighDefaultGcThresh1, - NetIpv4NeighDefaultGcThresh2: s.LinuxOSConfig.Sysctls.NetIpv4NeighDefaultGcThresh2, - NetIpv4NeighDefaultGcThresh3: s.LinuxOSConfig.Sysctls.NetIpv4NeighDefaultGcThresh3, - NetIpv4TCPFinTimeout: s.LinuxOSConfig.Sysctls.NetIpv4TCPFinTimeout, - NetIpv4TCPKeepaliveProbes: s.LinuxOSConfig.Sysctls.NetIpv4TCPKeepaliveProbes, - NetIpv4TCPKeepaliveTime: s.LinuxOSConfig.Sysctls.NetIpv4TCPKeepaliveTime, - NetIpv4TCPMaxSynBacklog: s.LinuxOSConfig.Sysctls.NetIpv4TCPMaxSynBacklog, - NetIpv4TCPMaxTwBuckets: s.LinuxOSConfig.Sysctls.NetIpv4TCPMaxTwBuckets, - NetIpv4TCPTwReuse: s.LinuxOSConfig.Sysctls.NetIpv4TCPTwReuse, - NetIpv4TcpkeepaliveIntvl: s.LinuxOSConfig.Sysctls.NetIpv4TCPkeepaliveIntvl, + NetIPv4IPLocalPortRange: s.LinuxOSConfig.Sysctls.NetIpv4IPLocalPortRange, + NetIPv4NeighDefaultGcThresh1: s.LinuxOSConfig.Sysctls.NetIpv4NeighDefaultGcThresh1, + NetIPv4NeighDefaultGcThresh2: s.LinuxOSConfig.Sysctls.NetIpv4NeighDefaultGcThresh2, + NetIPv4NeighDefaultGcThresh3: s.LinuxOSConfig.Sysctls.NetIpv4NeighDefaultGcThresh3, + NetIPv4TCPFinTimeout: s.LinuxOSConfig.Sysctls.NetIpv4TCPFinTimeout, + NetIPv4TCPKeepaliveProbes: s.LinuxOSConfig.Sysctls.NetIpv4TCPKeepaliveProbes, + NetIPv4TCPKeepaliveTime: s.LinuxOSConfig.Sysctls.NetIpv4TCPKeepaliveTime, + NetIPv4TCPMaxSynBacklog: s.LinuxOSConfig.Sysctls.NetIpv4TCPMaxSynBacklog, + NetIPv4TCPMaxTwBuckets: s.LinuxOSConfig.Sysctls.NetIpv4TCPMaxTwBuckets, + NetIPv4TCPTwReuse: s.LinuxOSConfig.Sysctls.NetIpv4TCPTwReuse, + NetIPv4TcpkeepaliveIntvl: s.LinuxOSConfig.Sysctls.NetIpv4TCPkeepaliveIntvl, NetNetfilterNfConntrackBuckets: s.LinuxOSConfig.Sysctls.NetNetfilterNfConntrackBuckets, NetNetfilterNfConntrackMax: s.LinuxOSConfig.Sysctls.NetNetfilterNfConntrackMax, VMMaxMapCount: s.LinuxOSConfig.Sysctls.VMMaxMapCount, @@ -356,28 +350,28 @@ func (s *AgentPoolSpec) Parameters(ctx context.Context, existing interface{}) (p } } - agentPool := containerservice.AgentPool{ - ManagedClusterAgentPoolProfileProperties: &containerservice.ManagedClusterAgentPoolProfileProperties{ + agentPool := armcontainerservice.AgentPool{ + Properties: &armcontainerservice.ManagedClusterAgentPoolProfileProperties{ AvailabilityZones: availabilityZones, Count: &s.Replicas, EnableAutoScaling: ptr.To(s.EnableAutoScaling), EnableUltraSSD: s.EnableUltraSSD, KubeletConfig: kubeletConfig, - KubeletDiskType: containerservice.KubeletDiskType(ptr.Deref((*string)(s.KubeletDiskType), "")), + KubeletDiskType: azure.AliasOrNil[armcontainerservice.KubeletDiskType]((*string)(s.KubeletDiskType)), MaxCount: s.MaxCount, MaxPods: s.MaxPods, MinCount: s.MinCount, - Mode: containerservice.AgentPoolMode(s.Mode), + Mode: ptr.To(armcontainerservice.AgentPoolMode(s.Mode)), NodeLabels: nodeLabels, NodeTaints: nodeTaints, OrchestratorVersion: s.Version, - OsDiskSizeGB: &s.OSDiskSizeGB, - OsDiskType: containerservice.OSDiskType(ptr.Deref(s.OsDiskType, "")), - OsType: containerservice.OSType(ptr.Deref(s.OSType, "")), - ScaleSetPriority: containerservice.ScaleSetPriority(ptr.Deref(s.ScaleSetPriority, "")), - ScaleDownMode: containerservice.ScaleDownMode(ptr.Deref(s.ScaleDownMode, "")), + OSDiskSizeGB: &s.OSDiskSizeGB, + OSDiskType: azure.AliasOrNil[armcontainerservice.OSDiskType](s.OsDiskType), + OSType: azure.AliasOrNil[armcontainerservice.OSType](s.OSType), + ScaleSetPriority: azure.AliasOrNil[armcontainerservice.ScaleSetPriority](s.ScaleSetPriority), + ScaleDownMode: azure.AliasOrNil[armcontainerservice.ScaleDownMode](s.ScaleDownMode), SpotMaxPrice: spotMaxPrice, - Type: containerservice.AgentPoolTypeVirtualMachineScaleSets, + Type: ptr.To(armcontainerservice.AgentPoolTypeVirtualMachineScaleSets), VMSize: sku, VnetSubnetID: vnetSubnetID, EnableNodePublicIP: s.EnableNodePublicIP, diff --git a/azure/services/agentpools/spec_test.go b/azure/services/agentpools/spec_test.go index 2fdea4f7e62..fb2395a3e2e 100644 --- a/azure/services/agentpools/spec_test.go +++ b/azure/services/agentpools/spec_test.go @@ -22,7 +22,7 @@ import ( "testing" "time" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" "github.com/google/go-cmp/cmp" . "github.com/onsi/gomega" "github.com/pkg/errors" @@ -83,27 +83,26 @@ func withSpotMaxPrice(spotMaxPrice string) func(*AgentPoolSpec) { pool.SpotMaxPrice = &quantity } } - -func sdkFakeAgentPool(changes ...func(*containerservice.AgentPool)) containerservice.AgentPool { - pool := containerservice.AgentPool{ - ManagedClusterAgentPoolProfileProperties: &containerservice.ManagedClusterAgentPoolProfileProperties{ - AvailabilityZones: &[]string{"fake-zone"}, +func sdkFakeAgentPool(changes ...func(*armcontainerservice.AgentPool)) armcontainerservice.AgentPool { + pool := armcontainerservice.AgentPool{ + Properties: &armcontainerservice.ManagedClusterAgentPoolProfileProperties{ + AvailabilityZones: []*string{ptr.To("fake-zone")}, Count: ptr.To[int32](1), // updates if changed EnableAutoScaling: ptr.To(true), // updates if changed EnableUltraSSD: ptr.To(true), - KubeletDiskType: containerservice.KubeletDiskType("fake-kubelet-disk-type"), + KubeletDiskType: ptr.To(armcontainerservice.KubeletDiskType("fake-kubelet-disk-type")), MaxCount: ptr.To[int32](5), // updates if changed MaxPods: ptr.To[int32](10), MinCount: ptr.To[int32](1), // updates if changed - Mode: containerservice.AgentPoolMode("fake-mode"), // updates if changed + Mode: ptr.To(armcontainerservice.AgentPoolMode("fake-mode")), // updates if changed NodeLabels: map[string]*string{"fake-label": ptr.To("fake-value")}, // updates if changed - NodeTaints: &[]string{"fake-taint"}, // updates if changed + NodeTaints: []*string{ptr.To("fake-taint")}, // updates if changed OrchestratorVersion: ptr.To("fake-version"), // updates if changed - OsDiskSizeGB: ptr.To[int32](2), - OsDiskType: containerservice.OSDiskType("fake-os-disk-type"), - OsType: containerservice.OSType("fake-os-type"), + OSDiskSizeGB: ptr.To[int32](2), + OSDiskType: ptr.To(armcontainerservice.OSDiskType("fake-os-disk-type")), + OSType: ptr.To(armcontainerservice.OSType("fake-os-type")), Tags: map[string]*string{"fake": ptr.To("tag")}, - Type: containerservice.AgentPoolTypeVirtualMachineScaleSets, + Type: ptr.To(armcontainerservice.AgentPoolTypeVirtualMachineScaleSets), VMSize: ptr.To("fake-sku"), VnetSubnetID: ptr.To("fake-vnet-subnet-id"), }, @@ -116,33 +115,37 @@ func sdkFakeAgentPool(changes ...func(*containerservice.AgentPool)) containerser return pool } -func sdkWithAutoscaling(enableAutoscaling bool) func(*containerservice.AgentPool) { - return func(pool *containerservice.AgentPool) { - pool.ManagedClusterAgentPoolProfileProperties.EnableAutoScaling = ptr.To(enableAutoscaling) +func sdkWithAutoscaling(enableAutoscaling bool) func(*armcontainerservice.AgentPool) { + return func(pool *armcontainerservice.AgentPool) { + pool.Properties.EnableAutoScaling = ptr.To(enableAutoscaling) } } -func sdkWithScaleDownMode(scaleDownMode containerservice.ScaleDownMode) func(*containerservice.AgentPool) { - return func(pool *containerservice.AgentPool) { - pool.ManagedClusterAgentPoolProfileProperties.ScaleDownMode = scaleDownMode +func sdkWithCount(count int32) func(*armcontainerservice.AgentPool) { + return func(pool *armcontainerservice.AgentPool) { + pool.Properties.Count = ptr.To[int32](count) } } -func sdkWithSpotMaxPrice(spotMaxPrice float64) func(*containerservice.AgentPool) { - return func(pool *containerservice.AgentPool) { - pool.ManagedClusterAgentPoolProfileProperties.SpotMaxPrice = &spotMaxPrice +func sdkWithProvisioningState(state string) func(*armcontainerservice.AgentPool) { + return func(pool *armcontainerservice.AgentPool) { + pool.Properties.ProvisioningState = ptr.To(state) } } -func sdkWithCount(count int32) func(*containerservice.AgentPool) { - return func(pool *containerservice.AgentPool) { - pool.ManagedClusterAgentPoolProfileProperties.Count = ptr.To[int32](count) +func sdkWithScaleDownMode(scaleDownMode armcontainerservice.ScaleDownMode) func(*armcontainerservice.AgentPool) { + return func(pool *armcontainerservice.AgentPool) { + if scaleDownMode == "" { + pool.Properties.ScaleDownMode = nil + } else { + pool.Properties.ScaleDownMode = ptr.To(scaleDownMode) + } } } -func sdkWithProvisioningState(state string) func(*containerservice.AgentPool) { - return func(pool *containerservice.AgentPool) { - pool.ManagedClusterAgentPoolProfileProperties.ProvisioningState = ptr.To(state) +func sdkWithSpotMaxPrice(spotMaxPrice float32) func(*armcontainerservice.AgentPool) { + return func(pool *armcontainerservice.AgentPool) { + pool.Properties.SpotMaxPrice = &spotMaxPrice } } @@ -239,7 +242,7 @@ func TestParameters(t *testing.T) { name: "parameters with an existing agent pool and update needed on scale down mode", spec: fakeAgentPool(), existing: sdkFakeAgentPool( - sdkWithScaleDownMode(containerservice.ScaleDownModeDeallocate), + sdkWithScaleDownMode(armcontainerservice.ScaleDownModeDeallocate), sdkWithProvisioningState("Succeeded"), ), expected: sdkFakeAgentPool(), @@ -272,7 +275,7 @@ func TestParameters(t *testing.T) { name: "parameters with an existing agent pool and update needed on max count", spec: fakeAgentPool(), existing: sdkFakeAgentPool( - func(pool *containerservice.AgentPool) { pool.MaxCount = ptr.To[int32](3) }, + func(pool *armcontainerservice.AgentPool) { pool.Properties.MaxCount = ptr.To[int32](3) }, sdkWithProvisioningState("Succeeded"), ), expected: sdkFakeAgentPool(), @@ -282,7 +285,7 @@ func TestParameters(t *testing.T) { name: "parameters with an existing agent pool and update needed on min count", spec: fakeAgentPool(), existing: sdkFakeAgentPool( - func(pool *containerservice.AgentPool) { pool.MinCount = ptr.To[int32](3) }, + func(pool *armcontainerservice.AgentPool) { pool.Properties.MinCount = ptr.To[int32](3) }, sdkWithProvisioningState("Succeeded"), ), expected: sdkFakeAgentPool(), @@ -292,7 +295,9 @@ func TestParameters(t *testing.T) { name: "parameters with an existing agent pool and update needed on mode", spec: fakeAgentPool(), existing: sdkFakeAgentPool( - func(pool *containerservice.AgentPool) { pool.Mode = "fake-old-mode" }, + func(pool *armcontainerservice.AgentPool) { + pool.Properties.Mode = ptr.To(armcontainerservice.AgentPoolMode("fake-old-mode")) + }, sdkWithProvisioningState("Succeeded"), ), expected: sdkFakeAgentPool(), @@ -302,8 +307,8 @@ func TestParameters(t *testing.T) { name: "parameters with an existing agent pool and update needed on node labels", spec: fakeAgentPool(), existing: sdkFakeAgentPool( - func(pool *containerservice.AgentPool) { - pool.NodeLabels = map[string]*string{ + func(pool *armcontainerservice.AgentPool) { + pool.Properties.NodeLabels = map[string]*string{ "fake-label": ptr.To("fake-value"), "fake-old-label": ptr.To("fake-old-value"), } @@ -323,8 +328,8 @@ func TestParameters(t *testing.T) { }, ), existing: sdkFakeAgentPool( - func(pool *containerservice.AgentPool) { - pool.NodeLabels = map[string]*string{ + func(pool *armcontainerservice.AgentPool) { + pool.Properties.NodeLabels = map[string]*string{ "fake-label": ptr.To("fake-value"), "kubernetes.azure.com/scalesetpriority": ptr.To("spot"), } @@ -338,7 +343,9 @@ func TestParameters(t *testing.T) { name: "parameters with an existing agent pool and update needed on node taints", spec: fakeAgentPool(), existing: sdkFakeAgentPool( - func(pool *containerservice.AgentPool) { pool.NodeTaints = &[]string{"fake-old-taint"} }, + func(pool *armcontainerservice.AgentPool) { + pool.Properties.NodeTaints = []*string{ptr.To("fake-old-taint")} + }, sdkWithProvisioningState("Succeeded"), ), expected: sdkFakeAgentPool(), @@ -367,7 +374,7 @@ func TestParameters(t *testing.T) { func(pool *AgentPoolSpec) { pool.NodeTaints = nil }, ), existing: sdkFakeAgentPool( - func(pool *containerservice.AgentPool) { pool.NodeTaints = nil }, + func(pool *armcontainerservice.AgentPool) { pool.Properties.NodeTaints = nil }, sdkWithProvisioningState("Succeeded"), ), expected: nil, diff --git a/azure/services/managedclusters/client.go b/azure/services/managedclusters/client.go index b82f340f673..daa693a1678 100644 --- a/azure/services/managedclusters/client.go +++ b/azure/services/managedclusters/client.go @@ -18,14 +18,12 @@ package managedclusters import ( "context" - "encoding/json" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" - "github.com/Azure/go-autorest/autorest" - azureautorest "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" "github.com/pkg/errors" - infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" "sigs.k8s.io/cluster-api-provider-azure/azure" + "sigs.k8s.io/cluster-api-provider-azure/azure/services/asyncpoller" "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -37,21 +35,20 @@ type CredentialGetter interface { // azureClient contains the Azure go-sdk Client. type azureClient struct { - managedclusters containerservice.ManagedClustersClient + managedclusters *armcontainerservice.ManagedClustersClient } -// newClient creates a new managed cluster client from an authorizer. -func newClient(auth azure.Authorizer) *azureClient { - return &azureClient{ - managedclusters: newManagedClustersClient(auth.SubscriptionID(), auth.BaseURI(), auth.Authorizer()), +// newClient creates a new managedclusters client from an authorizer. +func newClient(scope ManagedClusterScope) (*azureClient, error) { + opts, err := azure.ARMClientOptions(scope.CloudEnvironment(), azure.CustomPutPatchHeaderPolicy{Getter: scope.ManagedClusterSpec()}) + if err != nil { + return nil, errors.Wrap(err, "failed to create managedclusters client options") } -} - -// newManagedClustersClient creates a new managed clusters client from subscription ID. -func newManagedClustersClient(subscriptionID string, baseURI string, authorizer autorest.Authorizer) containerservice.ManagedClustersClient { - managedClustersClient := containerservice.NewManagedClustersClientWithBaseURI(baseURI, subscriptionID) - azure.SetAutoRestClientDefaults(&managedClustersClient.Client, authorizer) - return managedClustersClient + factory, err := armcontainerservice.NewClientFactory(scope.SubscriptionID(), scope.Token(), opts) + if err != nil { + return nil, errors.Wrap(err, "failed to create armcontainerservice client factory") + } + return &azureClient{factory.NewManagedClustersClient()}, nil } // Get gets a managed cluster. @@ -59,7 +56,11 @@ func (ac *azureClient) Get(ctx context.Context, spec azure.ResourceSpecGetter) ( ctx, _, done := tele.StartSpanWithLogger(ctx, "managedclusters.azureClient.Get") defer done() - return ac.managedclusters.Get(ctx, spec.ResourceGroupName(), spec.ResourceName()) + resp, err := ac.managedclusters.Get(ctx, spec.ResourceGroupName(), spec.ResourceName(), nil) + if err != nil { + return nil, err + } + return resp.ManagedCluster, nil } // GetCredentials fetches the admin kubeconfig for a managed cluster. @@ -67,45 +68,38 @@ func (ac *azureClient) GetCredentials(ctx context.Context, resourceGroupName, na ctx, _, done := tele.StartSpanWithLogger(ctx, "managedclusters.azureClient.GetCredentials") defer done() - credentialList, err := ac.managedclusters.ListClusterAdminCredentials(ctx, resourceGroupName, name, "") + credentialList, err := ac.managedclusters.ListClusterAdminCredentials(ctx, resourceGroupName, name, nil) if err != nil { return nil, err } - if credentialList.Kubeconfigs == nil || len(*credentialList.Kubeconfigs) < 1 { - return nil, errors.New("no kubeconfigs available for the managed cluster cluster") + if len(credentialList.Kubeconfigs) == 0 { + return nil, errors.New("no kubeconfigs available for the managed cluster") } - return *(*credentialList.Kubeconfigs)[0].Value, nil + return credentialList.Kubeconfigs[0].Value, nil } // CreateOrUpdateAsync creates or updates a managed cluster. -// It sends a PUT request to Azure and if accepted without error, the func will return a Future which can be used to track the ongoing +// It sends a PUT request to Azure and if accepted without error, the func will return a Poller which can be used to track the ongoing // progress of the operation. -func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.ResourceSpecGetter, parameters interface{}) (result interface{}, future azureautorest.FutureAPI, err error) { - ctx, _, done := tele.StartSpanWithLogger(ctx, "managedclusters.azureClient.CreateOrUpdate") +func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string, parameters interface{}) ( + result interface{}, poller *runtime.Poller[armcontainerservice.ManagedClustersClientCreateOrUpdateResponse], err error) { + ctx, log, done := tele.StartSpanWithLogger(ctx, "managedclusters.azureClient.CreateOrUpdateAsync") defer done() - managedcluster, ok := parameters.(containerservice.ManagedCluster) - if !ok { - return nil, nil, errors.Errorf("%T is not a containerservice.ManagedCluster", parameters) - } - - preparer, err := ac.managedclusters.CreateOrUpdatePreparer(ctx, spec.ResourceGroupName(), spec.ResourceName(), managedcluster) - if err != nil { - return nil, nil, errors.Wrap(err, "failed to prepare operation") - } - - headerSpec, ok := spec.(azure.ResourceSpecGetterWithHeaders) - if !ok { - return nil, nil, errors.Errorf("%T is not a azure.ResourceSpecGetterWithHeaders", spec) - } - - for key, value := range headerSpec.CustomHeaders() { - preparer.Header.Add(key, value) + var managedCluster armcontainerservice.ManagedCluster + if parameters != nil { + mc, ok := parameters.(armcontainerservice.ManagedCluster) + if !ok { + return nil, nil, errors.Errorf("%T is not an armcontainerservice.ManagedCluster", parameters) + } + managedCluster = mc } - createFuture, err := ac.managedclusters.CreateOrUpdateSender(preparer) + opts := &armcontainerservice.ManagedClustersClientBeginCreateOrUpdateOptions{ResumeToken: resumeToken} + log.V(4).Info("sending request", "resumeToken", resumeToken) + poller, err = ac.managedclusters.BeginCreateOrUpdate(ctx, spec.ResourceGroupName(), spec.ResourceName(), managedCluster, opts) if err != nil { return nil, nil, err } @@ -113,26 +107,28 @@ func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.Resou ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) defer cancel() - err = createFuture.WaitForCompletionRef(ctx, ac.managedclusters.Client) + pollOpts := &runtime.PollUntilDoneOptions{Frequency: asyncpoller.DefaultPollerFrequency} + resp, err := poller.PollUntilDone(ctx, pollOpts) if err != nil { - // if an error occurs, return the future. - // this means the long-running operation didn't finish in the specified timeout. - return nil, &createFuture, err + // If an error occurs, return the poller. + return nil, poller, err } - result, err = createFuture.Result(ac.managedclusters) - // if the operation completed, return a nil future - return result, nil, err + // if the operation completed, return a nil poller + return resp.ManagedCluster, nil, err } // DeleteAsync deletes a managed cluster asynchronously. DeleteAsync sends a DELETE -// request to Azure and if accepted without error, the func will return a Future which can be used to track the ongoing +// request to Azure and if accepted without error, the func will return a Poller which can be used to track the ongoing // progress of the operation. -func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecGetter) (future azureautorest.FutureAPI, err error) { - ctx, _, done := tele.StartSpanWithLogger(ctx, "managedclusters.azureClient.DeleteAsync") +func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecGetter, resumeToken string) ( + poller *runtime.Poller[armcontainerservice.ManagedClustersClientDeleteResponse], err error) { + ctx, log, done := tele.StartSpanWithLogger(ctx, "managedclusters.azureClient.DeleteAsync") defer done() - deleteFuture, err := ac.managedclusters.Delete(ctx, spec.ResourceGroupName(), spec.ResourceName()) + opts := &armcontainerservice.ManagedClustersClientBeginDeleteOptions{ResumeToken: resumeToken} + log.V(4).Info("sending request", "resumeToken", resumeToken) + poller, err = ac.managedclusters.BeginDelete(ctx, spec.ResourceGroupName(), spec.ResourceName(), opts) if err != nil { return nil, err } @@ -140,54 +136,14 @@ func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) defer cancel() - err = deleteFuture.WaitForCompletionRef(ctx, ac.managedclusters.Client) + pollOpts := &runtime.PollUntilDoneOptions{Frequency: asyncpoller.DefaultPollerFrequency} + _, err = poller.PollUntilDone(ctx, pollOpts) if err != nil { - // if an error occurs, return the future. - // this means the long-running operation didn't finish in the specified timeout. - return &deleteFuture, err + // If an error occurs, return the poller. + // This means the long-running operation didn't finish in the specified timeout. + return poller, err } - _, err = deleteFuture.Result(ac.managedclusters) - // if the operation completed, return a nil future. - return nil, err -} - -// IsDone returns true if the long-running operation has completed. -func (ac *azureClient) IsDone(ctx context.Context, future azureautorest.FutureAPI) (bool, error) { - ctx, _, done := tele.StartSpanWithLogger(ctx, "managedclusters.azureClient.IsDone") - defer done() - - return future.DoneWithContext(ctx, ac.managedclusters) -} - -// Result fetches the result of a long-running operation future. -func (ac *azureClient) Result(ctx context.Context, future azureautorest.FutureAPI, futureType string) (result interface{}, err error) { - _, _, done := tele.StartSpanWithLogger(ctx, "managedclusters.azureClient.Result") - defer done() - if future == nil { - return nil, errors.Errorf("cannot get result from nil future") - } - - switch futureType { - case infrav1.PutFuture: - // Marshal and Unmarshal the future to put it into the correct future type so we can access the Result function. - // Unfortunately the FutureAPI can't be casted directly to ManagedClustersCreateOrUpdateFuture because it is a azureautorest.Future, which doesn't implement the Result function. See PR #1686 for discussion on alternatives. - // It was converted back to a generic azureautorest.Future from the CAPZ infrav1.Future type stored in Status: https://github.com/kubernetes-sigs/cluster-api-provider-azure/blob/main/azure/converters/futures.go#L49. - var createFuture *containerservice.ManagedClustersCreateOrUpdateFuture - jsonData, err := future.MarshalJSON() - if err != nil { - return nil, errors.Wrap(err, "failed to marshal future") - } - if err := json.Unmarshal(jsonData, &createFuture); err != nil { - return nil, errors.Wrap(err, "failed to unmarshal future data") - } - return createFuture.Result(ac.managedclusters) - - case infrav1.DeleteFuture: - // Delete does not return a result managed cluster. - return nil, nil - - default: - return nil, errors.Errorf("unknown future type %q", futureType) - } + // if the operation completed, return a nil poller. + return nil, err } diff --git a/azure/services/managedclusters/managedclusters.go b/azure/services/managedclusters/managedclusters.go index 9ec778de75c..51f34df44ae 100644 --- a/azure/services/managedclusters/managedclusters.go +++ b/azure/services/managedclusters/managedclusters.go @@ -19,13 +19,13 @@ package managedclusters import ( "context" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" "k8s.io/utils/ptr" infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" "sigs.k8s.io/cluster-api-provider-azure/azure" - "sigs.k8s.io/cluster-api-provider-azure/azure/services/async" + "sigs.k8s.io/cluster-api-provider-azure/azure/services/asyncpoller" "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -50,18 +50,22 @@ type ManagedClusterScope interface { // Service provides operations on azure resources. type Service struct { Scope ManagedClusterScope - async.Reconciler + asyncpoller.Reconciler CredentialGetter } // New creates a new service. -func New(scope ManagedClusterScope) *Service { - client := newClient(scope) +func New(scope ManagedClusterScope) (*Service, error) { + client, err := newClient(scope) + if err != nil { + return nil, err + } return &Service{ - Scope: scope, - Reconciler: async.New(scope, client, client), + Scope: scope, + Reconciler: asyncpoller.New[armcontainerservice.ManagedClustersClientCreateOrUpdateResponse, + armcontainerservice.ManagedClustersClientDeleteResponse](scope, client, client), CredentialGetter: client, - } + }, nil } // Name returns the service name. @@ -84,13 +88,13 @@ func (s *Service) Reconcile(ctx context.Context) error { result, resultErr := s.CreateOrUpdateResource(ctx, managedClusterSpec, serviceName) if resultErr == nil { - managedCluster, ok := result.(containerservice.ManagedCluster) + managedCluster, ok := result.(armcontainerservice.ManagedCluster) if !ok { - return errors.Errorf("%T is not a containerservice.ManagedCluster", result) + return errors.Errorf("%T is not an armcontainerservice.ManagedCluster\n%v\n%v", result, result, managedCluster) } // Update control plane endpoint. endpoint := clusterv1.APIEndpoint{ - Host: ptr.Deref(managedCluster.ManagedClusterProperties.Fqdn, ""), + Host: ptr.Deref(managedCluster.Properties.Fqdn, ""), Port: 443, } s.Scope.SetControlPlaneEndpoint(endpoint) @@ -105,7 +109,7 @@ func (s *Service) Reconcile(ctx context.Context) error { // This field gets populated by AKS when not set by the user. Persist AKS's value so for future diffs, // the "before" reflects the correct value. - if id := managedCluster.ManagedClusterProperties.IdentityProfile[kubeletIdentityKey]; id != nil && id.ResourceID != nil { + if id := managedCluster.Properties.IdentityProfile[kubeletIdentityKey]; id != nil && id.ResourceID != nil { s.Scope.SetKubeletIdentity(*id.ResourceID) } } diff --git a/azure/services/managedclusters/managedclusters_test.go b/azure/services/managedclusters/managedclusters_test.go index 3c38efd6099..52ed19d3657 100644 --- a/azure/services/managedclusters/managedclusters_test.go +++ b/azure/services/managedclusters/managedclusters_test.go @@ -21,7 +21,7 @@ import ( "errors" "testing" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" . "github.com/onsi/gomega" "go.uber.org/mock/gomock" "k8s.io/utils/ptr" @@ -61,11 +61,11 @@ func TestReconcile(t *testing.T) { expectedError: "", expect: func(m *mock_managedclusters.MockCredentialGetterMockRecorder, s *mock_managedclusters.MockManagedClusterScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { s.ManagedClusterSpec().Return(fakeManagedClusterSpec) - r.CreateOrUpdateResource(gomockinternal.AContext(), fakeManagedClusterSpec, serviceName).Return(containerservice.ManagedCluster{ - ManagedClusterProperties: &containerservice.ManagedClusterProperties{ + r.CreateOrUpdateResource(gomockinternal.AContext(), fakeManagedClusterSpec, serviceName).Return(armcontainerservice.ManagedCluster{ + Properties: &armcontainerservice.ManagedClusterProperties{ Fqdn: ptr.To("my-managedcluster-fqdn"), ProvisioningState: ptr.To("Succeeded"), - IdentityProfile: map[string]*containerservice.UserAssignedIdentity{ + IdentityProfile: map[string]*armcontainerservice.UserAssignedIdentity{ kubeletIdentityKey: { ResourceID: ptr.To("kubelet-id"), }, @@ -87,8 +87,8 @@ func TestReconcile(t *testing.T) { expectedError: "failed to get credentials for managed cluster: internal server error", expect: func(m *mock_managedclusters.MockCredentialGetterMockRecorder, s *mock_managedclusters.MockManagedClusterScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { s.ManagedClusterSpec().Return(fakeManagedClusterSpec) - r.CreateOrUpdateResource(gomockinternal.AContext(), fakeManagedClusterSpec, serviceName).Return(containerservice.ManagedCluster{ - ManagedClusterProperties: &containerservice.ManagedClusterProperties{ + r.CreateOrUpdateResource(gomockinternal.AContext(), fakeManagedClusterSpec, serviceName).Return(armcontainerservice.ManagedCluster{ + Properties: &armcontainerservice.ManagedClusterProperties{ Fqdn: ptr.To("my-managedcluster-fqdn"), ProvisioningState: ptr.To("Succeeded"), }, diff --git a/azure/services/managedclusters/spec.go b/azure/services/managedclusters/spec.go index f6ca3d6282d..1114e0f9852 100644 --- a/azure/services/managedclusters/spec.go +++ b/azure/services/managedclusters/spec.go @@ -24,7 +24,7 @@ import ( "reflect" "time" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" "github.com/google/go-cmp/cmp" "github.com/pkg/errors" "k8s.io/utils/ptr" @@ -254,12 +254,12 @@ func (s *ManagedClusterSpec) CustomHeaders() map[string]string { } // buildAutoScalerProfile builds the AutoScalerProfile for the ManagedClusterProperties. -func buildAutoScalerProfile(autoScalerProfile *AutoScalerProfile) *containerservice.ManagedClusterPropertiesAutoScalerProfile { +func buildAutoScalerProfile(autoScalerProfile *AutoScalerProfile) *armcontainerservice.ManagedClusterPropertiesAutoScalerProfile { if autoScalerProfile == nil { return nil } - mcAutoScalerProfile := &containerservice.ManagedClusterPropertiesAutoScalerProfile{ + mcAutoScalerProfile := &armcontainerservice.ManagedClusterPropertiesAutoScalerProfile{ BalanceSimilarNodeGroups: autoScalerProfile.BalanceSimilarNodeGroups, MaxEmptyBulkDelete: autoScalerProfile.MaxEmptyBulkDelete, MaxGracefulTerminationSec: autoScalerProfile.MaxGracefulTerminationSec, @@ -278,7 +278,7 @@ func buildAutoScalerProfile(autoScalerProfile *AutoScalerProfile) *containerserv SkipNodesWithSystemPods: autoScalerProfile.SkipNodesWithSystemPods, } if autoScalerProfile.Expander != nil { - mcAutoScalerProfile.Expander = containerservice.Expander(*autoScalerProfile.Expander) + mcAutoScalerProfile.Expander = ptr.To(armcontainerservice.Expander(*autoScalerProfile.Expander)) } return mcAutoScalerProfile @@ -299,9 +299,9 @@ func (s *ManagedClusterSpec) Parameters(ctx context.Context, existing interface{ } } - managedCluster := containerservice.ManagedCluster{ - Identity: &containerservice.ManagedClusterIdentity{ - Type: containerservice.ResourceIdentityTypeSystemAssigned, + managedCluster := armcontainerservice.ManagedCluster{ + Identity: &armcontainerservice.ManagedClusterIdentity{ + Type: ptr.To(armcontainerservice.ResourceIdentityTypeSystemAssigned), }, Location: &s.Location, Tags: converters.TagsToMap(infrav1.Build(infrav1.BuildParams{ @@ -311,29 +311,29 @@ func (s *ManagedClusterSpec) Parameters(ctx context.Context, existing interface{ Role: ptr.To(infrav1.CommonRole), Additional: s.Tags, })), - ManagedClusterProperties: &containerservice.ManagedClusterProperties{ + Properties: &armcontainerservice.ManagedClusterProperties{ NodeResourceGroup: &s.NodeResourceGroup, EnableRBAC: ptr.To(true), DNSPrefix: &s.Name, KubernetesVersion: &s.Version, - ServicePrincipalProfile: &containerservice.ManagedClusterServicePrincipalProfile{ + ServicePrincipalProfile: &armcontainerservice.ManagedClusterServicePrincipalProfile{ ClientID: ptr.To("msi"), }, - AgentPoolProfiles: &[]containerservice.ManagedClusterAgentPoolProfile{}, - NetworkProfile: &containerservice.NetworkProfile{ - NetworkPlugin: containerservice.NetworkPlugin(s.NetworkPlugin), - LoadBalancerSku: containerservice.LoadBalancerSku(s.LoadBalancerSKU), - NetworkPolicy: containerservice.NetworkPolicy(s.NetworkPolicy), + AgentPoolProfiles: []*armcontainerservice.ManagedClusterAgentPoolProfile{}, + NetworkProfile: &armcontainerservice.NetworkProfile{ + NetworkPlugin: azure.AliasOrNil[armcontainerservice.NetworkPlugin](&s.NetworkPlugin), + LoadBalancerSKU: azure.AliasOrNil[armcontainerservice.LoadBalancerSKU](&s.LoadBalancerSKU), + NetworkPolicy: azure.AliasOrNil[armcontainerservice.NetworkPolicy](&s.NetworkPolicy), }, }, } if decodedSSHPublicKey != nil { - managedCluster.LinuxProfile = &containerservice.LinuxProfile{ + managedCluster.Properties.LinuxProfile = &armcontainerservice.LinuxProfile{ AdminUsername: ptr.To(azure.DefaultAKSUserName), - SSH: &containerservice.SSHConfiguration{ - PublicKeys: &[]containerservice.SSHPublicKey{ + SSH: &armcontainerservice.SSHConfiguration{ + PublicKeys: []*armcontainerservice.SSHPublicKey{ { KeyData: ptr.To(string(decodedSSHPublicKey)), }, @@ -343,12 +343,12 @@ func (s *ManagedClusterSpec) Parameters(ctx context.Context, existing interface{ } if s.PodCIDR != "" { - managedCluster.NetworkProfile.PodCidr = &s.PodCIDR + managedCluster.Properties.NetworkProfile.PodCidr = &s.PodCIDR } if s.ServiceCIDR != "" { if s.DNSServiceIP == nil { - managedCluster.NetworkProfile.ServiceCidr = &s.ServiceCIDR + managedCluster.Properties.NetworkProfile.ServiceCidr = &s.ServiceCIDR ip, _, err := net.ParseCIDR(s.ServiceCIDR) if err != nil { return nil, fmt.Errorf("failed to parse service cidr: %w", err) @@ -359,63 +359,63 @@ func (s *ManagedClusterSpec) Parameters(ctx context.Context, existing interface{ // https://golang.org/src/net/ip.go#L48 ip[15] = byte(10) dnsIP := ip.String() - managedCluster.NetworkProfile.DNSServiceIP = &dnsIP + managedCluster.Properties.NetworkProfile.DNSServiceIP = &dnsIP } else { - managedCluster.NetworkProfile.DNSServiceIP = s.DNSServiceIP + managedCluster.Properties.NetworkProfile.DNSServiceIP = s.DNSServiceIP } } if s.AADProfile != nil { - managedCluster.AadProfile = &containerservice.ManagedClusterAADProfile{ + managedCluster.Properties.AADProfile = &armcontainerservice.ManagedClusterAADProfile{ Managed: &s.AADProfile.Managed, EnableAzureRBAC: &s.AADProfile.EnableAzureRBAC, - AdminGroupObjectIDs: &s.AADProfile.AdminGroupObjectIDs, + AdminGroupObjectIDs: azure.PtrSlice[string](&s.AADProfile.AdminGroupObjectIDs), } } for i := range s.AddonProfiles { - if managedCluster.AddonProfiles == nil { - managedCluster.AddonProfiles = map[string]*containerservice.ManagedClusterAddonProfile{} + if managedCluster.Properties.AddonProfiles == nil { + managedCluster.Properties.AddonProfiles = map[string]*armcontainerservice.ManagedClusterAddonProfile{} } item := s.AddonProfiles[i] - addonProfile := &containerservice.ManagedClusterAddonProfile{ + addonProfile := &armcontainerservice.ManagedClusterAddonProfile{ Enabled: &item.Enabled, } if item.Config != nil { addonProfile.Config = azure.StringMapPtr(item.Config) } - managedCluster.AddonProfiles[item.Name] = addonProfile + managedCluster.Properties.AddonProfiles[item.Name] = addonProfile } if s.SKU != nil { - tierName := containerservice.ManagedClusterSKUTier(s.SKU.Tier) - managedCluster.Sku = &containerservice.ManagedClusterSKU{ - Name: containerservice.ManagedClusterSKUNameBasic, - Tier: tierName, + tierName := armcontainerservice.ManagedClusterSKUTier(s.SKU.Tier) + managedCluster.SKU = &armcontainerservice.ManagedClusterSKU{ + Name: ptr.To(armcontainerservice.ManagedClusterSKUName("Base")), + Tier: ptr.To(tierName), } } if s.LoadBalancerProfile != nil { - managedCluster.NetworkProfile.LoadBalancerProfile = s.GetLoadBalancerProfile() + managedCluster.Properties.NetworkProfile.LoadBalancerProfile = s.GetLoadBalancerProfile() } if s.APIServerAccessProfile != nil { - managedCluster.APIServerAccessProfile = &containerservice.ManagedClusterAPIServerAccessProfile{ + managedCluster.Properties.APIServerAccessProfile = &armcontainerservice.ManagedClusterAPIServerAccessProfile{ EnablePrivateCluster: s.APIServerAccessProfile.EnablePrivateCluster, PrivateDNSZone: s.APIServerAccessProfile.PrivateDNSZone, EnablePrivateClusterPublicFQDN: s.APIServerAccessProfile.EnablePrivateClusterPublicFQDN, } if s.APIServerAccessProfile.AuthorizedIPRanges != nil { - managedCluster.APIServerAccessProfile.AuthorizedIPRanges = &s.APIServerAccessProfile.AuthorizedIPRanges + managedCluster.Properties.APIServerAccessProfile.AuthorizedIPRanges = azure.PtrSlice[string](&s.APIServerAccessProfile.AuthorizedIPRanges) } } if s.OutboundType != nil { - managedCluster.NetworkProfile.OutboundType = containerservice.OutboundType(*s.OutboundType) + managedCluster.Properties.NetworkProfile.OutboundType = ptr.To(armcontainerservice.OutboundType(*s.OutboundType)) } - managedCluster.AutoScalerProfile = buildAutoScalerProfile(s.AutoScalerProfile) + managedCluster.Properties.AutoScalerProfile = buildAutoScalerProfile(s.AutoScalerProfile) if s.Identity != nil { managedCluster.Identity, err = getIdentity(s.Identity) @@ -425,7 +425,7 @@ func (s *ManagedClusterSpec) Parameters(ctx context.Context, existing interface{ } if s.KubeletUserAssignedIdentity != "" { - managedCluster.ManagedClusterProperties.IdentityProfile = map[string]*containerservice.UserAssignedIdentity{ + managedCluster.Properties.IdentityProfile = map[string]*armcontainerservice.UserAssignedIdentity{ kubeletIdentityKey: { ResourceID: ptr.To(s.KubeletUserAssignedIdentity), }, @@ -433,48 +433,48 @@ func (s *ManagedClusterSpec) Parameters(ctx context.Context, existing interface{ } if s.HTTPProxyConfig != nil { - managedCluster.HTTPProxyConfig = &containerservice.ManagedClusterHTTPProxyConfig{ + managedCluster.Properties.HTTPProxyConfig = &armcontainerservice.ManagedClusterHTTPProxyConfig{ HTTPProxy: s.HTTPProxyConfig.HTTPProxy, HTTPSProxy: s.HTTPProxyConfig.HTTPSProxy, TrustedCa: s.HTTPProxyConfig.TrustedCA, } if s.HTTPProxyConfig.NoProxy != nil { - managedCluster.HTTPProxyConfig.NoProxy = &s.HTTPProxyConfig.NoProxy + managedCluster.Properties.HTTPProxyConfig.NoProxy = azure.PtrSlice(&s.HTTPProxyConfig.NoProxy) } } if existing != nil { - existingMC, ok := existing.(containerservice.ManagedCluster) + existingMC, ok := existing.(armcontainerservice.ManagedCluster) if !ok { - return nil, fmt.Errorf("%T is not a containerservice.ManagedCluster", existing) + return nil, fmt.Errorf("%T is not an armcontainerservice.ManagedCluster", existing) } - ps := *existingMC.ManagedClusterProperties.ProvisioningState + ps := *existingMC.Properties.ProvisioningState if ps != string(infrav1.Canceled) && ps != string(infrav1.Failed) && ps != string(infrav1.Succeeded) { return nil, azure.WithTransientError(errors.Errorf("Unable to update existing managed cluster in non-terminal state. Managed cluster must be in one of the following provisioning states: Canceled, Failed, or Succeeded. Actual state: %s", ps), 20*time.Second) } // Normalize the LoadBalancerProfile so the diff below doesn't get thrown off by AKS added properties. - if managedCluster.NetworkProfile.LoadBalancerProfile == nil { + if managedCluster.Properties.NetworkProfile.LoadBalancerProfile == nil { // If our LoadBalancerProfile generated by the spec is nil, then don't worry about what AKS has added. - existingMC.NetworkProfile.LoadBalancerProfile = nil + existingMC.Properties.NetworkProfile.LoadBalancerProfile = nil } else { // If our LoadBalancerProfile generated by the spec is not nil, then remove the effective outbound IPs from // AKS. - existingMC.NetworkProfile.LoadBalancerProfile.EffectiveOutboundIPs = nil + existingMC.Properties.NetworkProfile.LoadBalancerProfile.EffectiveOutboundIPs = nil } // Avoid changing agent pool profiles through AMCP and just use the existing agent pool profiles // AgentPool changes are managed through AMMP. - managedCluster.AgentPoolProfiles = existingMC.AgentPoolProfiles + managedCluster.Properties.AgentPoolProfiles = existingMC.Properties.AgentPoolProfiles // if the AuthorizedIPRanges is nil in the user-updated spec, but not nil in the existing spec, then - // we need to set the AuthorizedIPRanges to empty array (&[]string{}) once so that the Azure API will + // we need to set the AuthorizedIPRanges to empty array ([]*string{}) once so that the Azure API will // update the existing authorized IP ranges to nil. if !isAuthIPRangesNilOrEmpty(existingMC) && isAuthIPRangesNilOrEmpty(managedCluster) { log.V(4).Info("managed cluster spec has nil AuthorizedIPRanges, updating existing authorized IP ranges to an empty list") - managedCluster.APIServerAccessProfile = &containerservice.ManagedClusterAPIServerAccessProfile{ - AuthorizedIPRanges: &[]string{}, + managedCluster.Properties.APIServerAccessProfile = &armcontainerservice.ManagedClusterAPIServerAccessProfile{ + AuthorizedIPRanges: []*string{}, } } @@ -496,218 +496,218 @@ func (s *ManagedClusterSpec) Parameters(ctx context.Context, existing interface{ if err != nil { return nil, errors.Wrapf(err, "failed to get agent pool parameters for managed cluster %s", s.Name) } - agentPool, ok := params.(containerservice.AgentPool) + agentPool, ok := params.(armcontainerservice.AgentPool) if !ok { - return nil, fmt.Errorf("%T is not a containerservice.AgentPool", agentPool) + return nil, fmt.Errorf("%T is not an armcontainerservice.AgentPool", agentPool) } agentPool.Name = ptr.To(spec.ResourceName()) profile := converters.AgentPoolToManagedClusterAgentPoolProfile(agentPool) - *managedCluster.AgentPoolProfiles = append(*managedCluster.AgentPoolProfiles, profile) + managedCluster.Properties.AgentPoolProfiles = append(managedCluster.Properties.AgentPoolProfiles, &profile) } } return managedCluster, nil } -// GetLoadBalancerProfile returns a containerservice.ManagedClusterLoadBalancerProfile from the +// GetLoadBalancerProfile returns an armcontainerservice.ManagedClusterLoadBalancerProfile from the // information present in ManagedClusterSpec.LoadBalancerProfile. -func (s *ManagedClusterSpec) GetLoadBalancerProfile() (loadBalancerProfile *containerservice.ManagedClusterLoadBalancerProfile) { - loadBalancerProfile = &containerservice.ManagedClusterLoadBalancerProfile{ +func (s *ManagedClusterSpec) GetLoadBalancerProfile() (loadBalancerProfile *armcontainerservice.ManagedClusterLoadBalancerProfile) { + loadBalancerProfile = &armcontainerservice.ManagedClusterLoadBalancerProfile{ AllocatedOutboundPorts: s.LoadBalancerProfile.AllocatedOutboundPorts, IdleTimeoutInMinutes: s.LoadBalancerProfile.IdleTimeoutInMinutes, } if s.LoadBalancerProfile.ManagedOutboundIPs != nil { - loadBalancerProfile.ManagedOutboundIPs = &containerservice.ManagedClusterLoadBalancerProfileManagedOutboundIPs{Count: s.LoadBalancerProfile.ManagedOutboundIPs} + loadBalancerProfile.ManagedOutboundIPs = &armcontainerservice.ManagedClusterLoadBalancerProfileManagedOutboundIPs{Count: s.LoadBalancerProfile.ManagedOutboundIPs} } if len(s.LoadBalancerProfile.OutboundIPPrefixes) > 0 { - loadBalancerProfile.OutboundIPPrefixes = &containerservice.ManagedClusterLoadBalancerProfileOutboundIPPrefixes{ + loadBalancerProfile.OutboundIPPrefixes = &armcontainerservice.ManagedClusterLoadBalancerProfileOutboundIPPrefixes{ PublicIPPrefixes: convertToResourceReferences(s.LoadBalancerProfile.OutboundIPPrefixes), } } if len(s.LoadBalancerProfile.OutboundIPs) > 0 { - loadBalancerProfile.OutboundIPs = &containerservice.ManagedClusterLoadBalancerProfileOutboundIPs{ + loadBalancerProfile.OutboundIPs = &armcontainerservice.ManagedClusterLoadBalancerProfileOutboundIPs{ PublicIPs: convertToResourceReferences(s.LoadBalancerProfile.OutboundIPs), } } return } -func convertToResourceReferences(resources []string) *[]containerservice.ResourceReference { - resourceReferences := make([]containerservice.ResourceReference, len(resources)) +func convertToResourceReferences(resources []string) []*armcontainerservice.ResourceReference { + resourceReferences := make([]*armcontainerservice.ResourceReference, len(resources)) for i := range resources { - resourceReferences[i] = containerservice.ResourceReference{ID: &resources[i]} + resourceReferences[i] = &armcontainerservice.ResourceReference{ID: &resources[i]} } - return &resourceReferences + return resourceReferences } -func computeDiffOfNormalizedClusters(managedCluster containerservice.ManagedCluster, existingMC containerservice.ManagedCluster) string { +func computeDiffOfNormalizedClusters(managedCluster armcontainerservice.ManagedCluster, existingMC armcontainerservice.ManagedCluster) string { // Normalize properties for the desired (CR spec) and existing managed // cluster, so that we check only those fields that were specified in // the initial CreateOrUpdate request and that can be modified. // Without comparing to normalized properties, we would always get a // difference in desired and existing, which would result in sending // unnecessary Azure API requests. - propertiesNormalized := &containerservice.ManagedClusterProperties{ - KubernetesVersion: managedCluster.ManagedClusterProperties.KubernetesVersion, - NetworkProfile: &containerservice.NetworkProfile{}, - AutoScalerProfile: &containerservice.ManagedClusterPropertiesAutoScalerProfile{}, + propertiesNormalized := &armcontainerservice.ManagedClusterProperties{ + KubernetesVersion: managedCluster.Properties.KubernetesVersion, + NetworkProfile: &armcontainerservice.NetworkProfile{}, + AutoScalerProfile: &armcontainerservice.ManagedClusterPropertiesAutoScalerProfile{}, } - existingMCPropertiesNormalized := &containerservice.ManagedClusterProperties{ - KubernetesVersion: existingMC.ManagedClusterProperties.KubernetesVersion, - NetworkProfile: &containerservice.NetworkProfile{}, - AutoScalerProfile: &containerservice.ManagedClusterPropertiesAutoScalerProfile{}, + existingMCPropertiesNormalized := &armcontainerservice.ManagedClusterProperties{ + KubernetesVersion: existingMC.Properties.KubernetesVersion, + NetworkProfile: &armcontainerservice.NetworkProfile{}, + AutoScalerProfile: &armcontainerservice.ManagedClusterPropertiesAutoScalerProfile{}, } - if managedCluster.AadProfile != nil { - propertiesNormalized.AadProfile = &containerservice.ManagedClusterAADProfile{ - Managed: managedCluster.AadProfile.Managed, - EnableAzureRBAC: managedCluster.AadProfile.EnableAzureRBAC, - AdminGroupObjectIDs: managedCluster.AadProfile.AdminGroupObjectIDs, + if managedCluster.Properties.AADProfile != nil { + propertiesNormalized.AADProfile = &armcontainerservice.ManagedClusterAADProfile{ + Managed: managedCluster.Properties.AADProfile.Managed, + EnableAzureRBAC: managedCluster.Properties.AADProfile.EnableAzureRBAC, + AdminGroupObjectIDs: managedCluster.Properties.AADProfile.AdminGroupObjectIDs, } } - if existingMC.AadProfile != nil { - existingMCPropertiesNormalized.AadProfile = &containerservice.ManagedClusterAADProfile{ - Managed: existingMC.AadProfile.Managed, - EnableAzureRBAC: existingMC.AadProfile.EnableAzureRBAC, - AdminGroupObjectIDs: existingMC.AadProfile.AdminGroupObjectIDs, + if existingMC.Properties.AADProfile != nil { + existingMCPropertiesNormalized.AADProfile = &armcontainerservice.ManagedClusterAADProfile{ + Managed: existingMC.Properties.AADProfile.Managed, + EnableAzureRBAC: existingMC.Properties.AADProfile.EnableAzureRBAC, + AdminGroupObjectIDs: existingMC.Properties.AADProfile.AdminGroupObjectIDs, } } - if managedCluster.NetworkProfile != nil { - propertiesNormalized.NetworkProfile.LoadBalancerProfile = managedCluster.NetworkProfile.LoadBalancerProfile + if managedCluster.Properties.NetworkProfile != nil { + propertiesNormalized.NetworkProfile.LoadBalancerProfile = managedCluster.Properties.NetworkProfile.LoadBalancerProfile } - if existingMC.NetworkProfile != nil { - existingMCPropertiesNormalized.NetworkProfile.LoadBalancerProfile = existingMC.NetworkProfile.LoadBalancerProfile + if existingMC.Properties.NetworkProfile != nil { + existingMCPropertiesNormalized.NetworkProfile.LoadBalancerProfile = existingMC.Properties.NetworkProfile.LoadBalancerProfile } - if managedCluster.APIServerAccessProfile != nil { - propertiesNormalized.APIServerAccessProfile = &containerservice.ManagedClusterAPIServerAccessProfile{ - AuthorizedIPRanges: managedCluster.APIServerAccessProfile.AuthorizedIPRanges, + if managedCluster.Properties.APIServerAccessProfile != nil { + propertiesNormalized.APIServerAccessProfile = &armcontainerservice.ManagedClusterAPIServerAccessProfile{ + AuthorizedIPRanges: managedCluster.Properties.APIServerAccessProfile.AuthorizedIPRanges, } } - if existingMC.APIServerAccessProfile != nil { - existingMCPropertiesNormalized.APIServerAccessProfile = &containerservice.ManagedClusterAPIServerAccessProfile{ - AuthorizedIPRanges: existingMC.APIServerAccessProfile.AuthorizedIPRanges, + if existingMC.Properties.APIServerAccessProfile != nil { + existingMCPropertiesNormalized.APIServerAccessProfile = &armcontainerservice.ManagedClusterAPIServerAccessProfile{ + AuthorizedIPRanges: existingMC.Properties.APIServerAccessProfile.AuthorizedIPRanges, } } - if managedCluster.AutoScalerProfile != nil { - propertiesNormalized.AutoScalerProfile = &containerservice.ManagedClusterPropertiesAutoScalerProfile{ - BalanceSimilarNodeGroups: managedCluster.AutoScalerProfile.BalanceSimilarNodeGroups, - Expander: managedCluster.AutoScalerProfile.Expander, - MaxEmptyBulkDelete: managedCluster.AutoScalerProfile.MaxEmptyBulkDelete, - MaxGracefulTerminationSec: managedCluster.AutoScalerProfile.MaxGracefulTerminationSec, - MaxNodeProvisionTime: managedCluster.AutoScalerProfile.MaxNodeProvisionTime, - MaxTotalUnreadyPercentage: managedCluster.AutoScalerProfile.MaxTotalUnreadyPercentage, - NewPodScaleUpDelay: managedCluster.AutoScalerProfile.NewPodScaleUpDelay, - OkTotalUnreadyCount: managedCluster.AutoScalerProfile.OkTotalUnreadyCount, - ScanInterval: managedCluster.AutoScalerProfile.ScanInterval, - ScaleDownDelayAfterAdd: managedCluster.AutoScalerProfile.ScaleDownDelayAfterAdd, - ScaleDownDelayAfterDelete: managedCluster.AutoScalerProfile.ScaleDownDelayAfterDelete, - ScaleDownDelayAfterFailure: managedCluster.AutoScalerProfile.ScaleDownDelayAfterFailure, - ScaleDownUnneededTime: managedCluster.AutoScalerProfile.ScaleDownUnneededTime, - ScaleDownUnreadyTime: managedCluster.AutoScalerProfile.ScaleDownUnreadyTime, - ScaleDownUtilizationThreshold: managedCluster.AutoScalerProfile.ScaleDownUtilizationThreshold, - SkipNodesWithLocalStorage: managedCluster.AutoScalerProfile.SkipNodesWithLocalStorage, - SkipNodesWithSystemPods: managedCluster.AutoScalerProfile.SkipNodesWithSystemPods, + if managedCluster.Properties.AutoScalerProfile != nil { + propertiesNormalized.AutoScalerProfile = &armcontainerservice.ManagedClusterPropertiesAutoScalerProfile{ + BalanceSimilarNodeGroups: managedCluster.Properties.AutoScalerProfile.BalanceSimilarNodeGroups, + Expander: managedCluster.Properties.AutoScalerProfile.Expander, + MaxEmptyBulkDelete: managedCluster.Properties.AutoScalerProfile.MaxEmptyBulkDelete, + MaxGracefulTerminationSec: managedCluster.Properties.AutoScalerProfile.MaxGracefulTerminationSec, + MaxNodeProvisionTime: managedCluster.Properties.AutoScalerProfile.MaxNodeProvisionTime, + MaxTotalUnreadyPercentage: managedCluster.Properties.AutoScalerProfile.MaxTotalUnreadyPercentage, + NewPodScaleUpDelay: managedCluster.Properties.AutoScalerProfile.NewPodScaleUpDelay, + OkTotalUnreadyCount: managedCluster.Properties.AutoScalerProfile.OkTotalUnreadyCount, + ScanInterval: managedCluster.Properties.AutoScalerProfile.ScanInterval, + ScaleDownDelayAfterAdd: managedCluster.Properties.AutoScalerProfile.ScaleDownDelayAfterAdd, + ScaleDownDelayAfterDelete: managedCluster.Properties.AutoScalerProfile.ScaleDownDelayAfterDelete, + ScaleDownDelayAfterFailure: managedCluster.Properties.AutoScalerProfile.ScaleDownDelayAfterFailure, + ScaleDownUnneededTime: managedCluster.Properties.AutoScalerProfile.ScaleDownUnneededTime, + ScaleDownUnreadyTime: managedCluster.Properties.AutoScalerProfile.ScaleDownUnreadyTime, + ScaleDownUtilizationThreshold: managedCluster.Properties.AutoScalerProfile.ScaleDownUtilizationThreshold, + SkipNodesWithLocalStorage: managedCluster.Properties.AutoScalerProfile.SkipNodesWithLocalStorage, + SkipNodesWithSystemPods: managedCluster.Properties.AutoScalerProfile.SkipNodesWithSystemPods, } } - if existingMC.AutoScalerProfile != nil { - existingMCPropertiesNormalized.AutoScalerProfile = &containerservice.ManagedClusterPropertiesAutoScalerProfile{ - BalanceSimilarNodeGroups: existingMC.AutoScalerProfile.BalanceSimilarNodeGroups, - Expander: existingMC.AutoScalerProfile.Expander, - MaxEmptyBulkDelete: existingMC.AutoScalerProfile.MaxEmptyBulkDelete, - MaxGracefulTerminationSec: existingMC.AutoScalerProfile.MaxGracefulTerminationSec, - MaxNodeProvisionTime: existingMC.AutoScalerProfile.MaxNodeProvisionTime, - MaxTotalUnreadyPercentage: existingMC.AutoScalerProfile.MaxTotalUnreadyPercentage, - NewPodScaleUpDelay: existingMC.AutoScalerProfile.NewPodScaleUpDelay, - OkTotalUnreadyCount: existingMC.AutoScalerProfile.OkTotalUnreadyCount, - ScanInterval: existingMC.AutoScalerProfile.ScanInterval, - ScaleDownDelayAfterAdd: existingMC.AutoScalerProfile.ScaleDownDelayAfterAdd, - ScaleDownDelayAfterDelete: existingMC.AutoScalerProfile.ScaleDownDelayAfterDelete, - ScaleDownDelayAfterFailure: existingMC.AutoScalerProfile.ScaleDownDelayAfterFailure, - ScaleDownUnneededTime: existingMC.AutoScalerProfile.ScaleDownUnneededTime, - ScaleDownUnreadyTime: existingMC.AutoScalerProfile.ScaleDownUnreadyTime, - ScaleDownUtilizationThreshold: existingMC.AutoScalerProfile.ScaleDownUtilizationThreshold, - SkipNodesWithLocalStorage: existingMC.AutoScalerProfile.SkipNodesWithLocalStorage, - SkipNodesWithSystemPods: existingMC.AutoScalerProfile.SkipNodesWithSystemPods, + if existingMC.Properties.AutoScalerProfile != nil { + existingMCPropertiesNormalized.AutoScalerProfile = &armcontainerservice.ManagedClusterPropertiesAutoScalerProfile{ + BalanceSimilarNodeGroups: existingMC.Properties.AutoScalerProfile.BalanceSimilarNodeGroups, + Expander: existingMC.Properties.AutoScalerProfile.Expander, + MaxEmptyBulkDelete: existingMC.Properties.AutoScalerProfile.MaxEmptyBulkDelete, + MaxGracefulTerminationSec: existingMC.Properties.AutoScalerProfile.MaxGracefulTerminationSec, + MaxNodeProvisionTime: existingMC.Properties.AutoScalerProfile.MaxNodeProvisionTime, + MaxTotalUnreadyPercentage: existingMC.Properties.AutoScalerProfile.MaxTotalUnreadyPercentage, + NewPodScaleUpDelay: existingMC.Properties.AutoScalerProfile.NewPodScaleUpDelay, + OkTotalUnreadyCount: existingMC.Properties.AutoScalerProfile.OkTotalUnreadyCount, + ScanInterval: existingMC.Properties.AutoScalerProfile.ScanInterval, + ScaleDownDelayAfterAdd: existingMC.Properties.AutoScalerProfile.ScaleDownDelayAfterAdd, + ScaleDownDelayAfterDelete: existingMC.Properties.AutoScalerProfile.ScaleDownDelayAfterDelete, + ScaleDownDelayAfterFailure: existingMC.Properties.AutoScalerProfile.ScaleDownDelayAfterFailure, + ScaleDownUnneededTime: existingMC.Properties.AutoScalerProfile.ScaleDownUnneededTime, + ScaleDownUnreadyTime: existingMC.Properties.AutoScalerProfile.ScaleDownUnreadyTime, + ScaleDownUtilizationThreshold: existingMC.Properties.AutoScalerProfile.ScaleDownUtilizationThreshold, + SkipNodesWithLocalStorage: existingMC.Properties.AutoScalerProfile.SkipNodesWithLocalStorage, + SkipNodesWithSystemPods: existingMC.Properties.AutoScalerProfile.SkipNodesWithSystemPods, } } - if managedCluster.IdentityProfile != nil { - propertiesNormalized.IdentityProfile = map[string]*containerservice.UserAssignedIdentity{ + if managedCluster.Properties.IdentityProfile != nil { + propertiesNormalized.IdentityProfile = map[string]*armcontainerservice.UserAssignedIdentity{ kubeletIdentityKey: { - ResourceID: managedCluster.IdentityProfile[kubeletIdentityKey].ResourceID, + ResourceID: managedCluster.Properties.IdentityProfile[kubeletIdentityKey].ResourceID, }, } } - if existingMC.IdentityProfile != nil { - existingMCPropertiesNormalized.IdentityProfile = map[string]*containerservice.UserAssignedIdentity{ + if existingMC.Properties.IdentityProfile != nil { + existingMCPropertiesNormalized.IdentityProfile = map[string]*armcontainerservice.UserAssignedIdentity{ kubeletIdentityKey: { - ResourceID: existingMC.IdentityProfile[kubeletIdentityKey].ResourceID, + ResourceID: existingMC.Properties.IdentityProfile[kubeletIdentityKey].ResourceID, }, } } // Once the AKS autoscaler has been updated it will always return values so we need to // respect those values even though the settings are now not being explicitly set by CAPZ. - if existingMC.AutoScalerProfile != nil && managedCluster.AutoScalerProfile == nil { + if existingMC.Properties.AutoScalerProfile != nil && managedCluster.Properties.AutoScalerProfile == nil { existingMCPropertiesNormalized.AutoScalerProfile = nil propertiesNormalized.AutoScalerProfile = nil } - clusterNormalized := &containerservice.ManagedCluster{ - ManagedClusterProperties: propertiesNormalized, + clusterNormalized := &armcontainerservice.ManagedCluster{ + Properties: propertiesNormalized, } - existingMCClusterNormalized := &containerservice.ManagedCluster{ - ManagedClusterProperties: existingMCPropertiesNormalized, + existingMCClusterNormalized := &armcontainerservice.ManagedCluster{ + Properties: existingMCPropertiesNormalized, } if managedCluster.Identity != nil { - clusterNormalized.Identity = &containerservice.ManagedClusterIdentity{ + clusterNormalized.Identity = &armcontainerservice.ManagedClusterIdentity{ Type: managedCluster.Identity.Type, UserAssignedIdentities: managedCluster.Identity.UserAssignedIdentities, } } if existingMC.Identity != nil { - existingMCClusterNormalized.Identity = &containerservice.ManagedClusterIdentity{ + existingMCClusterNormalized.Identity = &armcontainerservice.ManagedClusterIdentity{ Type: existingMC.Identity.Type, UserAssignedIdentities: existingMC.Identity.UserAssignedIdentities, } } - if managedCluster.Sku != nil { - clusterNormalized.Sku = managedCluster.Sku + if managedCluster.SKU != nil { + clusterNormalized.SKU = managedCluster.SKU } - if existingMC.Sku != nil { - existingMCClusterNormalized.Sku = existingMC.Sku + if existingMC.SKU != nil { + existingMCClusterNormalized.SKU = existingMC.SKU } diff := cmp.Diff(clusterNormalized, existingMCClusterNormalized) return diff } -func getIdentity(identity *infrav1.Identity) (managedClusterIdentity *containerservice.ManagedClusterIdentity, err error) { +func getIdentity(identity *infrav1.Identity) (managedClusterIdentity *armcontainerservice.ManagedClusterIdentity, err error) { if identity.Type == "" { return } - managedClusterIdentity = &containerservice.ManagedClusterIdentity{ - Type: containerservice.ResourceIdentityType(identity.Type), + managedClusterIdentity = &armcontainerservice.ManagedClusterIdentity{ + Type: ptr.To(armcontainerservice.ResourceIdentityType(identity.Type)), } - if managedClusterIdentity.Type == containerservice.ResourceIdentityTypeUserAssigned { + if ptr.Deref(managedClusterIdentity.Type, "") == armcontainerservice.ResourceIdentityTypeUserAssigned { if identity.UserAssignedIdentityResourceID == "" { err = errors.Errorf("Identity is set to \"UserAssigned\" but no UserAssignedIdentityResourceID is present") return } - managedClusterIdentity.UserAssignedIdentities = map[string]*containerservice.ManagedClusterIdentityUserAssignedIdentitiesValue{ + managedClusterIdentity.UserAssignedIdentities = map[string]*armcontainerservice.ManagedServiceIdentityUserAssignedIdentitiesValue{ identity.UserAssignedIdentityResourceID: {}, } } @@ -715,9 +715,8 @@ func getIdentity(identity *infrav1.Identity) (managedClusterIdentity *containers } // isAuthIPRangesNilOrEmpty returns true if the managed cluster's APIServerAccessProfile or AuthorizedIPRanges is nil or if AuthorizedIPRanges is empty. -func isAuthIPRangesNilOrEmpty(managedCluster containerservice.ManagedCluster) bool { - if managedCluster.APIServerAccessProfile == nil || managedCluster.APIServerAccessProfile.AuthorizedIPRanges == nil || reflect.DeepEqual(managedCluster.APIServerAccessProfile.AuthorizedIPRanges, &[]string{}) { - return true - } - return false +func isAuthIPRangesNilOrEmpty(managedCluster armcontainerservice.ManagedCluster) bool { + return managedCluster.Properties.APIServerAccessProfile == nil || + managedCluster.Properties.APIServerAccessProfile.AuthorizedIPRanges == nil || + reflect.DeepEqual(managedCluster.Properties.APIServerAccessProfile.AuthorizedIPRanges, []*string{}) } diff --git a/azure/services/managedclusters/spec_test.go b/azure/services/managedclusters/spec_test.go index 8506a5f2374..e77f1d2ff20 100644 --- a/azure/services/managedclusters/spec_test.go +++ b/azure/services/managedclusters/spec_test.go @@ -21,7 +21,7 @@ import ( "encoding/base64" "testing" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" "github.com/google/go-cmp/cmp" . "github.com/onsi/gomega" "github.com/onsi/gomega/format" @@ -43,8 +43,8 @@ func TestParameters(t *testing.T) { }{ { name: "managedcluster in non-terminal provisioning state", - existing: containerservice.ManagedCluster{ - ManagedClusterProperties: &containerservice.ManagedClusterProperties{ + existing: armcontainerservice.ManagedCluster{ + Properties: &armcontainerservice.ManagedClusterProperties{ ProvisioningState: ptr.To("Deleting"), }, }, @@ -69,7 +69,7 @@ func TestParameters(t *testing.T) { "test-tag": "test-value", }, Version: "v1.22.0", - LoadBalancerSKU: "Standard", + LoadBalancerSKU: "standard", SSHPublicKey: base64.StdEncoding.EncodeToString([]byte("test-ssh-key")), GetAllAgentPools: func() ([]azure.ResourceSpecGetter, error) { return []azure.ResourceSpecGetter{ @@ -101,8 +101,9 @@ func TestParameters(t *testing.T) { }, }, expect: func(g *WithT, result interface{}) { - g.Expect(result).To(BeAssignableToTypeOf(containerservice.ManagedCluster{})) - g.Expect(gomockinternal.DiffEq(result).Matches(getSampleManagedCluster())).To(BeTrue(), cmp.Diff(result, getSampleManagedCluster())) + g.Expect(result).To(BeAssignableToTypeOf(armcontainerservice.ManagedCluster{})) + sampleCluster := getSampleManagedCluster() + g.Expect(gomockinternal.DiffEq(result).Matches(sampleCluster)).To(BeTrue(), cmp.Diff(result, getSampleManagedCluster())) }, }, { @@ -116,7 +117,7 @@ func TestParameters(t *testing.T) { "test-tag": "test-value", }, Version: "v1.22.0", - LoadBalancerSKU: "Standard", + LoadBalancerSKU: "standard", }, expect: func(g *WithT, result interface{}) { g.Expect(result).To(BeNil()) @@ -133,7 +134,7 @@ func TestParameters(t *testing.T) { "test-tag": "test-value", }, Version: "v1.22.99", - LoadBalancerSKU: "Standard", + LoadBalancerSKU: "standard", Identity: &infrav1.Identity{ Type: infrav1.ManagedControlPlaneIdentityTypeUserAssigned, UserAssignedIdentityResourceID: "/resource/ID", @@ -141,11 +142,11 @@ func TestParameters(t *testing.T) { KubeletUserAssignedIdentity: "/resource/ID", }, expect: func(g *WithT, result interface{}) { - g.Expect(result).To(BeAssignableToTypeOf(containerservice.ManagedCluster{})) - g.Expect(result.(containerservice.ManagedCluster).KubernetesVersion).To(Equal(ptr.To("v1.22.99"))) - g.Expect(result.(containerservice.ManagedCluster).Identity.Type).To(Equal(containerservice.ResourceIdentityType("UserAssigned"))) - g.Expect(result.(containerservice.ManagedCluster).Identity.UserAssignedIdentities).To(Equal(map[string]*containerservice.ManagedClusterIdentityUserAssignedIdentitiesValue{"/resource/ID": {}})) - g.Expect(result.(containerservice.ManagedCluster).IdentityProfile).To(Equal(map[string]*containerservice.UserAssignedIdentity{kubeletIdentityKey: {ResourceID: ptr.To("/resource/ID")}})) + g.Expect(result).To(BeAssignableToTypeOf(armcontainerservice.ManagedCluster{})) + g.Expect(result.(armcontainerservice.ManagedCluster).Properties.KubernetesVersion).To(Equal(ptr.To("v1.22.99"))) + g.Expect(result.(armcontainerservice.ManagedCluster).Identity.Type).To(Equal(ptr.To(armcontainerservice.ResourceIdentityType("UserAssigned")))) + g.Expect(result.(armcontainerservice.ManagedCluster).Identity.UserAssignedIdentities).To(Equal(map[string]*armcontainerservice.ManagedServiceIdentityUserAssignedIdentitiesValue{"/resource/ID": {}})) + g.Expect(result.(armcontainerservice.ManagedCluster).Properties.IdentityProfile).To(Equal(map[string]*armcontainerservice.UserAssignedIdentity{kubeletIdentityKey: {ResourceID: ptr.To("/resource/ID")}})) }, }, { @@ -157,7 +158,7 @@ func TestParameters(t *testing.T) { Location: "test-location", Tags: nil, Version: "v1.22.0", - LoadBalancerSKU: "Standard", + LoadBalancerSKU: "standard", }, expect: func(g *WithT, result interface{}) { // Additional tags are handled by azure/services/tags, so a diff @@ -174,7 +175,7 @@ func TestParameters(t *testing.T) { Location: "test-location", Tags: nil, Version: "v1.22.0", - LoadBalancerSKU: "Standard", + LoadBalancerSKU: "standard", SSHPublicKey: base64.StdEncoding.EncodeToString([]byte("test-ssh-key")), GetAllAgentPools: func() ([]azure.ResourceSpecGetter, error) { return []azure.ResourceSpecGetter{ @@ -191,9 +192,9 @@ func TestParameters(t *testing.T) { }, }, expect: func(g *WithT, result interface{}) { - g.Expect(result).To(BeAssignableToTypeOf(containerservice.ManagedCluster{})) - g.Expect(result.(containerservice.ManagedCluster).LinuxProfile).To(Not(BeNil())) - g.Expect(*(*result.(containerservice.ManagedCluster).LinuxProfile.SSH.PublicKeys)[0].KeyData).To(Equal("test-ssh-key")) + g.Expect(result).To(BeAssignableToTypeOf(armcontainerservice.ManagedCluster{})) + g.Expect(result.(armcontainerservice.ManagedCluster).Properties.LinuxProfile).To(Not(BeNil())) + g.Expect(*(result.(armcontainerservice.ManagedCluster).Properties.LinuxProfile.SSH.PublicKeys)[0].KeyData).To(Equal("test-ssh-key")) }, }, { @@ -205,7 +206,7 @@ func TestParameters(t *testing.T) { Location: "test-location", Tags: nil, Version: "v1.22.0", - LoadBalancerSKU: "Standard", + LoadBalancerSKU: "standard", HTTPProxyConfig: &HTTPProxyConfig{ HTTPProxy: ptr.To("http://proxy.com"), HTTPSProxy: ptr.To("https://proxy.com"), @@ -215,9 +216,9 @@ func TestParameters(t *testing.T) { }, }, expect: func(g *WithT, result interface{}) { - g.Expect(result).To(BeAssignableToTypeOf(containerservice.ManagedCluster{})) - g.Expect(result.(containerservice.ManagedCluster).HTTPProxyConfig).To(Not(BeNil())) - g.Expect((*result.(containerservice.ManagedCluster).HTTPProxyConfig.HTTPProxy)).To(Equal("http://proxy.com")) + g.Expect(result).To(BeAssignableToTypeOf(armcontainerservice.ManagedCluster{})) + g.Expect(result.(armcontainerservice.ManagedCluster).Properties.HTTPProxyConfig).To(Not(BeNil())) + g.Expect((*result.(armcontainerservice.ManagedCluster).Properties.HTTPProxyConfig.HTTPProxy)).To(Equal("http://proxy.com")) }, }, { @@ -229,7 +230,7 @@ func TestParameters(t *testing.T) { Location: "test-location", Tags: nil, Version: "v1.22.0", - LoadBalancerSKU: "Standard", + LoadBalancerSKU: "standard", HTTPProxyConfig: &HTTPProxyConfig{ NoProxy: []string{"noproxy1", "noproxy2"}, }, @@ -238,9 +239,9 @@ func TestParameters(t *testing.T) { }, }, expect: func(g *WithT, result interface{}) { - g.Expect(result).To(BeAssignableToTypeOf(containerservice.ManagedCluster{})) - g.Expect(result.(containerservice.ManagedCluster).HTTPProxyConfig).To(Not(BeNil())) - g.Expect((*result.(containerservice.ManagedCluster).HTTPProxyConfig.NoProxy)).To(Equal([]string{"noproxy1", "noproxy2"})) + g.Expect(result).To(BeAssignableToTypeOf(armcontainerservice.ManagedCluster{})) + g.Expect(result.(armcontainerservice.ManagedCluster).Properties.HTTPProxyConfig).To(Not(BeNil())) + g.Expect((result.(armcontainerservice.ManagedCluster).Properties.HTTPProxyConfig.NoProxy)).To(Equal([]*string{ptr.To("noproxy1"), ptr.To("noproxy2")})) }, }, { @@ -252,7 +253,7 @@ func TestParameters(t *testing.T) { Location: "test-location", Tags: nil, Version: "v1.22.0", - LoadBalancerSKU: "Standard", + LoadBalancerSKU: "standard", SSHPublicKey: "", GetAllAgentPools: func() ([]azure.ResourceSpecGetter, error) { return []azure.ResourceSpecGetter{ @@ -269,8 +270,8 @@ func TestParameters(t *testing.T) { }, }, expect: func(g *WithT, result interface{}) { - g.Expect(result).To(BeAssignableToTypeOf(containerservice.ManagedCluster{})) - g.Expect(result.(containerservice.ManagedCluster).LinuxProfile).To(BeNil()) + g.Expect(result).To(BeAssignableToTypeOf(armcontainerservice.ManagedCluster{})) + g.Expect(result.(armcontainerservice.ManagedCluster).Properties.LinuxProfile).To(BeNil()) }, }, { @@ -284,7 +285,7 @@ func TestParameters(t *testing.T) { "test-tag": "test-value", }, Version: "v1.22.0", - LoadBalancerSKU: "Standard", + LoadBalancerSKU: "standard", APIServerAccessProfile: &APIServerAccessProfile{ AuthorizedIPRanges: func() []string { var arr []string @@ -307,12 +308,12 @@ func TestParameters(t *testing.T) { "test-tag": "test-value", }, Version: "v1.22.0", - LoadBalancerSKU: "Standard", + LoadBalancerSKU: "standard", }, expect: func(g *WithT, result interface{}) { - g.Expect(result).To(BeAssignableToTypeOf(containerservice.ManagedCluster{})) - g.Expect(result.(containerservice.ManagedCluster).APIServerAccessProfile).To(Not(BeNil())) - g.Expect(result.(containerservice.ManagedCluster).APIServerAccessProfile.AuthorizedIPRanges).To(Equal(&[]string{})) + g.Expect(result).To(BeAssignableToTypeOf(armcontainerservice.ManagedCluster{})) + g.Expect(result.(armcontainerservice.ManagedCluster).Properties.APIServerAccessProfile).To(Not(BeNil())) + g.Expect(result.(armcontainerservice.ManagedCluster).Properties.APIServerAccessProfile.AuthorizedIPRanges).To(Equal([]*string{})) }, }, { @@ -326,15 +327,15 @@ func TestParameters(t *testing.T) { "test-tag": "test-value", }, Version: "v1.22.0", - LoadBalancerSKU: "Standard", + LoadBalancerSKU: "standard", APIServerAccessProfile: &APIServerAccessProfile{ AuthorizedIPRanges: []string{"192.168.0.1/32, 192.168.0.2/32, 192.168.0.3/32"}, }, }, expect: func(g *WithT, result interface{}) { - g.Expect(result).To(BeAssignableToTypeOf(containerservice.ManagedCluster{})) - g.Expect(result.(containerservice.ManagedCluster).APIServerAccessProfile).To(Not(BeNil())) - g.Expect(result.(containerservice.ManagedCluster).APIServerAccessProfile.AuthorizedIPRanges).To(Equal(&[]string{"192.168.0.1/32, 192.168.0.2/32, 192.168.0.3/32"})) + g.Expect(result).To(BeAssignableToTypeOf(armcontainerservice.ManagedCluster{})) + g.Expect(result.(armcontainerservice.ManagedCluster).Properties.APIServerAccessProfile).To(Not(BeNil())) + g.Expect(result.(armcontainerservice.ManagedCluster).Properties.APIServerAccessProfile.AuthorizedIPRanges).To(Equal([]*string{ptr.To("192.168.0.1/32, 192.168.0.2/32, 192.168.0.3/32")})) }, }, { @@ -348,7 +349,7 @@ func TestParameters(t *testing.T) { "test-tag": "test-value", }, Version: "v1.22.0", - LoadBalancerSKU: "Standard", + LoadBalancerSKU: "standard", APIServerAccessProfile: &APIServerAccessProfile{ AuthorizedIPRanges: []string{"192.168.0.1/32, 192.168.0.2/32, 192.168.0.3/32"}, }, @@ -381,7 +382,7 @@ func TestGetIdentity(t *testing.T) { testcases := []struct { name string identity *infrav1.Identity - expectedType containerservice.ResourceIdentityType + expectedType *armcontainerservice.ResourceIdentityType }{ { name: "default", @@ -393,14 +394,14 @@ func TestGetIdentity(t *testing.T) { Type: infrav1.ManagedControlPlaneIdentityTypeUserAssigned, UserAssignedIdentityResourceID: "/subscriptions/fae7cc14-bfba-4471-9435-f945b42a16dd/resourcegroups/my-identities/providers/Microsoft.ManagedIdentity/userAssignedIdentities/my-cluster-user-identity", }, - expectedType: containerservice.ResourceIdentityTypeUserAssigned, + expectedType: ptr.To(armcontainerservice.ResourceIdentityTypeUserAssigned), }, { name: "system-assigned identity", identity: &infrav1.Identity{ Type: infrav1.ManagedControlPlaneIdentityTypeSystemAssigned, }, - expectedType: containerservice.ResourceIdentityTypeSystemAssigned, + expectedType: ptr.To(armcontainerservice.ResourceIdentityTypeSystemAssigned), }, } for _, tc := range testcases { @@ -415,7 +416,7 @@ func TestGetIdentity(t *testing.T) { g.Expect(result.Type).To(Equal(tc.expectedType)) if tc.identity.Type == infrav1.ManagedControlPlaneIdentityTypeUserAssigned { g.Expect(result.UserAssignedIdentities).To(Not(BeEmpty())) - g.Expect(*result.UserAssignedIdentities[tc.identity.UserAssignedIdentityResourceID]).To(Equal(containerservice.ManagedClusterIdentityUserAssignedIdentitiesValue{})) + g.Expect(*result.UserAssignedIdentities[tc.identity.UserAssignedIdentityResourceID]).To(Equal(armcontainerservice.ManagedServiceIdentityUserAssignedIdentitiesValue{})) } else { g.Expect(result.UserAssignedIdentities).To(BeEmpty()) } @@ -426,33 +427,33 @@ func TestGetIdentity(t *testing.T) { } } -func getExistingClusterWithAPIServerAccessProfile() containerservice.ManagedCluster { +func getExistingClusterWithAPIServerAccessProfile() armcontainerservice.ManagedCluster { mc := getExistingCluster() - mc.APIServerAccessProfile = &containerservice.ManagedClusterAPIServerAccessProfile{ + mc.Properties.APIServerAccessProfile = &armcontainerservice.ManagedClusterAPIServerAccessProfile{ EnablePrivateCluster: ptr.To(false), } return mc } -func getExistingCluster() containerservice.ManagedCluster { +func getExistingCluster() armcontainerservice.ManagedCluster { mc := getSampleManagedCluster() - mc.ProvisioningState = ptr.To("Succeeded") + mc.Properties.ProvisioningState = ptr.To("Succeeded") mc.ID = ptr.To("test-id") return mc } -func getSampleManagedCluster() containerservice.ManagedCluster { - return containerservice.ManagedCluster{ - ManagedClusterProperties: &containerservice.ManagedClusterProperties{ +func getSampleManagedCluster() armcontainerservice.ManagedCluster { + return armcontainerservice.ManagedCluster{ + Properties: &armcontainerservice.ManagedClusterProperties{ KubernetesVersion: ptr.To("v1.22.0"), DNSPrefix: ptr.To("test-managedcluster"), - AgentPoolProfiles: &[]containerservice.ManagedClusterAgentPoolProfile{ + AgentPoolProfiles: []*armcontainerservice.ManagedClusterAgentPoolProfile{ { Name: ptr.To("test-agentpool-0"), - Mode: containerservice.AgentPoolMode(infrav1.NodePoolModeSystem), + Mode: ptr.To(armcontainerservice.AgentPoolMode(infrav1.NodePoolModeSystem)), Count: ptr.To[int32](2), - Type: containerservice.AgentPoolTypeVirtualMachineScaleSets, - OsDiskSizeGB: ptr.To[int32](0), + Type: ptr.To(armcontainerservice.AgentPoolTypeVirtualMachineScaleSets), + OSDiskSizeGB: ptr.To[int32](0), Tags: map[string]*string{ "test-tag": ptr.To("test-value"), }, @@ -460,40 +461,40 @@ func getSampleManagedCluster() containerservice.ManagedCluster { }, { Name: ptr.To("test-agentpool-1"), - Mode: containerservice.AgentPoolMode(infrav1.NodePoolModeUser), + Mode: ptr.To(armcontainerservice.AgentPoolMode(infrav1.NodePoolModeUser)), Count: ptr.To[int32](4), - Type: containerservice.AgentPoolTypeVirtualMachineScaleSets, - OsDiskSizeGB: ptr.To[int32](0), + Type: ptr.To(armcontainerservice.AgentPoolTypeVirtualMachineScaleSets), + OSDiskSizeGB: ptr.To[int32](0), VMSize: ptr.To("test_SKU"), OrchestratorVersion: ptr.To("v1.22.0"), VnetSubnetID: ptr.To("fake/subnet/id"), MaxPods: ptr.To[int32](int32(32)), - AvailabilityZones: &[]string{"1", "2"}, + AvailabilityZones: []*string{ptr.To("1"), ptr.To("2")}, Tags: map[string]*string{ "test-tag": ptr.To("test-value"), }, EnableAutoScaling: ptr.To(false), }, }, - LinuxProfile: &containerservice.LinuxProfile{ + LinuxProfile: &armcontainerservice.LinuxProfile{ AdminUsername: ptr.To(azure.DefaultAKSUserName), - SSH: &containerservice.SSHConfiguration{ - PublicKeys: &[]containerservice.SSHPublicKey{ + SSH: &armcontainerservice.SSHConfiguration{ + PublicKeys: []*armcontainerservice.SSHPublicKey{ { KeyData: ptr.To("test-ssh-key"), }, }, }, }, - ServicePrincipalProfile: &containerservice.ManagedClusterServicePrincipalProfile{ClientID: ptr.To("msi")}, + ServicePrincipalProfile: &armcontainerservice.ManagedClusterServicePrincipalProfile{ClientID: ptr.To("msi")}, NodeResourceGroup: ptr.To("test-node-rg"), EnableRBAC: ptr.To(true), - NetworkProfile: &containerservice.NetworkProfile{ - LoadBalancerSku: "Standard", + NetworkProfile: &armcontainerservice.NetworkProfile{ + LoadBalancerSKU: ptr.To(armcontainerservice.LoadBalancerSKUStandard), }, }, - Identity: &containerservice.ManagedClusterIdentity{ - Type: containerservice.ResourceIdentityTypeSystemAssigned, + Identity: &armcontainerservice.ManagedClusterIdentity{ + Type: ptr.To(armcontainerservice.ResourceIdentityTypeSystemAssigned), }, Location: ptr.To("test-location"), Tags: converters.TagsToMap(infrav1.Build(infrav1.BuildParams{ @@ -508,10 +509,10 @@ func getSampleManagedCluster() containerservice.ManagedCluster { } } -func getExistingClusterWithAuthorizedIPRanges() containerservice.ManagedCluster { +func getExistingClusterWithAuthorizedIPRanges() armcontainerservice.ManagedCluster { mc := getExistingCluster() - mc.APIServerAccessProfile = &containerservice.ManagedClusterAPIServerAccessProfile{ - AuthorizedIPRanges: &[]string{"192.168.0.1/32, 192.168.0.2/32, 192.168.0.3/32"}, + mc.Properties.APIServerAccessProfile = &armcontainerservice.ManagedClusterAPIServerAccessProfile{ + AuthorizedIPRanges: []*string{ptr.To("192.168.0.1/32, 192.168.0.2/32, 192.168.0.3/32")}, } return mc } diff --git a/controllers/azuremanagedcontrolplane_controller.go b/controllers/azuremanagedcontrolplane_controller.go index 524c34ae4d5..a7b53e01f82 100644 --- a/controllers/azuremanagedcontrolplane_controller.go +++ b/controllers/azuremanagedcontrolplane_controller.go @@ -235,7 +235,11 @@ func (amcpr *AzureManagedControlPlaneReconciler) reconcileNormal(ctx context.Con } } - if err := newAzureManagedControlPlaneReconciler(scope).Reconcile(ctx); err != nil { + svc, err := newAzureManagedControlPlaneReconciler(scope) + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to create azureManagedControlPlane service") + } + if err := svc.Reconcile(ctx); err != nil { // Handle transient and terminal errors log := log.WithValues("name", scope.ControlPlane.Name, "namespace", scope.ControlPlane.Namespace) var reconcileError azure.ReconcileError @@ -246,7 +250,7 @@ func (amcpr *AzureManagedControlPlaneReconciler) reconcileNormal(ctx context.Con } if reconcileError.IsTransient() { - log.V(4).Info("requeuing due to transient transient failure", "error", err) + log.V(4).Info("requeuing due to transient failure", "error", err) return reconcile.Result{RequeueAfter: reconcileError.RequeueAfter()}, nil } @@ -271,7 +275,11 @@ func (amcpr *AzureManagedControlPlaneReconciler) reconcilePause(ctx context.Cont log.Info("Reconciling AzureManagedControlPlane pause") - if err := newAzureManagedControlPlaneReconciler(scope).Pause(ctx); err != nil { + svc, err := newAzureManagedControlPlaneReconciler(scope) + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to create azureManagedControlPlane service") + } + if err := svc.Pause(ctx); err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to pause control plane services") } @@ -284,7 +292,11 @@ func (amcpr *AzureManagedControlPlaneReconciler) reconcileDelete(ctx context.Con log.Info("Reconciling AzureManagedControlPlane delete") - if err := newAzureManagedControlPlaneReconciler(scope).Delete(ctx); err != nil { + svc, err := newAzureManagedControlPlaneReconciler(scope) + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to create azureManagedControlPlane service") + } + if err := svc.Delete(ctx); err != nil { // Handle transient errors var reconcileError azure.ReconcileError if errors.As(err, &reconcileError) && reconcileError.IsTransient() { diff --git a/controllers/azuremanagedcontrolplane_reconciler.go b/controllers/azuremanagedcontrolplane_reconciler.go index f4ac858a2ed..615792a05c7 100644 --- a/controllers/azuremanagedcontrolplane_reconciler.go +++ b/controllers/azuremanagedcontrolplane_reconciler.go @@ -44,11 +44,15 @@ type azureManagedControlPlaneService struct { } // newAzureManagedControlPlaneReconciler populates all the services based on input scope. -func newAzureManagedControlPlaneReconciler(scope *scope.ManagedControlPlaneScope) *azureManagedControlPlaneService { +func newAzureManagedControlPlaneReconciler(scope *scope.ManagedControlPlaneScope) (*azureManagedControlPlaneService, error) { var groupsService azure.ServiceReconciler = asogroups.New(scope) if scope.UseLegacyGroups { groupsService = groups.New(scope) } + managedClustersService, err := managedclusters.New(scope) + if err != nil { + return nil, err + } return &azureManagedControlPlaneService{ kubeclient: scope.Client, scope: scope, @@ -56,12 +60,12 @@ func newAzureManagedControlPlaneReconciler(scope *scope.ManagedControlPlaneScope groupsService, virtualnetworks.New(scope), subnets.New(scope), - managedclusters.New(scope), + managedClustersService, privateendpoints.New(scope), tags.New(scope), resourcehealth.New(scope), }, - } + }, nil } // Reconcile reconciles all the services in a predetermined order. diff --git a/controllers/azuremanagedmachinepool_controller.go b/controllers/azuremanagedmachinepool_controller.go index eb3af33f5e0..c99715dcce4 100644 --- a/controllers/azuremanagedmachinepool_controller.go +++ b/controllers/azuremanagedmachinepool_controller.go @@ -279,7 +279,7 @@ func (ammpr *AzureManagedMachinePoolReconciler) reconcileNormal(ctx context.Cont } if reconcileError.IsTransient() { - log.V(4).Info("requeuing due to transient transient failure", "error", err) + log.V(4).Info("requeuing due to transient failure", "error", err) return reconcile.Result{RequeueAfter: reconcileError.RequeueAfter()}, nil } diff --git a/controllers/azuremanagedmachinepool_reconciler.go b/controllers/azuremanagedmachinepool_reconciler.go index d2c64612d3b..2dea68150a4 100644 --- a/controllers/azuremanagedmachinepool_reconciler.go +++ b/controllers/azuremanagedmachinepool_reconciler.go @@ -75,6 +75,10 @@ func (a *AgentPoolVMSSNotFoundError) Is(target error) bool { // newAzureManagedMachinePoolService populates all the services based on input scope. func newAzureManagedMachinePoolService(scope *scope.ManagedMachinePoolScope) (*azureManagedMachinePoolService, error) { + agentPoolsSvc, err := agentpools.New(scope) + if err != nil { + return nil, err + } scaleSetAuthorizer, err := scaleSetAuthorizer(scope) if err != nil { return nil, err @@ -82,7 +86,7 @@ func newAzureManagedMachinePoolService(scope *scope.ManagedMachinePoolScope) (*a return &azureManagedMachinePoolService{ scope: scope, - agentPoolsSvc: agentpools.New(scope), + agentPoolsSvc: agentPoolsSvc, scaleSetsSvc: scalesets.NewClient(scaleSetAuthorizer), }, nil } diff --git a/go.mod b/go.mod index 42e294c4cad..caa04c0f621 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.1.0 + github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4 v4.1.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4 v4.1.0 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 github.com/Azure/azure-service-operator/v2 v2.2.0 diff --git a/go.sum b/go.sum index 3602f49cc0f..58147941971 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/appconfiguration/armappcon github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.1.0 h1:Sg/D8VuUQ+bw+FOYJF+xRKcwizCOP13HL0Se8pWNBzE= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5 v5.1.0/go.mod h1:Kyqzdqq0XDoCm+o9aZ25wZBmBUBzPBzPAj1R5rYsT6I= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice v1.0.0 h1:figxyQZXzZQIcP3njhC68bYUiTw45J8/SsHaLW8Ax0M= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4 v4.1.0 h1:F3UFtsypziTN34SuTJZo0pC18C57Ylsx6QA2L81WA4g= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4 v4.1.0/go.mod h1:RhBTnPBGgOpK2BMC7P5KrlhzAOWRpsNytcHjAkGP21U= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/cosmos/armcosmos v1.0.0 h1:Fv8iibGn1eSw0lt2V3cTsuokBEnOP+M//n8OiMcCgTM= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal v1.1.2 h1:mLY+pNLjCUeKhgnAJWAKhEUQM+RJQo2H1fuGSw1Ky1E= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/iothub/armiothub v1.1.1 h1:Dh8SxVXcSyQN76LI4IseKyrnqyTUsx336Axg8zDYSMs= diff --git a/test/e2e/aks_azure_cluster_autoscaler.go b/test/e2e/aks_azure_cluster_autoscaler.go index 2df7ddfbccf..541bb79ddda 100644 --- a/test/e2e/aks_azure_cluster_autoscaler.go +++ b/test/e2e/aks_azure_cluster_autoscaler.go @@ -22,7 +22,8 @@ package e2e import ( "context" - "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2022-03-01/containerservice" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4" "github.com/Azure/go-autorest/autorest/azure/auth" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -43,14 +44,15 @@ func AKSAzureClusterAutoscalerSettingsSpec(ctx context.Context, inputGetter func settings, err := auth.GetSettingsFromEnvironment() Expect(err).NotTo(HaveOccurred()) subscriptionID := settings.GetSubscriptionID() - auth, err := settings.GetAuthorizer() Expect(err).NotTo(HaveOccurred()) mgmtClient := bootstrapClusterProxy.GetClient() Expect(mgmtClient).NotTo(BeNil()) - containerserviceClient := containerservice.NewManagedClustersClient(subscriptionID) - containerserviceClient.Authorizer = auth + cred, err := azidentity.NewDefaultAzureCredential(nil) + Expect(err).NotTo(HaveOccurred()) + containerserviceClient, err := armcontainerservice.NewManagedClustersClient(subscriptionID, cred, nil) + Expect(err).NotTo(HaveOccurred()) - var expectedAksExpander containerservice.Expander + var expectedAksExpander armcontainerservice.Expander var newExpanderValue infrav1.Expander var amcpInitialAutoScalerProfile = &infrav1.AutoScalerProfile{} amcp := &infrav1.AzureManagedControlPlane{} @@ -62,16 +64,16 @@ func AKSAzureClusterAutoscalerSettingsSpec(ctx context.Context, inputGetter func g.Expect(err).NotTo(HaveOccurred()) amcpInitialAutoScalerProfile = amcp.Spec.AutoScalerProfile - aks, err := containerserviceClient.Get(ctx, amcp.Spec.ResourceGroupName, amcp.Name) + aks, err := containerserviceClient.Get(ctx, amcp.Spec.ResourceGroupName, amcp.Name, nil) g.Expect(err).NotTo(HaveOccurred()) - aksInitialAutoScalerProfile := aks.AutoScalerProfile + aksInitialAutoScalerProfile := aks.Properties.AutoScalerProfile // Conditional is based off of the actual AKS settings not the AzureManagedControlPlane if aksInitialAutoScalerProfile == nil { - expectedAksExpander = containerservice.ExpanderLeastWaste + expectedAksExpander = armcontainerservice.ExpanderLeastWaste newExpanderValue = infrav1.ExpanderLeastWaste - } else if aksInitialAutoScalerProfile.Expander == containerservice.ExpanderLeastWaste { - expectedAksExpander = containerservice.ExpanderMostPods + } else if aksInitialAutoScalerProfile.Expander == ptr.To(armcontainerservice.ExpanderLeastWaste) { + expectedAksExpander = armcontainerservice.ExpanderMostPods newExpanderValue = infrav1.ExpanderMostPods } @@ -107,10 +109,10 @@ func AKSAzureClusterAutoscalerSettingsSpec(ctx context.Context, inputGetter func By("Verifying the cluster-autoscaler settings have changed") Eventually(func(g Gomega) { // Check that the autoscaler settings have been sync'd to AKS - aks, err := containerserviceClient.Get(ctx, amcp.Spec.ResourceGroupName, amcp.Name) + aks, err := containerserviceClient.Get(ctx, amcp.Spec.ResourceGroupName, amcp.Name, nil) g.Expect(err).NotTo(HaveOccurred()) - g.Expect(aks.AutoScalerProfile).ToNot(BeNil()) - g.Expect(aks.AutoScalerProfile.Expander).To(Equal(expectedAksExpander)) + g.Expect(aks.Properties.AutoScalerProfile).ToNot(BeNil()) + g.Expect(aks.Properties.AutoScalerProfile.Expander).To(Equal(&expectedAksExpander)) }, input.WaitIntervals...).Should(Succeed()) Eventually(func(g Gomega) { diff --git a/test/e2e/aks_public_ip_prefix.go b/test/e2e/aks_public_ip_prefix.go index 690f2dd6569..5b2758bbf7f 100644 --- a/test/e2e/aks_public_ip_prefix.go +++ b/test/e2e/aks_public_ip_prefix.go @@ -82,7 +82,7 @@ func AKSPublicIPPrefixSpec(ctx context.Context, inputGetter func() AKSPublicIPPr g.Expect(err).NotTo(HaveOccurred()) }, input.WaitIntervals...).Should(Succeed(), "failed to create public IP prefix") - By("Creating node pool with 3 nodes") + By("Creating node pool with 2 nodes") infraMachinePool := &infrav1.AzureManagedMachinePool{ ObjectMeta: metav1.ObjectMeta{ Name: "pool3", @@ -105,7 +105,7 @@ func AKSPublicIPPrefixSpec(ctx context.Context, inputGetter func() AKSPublicIPPr }, Spec: expv1.MachinePoolSpec{ ClusterName: input.Cluster.Name, - Replicas: ptr.To[int32](3), + Replicas: ptr.To[int32](2), Template: clusterv1.MachineTemplateSpec{ Spec: clusterv1.MachineSpec{ Bootstrap: clusterv1.Bootstrap{ @@ -141,27 +141,6 @@ func AKSPublicIPPrefixSpec(ctx context.Context, inputGetter func() AKSPublicIPPr }, input.WaitIntervals...).Should(Succeed(), "Deleted AzureManagedMachinePool %s/%s still exists", infraMachinePool.Namespace, infraMachinePool.Name) }() - By("Verifying the AzureManagedMachinePool converges to a failed ready status") - Eventually(func(g Gomega) { - infraMachinePool := &infrav1.AzureManagedMachinePool{} - err := mgmtClient.Get(ctx, client.ObjectKeyFromObject(machinePool), infraMachinePool) - g.Expect(err).NotTo(HaveOccurred()) - cond := conditions.Get(infraMachinePool, infrav1.AgentPoolsReadyCondition) - g.Expect(cond).NotTo(BeNil()) - g.Expect(cond.Status).To(Equal(corev1.ConditionFalse)) - g.Expect(cond.Reason).To(Equal(infrav1.FailedReason)) - g.Expect(cond.Message).To(HavePrefix("failed to find vm scale set")) - }, input.WaitIntervals...).Should(Succeed()) - - By("Scaling the MachinePool to 2 nodes") - Eventually(func(g Gomega) { - err = mgmtClient.Get(ctx, client.ObjectKeyFromObject(machinePool), machinePool) - g.Expect(err).NotTo(HaveOccurred()) - machinePool.Spec.Replicas = ptr.To[int32](2) - err = mgmtClient.Update(ctx, machinePool) - g.Expect(err).NotTo(HaveOccurred()) - }, input.WaitIntervals...).Should(Succeed()) - By("Verifying the AzureManagedMachinePool becomes ready") Eventually(func(g Gomega) { infraMachinePool := &infrav1.AzureManagedMachinePool{}