From 04a756124f2e19c7590dbdad7133b38a1202a9f5 Mon Sep 17 00:00:00 2001 From: Cecile Robert-Michon Date: Fri, 15 Dec 2023 00:40:34 +0000 Subject: [PATCH] Make all reconcile timeouts configurable --- azure/interfaces.go | 10 + azure/mock_azure/azure_mock.go | 192 ++++++++++++++++++ azure/scope/cluster.go | 15 +- azure/scope/managedcontrolplane.go | 3 + .../mock_agentpools/agentpools_mock.go | 43 ++++ azure/services/aso/mock_aso/aso_mock.go | 43 ++++ azure/services/aso/service.go | 5 +- azure/services/aso/service_test.go | 13 ++ azure/services/async/async.go | 8 +- azure/services/async/async_test.go | 4 + azure/services/async/mock_async/async_mock.go | 43 ++++ .../availabilitysets/availabilitysets.go | 5 +- .../availabilitysets/availabilitysets_test.go | 13 ++ .../availabilitysets_mock.go | 43 ++++ azure/services/disks/client.go | 11 +- azure/services/disks/disks.go | 5 +- azure/services/disks/disks_test.go | 5 + azure/services/disks/mock_disks/disks_mock.go | 43 ++++ .../groups/mock_groups/groups_mock.go | 43 ++++ azure/services/inboundnatrules/client.go | 11 +- .../inboundnatrules/inboundnatrules.go | 11 +- .../inboundnatrules/inboundnatrules_test.go | 10 + .../inboundnatrules_mock.go | 43 ++++ azure/services/loadbalancers/client.go | 15 +- azure/services/loadbalancers/loadbalancers.go | 7 +- .../loadbalancers/loadbalancers_test.go | 11 + .../mock_loadbalancers/loadbalancers_mock.go | 43 ++++ .../managedclusters_mock.go | 43 ++++ .../mock_natgateways/natgateways_mock.go | 43 ++++ azure/services/networkinterfaces/client.go | 13 +- .../networkinterfaces_mock.go | 43 ++++ .../networkinterfaces/networkinterfaces.go | 7 +- .../networkinterfaces_test.go | 10 + azure/services/privatedns/link_client.go | 13 +- .../mock_privatedns/privatedns_mock.go | 43 ++++ azure/services/privatedns/privatedns.go | 9 +- azure/services/privatedns/privatedns_test.go | 20 ++ azure/services/privatedns/zone_client.go | 13 +- .../privateendpoints_mock.go | 43 ++++ azure/services/publicips/client.go | 13 +- .../mock_publicips/publicips_mock.go | 43 ++++ azure/services/publicips/publicips.go | 8 +- azure/services/publicips/publicips_test.go | 8 + .../roleassignments_mock.go | 43 ++++ .../roleassignments/roleassignments.go | 9 +- .../roleassignments/roleassignments_test.go | 8 +- azure/services/routetables/client.go | 13 +- .../mock_routetables/routetables_mock.go | 43 ++++ azure/services/routetables/routetables.go | 7 +- .../services/routetables/routetables_test.go | 11 + azure/services/scalesets/client.go | 18 +- .../mock_scalesets/scalesets_mock.go | 43 ++++ azure/services/scalesets/scalesets.go | 7 +- azure/services/scalesets/scalesets_test.go | 17 ++ azure/services/scalesetvms/client.go | 11 +- .../mock_scalesetvms/scalesetvms_mock.go | 43 ++++ azure/services/scalesetvms/scalesetvms.go | 4 +- azure/services/securitygroups/client.go | 11 +- .../securitygroups_mock.go | 43 ++++ .../services/securitygroups/securitygroups.go | 7 +- .../securitygroups/securitygroups_test.go | 13 ++ .../subnets/mock_subnets/subnets_mock.go | 43 ++++ azure/services/virtualmachines/client.go | 11 +- .../virtualmachines_mock.go | 43 ++++ .../virtualmachines/virtualmachines.go | 11 +- .../virtualmachines/virtualmachines_test.go | 10 + .../virtualnetworks_mock.go | 43 ++++ azure/services/vmextensions/client.go | 13 +- .../mock_vmextensions/vmextensions_mock.go | 43 ++++ azure/services/vmextensions/vmextensions.go | 5 +- .../vmextensions/vmextensions_test.go | 6 + azure/services/vnetpeerings/client.go | 13 +- .../mock_vnetpeerings/vnetpeerings_mock.go | 43 ++++ azure/services/vnetpeerings/vnetpeerings.go | 7 +- .../vnetpeerings/vnetpeerings_test.go | 19 ++ controllers/asosecret_controller.go | 7 +- controllers/azurecluster_controller.go | 10 +- controllers/azurecluster_controller_test.go | 4 +- controllers/azureidentity_controller.go | 5 +- controllers/azureidentity_controller_test.go | 4 +- controllers/azurejson_machine_controller.go | 6 +- .../azurejson_machinepool_controller.go | 7 +- .../azurejson_machinepool_controller_test.go | 6 +- .../azurejson_machinetemplate_controller.go | 6 +- controllers/azuremachine_controller.go | 10 +- controllers/azuremachine_controller_test.go | 2 +- controllers/azuremanagedcluster_controller.go | 5 +- .../azuremanagedcontrolplane_controller.go | 6 +- ...zuremanagedcontrolplane_controller_test.go | 2 +- .../azuremanagedmachinepool_controller.go | 17 +- ...azuremanagedmachinepool_controller_test.go | 5 +- .../azuremanagedmachinepool_reconciler.go | 4 +- controllers/helpers.go | 4 +- controllers/suite_test.go | 6 +- .../azuremachinepool_controller.go | 10 +- .../azuremachinepool_controller_test.go | 4 +- .../azuremachinepool_controller_unit_test.go | 1 + .../azuremachinepoolmachine_controller.go | 10 +- ...azuremachinepoolmachine_controller_test.go | 3 +- exp/controllers/suite_test.go | 4 +- main.go | 48 +++-- util/reconciler/defaults.go | 47 ++++- util/reconciler/defaults_test.go | 115 ++++++++++- 103 files changed, 1842 insertions(+), 247 deletions(-) diff --git a/azure/interfaces.go b/azure/interfaces.go index 7a6d611eb02..bf3e2dd3cbc 100644 --- a/azure/interfaces.go +++ b/azure/interfaces.go @@ -18,6 +18,7 @@ package azure import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-service-operator/v2/pkg/genruntime" @@ -101,6 +102,14 @@ type AsyncStatusUpdater interface { UpdatePutStatus(clusterv1.ConditionType, string, error) UpdateDeleteStatus(clusterv1.ConditionType, string, error) UpdatePatchStatus(clusterv1.ConditionType, string, error) + AsyncReconciler +} + +// AsyncReconciler is an interface used to get the default timeouts and requeue time for a reconciler that reconciles services asynchronously. +type AsyncReconciler interface { + DefaultedAzureCallTimeout() time.Duration + DefaultedAzureServiceReconcileTimeout() time.Duration + DefaultedReconcilerRequeue() time.Duration } // ClusterScoper combines the ClusterDescriber and NetworkDescriber interfaces. @@ -116,6 +125,7 @@ type ClusterScoper interface { type ManagedClusterScoper interface { ClusterDescriber NodeResourceGroup() string + AsyncReconciler } // ResourceSpecGetter is an interface for getting all the required information to create/update/delete an Azure resource. diff --git a/azure/mock_azure/azure_mock.go b/azure/mock_azure/azure_mock.go index 3ad477ea9f7..5d9f5213cdd 100644 --- a/azure/mock_azure/azure_mock.go +++ b/azure/mock_azure/azure_mock.go @@ -27,6 +27,7 @@ package mock_azure import ( context "context" reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" genruntime "github.com/Azure/azure-service-operator/v2/pkg/genruntime" @@ -882,6 +883,48 @@ func (m *MockAsyncStatusUpdater) EXPECT() *MockAsyncStatusUpdaterMockRecorder { return m.recorder } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockAsyncStatusUpdater) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockAsyncStatusUpdaterMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockAsyncStatusUpdater)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockAsyncStatusUpdater) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockAsyncStatusUpdaterMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockAsyncStatusUpdater)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockAsyncStatusUpdater) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockAsyncStatusUpdaterMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockAsyncStatusUpdater)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockAsyncStatusUpdater) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() @@ -956,6 +999,71 @@ func (mr *MockAsyncStatusUpdaterMockRecorder) UpdatePutStatus(arg0, arg1, arg2 a return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePutStatus", reflect.TypeOf((*MockAsyncStatusUpdater)(nil).UpdatePutStatus), arg0, arg1, arg2) } +// MockAsyncReconciler is a mock of AsyncReconciler interface. +type MockAsyncReconciler struct { + ctrl *gomock.Controller + recorder *MockAsyncReconcilerMockRecorder +} + +// MockAsyncReconcilerMockRecorder is the mock recorder for MockAsyncReconciler. +type MockAsyncReconcilerMockRecorder struct { + mock *MockAsyncReconciler +} + +// NewMockAsyncReconciler creates a new mock instance. +func NewMockAsyncReconciler(ctrl *gomock.Controller) *MockAsyncReconciler { + mock := &MockAsyncReconciler{ctrl: ctrl} + mock.recorder = &MockAsyncReconcilerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAsyncReconciler) EXPECT() *MockAsyncReconcilerMockRecorder { + return m.recorder +} + +// DefaultedAzureCallTimeout mocks base method. +func (m *MockAsyncReconciler) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockAsyncReconcilerMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockAsyncReconciler)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockAsyncReconciler) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockAsyncReconcilerMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockAsyncReconciler)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockAsyncReconciler) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockAsyncReconcilerMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockAsyncReconciler)(nil).DefaultedReconcilerRequeue)) +} + // MockClusterScoper is a mock of ClusterScoper interface. type MockClusterScoper struct { ctrl *gomock.Controller @@ -1161,6 +1269,48 @@ func (mr *MockClusterScoperMockRecorder) ControlPlaneSubnet() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ControlPlaneSubnet", reflect.TypeOf((*MockClusterScoper)(nil).ControlPlaneSubnet)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockClusterScoper) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockClusterScoperMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockClusterScoper)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockClusterScoper) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockClusterScoperMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockClusterScoper)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockClusterScoper) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockClusterScoperMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockClusterScoper)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockClusterScoper) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() @@ -1704,6 +1854,48 @@ func (mr *MockManagedClusterScoperMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockManagedClusterScoper)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockManagedClusterScoper) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockManagedClusterScoperMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockManagedClusterScoper)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockManagedClusterScoper) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockManagedClusterScoperMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockManagedClusterScoper)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockManagedClusterScoper) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockManagedClusterScoperMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockManagedClusterScoper)(nil).DefaultedReconcilerRequeue)) +} + // ExtendedLocation mocks base method. func (m *MockManagedClusterScoper) ExtendedLocation() *v1beta1.ExtendedLocationSpec { m.ctrl.T.Helper() diff --git a/azure/scope/cluster.go b/azure/scope/cluster.go index 6f093ad93fa..92c7a89b4e1 100644 --- a/azure/scope/cluster.go +++ b/azure/scope/cluster.go @@ -61,6 +61,7 @@ type ClusterScopeParams struct { Cluster *clusterv1.Cluster AzureCluster *infrav1.AzureCluster Cache *ClusterCache + Timeouts azure.AsyncReconciler } // NewClusterScope creates a new Scope from the supplied parameters. @@ -95,12 +96,13 @@ func NewClusterScope(ctx context.Context, params ClusterScopeParams) (*ClusterSc } return &ClusterScope{ - Client: params.Client, - AzureClients: params.AzureClients, - Cluster: params.Cluster, - AzureCluster: params.AzureCluster, - patchHelper: helper, - cache: params.Cache, + Client: params.Client, + AzureClients: params.AzureClients, + Cluster: params.Cluster, + AzureCluster: params.AzureCluster, + patchHelper: helper, + cache: params.Cache, + AsyncReconciler: params.Timeouts, }, nil } @@ -113,6 +115,7 @@ type ClusterScope struct { AzureClients Cluster *clusterv1.Cluster AzureCluster *infrav1.AzureCluster + azure.AsyncReconciler } // ClusterCache stores ClusterCache data locally so we don't have to hit the API multiple times within the same reconcile loop. diff --git a/azure/scope/managedcontrolplane.go b/azure/scope/managedcontrolplane.go index e165049732b..bdc2e383b75 100644 --- a/azure/scope/managedcontrolplane.go +++ b/azure/scope/managedcontrolplane.go @@ -69,6 +69,7 @@ type ManagedControlPlaneScopeParams struct { ControlPlane *infrav1.AzureManagedControlPlane ManagedMachinePools []ManagedMachinePool Cache *ManagedControlPlaneCache + Timeouts azure.AsyncReconciler } // NewManagedControlPlaneScope creates a new Scope from the supplied parameters. @@ -111,6 +112,7 @@ func NewManagedControlPlaneScope(ctx context.Context, params ManagedControlPlane ManagedMachinePools: params.ManagedMachinePools, PatchHelper: helper, cache: params.Cache, + AsyncReconciler: params.Timeouts, }, nil } @@ -126,6 +128,7 @@ type ManagedControlPlaneScope struct { Cluster *clusterv1.Cluster ControlPlane *infrav1.AzureManagedControlPlane ManagedMachinePools []ManagedMachinePool + azure.AsyncReconciler } // ManagedControlPlaneCache stores ManagedControlPlane data locally so we don't have to hit the API multiple times within the same reconcile loop. diff --git a/azure/services/agentpools/mock_agentpools/agentpools_mock.go b/azure/services/agentpools/mock_agentpools/agentpools_mock.go index 926944947d8..3dc372a8df5 100644 --- a/azure/services/agentpools/mock_agentpools/agentpools_mock.go +++ b/azure/services/agentpools/mock_agentpools/agentpools_mock.go @@ -26,6 +26,7 @@ package mock_agentpools import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" v1api20231001 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001" @@ -185,6 +186,48 @@ func (mr *MockAgentPoolScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockAgentPoolScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockAgentPoolScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockAgentPoolScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockAgentPoolScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockAgentPoolScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockAgentPoolScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockAgentPoolScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockAgentPoolScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockAgentPoolScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockAgentPoolScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockAgentPoolScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/aso/mock_aso/aso_mock.go b/azure/services/aso/mock_aso/aso_mock.go index 3806a18f417..da1dcee17b5 100644 --- a/azure/services/aso/mock_aso/aso_mock.go +++ b/azure/services/aso/mock_aso/aso_mock.go @@ -27,6 +27,7 @@ package mock_aso import ( context "context" reflect "reflect" + time "time" genruntime "github.com/Azure/azure-service-operator/v2/pkg/genruntime" gomock "go.uber.org/mock/gomock" @@ -216,6 +217,48 @@ func (mr *MockScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/aso/service.go b/azure/services/aso/service.go index b87552dbd7e..1f825a81f85 100644 --- a/azure/services/aso/service.go +++ b/azure/services/aso/service.go @@ -21,7 +21,6 @@ import ( "github.com/pkg/errors" "sigs.k8s.io/cluster-api-provider-azure/azure" - reconcilerutil "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" ) @@ -60,7 +59,7 @@ func (s *Service[T, S]) Reconcile(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "aso.Service.Reconcile") defer done() - ctx, cancel := context.WithTimeout(ctx, reconcilerutil.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() if len(s.Specs) == 0 { @@ -96,7 +95,7 @@ func (s *Service[T, S]) Delete(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "aso.Service.Delete") defer done() - ctx, cancel := context.WithTimeout(ctx, reconcilerutil.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() if len(s.Specs) == 0 { diff --git a/azure/services/aso/service_test.go b/azure/services/aso/service_test.go index 7b16e2e8011..b3c4b95e266 100644 --- a/azure/services/aso/service_test.go +++ b/azure/services/aso/service_test.go @@ -30,6 +30,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/mock_azure" "sigs.k8s.io/cluster-api-provider-azure/azure/services/aso/mock_aso" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + reconcilerutils "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ) @@ -45,6 +46,7 @@ func TestServiceReconcile(t *testing.T) { mockCtrl := gomock.NewController(t) scope := mock_aso.NewMockScope(mockCtrl) reconciler := mock_aso.NewMockReconciler[*asoresourcesv1.ResourceGroup](mockCtrl) + scope.EXPECT().DefaultedAzureServiceReconcileTimeout().Return(reconcilerutils.DefaultAzureServiceReconcileTimeout) s := &Service[*asoresourcesv1.ResourceGroup, *mock_aso.MockScope]{ Reconciler: reconciler, @@ -75,6 +77,7 @@ func TestServiceReconcile(t *testing.T) { reconciler := mock_aso.NewMockReconciler[*asoresourcesv1.ResourceGroup](mockCtrl) reconciler.EXPECT().CreateOrUpdateResource(gomockinternal.AContext(), specs[0], serviceName).Return(nil, reconcileErr) scope.EXPECT().UpdatePutStatus(conditionType, serviceName, reconcileErr) + scope.EXPECT().DefaultedAzureServiceReconcileTimeout().Return(reconcilerutils.DefaultAzureServiceReconcileTimeout) s := &Service[*asoresourcesv1.ResourceGroup, *mock_aso.MockScope]{ Reconciler: reconciler, @@ -105,6 +108,7 @@ func TestServiceReconcile(t *testing.T) { reconciler.EXPECT().CreateOrUpdateResource(gomockinternal.AContext(), specs[1], serviceName).Return(nil, nil) reconciler.EXPECT().CreateOrUpdateResource(gomockinternal.AContext(), specs[2], serviceName).Return(nil, nil) scope.EXPECT().UpdatePutStatus(conditionType, serviceName, nil) + scope.EXPECT().DefaultedAzureServiceReconcileTimeout().Return(reconcilerutils.DefaultAzureServiceReconcileTimeout) s := &Service[*asoresourcesv1.ResourceGroup, *mock_aso.MockScope]{ Reconciler: reconciler, @@ -136,6 +140,7 @@ func TestServiceReconcile(t *testing.T) { reconciler.EXPECT().CreateOrUpdateResource(gomockinternal.AContext(), specs[1], serviceName).Return(nil, reconcileErr) reconciler.EXPECT().CreateOrUpdateResource(gomockinternal.AContext(), specs[2], serviceName).Return(nil, nil) scope.EXPECT().UpdatePutStatus(conditionType, serviceName, reconcileErr) + scope.EXPECT().DefaultedAzureServiceReconcileTimeout().Return(reconcilerutils.DefaultAzureServiceReconcileTimeout) s := &Service[*asoresourcesv1.ResourceGroup, *mock_aso.MockScope]{ Reconciler: reconciler, @@ -167,6 +172,7 @@ func TestServiceReconcile(t *testing.T) { reconciler.EXPECT().CreateOrUpdateResource(gomockinternal.AContext(), specs[1], serviceName).Return(nil, reconcileErr) reconciler.EXPECT().CreateOrUpdateResource(gomockinternal.AContext(), specs[2], serviceName).Return(nil, azure.NewOperationNotDoneError(&infrav1.Future{})) scope.EXPECT().UpdatePutStatus(conditionType, serviceName, reconcileErr) + scope.EXPECT().DefaultedAzureServiceReconcileTimeout().Return(reconcilerutils.DefaultAzureServiceReconcileTimeout) s := &Service[*asoresourcesv1.ResourceGroup, *mock_aso.MockScope]{ Reconciler: reconciler, @@ -200,6 +206,7 @@ func TestServiceReconcile(t *testing.T) { }, }, reconcileErr) scope.EXPECT().UpdatePutStatus(conditionType, serviceName, postReconcileErr) + scope.EXPECT().DefaultedAzureServiceReconcileTimeout().Return(reconcilerutils.DefaultAzureServiceReconcileTimeout) s := &Service[*asoresourcesv1.ResourceGroup, *mock_aso.MockScope]{ Reconciler: reconciler, @@ -232,6 +239,7 @@ func TestServiceDelete(t *testing.T) { mockCtrl := gomock.NewController(t) scope := mock_aso.NewMockScope(mockCtrl) reconciler := mock_aso.NewMockReconciler[*asoresourcesv1.ResourceGroup](mockCtrl) + scope.EXPECT().DefaultedAzureServiceReconcileTimeout().Return(reconcilerutils.DefaultAzureServiceReconcileTimeout) s := &Service[*asoresourcesv1.ResourceGroup, *mock_aso.MockScope]{ Reconciler: reconciler, @@ -262,6 +270,7 @@ func TestServiceDelete(t *testing.T) { reconciler := mock_aso.NewMockReconciler[*asoresourcesv1.ResourceGroup](mockCtrl) reconciler.EXPECT().DeleteResource(gomockinternal.AContext(), specs[0], serviceName).Return(deleteErr) scope.EXPECT().UpdateDeleteStatus(conditionType, serviceName, deleteErr) + scope.EXPECT().DefaultedAzureServiceReconcileTimeout().Return(reconcilerutils.DefaultAzureServiceReconcileTimeout) s := &Service[*asoresourcesv1.ResourceGroup, *mock_aso.MockScope]{ Reconciler: reconciler, @@ -292,6 +301,7 @@ func TestServiceDelete(t *testing.T) { reconciler.EXPECT().DeleteResource(gomockinternal.AContext(), specs[1], serviceName).Return(nil) reconciler.EXPECT().DeleteResource(gomockinternal.AContext(), specs[2], serviceName).Return(nil) scope.EXPECT().UpdateDeleteStatus(conditionType, serviceName, nil) + scope.EXPECT().DefaultedAzureServiceReconcileTimeout().Return(reconcilerutils.DefaultAzureServiceReconcileTimeout) s := &Service[*asoresourcesv1.ResourceGroup, *mock_aso.MockScope]{ Reconciler: reconciler, @@ -323,6 +333,7 @@ func TestServiceDelete(t *testing.T) { reconciler.EXPECT().DeleteResource(gomockinternal.AContext(), specs[1], serviceName).Return(deleteErr) reconciler.EXPECT().DeleteResource(gomockinternal.AContext(), specs[2], serviceName).Return(nil) scope.EXPECT().UpdateDeleteStatus(conditionType, serviceName, deleteErr) + scope.EXPECT().DefaultedAzureServiceReconcileTimeout().Return(reconcilerutils.DefaultAzureServiceReconcileTimeout) s := &Service[*asoresourcesv1.ResourceGroup, *mock_aso.MockScope]{ Reconciler: reconciler, @@ -354,6 +365,7 @@ func TestServiceDelete(t *testing.T) { reconciler.EXPECT().DeleteResource(gomockinternal.AContext(), specs[1], serviceName).Return(deleteErr) reconciler.EXPECT().DeleteResource(gomockinternal.AContext(), specs[2], serviceName).Return(azure.NewOperationNotDoneError(&infrav1.Future{})) scope.EXPECT().UpdateDeleteStatus(conditionType, serviceName, deleteErr) + scope.EXPECT().DefaultedAzureServiceReconcileTimeout().Return(reconcilerutils.DefaultAzureServiceReconcileTimeout) s := &Service[*asoresourcesv1.ResourceGroup, *mock_aso.MockScope]{ Reconciler: reconciler, @@ -382,6 +394,7 @@ func TestServiceDelete(t *testing.T) { reconciler := mock_aso.NewMockReconciler[*asoresourcesv1.ResourceGroup](mockCtrl) reconciler.EXPECT().DeleteResource(gomockinternal.AContext(), specs[0], serviceName).Return(deleteErr) scope.EXPECT().UpdateDeleteStatus(conditionType, serviceName, postErr) + scope.EXPECT().DefaultedAzureServiceReconcileTimeout().Return(reconcilerutils.DefaultAzureServiceReconcileTimeout) s := &Service[*asoresourcesv1.ResourceGroup, *mock_aso.MockScope]{ Reconciler: reconciler, diff --git a/azure/services/async/async.go b/azure/services/async/async.go index 3a166ff3bf0..58ad1f473bb 100644 --- a/azure/services/async/async.go +++ b/azure/services/async/async.go @@ -112,7 +112,7 @@ func (s *Service[C, D]) CreateOrUpdateResource(ctx context.Context, spec azure.R return nil, errWrapped } s.Scope.SetLongRunningOperationState(future) - return nil, azure.WithTransientError(azure.NewOperationNotDoneError(future), requeueTime()) + return nil, azure.WithTransientError(azure.NewOperationNotDoneError(future), requeueTime(s.Scope)) } // Once the operation is done, delete the long-running operation state. Even if the operation ended with @@ -156,7 +156,7 @@ func (s *Service[C, D]) DeleteResource(ctx context.Context, spec azure.ResourceS return errors.Wrap(err, "failed to convert poller to future") } s.Scope.SetLongRunningOperationState(future) - return azure.WithTransientError(azure.NewOperationNotDoneError(future), requeueTime()) + return azure.WithTransientError(azure.NewOperationNotDoneError(future), requeueTime(s.Scope)) } // Once the operation is done, delete the long-running operation state. Even if the operation ended with @@ -174,8 +174,8 @@ func (s *Service[C, D]) DeleteResource(ctx context.Context, spec azure.ResourceS // requeueTime returns the time to wait before requeuing a reconciliation. // It would be ideal to use the "retry-after" header from the API response, but // that is not readily accessible in the SDK v2 Poller framework. -func requeueTime() time.Duration { - return reconciler.DefaultReconcilerRequeue +func requeueTime(timeouts azure.AsyncReconciler) time.Duration { + return timeouts.DefaultedReconcilerRequeue() } // getRetryAfterFromError returns the time.Duration from the http.Response in the azcore.ResponseError. diff --git a/azure/services/async/async_test.go b/azure/services/async/async_test.go index fdc5fbef90e..9d90a9f92af 100644 --- a/azure/services/async/async_test.go +++ b/azure/services/async/async_test.go @@ -37,6 +37,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/mock_azure" "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) func TestServiceCreateOrUpdateResource(t *testing.T) { @@ -86,6 +87,7 @@ func TestServiceCreateOrUpdateResource(t *testing.T) { s.GetLongRunningOperationState(resourceName, serviceName, infrav1.PutFuture).Return(validPutFuture), c.CreateOrUpdateAsync(gomockinternal.AContext(), gomock.AssignableToTypeOf(azureResourceGetterType), resumeToken, gomock.Any()).Return(nil, fakePoller[MockCreator](g, http.StatusAccepted), context.DeadlineExceeded), s.SetLongRunningOperationState(gomock.AssignableToTypeOf(&infrav1.Future{})), + s.DefaultedReconcilerRequeue().Return(reconciler.DefaultReconcilerRequeue), ) }, }, @@ -116,6 +118,7 @@ func TestServiceCreateOrUpdateResource(t *testing.T) { r.Parameters(gomockinternal.AContext(), nil).Return(fakeParameters, nil), c.CreateOrUpdateAsync(gomockinternal.AContext(), gomock.AssignableToTypeOf(azureResourceGetterType), "", gomock.Any()).Return(nil, fakePoller[MockCreator](g, http.StatusAccepted), context.DeadlineExceeded), s.SetLongRunningOperationState(gomock.AssignableToTypeOf(&infrav1.Future{})), + s.DefaultedReconcilerRequeue().Return(reconciler.DefaultReconcilerRequeue), ) }, }, @@ -227,6 +230,7 @@ func TestServiceDeleteResource(t *testing.T) { s.GetLongRunningOperationState(resourceName, serviceName, infrav1.DeleteFuture).Return(validDeleteFuture), d.DeleteAsync(gomockinternal.AContext(), gomock.AssignableToTypeOf(azureResourceGetterType), gomock.Any()).Return(fakePoller[MockDeleter](g, http.StatusAccepted), context.DeadlineExceeded), s.SetLongRunningOperationState(gomock.AssignableToTypeOf(&infrav1.Future{})), + s.DefaultedReconcilerRequeue().Return(reconciler.DefaultReconcilerRequeue), ) }, }, diff --git a/azure/services/async/mock_async/async_mock.go b/azure/services/async/mock_async/async_mock.go index 813f4807ebd..4cc48a4c17a 100644 --- a/azure/services/async/mock_async/async_mock.go +++ b/azure/services/async/mock_async/async_mock.go @@ -27,6 +27,7 @@ package mock_async import ( context "context" reflect "reflect" + time "time" runtime "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" armresources "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources" @@ -59,6 +60,48 @@ func (m *MockFutureScope) EXPECT() *MockFutureScopeMockRecorder { return m.recorder } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockFutureScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockFutureScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockFutureScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockFutureScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockFutureScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockFutureScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockFutureScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockFutureScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockFutureScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockFutureScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/availabilitysets/availabilitysets.go b/azure/services/availabilitysets/availabilitysets.go index 6e3db673d51..e38635ee2f3 100644 --- a/azure/services/availabilitysets/availabilitysets.go +++ b/azure/services/availabilitysets/availabilitysets.go @@ -25,7 +25,6 @@ import ( "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/resourceskus" - "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -71,7 +70,7 @@ func (s *Service) Reconcile(ctx context.Context) error { ctx, log, done := tele.StartSpanWithLogger(ctx, "availabilitysets.Service.Reconcile") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() var err error @@ -91,7 +90,7 @@ func (s *Service) Delete(ctx context.Context) error { ctx, log, done := tele.StartSpanWithLogger(ctx, "availabilitysets.Service.Delete") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() var resultingErr error diff --git a/azure/services/availabilitysets/availabilitysets_test.go b/azure/services/availabilitysets/availabilitysets_test.go index 39df89812f7..aef12407f24 100644 --- a/azure/services/availabilitysets/availabilitysets_test.go +++ b/azure/services/availabilitysets/availabilitysets_test.go @@ -33,6 +33,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/availabilitysets/mock_availabilitysets" "sigs.k8s.io/cluster-api-provider-azure/azure/services/resourceskus" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) var ( @@ -83,6 +84,7 @@ func TestReconcileAvailabilitySets(t *testing.T) { name: "create or update availability set", expectedError: "", expect: func(s *mock_availabilitysets.MockAvailabilitySetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.AvailabilitySetSpec().Return(&fakeSetSpec) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeSetSpec, serviceName).Return(nil, nil) s.UpdatePutStatus(infrav1.AvailabilitySetReadyCondition, serviceName, nil) @@ -92,6 +94,7 @@ func TestReconcileAvailabilitySets(t *testing.T) { name: "noop if no availability set spec returns nil", expectedError: "", expect: func(s *mock_availabilitysets.MockAvailabilitySetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.AvailabilitySetSpec().Return(nil) }, }, @@ -99,6 +102,7 @@ func TestReconcileAvailabilitySets(t *testing.T) { name: "missing required value in availability set spec", expectedError: "some error with parameters", expect: func(s *mock_availabilitysets.MockAvailabilitySetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.AvailabilitySetSpec().Return(&fakeSetSpecMissing) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeSetSpecMissing, serviceName).Return(nil, parameterError) s.UpdatePutStatus(infrav1.AvailabilitySetReadyCondition, serviceName, parameterError) @@ -108,6 +112,7 @@ func TestReconcileAvailabilitySets(t *testing.T) { name: "error in creating availability set", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(s *mock_availabilitysets.MockAvailabilitySetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.AvailabilitySetSpec().Return(&fakeSetSpec) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeSetSpec, serviceName).Return(nil, internalError) s.UpdatePutStatus(infrav1.AvailabilitySetReadyCondition, serviceName, internalError) @@ -155,6 +160,7 @@ func TestDeleteAvailabilitySets(t *testing.T) { expect: func(s *mock_availabilitysets.MockAvailabilitySetScopeMockRecorder, m *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { s.AvailabilitySetSpec().Return(&fakeSetSpec) gomock.InOrder( + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout), m.Get(gomockinternal.AContext(), &fakeSetSpec).Return(armcompute.AvailabilitySet{}, nil), r.DeleteResource(gomockinternal.AContext(), &fakeSetSpec, serviceName).Return(nil), s.UpdateDeleteStatus(infrav1.AvailabilitySetReadyCondition, serviceName, nil), @@ -165,6 +171,7 @@ func TestDeleteAvailabilitySets(t *testing.T) { name: "noop if AvailabilitySetSpec returns nil", expectedError: "", expect: func(s *mock_availabilitysets.MockAvailabilitySetScopeMockRecorder, m *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.AvailabilitySetSpec().Return(nil) }, }, @@ -174,6 +181,7 @@ func TestDeleteAvailabilitySets(t *testing.T) { expect: func(s *mock_availabilitysets.MockAvailabilitySetScopeMockRecorder, m *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { s.AvailabilitySetSpec().Return(&fakeSetSpecMissing) gomock.InOrder( + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout), m.Get(gomockinternal.AContext(), &fakeSetSpecMissing).Return(armcompute.AvailabilitySet{}, nil), r.DeleteResource(gomockinternal.AContext(), &fakeSetSpecMissing, serviceName).Return(nil), s.UpdateDeleteStatus(infrav1.AvailabilitySetReadyCondition, serviceName, nil), @@ -186,6 +194,7 @@ func TestDeleteAvailabilitySets(t *testing.T) { expect: func(s *mock_availabilitysets.MockAvailabilitySetScopeMockRecorder, m *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { s.AvailabilitySetSpec().Return(&fakeSetSpec) gomock.InOrder( + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout), m.Get(gomockinternal.AContext(), &fakeSetSpec).Return(fakeSetWithVMs, nil), s.UpdateDeleteStatus(infrav1.AvailabilitySetReadyCondition, serviceName, nil), ) @@ -197,6 +206,7 @@ func TestDeleteAvailabilitySets(t *testing.T) { expect: func(s *mock_availabilitysets.MockAvailabilitySetScopeMockRecorder, m *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { s.AvailabilitySetSpec().Return(&fakeSetSpec) gomock.InOrder( + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout), m.Get(gomockinternal.AContext(), &fakeSetSpec).Return(nil, notFoundError), s.UpdateDeleteStatus(infrav1.AvailabilitySetReadyCondition, serviceName, nil), ) @@ -208,6 +218,7 @@ func TestDeleteAvailabilitySets(t *testing.T) { expect: func(s *mock_availabilitysets.MockAvailabilitySetScopeMockRecorder, m *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { s.AvailabilitySetSpec().Return(&fakeSetSpec) gomock.InOrder( + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout), m.Get(gomockinternal.AContext(), &fakeSetSpec).Return(nil, internalError), s.UpdateDeleteStatus(infrav1.AvailabilitySetReadyCondition, serviceName, gomockinternal.ErrStrEq("failed to get availability set test-as in resource group test-rg: #: Internal Server Error: StatusCode=500")), ) @@ -219,6 +230,7 @@ func TestDeleteAvailabilitySets(t *testing.T) { expect: func(s *mock_availabilitysets.MockAvailabilitySetScopeMockRecorder, m *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { s.AvailabilitySetSpec().Return(&fakeSetSpec) gomock.InOrder( + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout), m.Get(gomockinternal.AContext(), &fakeSetSpec).Return("not an availability set", nil), s.UpdateDeleteStatus(infrav1.AvailabilitySetReadyCondition, serviceName, gomockinternal.ErrStrEq("string is not an armcompute.AvailabilitySet")), ) @@ -230,6 +242,7 @@ func TestDeleteAvailabilitySets(t *testing.T) { expect: func(s *mock_availabilitysets.MockAvailabilitySetScopeMockRecorder, m *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { s.AvailabilitySetSpec().Return(&fakeSetSpec) gomock.InOrder( + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout), m.Get(gomockinternal.AContext(), &fakeSetSpec).Return(armcompute.AvailabilitySet{}, nil), r.DeleteResource(gomockinternal.AContext(), &fakeSetSpec, serviceName).Return(internalError), s.UpdateDeleteStatus(infrav1.AvailabilitySetReadyCondition, serviceName, internalError), diff --git a/azure/services/availabilitysets/mock_availabilitysets/availabilitysets_mock.go b/azure/services/availabilitysets/mock_availabilitysets/availabilitysets_mock.go index 6a379dd1358..9af8cf9314b 100644 --- a/azure/services/availabilitysets/mock_availabilitysets/availabilitysets_mock.go +++ b/azure/services/availabilitysets/mock_availabilitysets/availabilitysets_mock.go @@ -26,6 +26,7 @@ package mock_availabilitysets import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -183,6 +184,48 @@ func (mr *MockAvailabilitySetScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockAvailabilitySetScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockAvailabilitySetScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockAvailabilitySetScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockAvailabilitySetScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockAvailabilitySetScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockAvailabilitySetScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockAvailabilitySetScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockAvailabilitySetScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockAvailabilitySetScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockAvailabilitySetScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockAvailabilitySetScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/disks/client.go b/azure/services/disks/client.go index 420d2cf3e2a..8e9434dbcb8 100644 --- a/azure/services/disks/client.go +++ b/azure/services/disks/client.go @@ -18,23 +18,24 @@ package disks import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) // azureClient contains the Azure go-sdk Client. type azureClient struct { - disks *armcompute.DisksClient + disks *armcompute.DisksClient + apiCallTimeout time.Duration } // newClient creates a new disks client from an authorizer. -func newClient(auth azure.Authorizer) (*azureClient, error) { +func newClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*azureClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to create disks client options") @@ -43,7 +44,7 @@ func newClient(auth azure.Authorizer) (*azureClient, error) { if err != nil { return nil, errors.Wrap(err, "failed to create armcompute client factory") } - return &azureClient{factory.NewDisksClient()}, nil + return &azureClient{factory.NewDisksClient(), apiCallTimeout}, nil } // DeleteAsync deletes a disk asynchronously. DeleteAsync sends a DELETE @@ -59,7 +60,7 @@ func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/disks/disks.go b/azure/services/disks/disks.go index 8c9cb6a4d06..4f0f6ded3cd 100644 --- a/azure/services/disks/disks.go +++ b/azure/services/disks/disks.go @@ -23,7 +23,6 @@ import ( 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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -44,7 +43,7 @@ type Service struct { // New creates a disks service. func New(scope DiskScope) (*Service, error) { - client, err := newClient(scope) + client, err := newClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -74,7 +73,7 @@ func (s *Service) Delete(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "disks.Service.Delete") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() specs := s.Scope.DiskSpecs() diff --git a/azure/services/disks/disks_test.go b/azure/services/disks/disks_test.go index 0a1cfc71dd6..ccb4bb91923 100644 --- a/azure/services/disks/disks_test.go +++ b/azure/services/disks/disks_test.go @@ -29,6 +29,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/disks/mock_disks" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) var ( @@ -60,6 +61,7 @@ func TestDeleteDisk(t *testing.T) { name: "noop if no disk specs are found", expectedError: "", expect: func(s *mock_disks.MockDiskScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.DiskSpecs().Return([]azure.ResourceSpecGetter{}) }, }, @@ -69,6 +71,7 @@ func TestDeleteDisk(t *testing.T) { expect: func(s *mock_disks.MockDiskScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { s.DiskSpecs().Return(fakeDiskSpecs) gomock.InOrder( + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout), r.DeleteResource(gomockinternal.AContext(), &diskSpec1, serviceName).Return(nil), r.DeleteResource(gomockinternal.AContext(), &diskSpec2, serviceName).Return(nil), s.UpdateDeleteStatus(infrav1.DisksReadyCondition, serviceName, nil), @@ -81,6 +84,7 @@ func TestDeleteDisk(t *testing.T) { expect: func(s *mock_disks.MockDiskScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { s.DiskSpecs().Return(fakeDiskSpecs) gomock.InOrder( + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout), r.DeleteResource(gomockinternal.AContext(), &diskSpec1, serviceName).Return(nil), r.DeleteResource(gomockinternal.AContext(), &diskSpec2, serviceName).Return(nil), s.UpdateDeleteStatus(infrav1.DisksReadyCondition, serviceName, nil), @@ -93,6 +97,7 @@ func TestDeleteDisk(t *testing.T) { expect: func(s *mock_disks.MockDiskScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { s.DiskSpecs().Return(fakeDiskSpecs) gomock.InOrder( + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout), r.DeleteResource(gomockinternal.AContext(), &diskSpec1, serviceName).Return(internalError), r.DeleteResource(gomockinternal.AContext(), &diskSpec2, serviceName).Return(nil), s.UpdateDeleteStatus(infrav1.DisksReadyCondition, serviceName, internalError), diff --git a/azure/services/disks/mock_disks/disks_mock.go b/azure/services/disks/mock_disks/disks_mock.go index 59c428747ed..c6fd4130c8e 100644 --- a/azure/services/disks/mock_disks/disks_mock.go +++ b/azure/services/disks/mock_disks/disks_mock.go @@ -26,6 +26,7 @@ package mock_disks import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -169,6 +170,48 @@ func (mr *MockDiskScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockDiskScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockDiskScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockDiskScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockDiskScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockDiskScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockDiskScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockDiskScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockDiskScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockDiskScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockDiskScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockDiskScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/groups/mock_groups/groups_mock.go b/azure/services/groups/mock_groups/groups_mock.go index 704f1f698b7..1cf3f923632 100644 --- a/azure/services/groups/mock_groups/groups_mock.go +++ b/azure/services/groups/mock_groups/groups_mock.go @@ -26,6 +26,7 @@ package mock_groups import ( reflect "reflect" + time "time" v1api20200601 "github.com/Azure/azure-service-operator/v2/api/resources/v1api20200601" gomock "go.uber.org/mock/gomock" @@ -72,6 +73,48 @@ func (mr *MockGroupScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockGroupScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockGroupScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockGroupScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockGroupScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockGroupScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockGroupScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockGroupScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockGroupScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockGroupScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockGroupScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockGroupScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/inboundnatrules/client.go b/azure/services/inboundnatrules/client.go index 1bf910508e8..a7f7c57fa42 100644 --- a/azure/services/inboundnatrules/client.go +++ b/azure/services/inboundnatrules/client.go @@ -18,13 +18,13 @@ package inboundnatrules import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4" "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -36,12 +36,13 @@ type client interface { // azureClient contains the Azure go-sdk Client. type azureClient struct { inboundnatrules *armnetwork.InboundNatRulesClient + apiCallTimeout time.Duration } var _ client = (*azureClient)(nil) // newClient creates a new inbound NAT rules client from an authorizer. -func newClient(auth azure.Authorizer) (*azureClient, error) { +func newClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*azureClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to create inboundnatrules client options") @@ -50,7 +51,7 @@ func newClient(auth azure.Authorizer) (*azureClient, error) { if err != nil { return nil, errors.Wrap(err, "failed to create armnetwork client factory") } - return &azureClient{factory.NewInboundNatRulesClient()}, nil + return &azureClient{factory.NewInboundNatRulesClient(), apiCallTimeout}, nil } // Get gets the specified inbound NAT rules. @@ -104,7 +105,7 @@ func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.Resou return nil, nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} @@ -133,7 +134,7 @@ func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/inboundnatrules/inboundnatrules.go b/azure/services/inboundnatrules/inboundnatrules.go index 4158dddf8eb..b5893e19fdf 100644 --- a/azure/services/inboundnatrules/inboundnatrules.go +++ b/azure/services/inboundnatrules/inboundnatrules.go @@ -24,7 +24,6 @@ import ( 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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -47,7 +46,7 @@ type Service struct { // New creates a new service. func New(scope InboundNatScope) (*Service, error) { - client, err := newClient(scope) + client, err := newClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -69,6 +68,9 @@ func (s *Service) Reconcile(ctx context.Context) error { ctx, log, done := tele.StartSpanWithLogger(ctx, "inboundnatrules.Service.Reconcile") defer done() + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) + defer cancel() + // Externally managed clusters might not have an LB if s.Scope.APIServerLBName() == "" { log.V(4).Info("Skipping InboundNatRule reconciliation as the cluster has no LB configured") @@ -80,9 +82,6 @@ func (s *Service) Reconcile(ctx context.Context) error { return nil } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) - defer cancel() - existingRules, err := s.client.List(ctx, s.Scope.ResourceGroup(), s.Scope.APIServerLBName()) if err != nil { result := errors.Wrapf(err, "failed to get existing NAT rules") @@ -129,7 +128,7 @@ func (s *Service) Delete(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "inboundnatrules.Service.Delete") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() specs := s.Scope.InboundNatSpecs() diff --git a/azure/services/inboundnatrules/inboundnatrules_test.go b/azure/services/inboundnatrules/inboundnatrules_test.go index 44ca569aa63..9c0eb2479d8 100644 --- a/azure/services/inboundnatrules/inboundnatrules_test.go +++ b/azure/services/inboundnatrules/inboundnatrules_test.go @@ -31,6 +31,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/inboundnatrules/mock_inboundnatrules" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) var ( @@ -96,6 +97,7 @@ func TestReconcileInboundNATRule(t *testing.T) { expect: func(s *mock_inboundnatrules.MockInboundNatScopeMockRecorder, m *mock_inboundnatrules.MockclientMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.ResourceGroup().AnyTimes().Return(fakeGroupName) s.APIServerLBName().AnyTimes().Return(fakeLBName) s.InboundNatSpecs().Return([]azure.ResourceSpecGetter{}) @@ -107,6 +109,7 @@ func TestReconcileInboundNATRule(t *testing.T) { expect: func(s *mock_inboundnatrules.MockInboundNatScopeMockRecorder, m *mock_inboundnatrules.MockclientMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.ResourceGroup().AnyTimes().Return(fakeGroupName) s.APIServerLBName().AnyTimes().Return(fakeLBName) m.List(gomockinternal.AContext(), fakeGroupName, fakeLBName).Return(noExistingRules, nil) @@ -124,6 +127,7 @@ func TestReconcileInboundNATRule(t *testing.T) { expect: func(s *mock_inboundnatrules.MockInboundNatScopeMockRecorder, m *mock_inboundnatrules.MockclientMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.ResourceGroup().AnyTimes().Return(fakeGroupName) s.APIServerLBName().AnyTimes().Return("my-lb") m.List(gomockinternal.AContext(), fakeGroupName, "my-lb").Return(fakeExistingRules, nil) @@ -140,6 +144,7 @@ func TestReconcileInboundNATRule(t *testing.T) { expect: func(s *mock_inboundnatrules.MockInboundNatScopeMockRecorder, m *mock_inboundnatrules.MockclientMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.APIServerLBName().AnyTimes().Return("") }, }, @@ -149,6 +154,7 @@ func TestReconcileInboundNATRule(t *testing.T) { expect: func(s *mock_inboundnatrules.MockInboundNatScopeMockRecorder, m *mock_inboundnatrules.MockclientMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.ResourceGroup().AnyTimes().Return(fakeGroupName) s.APIServerLBName().AnyTimes().Return("my-lb") s.InboundNatSpecs().Return([]azure.ResourceSpecGetter{&fakeNatSpec}) @@ -162,6 +168,7 @@ func TestReconcileInboundNATRule(t *testing.T) { expect: func(s *mock_inboundnatrules.MockInboundNatScopeMockRecorder, m *mock_inboundnatrules.MockclientMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.ResourceGroup().AnyTimes().Return(fakeGroupName) s.APIServerLBName().AnyTimes().Return("my-lb") m.List(gomockinternal.AContext(), fakeGroupName, "my-lb").Return(fakeExistingRules, nil) @@ -216,6 +223,7 @@ func TestDeleteNetworkInterface(t *testing.T) { expectedError: "", expect: func(s *mock_inboundnatrules.MockInboundNatScopeMockRecorder, m *mock_inboundnatrules.MockclientMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.InboundNatSpecs().Return([]azure.ResourceSpecGetter{}) }, }, @@ -224,6 +232,7 @@ func TestDeleteNetworkInterface(t *testing.T) { expectedError: "", expect: func(s *mock_inboundnatrules.MockInboundNatScopeMockRecorder, m *mock_inboundnatrules.MockclientMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.InboundNatSpecs().Return([]azure.ResourceSpecGetter{&fakeNatSpec}) s.ResourceGroup().AnyTimes().Return(fakeGroupName) s.APIServerLBName().AnyTimes().Return(fakeLBName) @@ -238,6 +247,7 @@ func TestDeleteNetworkInterface(t *testing.T) { expectedError: "#: Internal Server Error: StatusCode=500", expect: func(s *mock_inboundnatrules.MockInboundNatScopeMockRecorder, m *mock_inboundnatrules.MockclientMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.InboundNatSpecs().Return([]azure.ResourceSpecGetter{&fakeNatSpec}) s.ResourceGroup().AnyTimes().Return(fakeGroupName) s.APIServerLBName().AnyTimes().Return(fakeLBName) diff --git a/azure/services/inboundnatrules/mock_inboundnatrules/inboundnatrules_mock.go b/azure/services/inboundnatrules/mock_inboundnatrules/inboundnatrules_mock.go index c0fefc61f34..ac4127a9bbc 100644 --- a/azure/services/inboundnatrules/mock_inboundnatrules/inboundnatrules_mock.go +++ b/azure/services/inboundnatrules/mock_inboundnatrules/inboundnatrules_mock.go @@ -26,6 +26,7 @@ package mock_inboundnatrules import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -183,6 +184,48 @@ func (mr *MockInboundNatScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockInboundNatScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockInboundNatScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockInboundNatScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockInboundNatScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockInboundNatScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockInboundNatScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockInboundNatScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockInboundNatScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockInboundNatScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockInboundNatScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockInboundNatScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/loadbalancers/client.go b/azure/services/loadbalancers/client.go index 7d238d6d07c..143ee86e7bf 100644 --- a/azure/services/loadbalancers/client.go +++ b/azure/services/loadbalancers/client.go @@ -18,6 +18,7 @@ package loadbalancers import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" @@ -25,18 +26,18 @@ import ( "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) // azureClient contains the Azure go-sdk Client. type azureClient struct { - loadbalancers *armnetwork.LoadBalancersClient - auth azure.Authorizer + loadbalancers *armnetwork.LoadBalancersClient + auth azure.Authorizer + apiCallTimeout time.Duration } // newClient creates a new load balancer client from an authorizer. -func newClient(auth azure.Authorizer) (*azureClient, error) { +func newClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*azureClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to get load balancer client options") @@ -46,7 +47,7 @@ func newClient(auth azure.Authorizer) (*azureClient, error) { if err != nil { return nil, errors.Wrap(err, "failed to create armnetwork client factory") } - return &azureClient{factory.NewLoadBalancersClient(), auth}, nil + return &azureClient{factory.NewLoadBalancersClient(), auth, apiCallTimeout}, nil } // Get gets the specified load balancer. @@ -101,7 +102,7 @@ func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.Resou return nil, nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} @@ -129,7 +130,7 @@ func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/loadbalancers/loadbalancers.go b/azure/services/loadbalancers/loadbalancers.go index ce197d1499d..94ca914cb9a 100644 --- a/azure/services/loadbalancers/loadbalancers.go +++ b/azure/services/loadbalancers/loadbalancers.go @@ -23,7 +23,6 @@ import ( 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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -50,7 +49,7 @@ type Service struct { // New creates a new service. func New(scope LBScope) (*Service, error) { - client, err := newClient(scope) + client, err := newClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -71,7 +70,7 @@ func (s *Service) Reconcile(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "loadbalancers.Service.Reconcile") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() specs := s.Scope.LBSpecs() @@ -100,7 +99,7 @@ func (s *Service) Delete(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "loadbalancers.Service.Delete") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() specs := s.Scope.LBSpecs() diff --git a/azure/services/loadbalancers/loadbalancers_test.go b/azure/services/loadbalancers/loadbalancers_test.go index 3f67d7b9551..16c10356caf 100644 --- a/azure/services/loadbalancers/loadbalancers_test.go +++ b/azure/services/loadbalancers/loadbalancers_test.go @@ -30,6 +30,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/loadbalancers/mock_loadbalancers" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) var ( @@ -114,6 +115,7 @@ func TestReconcileLoadBalancer(t *testing.T) { name: "noop if no LBSpecs are found", expectedError: "", expect: func(s *mock_loadbalancers.MockLBScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.LBSpecs().Return([]azure.ResourceSpecGetter{}) }, }, @@ -121,6 +123,7 @@ func TestReconcileLoadBalancer(t *testing.T) { name: "fail to create a public LB", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(s *mock_loadbalancers.MockLBScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.LBSpecs().Return([]azure.ResourceSpecGetter{&fakePublicAPILBSpec}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicAPILBSpec, serviceName).Return(nil, internalError) s.UpdatePutStatus(infrav1.LoadBalancersReadyCondition, serviceName, internalError) @@ -130,6 +133,7 @@ func TestReconcileLoadBalancer(t *testing.T) { name: "create public apiserver LB", expectedError: "", expect: func(s *mock_loadbalancers.MockLBScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.LBSpecs().Return([]azure.ResourceSpecGetter{&fakePublicAPILBSpec}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicAPILBSpec, serviceName).Return(nil, nil) s.UpdatePutStatus(infrav1.LoadBalancersReadyCondition, serviceName, nil) @@ -139,6 +143,7 @@ func TestReconcileLoadBalancer(t *testing.T) { name: "create internal apiserver LB", expectedError: "", expect: func(s *mock_loadbalancers.MockLBScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.LBSpecs().Return([]azure.ResourceSpecGetter{&fakeInternalAPILBSpec}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeInternalAPILBSpec, serviceName).Return(nil, nil) s.UpdatePutStatus(infrav1.LoadBalancersReadyCondition, serviceName, nil) @@ -148,6 +153,7 @@ func TestReconcileLoadBalancer(t *testing.T) { name: "create node outbound LB", expectedError: "", expect: func(s *mock_loadbalancers.MockLBScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.LBSpecs().Return([]azure.ResourceSpecGetter{&fakeNodeOutboundLBSpec}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeNodeOutboundLBSpec, serviceName).Return(nil, nil) s.UpdatePutStatus(infrav1.LoadBalancersReadyCondition, serviceName, nil) @@ -157,6 +163,7 @@ func TestReconcileLoadBalancer(t *testing.T) { name: "create multiple LBs", expectedError: "", expect: func(s *mock_loadbalancers.MockLBScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.LBSpecs().Return([]azure.ResourceSpecGetter{&fakePublicAPILBSpec, &fakeInternalAPILBSpec, &fakeNodeOutboundLBSpec}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicAPILBSpec, serviceName).Return(nil, nil) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeInternalAPILBSpec, serviceName).Return(nil, nil) @@ -205,6 +212,7 @@ func TestDeleteLoadBalancer(t *testing.T) { name: "noop if no LBSpecs are found", expectedError: "", expect: func(s *mock_loadbalancers.MockLBScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.LBSpecs().Return([]azure.ResourceSpecGetter{}) }, }, @@ -212,6 +220,7 @@ func TestDeleteLoadBalancer(t *testing.T) { name: "delete a load balancer", expectedError: "", expect: func(s *mock_loadbalancers.MockLBScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.LBSpecs().Return([]azure.ResourceSpecGetter{&fakePublicAPILBSpec}) r.DeleteResource(gomockinternal.AContext(), &fakePublicAPILBSpec, serviceName).Return(nil) s.UpdateDeleteStatus(infrav1.LoadBalancersReadyCondition, serviceName, nil) @@ -221,6 +230,7 @@ func TestDeleteLoadBalancer(t *testing.T) { name: "delete multiple load balancers", expectedError: "", expect: func(s *mock_loadbalancers.MockLBScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.LBSpecs().Return([]azure.ResourceSpecGetter{&fakePublicAPILBSpec, &fakeInternalAPILBSpec, &fakeNodeOutboundLBSpec}) r.DeleteResource(gomockinternal.AContext(), &fakePublicAPILBSpec, serviceName).Return(nil) r.DeleteResource(gomockinternal.AContext(), &fakeInternalAPILBSpec, serviceName).Return(nil) @@ -232,6 +242,7 @@ func TestDeleteLoadBalancer(t *testing.T) { name: "load balancer deletion fails", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(s *mock_loadbalancers.MockLBScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.LBSpecs().Return([]azure.ResourceSpecGetter{&fakePublicAPILBSpec}) r.DeleteResource(gomockinternal.AContext(), &fakePublicAPILBSpec, serviceName).Return(internalError) s.UpdateDeleteStatus(infrav1.LoadBalancersReadyCondition, serviceName, internalError) diff --git a/azure/services/loadbalancers/mock_loadbalancers/loadbalancers_mock.go b/azure/services/loadbalancers/mock_loadbalancers/loadbalancers_mock.go index e9a816f1481..80bfd514011 100644 --- a/azure/services/loadbalancers/mock_loadbalancers/loadbalancers_mock.go +++ b/azure/services/loadbalancers/mock_loadbalancers/loadbalancers_mock.go @@ -26,6 +26,7 @@ package mock_loadbalancers import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -241,6 +242,48 @@ func (mr *MockLBScopeMockRecorder) ControlPlaneSubnet() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ControlPlaneSubnet", reflect.TypeOf((*MockLBScope)(nil).ControlPlaneSubnet)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockLBScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockLBScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockLBScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockLBScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockLBScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockLBScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockLBScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockLBScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockLBScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockLBScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/managedclusters/mock_managedclusters/managedclusters_mock.go b/azure/services/managedclusters/mock_managedclusters/managedclusters_mock.go index b83690742d9..b89afbfcb9e 100644 --- a/azure/services/managedclusters/mock_managedclusters/managedclusters_mock.go +++ b/azure/services/managedclusters/mock_managedclusters/managedclusters_mock.go @@ -27,6 +27,7 @@ package mock_managedclusters import ( context "context" reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" v1api20231001 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001" @@ -145,6 +146,48 @@ func (mr *MockManagedClusterScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockManagedClusterScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockManagedClusterScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockManagedClusterScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockManagedClusterScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockManagedClusterScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockManagedClusterScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockManagedClusterScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockManagedClusterScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockManagedClusterScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockManagedClusterScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockManagedClusterScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/natgateways/mock_natgateways/natgateways_mock.go b/azure/services/natgateways/mock_natgateways/natgateways_mock.go index 72a4e11b2fa..21467637002 100644 --- a/azure/services/natgateways/mock_natgateways/natgateways_mock.go +++ b/azure/services/natgateways/mock_natgateways/natgateways_mock.go @@ -26,6 +26,7 @@ package mock_natgateways import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" v1api20220701 "github.com/Azure/azure-service-operator/v2/api/network/v1api20220701" @@ -242,6 +243,48 @@ func (mr *MockNatGatewayScopeMockRecorder) ControlPlaneSubnet() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ControlPlaneSubnet", reflect.TypeOf((*MockNatGatewayScope)(nil).ControlPlaneSubnet)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockNatGatewayScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockNatGatewayScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockNatGatewayScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockNatGatewayScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockNatGatewayScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockNatGatewayScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockNatGatewayScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockNatGatewayScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockNatGatewayScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockNatGatewayScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/networkinterfaces/client.go b/azure/services/networkinterfaces/client.go index dfa156a7cda..0f6a62302d3 100644 --- a/azure/services/networkinterfaces/client.go +++ b/azure/services/networkinterfaces/client.go @@ -18,23 +18,24 @@ package networkinterfaces import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4" "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) // azureClient contains the Azure go-sdk Client. type azureClient struct { - interfaces *armnetwork.InterfacesClient + interfaces *armnetwork.InterfacesClient + apiCallTimeout time.Duration } // NewClient creates a new network interfaces client from an authorizer. -func NewClient(auth azure.Authorizer) (*azureClient, error) { +func NewClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*azureClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to create networkinterfaces client options") @@ -43,7 +44,7 @@ func NewClient(auth azure.Authorizer) (*azureClient, error) { if err != nil { return nil, errors.Wrap(err, "failed to create armnetwork client factory") } - return &azureClient{factory.NewInterfacesClient()}, nil + return &azureClient{factory.NewInterfacesClient(), apiCallTimeout}, nil } // Get gets the specified network interface. @@ -76,7 +77,7 @@ func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.Resou return nil, nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} @@ -104,7 +105,7 @@ func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/networkinterfaces/mock_networkinterfaces/networkinterfaces_mock.go b/azure/services/networkinterfaces/mock_networkinterfaces/networkinterfaces_mock.go index de024eab203..8467628b0b0 100644 --- a/azure/services/networkinterfaces/mock_networkinterfaces/networkinterfaces_mock.go +++ b/azure/services/networkinterfaces/mock_networkinterfaces/networkinterfaces_mock.go @@ -26,6 +26,7 @@ package mock_networkinterfaces import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -169,6 +170,48 @@ func (mr *MockNICScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockNICScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockNICScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockNICScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockNICScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockNICScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockNICScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockNICScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockNICScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockNICScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockNICScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockNICScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/networkinterfaces/networkinterfaces.go b/azure/services/networkinterfaces/networkinterfaces.go index bd2a761d2d1..4f0b20d6f6d 100644 --- a/azure/services/networkinterfaces/networkinterfaces.go +++ b/azure/services/networkinterfaces/networkinterfaces.go @@ -24,7 +24,6 @@ import ( "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/resourceskus" - "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -46,7 +45,7 @@ type Service struct { // New creates a new service. func New(scope NICScope, skuCache *resourceskus.Cache) (*Service, error) { - client, err := NewClient(scope) + client, err := NewClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -68,7 +67,7 @@ func (s *Service) Reconcile(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "networkinterfaces.Service.Reconcile") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() specs := s.Scope.NICSpecs() @@ -97,7 +96,7 @@ func (s *Service) Delete(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "networkinterfaces.Service.Delete") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() specs := s.Scope.NICSpecs() diff --git a/azure/services/networkinterfaces/networkinterfaces_test.go b/azure/services/networkinterfaces/networkinterfaces_test.go index c16d90831ff..a9c65c8a488 100644 --- a/azure/services/networkinterfaces/networkinterfaces_test.go +++ b/azure/services/networkinterfaces/networkinterfaces_test.go @@ -31,6 +31,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/networkinterfaces/mock_networkinterfaces" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) var ( @@ -83,6 +84,7 @@ func TestReconcileNetworkInterface(t *testing.T) { name: "noop if no network interface specs are found", expectedError: "", expect: func(s *mock_networkinterfaces.MockNICScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.NICSpecs().Return([]azure.ResourceSpecGetter{}) }, }, @@ -90,6 +92,7 @@ func TestReconcileNetworkInterface(t *testing.T) { name: "successfully create a network interface", expectedError: "", expect: func(s *mock_networkinterfaces.MockNICScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.NICSpecs().Return([]azure.ResourceSpecGetter{&fakeNICSpec1}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeNICSpec1, serviceName).Return(nil, nil) s.UpdatePutStatus(infrav1.NetworkInterfaceReadyCondition, serviceName, nil) @@ -99,6 +102,7 @@ func TestReconcileNetworkInterface(t *testing.T) { name: "successfully create a network interface with multiple IPConfigs", expectedError: "", expect: func(s *mock_networkinterfaces.MockNICScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.NICSpecs().Return([]azure.ResourceSpecGetter{&fakeNICSpec3}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeNICSpec3, serviceName).Return(nil, nil) s.UpdatePutStatus(infrav1.NetworkInterfaceReadyCondition, serviceName, nil) @@ -108,6 +112,7 @@ func TestReconcileNetworkInterface(t *testing.T) { name: "successfully create multiple network interfaces", expectedError: "", expect: func(s *mock_networkinterfaces.MockNICScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.NICSpecs().Return([]azure.ResourceSpecGetter{&fakeNICSpec1, &fakeNICSpec2}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeNICSpec1, serviceName).Return(nil, nil) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeNICSpec2, serviceName).Return(nil, nil) @@ -118,6 +123,7 @@ func TestReconcileNetworkInterface(t *testing.T) { name: "network interface create fails", expectedError: internalError.Error(), expect: func(s *mock_networkinterfaces.MockNICScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.NICSpecs().Return([]azure.ResourceSpecGetter{&fakeNICSpec1, &fakeNICSpec2}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeNICSpec1, serviceName).Return(nil, internalError) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeNICSpec2, serviceName).Return(nil, nil) @@ -166,6 +172,7 @@ func TestDeleteNetworkInterface(t *testing.T) { name: "noop if no network interface specs are found", expectedError: "", expect: func(s *mock_networkinterfaces.MockNICScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.NICSpecs().Return([]azure.ResourceSpecGetter{}) }, }, @@ -173,6 +180,7 @@ func TestDeleteNetworkInterface(t *testing.T) { name: "successfully delete an existing network interface", expectedError: "", expect: func(s *mock_networkinterfaces.MockNICScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.NICSpecs().Return([]azure.ResourceSpecGetter{&fakeNICSpec1}) r.DeleteResource(gomockinternal.AContext(), &fakeNICSpec1, serviceName).Return(nil) s.UpdateDeleteStatus(infrav1.NetworkInterfaceReadyCondition, serviceName, nil) @@ -182,6 +190,7 @@ func TestDeleteNetworkInterface(t *testing.T) { name: "successfully delete multiple existing network interfaces", expectedError: "", expect: func(s *mock_networkinterfaces.MockNICScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.NICSpecs().Return([]azure.ResourceSpecGetter{&fakeNICSpec1, &fakeNICSpec2}) r.DeleteResource(gomockinternal.AContext(), &fakeNICSpec1, serviceName).Return(nil) r.DeleteResource(gomockinternal.AContext(), &fakeNICSpec2, serviceName).Return(nil) @@ -192,6 +201,7 @@ func TestDeleteNetworkInterface(t *testing.T) { name: "network interface deletion fails", expectedError: internalError.Error(), expect: func(s *mock_networkinterfaces.MockNICScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.NICSpecs().Return([]azure.ResourceSpecGetter{&fakeNICSpec1, &fakeNICSpec2}) r.DeleteResource(gomockinternal.AContext(), &fakeNICSpec1, serviceName).Return(nil) r.DeleteResource(gomockinternal.AContext(), &fakeNICSpec2, serviceName).Return(internalError) diff --git a/azure/services/privatedns/link_client.go b/azure/services/privatedns/link_client.go index 84041b69cec..495f73f3b66 100644 --- a/azure/services/privatedns/link_client.go +++ b/azure/services/privatedns/link_client.go @@ -18,23 +18,24 @@ package privatedns import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns" "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) // azureVirtualNetworkLinksClient contains the Azure go-sdk Client for virtual network links. type azureVirtualNetworkLinksClient struct { - vnetlinks *armprivatedns.VirtualNetworkLinksClient + vnetlinks *armprivatedns.VirtualNetworkLinksClient + apiCallTimeout time.Duration } // newVirtualNetworkLinksClient creates a virtual network links client from an authorizer. -func newVirtualNetworkLinksClient(auth azure.Authorizer) (*azureVirtualNetworkLinksClient, error) { +func newVirtualNetworkLinksClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*azureVirtualNetworkLinksClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to create virtualnetworkslink client options") @@ -43,7 +44,7 @@ func newVirtualNetworkLinksClient(auth azure.Authorizer) (*azureVirtualNetworkLi if err != nil { return nil, errors.Wrap(err, "failed to create armprivatedns client factory") } - return &azureVirtualNetworkLinksClient{factory.NewVirtualNetworkLinksClient()}, nil + return &azureVirtualNetworkLinksClient{factory.NewVirtualNetworkLinksClient(), apiCallTimeout}, nil } // Get gets the specified virtual network link. @@ -76,7 +77,7 @@ func (avc *azureVirtualNetworkLinksClient) CreateOrUpdateAsync(ctx context.Conte return nil, nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, avc.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} @@ -104,7 +105,7 @@ func (avc *azureVirtualNetworkLinksClient) DeleteAsync(ctx context.Context, spec return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, avc.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/privatedns/mock_privatedns/privatedns_mock.go b/azure/services/privatedns/mock_privatedns/privatedns_mock.go index 17520ff0a3e..cf995bc59a0 100644 --- a/azure/services/privatedns/mock_privatedns/privatedns_mock.go +++ b/azure/services/privatedns/mock_privatedns/privatedns_mock.go @@ -26,6 +26,7 @@ package mock_privatedns import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -169,6 +170,48 @@ func (mr *MockScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/privatedns/privatedns.go b/azure/services/privatedns/privatedns.go index 5ebd99fd3c9..e719d3761b1 100644 --- a/azure/services/privatedns/privatedns.go +++ b/azure/services/privatedns/privatedns.go @@ -26,7 +26,6 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/converters" "sigs.k8s.io/cluster-api-provider-azure/azure/services/async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/tags" - "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -51,11 +50,11 @@ type Service struct { // New creates a new private dns service. func New(scope Scope) (*Service, error) { - zoneClient, err := newPrivateZonesClient(scope) + zoneClient, err := newPrivateZonesClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } - vnetLinkClient, err := newVirtualNetworkLinksClient(scope) + vnetLinkClient, err := newVirtualNetworkLinksClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -89,7 +88,7 @@ func (s *Service) Reconcile(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "privatedns.Service.Reconcile") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() zoneSpec, links, records := s.Scope.PrivateDNSSpec() @@ -123,7 +122,7 @@ func (s *Service) Delete(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "privatedns.Service.Delete") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() zoneSpec, links, _ := s.Scope.PrivateDNSSpec() diff --git a/azure/services/privatedns/privatedns_test.go b/azure/services/privatedns/privatedns_test.go index d7217ea6240..cdba1c88023 100644 --- a/azure/services/privatedns/privatedns_test.go +++ b/azure/services/privatedns/privatedns_test.go @@ -31,6 +31,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/privatedns/mock_privatedns" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) const ( @@ -105,6 +106,7 @@ func TestReconcilePrivateDNS(t *testing.T) { name: "no private dns", expectedError: "", expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(nil, nil, nil) }, }, @@ -112,6 +114,7 @@ func TestReconcilePrivateDNS(t *testing.T) { name: "create private dns with multiple links successfully", expectedError: "", expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -136,6 +139,7 @@ func TestReconcilePrivateDNS(t *testing.T) { name: "zone creation in progress", expectedError: "operation type resourceType on Azure resource my-rg/resourceName is not done", expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -149,6 +153,7 @@ func TestReconcilePrivateDNS(t *testing.T) { name: "zone creation fails", expectedError: "this is an error", expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -161,6 +166,7 @@ func TestReconcilePrivateDNS(t *testing.T) { { name: "unmanaged zone does not update ready condition", expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -184,6 +190,7 @@ func TestReconcilePrivateDNS(t *testing.T) { name: "link 1 creation fails but still proceeds to link 2, and returns the error", expectedError: "this is an error", expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -206,6 +213,7 @@ func TestReconcilePrivateDNS(t *testing.T) { name: "link 2 creation fails", expectedError: "this is an error", expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -228,6 +236,7 @@ func TestReconcilePrivateDNS(t *testing.T) { name: "link 1 is long running, link 2 fails, it returns the failure of link2", expectedError: "this is an error", expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -249,6 +258,7 @@ func TestReconcilePrivateDNS(t *testing.T) { { name: "unmanaged link does not update ready condition", expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -271,6 +281,7 @@ func TestReconcilePrivateDNS(t *testing.T) { { name: "vnet link is considered managed if at least one of the links is managed", expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -295,6 +306,7 @@ func TestReconcilePrivateDNS(t *testing.T) { name: "record creation fails", expectedError: "this is an error", expect: func(s *mock_privatedns.MockScopeMockRecorder, z, l, r *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -362,6 +374,7 @@ func TestDeletePrivateDNS(t *testing.T) { name: "no private dns", expectedError: "", expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(nil, nil, nil) }, }, @@ -369,6 +382,7 @@ func TestDeletePrivateDNS(t *testing.T) { name: "dns and links deletion succeeds", expectedError: "", expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -397,6 +411,7 @@ func TestDeletePrivateDNS(t *testing.T) { name: "skips if zone and links are unmanaged", expectedError: "", expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -416,6 +431,7 @@ func TestDeletePrivateDNS(t *testing.T) { name: "skips if unmanaged, but deletes the next resource if it is managed", expectedError: "", expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -441,6 +457,7 @@ func TestDeletePrivateDNS(t *testing.T) { name: "link1 is deleted, link2 is long running. It returns not done error", expectedError: "operation type resourceType on Azure resource my-rg/resourceName is not done", expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}) s.SubscriptionID().Return("123") @@ -461,6 +478,7 @@ func TestDeletePrivateDNS(t *testing.T) { name: "link1 deletion fails and link2 is long running, returns the more pressing error", expectedError: "this is an error", expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}) s.SubscriptionID().Return("123") @@ -481,6 +499,7 @@ func TestDeletePrivateDNS(t *testing.T) { name: "links are deleted, zone is long running", expectedError: "operation type resourceType on Azure resource my-rg/resourceName is not done", expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") @@ -510,6 +529,7 @@ func TestDeletePrivateDNS(t *testing.T) { name: "links are deleted, zone deletion fails with error", expectedError: "this is an error", expect: func(s *mock_privatedns.MockScopeMockRecorder, lr, zr *mock_async.MockReconcilerMockRecorder, tg *mock_async.MockTagsGetterMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PrivateDNSSpec().Return(fakeZone, []azure.ResourceSpecGetter{fakeLink1, fakeLink2}, []azure.ResourceSpecGetter{fakeRecord1}).Times(2) s.SubscriptionID().Return("123") diff --git a/azure/services/privatedns/zone_client.go b/azure/services/privatedns/zone_client.go index cd7bc7ab515..a391b6964f1 100644 --- a/azure/services/privatedns/zone_client.go +++ b/azure/services/privatedns/zone_client.go @@ -18,23 +18,24 @@ package privatedns import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns" "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) // azureZonesClient contains the Azure go-sdk Client for private dns zone. type azureZonesClient struct { - privatezones *armprivatedns.PrivateZonesClient + privatezones *armprivatedns.PrivateZonesClient + apiCallTimeout time.Duration } // newPrivateZonesClient creates a private zones client from an authorizer. -func newPrivateZonesClient(auth azure.Authorizer) (*azureZonesClient, error) { +func newPrivateZonesClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*azureZonesClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to create privatezones client options") @@ -43,7 +44,7 @@ func newPrivateZonesClient(auth azure.Authorizer) (*azureZonesClient, error) { if err != nil { return nil, errors.Wrap(err, "failed to create armprivatedns client factory") } - return &azureZonesClient{factory.NewPrivateZonesClient()}, nil + return &azureZonesClient{factory.NewPrivateZonesClient(), apiCallTimeout}, nil } // Get gets the specified private dns zone. @@ -76,7 +77,7 @@ func (azc *azureZonesClient) CreateOrUpdateAsync(ctx context.Context, spec azure return nil, nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, azc.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} @@ -104,7 +105,7 @@ func (azc *azureZonesClient) DeleteAsync(ctx context.Context, spec azure.Resourc return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, azc.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/privateendpoints/mock_privateendpoints/privateendpoints_mock.go b/azure/services/privateendpoints/mock_privateendpoints/privateendpoints_mock.go index faea62448b9..e1c5047e212 100644 --- a/azure/services/privateendpoints/mock_privateendpoints/privateendpoints_mock.go +++ b/azure/services/privateendpoints/mock_privateendpoints/privateendpoints_mock.go @@ -26,6 +26,7 @@ package mock_privateendpoints import ( reflect "reflect" + time "time" v1api20220701 "github.com/Azure/azure-service-operator/v2/api/network/v1api20220701" gomock "go.uber.org/mock/gomock" @@ -72,6 +73,48 @@ func (mr *MockPrivateEndpointScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockPrivateEndpointScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockPrivateEndpointScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockPrivateEndpointScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockPrivateEndpointScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockPrivateEndpointScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockPrivateEndpointScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockPrivateEndpointScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockPrivateEndpointScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockPrivateEndpointScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockPrivateEndpointScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockPrivateEndpointScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/publicips/client.go b/azure/services/publicips/client.go index 59534848e81..eb3059e84a9 100644 --- a/azure/services/publicips/client.go +++ b/azure/services/publicips/client.go @@ -18,23 +18,24 @@ package publicips import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4" "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) // AzureClient contains the Azure go-sdk Client. type AzureClient struct { - publicips *armnetwork.PublicIPAddressesClient + publicips *armnetwork.PublicIPAddressesClient + apiCallTimeout time.Duration } // NewClient creates a new public IP client from an authorizer. -func NewClient(auth azure.Authorizer) (*AzureClient, error) { +func NewClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*AzureClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to create publicips client options") @@ -44,7 +45,7 @@ func NewClient(auth azure.Authorizer) (*AzureClient, error) { if err != nil { return nil, errors.Wrap(err, "failed to create publicips client factory") } - return &AzureClient{factory.NewPublicIPAddressesClient()}, nil + return &AzureClient{factory.NewPublicIPAddressesClient(), apiCallTimeout}, nil } // Get gets the specified public IP address in a specified resource group. @@ -77,7 +78,7 @@ func (ac *AzureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.Resou return nil, nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} @@ -105,7 +106,7 @@ func (ac *AzureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/publicips/mock_publicips/publicips_mock.go b/azure/services/publicips/mock_publicips/publicips_mock.go index 8acd5e526f8..4d608f3a740 100644 --- a/azure/services/publicips/mock_publicips/publicips_mock.go +++ b/azure/services/publicips/mock_publicips/publicips_mock.go @@ -26,6 +26,7 @@ package mock_publicips import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -169,6 +170,48 @@ func (mr *MockPublicIPScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockPublicIPScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockPublicIPScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockPublicIPScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockPublicIPScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockPublicIPScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockPublicIPScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockPublicIPScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockPublicIPScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockPublicIPScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockPublicIPScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockPublicIPScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/publicips/publicips.go b/azure/services/publicips/publicips.go index 360f04a9d79..023a2d65e50 100644 --- a/azure/services/publicips/publicips.go +++ b/azure/services/publicips/publicips.go @@ -49,7 +49,7 @@ type Service struct { // New creates a new service. func New(scope PublicIPScope) (*Service, error) { - client, err := NewClient(scope) + client, err := NewClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -75,6 +75,9 @@ func (s *Service) Reconcile(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "publicips.Service.Reconcile") defer done() + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) + defer cancel() + specs := s.Scope.PublicIPSpecs() if len(specs) == 0 { return nil @@ -101,6 +104,9 @@ func (s *Service) Delete(ctx context.Context) error { ctx, log, done := tele.StartSpanWithLogger(ctx, "publicips.Service.Delete") defer done() + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) + defer cancel() + specs := s.Scope.PublicIPSpecs() if len(specs) == 0 { return nil diff --git a/azure/services/publicips/publicips_test.go b/azure/services/publicips/publicips_test.go index d64642131cb..0e9a0049565 100644 --- a/azure/services/publicips/publicips_test.go +++ b/azure/services/publicips/publicips_test.go @@ -32,6 +32,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/publicips/mock_publicips" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ) @@ -125,6 +126,7 @@ func TestReconcilePublicIP(t *testing.T) { name: "noop if no public IPs", expectedError: "", expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{}) }, }, @@ -132,6 +134,7 @@ func TestReconcilePublicIP(t *testing.T) { name: "successfully create public IPs", expectedError: "", expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{&fakePublicIPSpec1, &fakePublicIPSpec2, &fakePublicIPSpec3, &fakePublicIPSpecIpv6}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicIPSpec1, serviceName).Return(nil, nil) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicIPSpec2, serviceName).Return(nil, nil) @@ -144,6 +147,7 @@ func TestReconcilePublicIP(t *testing.T) { name: "fail to create a public IP", expectedError: internalError.Error(), expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{&fakePublicIPSpec1, &fakePublicIPSpec2, &fakePublicIPSpec3, &fakePublicIPSpecIpv6}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicIPSpec1, serviceName).Return(nil, nil) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicIPSpec2, serviceName).Return(nil, nil) @@ -196,6 +200,7 @@ func TestDeletePublicIP(t *testing.T) { name: "noop if no public IPs", expectedError: "", expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{}) }, }, @@ -203,6 +208,7 @@ func TestDeletePublicIP(t *testing.T) { name: "successfully delete managed public IPs and ignore unmanaged public IPs", expectedError: "", expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{&fakePublicIPSpec1, &fakePublicIPSpec2, &fakePublicIPSpec3, &fakePublicIPSpecIpv6}) s.SubscriptionID().Return("123") @@ -231,6 +237,7 @@ func TestDeletePublicIP(t *testing.T) { name: "noop if no managed public IPs", expectedError: "", expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{&fakePublicIPSpec1, &fakePublicIPSpec2, &fakePublicIPSpec3, &fakePublicIPSpecIpv6}) s.SubscriptionID().Return("123") @@ -254,6 +261,7 @@ func TestDeletePublicIP(t *testing.T) { name: "fail to delete managed public IP", expectedError: internalError.Error(), expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{&fakePublicIPSpec1, &fakePublicIPSpec2, &fakePublicIPSpec3, &fakePublicIPSpecIpv6}) s.SubscriptionID().Return("123") diff --git a/azure/services/roleassignments/mock_roleassignments/roleassignments_mock.go b/azure/services/roleassignments/mock_roleassignments/roleassignments_mock.go index 221233443b8..e9415c7d312 100644 --- a/azure/services/roleassignments/mock_roleassignments/roleassignments_mock.go +++ b/azure/services/roleassignments/mock_roleassignments/roleassignments_mock.go @@ -26,6 +26,7 @@ package mock_roleassignments import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -113,6 +114,48 @@ func (mr *MockRoleAssignmentScopeMockRecorder) CloudEnvironment() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloudEnvironment", reflect.TypeOf((*MockRoleAssignmentScope)(nil).CloudEnvironment)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockRoleAssignmentScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockRoleAssignmentScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockRoleAssignmentScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockRoleAssignmentScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockRoleAssignmentScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockRoleAssignmentScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockRoleAssignmentScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockRoleAssignmentScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockRoleAssignmentScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockRoleAssignmentScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/roleassignments/roleassignments.go b/azure/services/roleassignments/roleassignments.go index aeb00762c94..344c319cde9 100644 --- a/azure/services/roleassignments/roleassignments.go +++ b/azure/services/roleassignments/roleassignments.go @@ -26,7 +26,6 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/scalesets" "sigs.k8s.io/cluster-api-provider-azure/azure/services/virtualmachines" - "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -57,11 +56,11 @@ func New(scope RoleAssignmentScope) (*Service, error) { if err != nil { return nil, errors.Wrap(err, "failed to create roleassignments service") } - scaleSetsClient, err := scalesets.NewClient(scope) + scaleSetsClient, err := scalesets.NewClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, errors.Wrap(err, "failed to create scalesets service") } - virtualMachinesClient, err := virtualmachines.NewClient(scope) + virtualMachinesClient, err := virtualmachines.NewClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, errors.Wrap(err, "failed to create virtualmachines service") } @@ -83,8 +82,10 @@ func (s *Service) Name() string { func (s *Service) Reconcile(ctx context.Context) error { ctx, log, done := tele.StartSpanWithLogger(ctx, "roleassignments.Service.Reconcile") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() + log.V(2).Info("reconciling role assignment") // Return early if the identity is not system assigned as there will be no diff --git a/azure/services/roleassignments/roleassignments_test.go b/azure/services/roleassignments/roleassignments_test.go index 69d0093d2bc..42b529ce422 100644 --- a/azure/services/roleassignments/roleassignments_test.go +++ b/azure/services/roleassignments/roleassignments_test.go @@ -34,6 +34,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/scalesets/mock_scalesets" "sigs.k8s.io/cluster-api-provider-azure/azure/services/virtualmachines" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) var ( @@ -71,10 +72,10 @@ func TestReconcileRoleAssignmentsVM(t *testing.T) { { name: "create a role assignment", expectedError: "", - expect: func(s *mock_roleassignments.MockRoleAssignmentScopeMockRecorder, m *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.SubscriptionID().AnyTimes().Return("12345") s.ResourceGroup().Return("my-rg") s.Name().Return(fakeRoleAssignment1.MachineName) @@ -95,6 +96,7 @@ func TestReconcileRoleAssignmentsVM(t *testing.T) { expect: func(s *mock_roleassignments.MockRoleAssignmentScopeMockRecorder, m *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.SubscriptionID().AnyTimes().Return("12345") s.ResourceGroup().Return("my-rg") s.Name().Return(fakeRoleAssignment1.MachineName) @@ -109,6 +111,7 @@ func TestReconcileRoleAssignmentsVM(t *testing.T) { expect: func(s *mock_roleassignments.MockRoleAssignmentScopeMockRecorder, m *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.SubscriptionID().AnyTimes().Return("12345") s.ResourceGroup().Return("my-rg") s.Name().Return(fakeRoleAssignment1.MachineName) @@ -169,6 +172,7 @@ func TestReconcileRoleAssignmentsVMSS(t *testing.T) { expect: func(s *mock_roleassignments.MockRoleAssignmentScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, mvmss *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.HasSystemAssignedIdentity().Return(true) s.RoleAssignmentSpecs(&fakePrincipalID).Return(fakeRoleAssignmentSpecs[1:2]) s.RoleAssignmentResourceType().Return(azure.VirtualMachineScaleSet) @@ -188,6 +192,7 @@ func TestReconcileRoleAssignmentsVMSS(t *testing.T) { expect: func(s *mock_roleassignments.MockRoleAssignmentScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, mvmss *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.RoleAssignmentResourceType().Return(azure.VirtualMachineScaleSet) s.ResourceGroup().Return("my-rg") s.Name().Return("test-vmss") @@ -202,6 +207,7 @@ func TestReconcileRoleAssignmentsVMSS(t *testing.T) { expect: func(s *mock_roleassignments.MockRoleAssignmentScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, mvmss *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.HasSystemAssignedIdentity().Return(true) s.RoleAssignmentSpecs(&fakePrincipalID).Return(fakeRoleAssignmentSpecs[1:2]) s.RoleAssignmentResourceType().Return(azure.VirtualMachineScaleSet) diff --git a/azure/services/routetables/client.go b/azure/services/routetables/client.go index c078bea7fab..1225fa6cbbe 100644 --- a/azure/services/routetables/client.go +++ b/azure/services/routetables/client.go @@ -18,23 +18,24 @@ package routetables import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4" "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) // azureClient contains the Azure go-sdk Client. type azureClient struct { - routetables *armnetwork.RouteTablesClient + routetables *armnetwork.RouteTablesClient + apiCallTimeout time.Duration } // newClient creates a new route tables client from an authorizer. -func newClient(auth azure.Authorizer) (*azureClient, error) { +func newClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*azureClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to create routetables client options") @@ -43,7 +44,7 @@ func newClient(auth azure.Authorizer) (*azureClient, error) { if err != nil { return nil, errors.Wrap(err, "failed to create armnetwork client factory") } - return &azureClient{factory.NewRouteTablesClient()}, nil + return &azureClient{factory.NewRouteTablesClient(), apiCallTimeout}, nil } // Get gets the specified route table. @@ -76,7 +77,7 @@ func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.Resou return nil, nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} @@ -104,7 +105,7 @@ func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/routetables/mock_routetables/routetables_mock.go b/azure/services/routetables/mock_routetables/routetables_mock.go index f48e107e2e5..6889c492b61 100644 --- a/azure/services/routetables/mock_routetables/routetables_mock.go +++ b/azure/services/routetables/mock_routetables/routetables_mock.go @@ -26,6 +26,7 @@ package mock_routetables import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -113,6 +114,48 @@ func (mr *MockRouteTableScopeMockRecorder) CloudEnvironment() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloudEnvironment", reflect.TypeOf((*MockRouteTableScope)(nil).CloudEnvironment)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockRouteTableScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockRouteTableScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockRouteTableScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockRouteTableScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockRouteTableScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockRouteTableScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockRouteTableScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockRouteTableScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockRouteTableScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockRouteTableScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/routetables/routetables.go b/azure/services/routetables/routetables.go index 30de8788532..b4bc34a3b11 100644 --- a/azure/services/routetables/routetables.go +++ b/azure/services/routetables/routetables.go @@ -24,7 +24,6 @@ import ( 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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -46,7 +45,7 @@ type Service struct { // New creates a new service. func New(scope RouteTableScope) (*Service, error) { - client, err := newClient(scope) + client, err := newClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -67,7 +66,7 @@ func (s *Service) Reconcile(ctx context.Context) error { ctx, log, done := tele.StartSpanWithLogger(ctx, "routetables.Service.Reconcile") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() var resErr error @@ -104,7 +103,7 @@ func (s *Service) Delete(ctx context.Context) error { ctx, log, done := tele.StartSpanWithLogger(ctx, "routetables.Service.Delete") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() // Only delete the route tables if their lifecycle is managed by this controller. diff --git a/azure/services/routetables/routetables_test.go b/azure/services/routetables/routetables_test.go index 91fbb9c9203..91e54f2d2eb 100644 --- a/azure/services/routetables/routetables_test.go +++ b/azure/services/routetables/routetables_test.go @@ -28,6 +28,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/routetables/mock_routetables" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) var ( @@ -61,6 +62,7 @@ func TestReconcileRouteTables(t *testing.T) { name: "noop if no route table specs are found", expectedError: "", expect: func(s *mock_routetables.MockRouteTableScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.RouteTableSpecs().Return([]azure.ResourceSpecGetter{}) }, @@ -69,6 +71,7 @@ func TestReconcileRouteTables(t *testing.T) { name: "create multiple route tables succeeds", expectedError: "", expect: func(s *mock_routetables.MockRouteTableScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.RouteTableSpecs().Return([]azure.ResourceSpecGetter{&fakeRT, &fakeRT2}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeRT, serviceName).Return(nil, nil) @@ -80,6 +83,7 @@ func TestReconcileRouteTables(t *testing.T) { name: "first route table create fails", expectedError: errFake.Error(), expect: func(s *mock_routetables.MockRouteTableScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.RouteTableSpecs().Return([]azure.ResourceSpecGetter{&fakeRT, &fakeRT2}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeRT, serviceName).Return(nil, errFake) @@ -91,6 +95,7 @@ func TestReconcileRouteTables(t *testing.T) { name: "second route table create not done", expectedError: errFake.Error(), expect: func(s *mock_routetables.MockRouteTableScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.RouteTableSpecs().Return([]azure.ResourceSpecGetter{&fakeRT, &fakeRT2}) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeRT, serviceName).Return(nil, errFake) @@ -102,6 +107,7 @@ func TestReconcileRouteTables(t *testing.T) { name: "noop if vnet is not managed", expectedError: "", expect: func(s *mock_routetables.MockRouteTableScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(false) }, }, @@ -146,6 +152,7 @@ func TestDeleteRouteTable(t *testing.T) { name: "noop if no route table specs are found", expectedError: "", expect: func(s *mock_routetables.MockRouteTableScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.RouteTableSpecs().Return([]azure.ResourceSpecGetter{}) }, @@ -154,6 +161,7 @@ func TestDeleteRouteTable(t *testing.T) { name: "delete multiple route tables succeeds", expectedError: "", expect: func(s *mock_routetables.MockRouteTableScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.RouteTableSpecs().Return([]azure.ResourceSpecGetter{&fakeRT, &fakeRT2}) r.DeleteResource(gomockinternal.AContext(), &fakeRT, serviceName).Return(nil) @@ -165,6 +173,7 @@ func TestDeleteRouteTable(t *testing.T) { name: "first route table delete fails", expectedError: errFake.Error(), expect: func(s *mock_routetables.MockRouteTableScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.RouteTableSpecs().Return([]azure.ResourceSpecGetter{&fakeRT, &fakeRT2}) r.DeleteResource(gomockinternal.AContext(), &fakeRT, serviceName).Return(errFake) @@ -176,6 +185,7 @@ func TestDeleteRouteTable(t *testing.T) { name: "second route table delete not done", expectedError: errFake.Error(), expect: func(s *mock_routetables.MockRouteTableScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.RouteTableSpecs().Return([]azure.ResourceSpecGetter{&fakeRT, &fakeRT2}) r.DeleteResource(gomockinternal.AContext(), &fakeRT, serviceName).Return(errFake) @@ -187,6 +197,7 @@ func TestDeleteRouteTable(t *testing.T) { name: "noop if vnet is not managed", expectedError: "", expect: func(s *mock_routetables.MockRouteTableScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(false) }, }, diff --git a/azure/services/scalesets/client.go b/azure/services/scalesets/client.go index 3cd900cc052..3bbc94990a3 100644 --- a/azure/services/scalesets/client.go +++ b/azure/services/scalesets/client.go @@ -18,13 +18,13 @@ package scalesets import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -40,14 +40,15 @@ type Client interface { // AzureClient contains the Azure go-sdk Client. type AzureClient struct { - scalesetvms *armcompute.VirtualMachineScaleSetVMsClient - scalesets *armcompute.VirtualMachineScaleSetsClient + scalesetvms *armcompute.VirtualMachineScaleSetVMsClient + scalesets *armcompute.VirtualMachineScaleSetsClient + apiCallTimeout time.Duration } var _ Client = &AzureClient{} // NewClient creates a new VMSS client from an authorizer. -func NewClient(auth azure.Authorizer) (*AzureClient, error) { +func NewClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*AzureClient, error) { scaleSetVMsClient, err := newVirtualMachineScaleSetVMsClient(auth) if err != nil { return nil, err @@ -57,8 +58,9 @@ func NewClient(auth azure.Authorizer) (*AzureClient, error) { return nil, err } return &AzureClient{ - scalesetvms: scaleSetVMsClient, - scalesets: scaleSetsClient, + scalesetvms: scaleSetVMsClient, + scalesets: scaleSetsClient, + apiCallTimeout: apiCallTimeout, }, nil } @@ -158,7 +160,7 @@ func (ac *AzureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.Resou return nil, nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} @@ -190,7 +192,7 @@ func (ac *AzureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/scalesets/mock_scalesets/scalesets_mock.go b/azure/services/scalesets/mock_scalesets/scalesets_mock.go index 00b76b13839..833485f1dc4 100644 --- a/azure/services/scalesets/mock_scalesets/scalesets_mock.go +++ b/azure/services/scalesets/mock_scalesets/scalesets_mock.go @@ -27,6 +27,7 @@ package mock_scalesets import ( context "context" reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -170,6 +171,48 @@ func (mr *MockScaleSetScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockScaleSetScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockScaleSetScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockScaleSetScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockScaleSetScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockScaleSetScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockScaleSetScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockScaleSetScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockScaleSetScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockScaleSetScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockScaleSetScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockScaleSetScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/scalesets/scalesets.go b/azure/services/scalesets/scalesets.go index a78c3b6c8da..383965482e9 100644 --- a/azure/services/scalesets/scalesets.go +++ b/azure/services/scalesets/scalesets.go @@ -29,7 +29,6 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/resourceskus" azureutil "sigs.k8s.io/cluster-api-provider-azure/util/azure" - "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/slice" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -60,7 +59,7 @@ type ( // New creates a new service. func New(scope ScaleSetScope, skuCache *resourceskus.Cache) (*Service, error) { - client, err := NewClient(scope) + client, err := NewClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -83,7 +82,7 @@ func (s *Service) Reconcile(ctx context.Context) (retErr error) { ctx, _, done := tele.StartSpanWithLogger(ctx, "scalesets.Service.Reconcile") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() if err := s.validateSpec(ctx); err != nil { @@ -142,7 +141,7 @@ func (s *Service) Delete(ctx context.Context) error { ctx, log, done := tele.StartSpanWithLogger(ctx, "scalesets.Service.Delete") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() scaleSetSpec := s.Scope.ScaleSetSpec(ctx) diff --git a/azure/services/scalesets/scalesets_test.go b/azure/services/scalesets/scalesets_test.go index 4e8228d39ee..41235ebe8e3 100644 --- a/azure/services/scalesets/scalesets_test.go +++ b/azure/services/scalesets/scalesets_test.go @@ -35,6 +35,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/scalesets/mock_scalesets" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" azureutil "sigs.k8s.io/cluster-api-provider-azure/util/azure" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ) @@ -104,6 +105,7 @@ func TestReconcileVMSS(t *testing.T) { name: "update an existing vmss", expectedError: "", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := getDefaultVMSSSpec() // Validate spec s.ScaleSetSpec(gomockinternal.AContext()).Return(spec).AnyTimes() @@ -121,6 +123,7 @@ func TestReconcileVMSS(t *testing.T) { name: "create a vmss, skip list instances if vmss doesn't exist", expectedError: "", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := getDefaultVMSSSpec() // Validate spec s.ScaleSetSpec(gomockinternal.AContext()).Return(spec).AnyTimes() @@ -137,6 +140,7 @@ func TestReconcileVMSS(t *testing.T) { name: "error getting existing vmss", expectedError: "failed to get existing VMSS: #: Internal Server Error: StatusCode=500", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := getDefaultVMSSSpec() // Validate spec s.ScaleSetSpec(gomockinternal.AContext()).Return(spec).AnyTimes() @@ -147,6 +151,7 @@ func TestReconcileVMSS(t *testing.T) { name: "failed to list instances", expectedError: "failed to get existing VMSS instances: #: Internal Server Error: StatusCode=500", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := getDefaultVMSSSpec() // Validate spec s.ScaleSetSpec(gomockinternal.AContext()).Return(spec).AnyTimes() @@ -159,6 +164,7 @@ func TestReconcileVMSS(t *testing.T) { name: "failed to create a vmss", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := getDefaultVMSSSpec() s.ScaleSetSpec(gomockinternal.AContext()).Return(spec).AnyTimes() m.Get(gomockinternal.AContext(), &defaultSpec).Return(&resultVMSS, nil) @@ -173,6 +179,7 @@ func TestReconcileVMSS(t *testing.T) { name: "failed to reconcile replicas", expectedError: "unable to reconcile VMSS replicas: #: Internal Server Error: StatusCode=500", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := getDefaultVMSSSpec() s.ScaleSetSpec(gomockinternal.AContext()).Return(spec).AnyTimes() m.Get(gomockinternal.AContext(), &defaultSpec).Return(&resultVMSS, nil) @@ -188,6 +195,7 @@ func TestReconcileVMSS(t *testing.T) { name: "validate spec failure: less than 2 vCPUs", expectedError: "reconcile error that cannot be recovered occurred: vm size should be bigger or equal to at least 2 vCPUs. Object will not be requeued", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := newDefaultVMSSSpec() spec.Size = "VM_SIZE_1_CPU" spec.Capacity = 2 @@ -199,6 +207,7 @@ func TestReconcileVMSS(t *testing.T) { name: "validate spec failure: Memory is less than 2Gi", expectedError: "reconcile error that cannot be recovered occurred: vm memory should be bigger or equal to at least 2Gi. Object will not be requeued", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := newDefaultVMSSSpec() spec.Size = "VM_SIZE_1_MEM" spec.Capacity = 2 @@ -210,6 +219,7 @@ func TestReconcileVMSS(t *testing.T) { name: "validate spec failure: failed to get SKU", expectedError: "failed to get SKU INVALID_VM_SIZE in compute api: reconcile error that cannot be recovered occurred: resource sku with name 'INVALID_VM_SIZE' and category 'virtualMachines' not found in location 'test-location'. Object will not be requeued", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := newDefaultVMSSSpec() spec.Size = "INVALID_VM_SIZE" spec.Capacity = 2 @@ -221,6 +231,7 @@ func TestReconcileVMSS(t *testing.T) { name: "validate spec failure: fail to create a vm with ultra disk implicitly enabled by data disk, when location not supported", expectedError: "reconcile error that cannot be recovered occurred: vm size VM_SIZE_USSD does not support ultra disks in location test-location. select a different vm size or disable ultra disks. Object will not be requeued", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := newDefaultVMSSSpec() spec.Size = vmSizeUSSD spec.Capacity = 2 @@ -237,6 +248,7 @@ func TestReconcileVMSS(t *testing.T) { name: "validate spec failure: fail to create a vm with ultra disk explicitly enabled via additional capabilities, when location not supported", expectedError: "reconcile error that cannot be recovered occurred: vm size VM_SIZE_USSD does not support ultra disks in location test-location. select a different vm size or disable ultra disks. Object will not be requeued", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := newDefaultVMSSSpec() spec.Size = vmSizeUSSD spec.Capacity = 2 @@ -251,6 +263,7 @@ func TestReconcileVMSS(t *testing.T) { name: "validate spec failure: fail to create a vm with ultra disk explicitly enabled via additional capabilities, when location not supported", expectedError: "reconcile error that cannot be recovered occurred: vm size VM_SIZE_USSD does not support ultra disks in location test-location. select a different vm size or disable ultra disks. Object will not be requeued", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := newDefaultVMSSSpec() spec.Size = vmSizeUSSD spec.Capacity = 2 @@ -270,6 +283,7 @@ func TestReconcileVMSS(t *testing.T) { name: "validate spec failure: fail to create a vm with diagnostics set to User Managed but empty StorageAccountURI", expectedError: "reconcile error that cannot be recovered occurred: userManaged must be specified when storageAccountType is 'UserManaged'. Object will not be requeued", expect: func(g *WithT, s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) spec := newDefaultVMSSSpec() spec.Size = vmSizeUSSD spec.Capacity = 2 @@ -334,6 +348,7 @@ func TestDeleteVMSS(t *testing.T) { name: "successfully delete an existing vmss", expectedError: "", expect: func(s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.ScaleSetSpec(gomockinternal.AContext()).Return(&defaultSpec).AnyTimes() r.DeleteResource(gomockinternal.AContext(), &defaultSpec, serviceName).Return(nil) s.UpdateDeleteStatus(infrav1.BootstrapSucceededCondition, serviceName, nil) @@ -347,6 +362,7 @@ func TestDeleteVMSS(t *testing.T) { name: "successfully delete an existing vmss, fetch call returns error", expectedError: "", expect: func(s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.ScaleSetSpec(gomockinternal.AContext()).Return(&defaultSpec).AnyTimes() r.DeleteResource(gomockinternal.AContext(), &defaultSpec, serviceName).Return(nil) s.UpdateDeleteStatus(infrav1.BootstrapSucceededCondition, serviceName, nil) @@ -357,6 +373,7 @@ func TestDeleteVMSS(t *testing.T) { name: "failed to delete an existing vmss", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(s *mock_scalesets.MockScaleSetScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder, m *mock_scalesets.MockClientMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.ScaleSetSpec(gomockinternal.AContext()).Return(&defaultSpec).AnyTimes() r.DeleteResource(gomockinternal.AContext(), &defaultSpec, serviceName).Return(internalError) s.UpdateDeleteStatus(infrav1.BootstrapSucceededCondition, serviceName, internalError) diff --git a/azure/services/scalesetvms/client.go b/azure/services/scalesetvms/client.go index e61465e7bfc..d146984dec7 100644 --- a/azure/services/scalesetvms/client.go +++ b/azure/services/scalesetvms/client.go @@ -18,13 +18,13 @@ package scalesetvms import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -37,13 +37,14 @@ type client interface { // azureClient contains the Azure go-sdk Client. type azureClient struct { - scalesetvms *armcompute.VirtualMachineScaleSetVMsClient + scalesetvms *armcompute.VirtualMachineScaleSetVMsClient + apiCallTimeout time.Duration } var _ client = &azureClient{} // newClient creates a VMSS client from an authorizer. -func newClient(auth azure.Authorizer) (*azureClient, error) { +func newClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*azureClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to create scalesetvms client options") @@ -52,7 +53,7 @@ func newClient(auth azure.Authorizer) (*azureClient, error) { if err != nil { return nil, errors.Wrap(err, "failed to create armcompute client factory") } - return &azureClient{factory.NewVirtualMachineScaleSetVMsClient()}, nil + return &azureClient{factory.NewVirtualMachineScaleSetVMsClient(), apiCallTimeout}, nil } // Get retrieves the Virtual Machine Scale Set Virtual Machine. @@ -88,7 +89,7 @@ func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/scalesetvms/mock_scalesetvms/scalesetvms_mock.go b/azure/services/scalesetvms/mock_scalesetvms/scalesetvms_mock.go index 1a5db75b072..8047d976129 100644 --- a/azure/services/scalesetvms/mock_scalesetvms/scalesetvms_mock.go +++ b/azure/services/scalesetvms/mock_scalesetvms/scalesetvms_mock.go @@ -26,6 +26,7 @@ package mock_scalesetvms import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -169,6 +170,48 @@ func (mr *MockScaleSetVMScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockScaleSetVMScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockScaleSetVMScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockScaleSetVMScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockScaleSetVMScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockScaleSetVMScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockScaleSetVMScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockScaleSetVMScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockScaleSetVMScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockScaleSetVMScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockScaleSetVMScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockScaleSetVMScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/scalesetvms/scalesetvms.go b/azure/services/scalesetvms/scalesetvms.go index b6b90f69fbb..42de959547a 100644 --- a/azure/services/scalesetvms/scalesetvms.go +++ b/azure/services/scalesetvms/scalesetvms.go @@ -54,11 +54,11 @@ type ( // NewService creates a new service. func NewService(scope ScaleSetVMScope) (*Service, error) { - client, err := newClient(scope) + client, err := newClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } - vmClient, err := virtualmachines.NewClient(scope) + vmClient, err := virtualmachines.NewClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } diff --git a/azure/services/securitygroups/client.go b/azure/services/securitygroups/client.go index 88502b7ca1f..94d1ecd89f5 100644 --- a/azure/services/securitygroups/client.go +++ b/azure/services/securitygroups/client.go @@ -18,6 +18,7 @@ package securitygroups import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" @@ -25,7 +26,6 @@ import ( "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -33,10 +33,11 @@ import ( type azureClient struct { securitygroups *armnetwork.SecurityGroupsClient auth azure.Authorizer + apiCallTimeout time.Duration } // newClient creates a new security groups client from an authorizer. -func newClient(auth azure.Authorizer) (*azureClient, error) { +func newClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*azureClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to create securitygroups client options") @@ -45,7 +46,7 @@ func newClient(auth azure.Authorizer) (*azureClient, error) { if err != nil { return nil, errors.Wrap(err, "failed to create armnetwork client factory") } - return &azureClient{factory.NewSecurityGroupsClient(), auth}, nil + return &azureClient{factory.NewSecurityGroupsClient(), auth, apiCallTimeout}, nil } // Get gets the specified network security group. @@ -98,7 +99,7 @@ func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.Resou return nil, nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} @@ -126,7 +127,7 @@ func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/securitygroups/mock_securitygroups/securitygroups_mock.go b/azure/services/securitygroups/mock_securitygroups/securitygroups_mock.go index 0a396f10493..2fb412d7bce 100644 --- a/azure/services/securitygroups/mock_securitygroups/securitygroups_mock.go +++ b/azure/services/securitygroups/mock_securitygroups/securitygroups_mock.go @@ -26,6 +26,7 @@ package mock_securitygroups import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -113,6 +114,48 @@ func (mr *MockNSGScopeMockRecorder) CloudEnvironment() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloudEnvironment", reflect.TypeOf((*MockNSGScope)(nil).CloudEnvironment)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockNSGScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockNSGScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockNSGScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockNSGScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockNSGScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockNSGScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockNSGScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockNSGScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockNSGScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockNSGScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/securitygroups/securitygroups.go b/azure/services/securitygroups/securitygroups.go index 4a07dfabe76..c56d056224b 100644 --- a/azure/services/securitygroups/securitygroups.go +++ b/azure/services/securitygroups/securitygroups.go @@ -24,7 +24,6 @@ import ( 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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -47,7 +46,7 @@ type Service struct { // New creates a new service. func New(scope NSGScope) (*Service, error) { - client, err := newClient(scope) + client, err := newClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -68,7 +67,7 @@ func (s *Service) Reconcile(ctx context.Context) error { ctx, log, done := tele.StartSpanWithLogger(ctx, "securitygroups.Service.Reconcile") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() // Only create the NSGs if their lifecycle is managed by this controller. @@ -123,7 +122,7 @@ func (s *Service) Delete(ctx context.Context) error { ctx, log, done := tele.StartSpanWithLogger(ctx, "securitygroups.Service.Delete") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() // Only delete the security groups if their lifecycle is managed by this controller. diff --git a/azure/services/securitygroups/securitygroups_test.go b/azure/services/securitygroups/securitygroups_test.go index 64bc28940cb..7468045ad81 100644 --- a/azure/services/securitygroups/securitygroups_test.go +++ b/azure/services/securitygroups/securitygroups_test.go @@ -30,6 +30,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/securitygroups/mock_securitygroups" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) var ( @@ -98,6 +99,7 @@ func TestReconcileSecurityGroups(t *testing.T) { name: "create single security group with single rule succeeds, should return no error", expectedError: "", expect: func(s *mock_securitygroups.MockNSGScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.NSGSpecs().Return([]azure.ResourceSpecGetter{&fakeNSG}) s.UpdateAnnotationJSON(annotation, map[string]interface{}{fakeNSG.Name: map[string]string{securityRule1.Name: securityRule1.Description}}).Times(1) @@ -109,6 +111,7 @@ func TestReconcileSecurityGroups(t *testing.T) { name: "create single security group with multiple rules succeeds, should return no error", expectedError: "", expect: func(s *mock_securitygroups.MockNSGScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.NSGSpecs().Return([]azure.ResourceSpecGetter{&multipleRulesNSG}) s.UpdateAnnotationJSON(annotation, map[string]interface{}{multipleRulesNSG.Name: map[string]string{securityRule1.Name: securityRule1.Description, securityRule2.Name: securityRule2.Description}}).Times(1) @@ -120,6 +123,7 @@ func TestReconcileSecurityGroups(t *testing.T) { name: "create multiple security groups, should return no error", expectedError: "", expect: func(s *mock_securitygroups.MockNSGScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.NSGSpecs().Return([]azure.ResourceSpecGetter{&fakeNSG, &noRulesNSG}) s.UpdateAnnotationJSON(annotation, map[string]interface{}{fakeNSG.Name: map[string]string{securityRule1.Name: securityRule1.Description}}).Times(1) @@ -132,6 +136,7 @@ func TestReconcileSecurityGroups(t *testing.T) { name: "first security groups create fails, should return error", expectedError: errFake.Error(), expect: func(s *mock_securitygroups.MockNSGScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.NSGSpecs().Return([]azure.ResourceSpecGetter{&fakeNSG, &noRulesNSG}) s.UpdateAnnotationJSON(annotation, map[string]interface{}{fakeNSG.Name: map[string]string{securityRule1.Name: securityRule1.Description}}).Times(1) @@ -144,6 +149,7 @@ func TestReconcileSecurityGroups(t *testing.T) { name: "first sg create fails, second sg create not done, should return create error", expectedError: errFake.Error(), expect: func(s *mock_securitygroups.MockNSGScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.NSGSpecs().Return([]azure.ResourceSpecGetter{&fakeNSG, &noRulesNSG}) s.UpdateAnnotationJSON(annotation, map[string]interface{}{fakeNSG.Name: map[string]string{securityRule1.Name: securityRule1.Description}}).Times(1) @@ -156,6 +162,7 @@ func TestReconcileSecurityGroups(t *testing.T) { name: "security groups create not done, should return not done error", expectedError: notDoneError.Error(), expect: func(s *mock_securitygroups.MockNSGScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.NSGSpecs().Return([]azure.ResourceSpecGetter{&fakeNSG}) s.UpdateAnnotationJSON(annotation, map[string]interface{}{fakeNSG.Name: map[string]string{securityRule1.Name: securityRule1.Description}}) @@ -167,6 +174,7 @@ func TestReconcileSecurityGroups(t *testing.T) { name: "vnet is not managed, should skip reconcile", expectedError: "", expect: func(s *mock_securitygroups.MockNSGScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(false) }, }, @@ -210,6 +218,7 @@ func TestDeleteSecurityGroups(t *testing.T) { name: "delete multiple security groups succeeds, should return no error", expectedError: "", expect: func(s *mock_securitygroups.MockNSGScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.NSGSpecs().Return([]azure.ResourceSpecGetter{&fakeNSG, &noRulesNSG}) r.DeleteResource(gomockinternal.AContext(), &fakeNSG, serviceName).Return(nil) @@ -221,6 +230,7 @@ func TestDeleteSecurityGroups(t *testing.T) { name: "first security groups delete fails, should return an error", expectedError: errFake.Error(), expect: func(s *mock_securitygroups.MockNSGScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.NSGSpecs().Return([]azure.ResourceSpecGetter{&fakeNSG, &noRulesNSG}) r.DeleteResource(gomockinternal.AContext(), &fakeNSG, serviceName).Return(errFake) @@ -232,6 +242,7 @@ func TestDeleteSecurityGroups(t *testing.T) { name: "first security groups delete fails and second security groups create not done, should return an error", expectedError: errFake.Error(), expect: func(s *mock_securitygroups.MockNSGScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.NSGSpecs().Return([]azure.ResourceSpecGetter{&fakeNSG, &noRulesNSG}) r.DeleteResource(gomockinternal.AContext(), &fakeNSG, serviceName).Return(errFake) @@ -243,6 +254,7 @@ func TestDeleteSecurityGroups(t *testing.T) { name: "security groups delete not done, should return not done error", expectedError: notDoneError.Error(), expect: func(s *mock_securitygroups.MockNSGScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(true) s.NSGSpecs().Return([]azure.ResourceSpecGetter{&fakeNSG}) r.DeleteResource(gomockinternal.AContext(), &fakeNSG, serviceName).Return(notDoneError) @@ -253,6 +265,7 @@ func TestDeleteSecurityGroups(t *testing.T) { name: "vnet is not managed, should skip delete", expectedError: "", expect: func(s *mock_securitygroups.MockNSGScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.IsVnetManaged().Return(false) }, }, diff --git a/azure/services/subnets/mock_subnets/subnets_mock.go b/azure/services/subnets/mock_subnets/subnets_mock.go index c6254e2a367..8274fffdcf4 100644 --- a/azure/services/subnets/mock_subnets/subnets_mock.go +++ b/azure/services/subnets/mock_subnets/subnets_mock.go @@ -26,6 +26,7 @@ package mock_subnets import ( reflect "reflect" + time "time" v1api20201101 "github.com/Azure/azure-service-operator/v2/api/network/v1api20201101" gomock "go.uber.org/mock/gomock" @@ -72,6 +73,48 @@ func (mr *MockSubnetScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockSubnetScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockSubnetScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockSubnetScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockSubnetScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockSubnetScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockSubnetScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockSubnetScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockSubnetScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockSubnetScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockSubnetScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockSubnetScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/virtualmachines/client.go b/azure/services/virtualmachines/client.go index f8fa7edd90e..2862f4b90d2 100644 --- a/azure/services/virtualmachines/client.go +++ b/azure/services/virtualmachines/client.go @@ -18,6 +18,7 @@ package virtualmachines import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" @@ -25,7 +26,6 @@ import ( "k8s.io/utils/ptr" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -33,6 +33,7 @@ type ( // AzureClient contains the Azure go-sdk Client. AzureClient struct { virtualmachines *armcompute.VirtualMachinesClient + apiCallTimeout time.Duration } // Client provides operations on Azure virtual machine resources. @@ -46,7 +47,7 @@ type ( var _ Client = &AzureClient{} // NewClient creates a VMs client from an authorizer. -func NewClient(auth azure.Authorizer) (*AzureClient, error) { +func NewClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*AzureClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to create virtualmachines client options") @@ -55,7 +56,7 @@ func NewClient(auth azure.Authorizer) (*AzureClient, error) { if err != nil { return nil, errors.Wrap(err, "failed to create armcompute client factory") } - return &AzureClient{factory.NewVirtualMachinesClient()}, nil + return &AzureClient{factory.NewVirtualMachinesClient(), apiCallTimeout}, nil } // Get retrieves information about the model view or the instance view of a virtual machine. @@ -88,7 +89,7 @@ func (ac *AzureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.Resou return nil, nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} @@ -117,7 +118,7 @@ func (ac *AzureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/virtualmachines/mock_virtualmachines/virtualmachines_mock.go b/azure/services/virtualmachines/mock_virtualmachines/virtualmachines_mock.go index e8f44342eed..67df0cf0ab3 100644 --- a/azure/services/virtualmachines/mock_virtualmachines/virtualmachines_mock.go +++ b/azure/services/virtualmachines/mock_virtualmachines/virtualmachines_mock.go @@ -26,6 +26,7 @@ package mock_virtualmachines import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -114,6 +115,48 @@ func (mr *MockVMScopeMockRecorder) CloudEnvironment() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloudEnvironment", reflect.TypeOf((*MockVMScope)(nil).CloudEnvironment)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockVMScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockVMScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockVMScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockVMScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockVMScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockVMScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockVMScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockVMScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockVMScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockVMScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/virtualmachines/virtualmachines.go b/azure/services/virtualmachines/virtualmachines.go index ee685a26f1a..32c7a74d7bb 100644 --- a/azure/services/virtualmachines/virtualmachines.go +++ b/azure/services/virtualmachines/virtualmachines.go @@ -34,7 +34,6 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/networkinterfaces" "sigs.k8s.io/cluster-api-provider-azure/azure/services/publicips" azureutil "sigs.k8s.io/cluster-api-provider-azure/util/azure" - "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" ) @@ -64,7 +63,7 @@ type Service struct { // New creates a new service. func New(scope VMScope) (*Service, error) { - Client, err := NewClient(scope) + Client, err := NewClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -72,11 +71,11 @@ func New(scope VMScope) (*Service, error) { if err != nil { return nil, err } - interfacesSvc, err := networkinterfaces.NewClient(scope) + interfacesSvc, err := networkinterfaces.NewClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } - publicIPsSvc, err := publicips.NewClient(scope) + publicIPsSvc, err := publicips.NewClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -100,7 +99,7 @@ func (s *Service) Reconcile(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "virtualmachines.Service.Reconcile") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() vmSpec := s.Scope.VMSpec() @@ -152,7 +151,7 @@ func (s *Service) Delete(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "virtualmachines.Service.Delete") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() vmSpec := s.Scope.VMSpec() diff --git a/azure/services/virtualmachines/virtualmachines_test.go b/azure/services/virtualmachines/virtualmachines_test.go index b53ea984d7e..dccce7e44b0 100644 --- a/azure/services/virtualmachines/virtualmachines_test.go +++ b/azure/services/virtualmachines/virtualmachines_test.go @@ -36,6 +36,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/publicips" "sigs.k8s.io/cluster-api-provider-azure/azure/services/virtualmachines/mock_virtualmachines" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ) @@ -129,6 +130,7 @@ func TestReconcileVM(t *testing.T) { name: "noop if no vm spec is found", expectedError: "", expect: func(s *mock_virtualmachines.MockVMScopeMockRecorder, mnic *mock_async.MockGetterMockRecorder, mpip *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMSpec().Return(nil) }, }, @@ -136,6 +138,7 @@ func TestReconcileVM(t *testing.T) { name: "create vm succeeds", expectedError: "", expect: func(s *mock_virtualmachines.MockVMScopeMockRecorder, mnic *mock_async.MockGetterMockRecorder, mpip *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMSpec().Return(&fakeVMSpec) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeVMSpec, serviceName).Return(fakeExistingVM, nil) s.UpdatePutStatus(infrav1.VMRunningCondition, serviceName, nil) @@ -152,6 +155,7 @@ func TestReconcileVM(t *testing.T) { name: "creating vm fails", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(s *mock_virtualmachines.MockVMScopeMockRecorder, mnic *mock_async.MockGetterMockRecorder, mpip *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMSpec().Return(&fakeVMSpec) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeVMSpec, serviceName).Return(nil, internalError) s.UpdatePutStatus(infrav1.VMRunningCondition, serviceName, internalError) @@ -162,6 +166,7 @@ func TestReconcileVM(t *testing.T) { name: "create vm succeeds but failed to get network interfaces", expectedError: "failed to fetch VM addresses: #: Internal Server Error: StatusCode=500", expect: func(s *mock_virtualmachines.MockVMScopeMockRecorder, mnic *mock_async.MockGetterMockRecorder, mpip *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMSpec().Return(&fakeVMSpec) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeVMSpec, serviceName).Return(fakeExistingVM, nil) s.UpdatePutStatus(infrav1.VMRunningCondition, serviceName, nil) @@ -175,6 +180,7 @@ func TestReconcileVM(t *testing.T) { name: "create vm succeeds but failed to get public IPs", expectedError: "failed to fetch VM addresses: #: Internal Server Error: StatusCode=500", expect: func(s *mock_virtualmachines.MockVMScopeMockRecorder, mnic *mock_async.MockGetterMockRecorder, mpip *mock_async.MockGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMSpec().Return(&fakeVMSpec) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakeVMSpec, serviceName).Return(fakeExistingVM, nil) s.UpdatePutStatus(infrav1.VMRunningCondition, serviceName, nil) @@ -230,6 +236,7 @@ func TestDeleteVM(t *testing.T) { name: "noop if no vm spec is found", expectedError: "", expect: func(s *mock_virtualmachines.MockVMScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMSpec().Return(nil) }, }, @@ -237,6 +244,7 @@ func TestDeleteVM(t *testing.T) { name: "vm doesn't exist", expectedError: "", expect: func(s *mock_virtualmachines.MockVMScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMSpec().AnyTimes().Return(&fakeVMSpec) r.DeleteResource(gomockinternal.AContext(), &fakeVMSpec, serviceName).Return(nil) s.SetVMState(infrav1.Deleted) @@ -247,6 +255,7 @@ func TestDeleteVM(t *testing.T) { name: "error occurs when deleting vm", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(s *mock_virtualmachines.MockVMScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMSpec().AnyTimes().Return(&fakeVMSpec) r.DeleteResource(gomockinternal.AContext(), &fakeVMSpec, serviceName).Return(internalError) s.SetVMState(infrav1.Deleting) @@ -257,6 +266,7 @@ func TestDeleteVM(t *testing.T) { name: "delete the vm successfully", expectedError: "", expect: func(s *mock_virtualmachines.MockVMScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMSpec().AnyTimes().Return(&fakeVMSpec) r.DeleteResource(gomockinternal.AContext(), &fakeVMSpec, serviceName).Return(nil) s.SetVMState(infrav1.Deleted) diff --git a/azure/services/virtualnetworks/mock_virtualnetworks/virtualnetworks_mock.go b/azure/services/virtualnetworks/mock_virtualnetworks/virtualnetworks_mock.go index 1a18df65495..fdafa2c4abc 100644 --- a/azure/services/virtualnetworks/mock_virtualnetworks/virtualnetworks_mock.go +++ b/azure/services/virtualnetworks/mock_virtualnetworks/virtualnetworks_mock.go @@ -26,6 +26,7 @@ package mock_virtualnetworks import ( reflect "reflect" + time "time" v1api20201101 "github.com/Azure/azure-service-operator/v2/api/network/v1api20201101" gomock "go.uber.org/mock/gomock" @@ -72,6 +73,48 @@ func (mr *MockVNetScopeMockRecorder) ClusterName() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClusterName", reflect.TypeOf((*MockVNetScope)(nil).ClusterName)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockVNetScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockVNetScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockVNetScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockVNetScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockVNetScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockVNetScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockVNetScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockVNetScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockVNetScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockVNetScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/vmextensions/client.go b/azure/services/vmextensions/client.go index 7f43308b5ea..e9afaa624e1 100644 --- a/azure/services/vmextensions/client.go +++ b/azure/services/vmextensions/client.go @@ -18,23 +18,24 @@ package vmextensions import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5" "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) // azureClient contains the Azure go-sdk Client. type azureClient struct { - vmextensions *armcompute.VirtualMachineExtensionsClient + vmextensions *armcompute.VirtualMachineExtensionsClient + apiCallTimeout time.Duration } // newClient creates a new vm extensions client from an authorizer. -func newClient(auth azure.Authorizer) (*azureClient, error) { +func newClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*azureClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to create virtualmachineextensions client options") @@ -43,7 +44,7 @@ func newClient(auth azure.Authorizer) (*azureClient, error) { if err != nil { return nil, errors.Wrap(err, "failed to create armcompute client factory") } - return &azureClient{factory.NewVirtualMachineExtensionsClient()}, nil + return &azureClient{factory.NewVirtualMachineExtensionsClient(), apiCallTimeout}, nil } // Get the specified virtual machine extension. @@ -76,7 +77,7 @@ func (ac *azureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.Resou return nil, nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} @@ -104,7 +105,7 @@ func (ac *azureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/vmextensions/mock_vmextensions/vmextensions_mock.go b/azure/services/vmextensions/mock_vmextensions/vmextensions_mock.go index 422826e2486..ac4ca45b15c 100644 --- a/azure/services/vmextensions/mock_vmextensions/vmextensions_mock.go +++ b/azure/services/vmextensions/mock_vmextensions/vmextensions_mock.go @@ -26,6 +26,7 @@ package mock_vmextensions import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -113,6 +114,48 @@ func (mr *MockVMExtensionScopeMockRecorder) CloudEnvironment() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloudEnvironment", reflect.TypeOf((*MockVMExtensionScope)(nil).CloudEnvironment)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockVMExtensionScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockVMExtensionScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockVMExtensionScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockVMExtensionScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockVMExtensionScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockVMExtensionScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockVMExtensionScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockVMExtensionScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockVMExtensionScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockVMExtensionScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/vmextensions/vmextensions.go b/azure/services/vmextensions/vmextensions.go index 90fc4b350ab..f2bc2110dc1 100644 --- a/azure/services/vmextensions/vmextensions.go +++ b/azure/services/vmextensions/vmextensions.go @@ -24,7 +24,6 @@ import ( 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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -45,7 +44,7 @@ type Service struct { // New creates a new vm extension service. func New(scope VMExtensionScope) (*Service, error) { - client, err := newClient(scope) + client, err := newClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -66,7 +65,7 @@ func (s *Service) Reconcile(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "vmextensions.Service.Reconcile") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() specs := s.Scope.VMExtensionSpecs() diff --git a/azure/services/vmextensions/vmextensions_test.go b/azure/services/vmextensions/vmextensions_test.go index 7297bd87141..bb38b648d9b 100644 --- a/azure/services/vmextensions/vmextensions_test.go +++ b/azure/services/vmextensions/vmextensions_test.go @@ -30,6 +30,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/vmextensions/mock_vmextensions" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) var ( @@ -72,6 +73,7 @@ func TestReconcileVMExtension(t *testing.T) { name: "extension is in succeeded state", expectedError: "", expect: func(s *mock_vmextensions.MockVMExtensionScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMExtensionSpecs().Return([]azure.ResourceSpecGetter{&extensionSpec1}) r.CreateOrUpdateResource(gomockinternal.AContext(), &extensionSpec1, serviceName).Return(nil, nil) s.UpdatePutStatus(infrav1.BootstrapSucceededCondition, serviceName, nil) @@ -81,6 +83,7 @@ func TestReconcileVMExtension(t *testing.T) { name: "extension is in failed state", expectedError: extensionFailedError.Error(), expect: func(s *mock_vmextensions.MockVMExtensionScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMExtensionSpecs().Return([]azure.ResourceSpecGetter{&extensionSpec1}) r.CreateOrUpdateResource(gomockinternal.AContext(), &extensionSpec1, serviceName).Return(nil, internalError) s.UpdatePutStatus(infrav1.BootstrapSucceededCondition, serviceName, gomockinternal.ErrStrEq(extensionFailedError.Error())) @@ -90,6 +93,7 @@ func TestReconcileVMExtension(t *testing.T) { name: "extension is still creating", expectedError: extensionNotDoneError.Error(), expect: func(s *mock_vmextensions.MockVMExtensionScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMExtensionSpecs().Return([]azure.ResourceSpecGetter{&extensionSpec1}) r.CreateOrUpdateResource(gomockinternal.AContext(), &extensionSpec1, serviceName).Return(nil, notDoneError) s.UpdatePutStatus(infrav1.BootstrapSucceededCondition, serviceName, gomockinternal.ErrStrEq(extensionNotDoneError.Error())) @@ -99,6 +103,7 @@ func TestReconcileVMExtension(t *testing.T) { name: "reconcile multiple extensions", expectedError: "", expect: func(s *mock_vmextensions.MockVMExtensionScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMExtensionSpecs().Return([]azure.ResourceSpecGetter{&extensionSpec1, &extensionSpec2}) r.CreateOrUpdateResource(gomockinternal.AContext(), &extensionSpec1, serviceName).Return(nil, nil) r.CreateOrUpdateResource(gomockinternal.AContext(), &extensionSpec2, serviceName).Return(nil, nil) @@ -109,6 +114,7 @@ func TestReconcileVMExtension(t *testing.T) { name: "error creating the first extension", expectedError: extensionFailedError.Error(), expect: func(s *mock_vmextensions.MockVMExtensionScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) s.VMExtensionSpecs().Return([]azure.ResourceSpecGetter{&extensionSpec1, &extensionSpec2}) r.CreateOrUpdateResource(gomockinternal.AContext(), &extensionSpec1, serviceName).Return(nil, internalError) r.CreateOrUpdateResource(gomockinternal.AContext(), &extensionSpec2, serviceName).Return(nil, nil) diff --git a/azure/services/vnetpeerings/client.go b/azure/services/vnetpeerings/client.go index 32a799bd0ac..fc537d7e7e3 100644 --- a/azure/services/vnetpeerings/client.go +++ b/azure/services/vnetpeerings/client.go @@ -18,23 +18,24 @@ package vnetpeerings import ( "context" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4" "github.com/pkg/errors" "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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) // AzureClient contains the Azure go-sdk Client. type AzureClient struct { - peerings *armnetwork.VirtualNetworkPeeringsClient + peerings *armnetwork.VirtualNetworkPeeringsClient + apiCallTimeout time.Duration } // NewClient creates a new virtual network peerings client from an authorizer. -func NewClient(auth azure.Authorizer) (*AzureClient, error) { +func NewClient(auth azure.Authorizer, apiCallTimeout time.Duration) (*AzureClient, error) { opts, err := azure.ARMClientOptions(auth.CloudEnvironment()) if err != nil { return nil, errors.Wrap(err, "failed to create vnetpeerings client options") @@ -43,7 +44,7 @@ func NewClient(auth azure.Authorizer) (*AzureClient, error) { if err != nil { return nil, errors.Wrap(err, "failed to create armnetwork client factory") } - return &AzureClient{factory.NewVirtualNetworkPeeringsClient()}, nil + return &AzureClient{factory.NewVirtualNetworkPeeringsClient(), apiCallTimeout}, nil } // Get gets the specified virtual network peering by the peering name, virtual network, and resource group. @@ -76,7 +77,7 @@ func (ac *AzureClient) CreateOrUpdateAsync(ctx context.Context, spec azure.Resou return nil, nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} @@ -104,7 +105,7 @@ func (ac *AzureClient) DeleteAsync(ctx context.Context, spec azure.ResourceSpecG return nil, err } - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureCallTimeout) + ctx, cancel := context.WithTimeout(ctx, ac.apiCallTimeout) defer cancel() pollOpts := &runtime.PollUntilDoneOptions{Frequency: async.DefaultPollerFrequency} diff --git a/azure/services/vnetpeerings/mock_vnetpeerings/vnetpeerings_mock.go b/azure/services/vnetpeerings/mock_vnetpeerings/vnetpeerings_mock.go index e7234a31e19..d54f4c9e487 100644 --- a/azure/services/vnetpeerings/mock_vnetpeerings/vnetpeerings_mock.go +++ b/azure/services/vnetpeerings/mock_vnetpeerings/vnetpeerings_mock.go @@ -26,6 +26,7 @@ package mock_vnetpeerings import ( reflect "reflect" + time "time" azcore "github.com/Azure/azure-sdk-for-go/sdk/azcore" gomock "go.uber.org/mock/gomock" @@ -113,6 +114,48 @@ func (mr *MockVnetPeeringScopeMockRecorder) CloudEnvironment() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloudEnvironment", reflect.TypeOf((*MockVnetPeeringScope)(nil).CloudEnvironment)) } +// DefaultedAzureCallTimeout mocks base method. +func (m *MockVnetPeeringScope) DefaultedAzureCallTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureCallTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureCallTimeout indicates an expected call of DefaultedAzureCallTimeout. +func (mr *MockVnetPeeringScopeMockRecorder) DefaultedAzureCallTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureCallTimeout", reflect.TypeOf((*MockVnetPeeringScope)(nil).DefaultedAzureCallTimeout)) +} + +// DefaultedAzureServiceReconcileTimeout mocks base method. +func (m *MockVnetPeeringScope) DefaultedAzureServiceReconcileTimeout() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedAzureServiceReconcileTimeout") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedAzureServiceReconcileTimeout indicates an expected call of DefaultedAzureServiceReconcileTimeout. +func (mr *MockVnetPeeringScopeMockRecorder) DefaultedAzureServiceReconcileTimeout() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedAzureServiceReconcileTimeout", reflect.TypeOf((*MockVnetPeeringScope)(nil).DefaultedAzureServiceReconcileTimeout)) +} + +// DefaultedReconcilerRequeue mocks base method. +func (m *MockVnetPeeringScope) DefaultedReconcilerRequeue() time.Duration { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultedReconcilerRequeue") + ret0, _ := ret[0].(time.Duration) + return ret0 +} + +// DefaultedReconcilerRequeue indicates an expected call of DefaultedReconcilerRequeue. +func (mr *MockVnetPeeringScopeMockRecorder) DefaultedReconcilerRequeue() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultedReconcilerRequeue", reflect.TypeOf((*MockVnetPeeringScope)(nil).DefaultedReconcilerRequeue)) +} + // DeleteLongRunningOperationState mocks base method. func (m *MockVnetPeeringScope) DeleteLongRunningOperationState(arg0, arg1, arg2 string) { m.ctrl.T.Helper() diff --git a/azure/services/vnetpeerings/vnetpeerings.go b/azure/services/vnetpeerings/vnetpeerings.go index 3d156d75ab9..e2c1c4c5d6f 100644 --- a/azure/services/vnetpeerings/vnetpeerings.go +++ b/azure/services/vnetpeerings/vnetpeerings.go @@ -23,7 +23,6 @@ import ( 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/util/reconciler" "sigs.k8s.io/cluster-api-provider-azure/util/tele" ) @@ -45,7 +44,7 @@ type Service struct { // New creates a new service. func New(scope VnetPeeringScope) (*Service, error) { - Client, err := NewClient(scope) + Client, err := NewClient(scope, scope.DefaultedAzureCallTimeout()) if err != nil { return nil, err } @@ -66,7 +65,7 @@ func (s *Service) Reconcile(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "vnetpeerings.Service.Reconcile") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() specs := s.Scope.VnetPeeringSpecs() @@ -95,7 +94,7 @@ func (s *Service) Delete(ctx context.Context) error { ctx, _, done := tele.StartSpanWithLogger(ctx, "vnetpeerings.Service.Delete") defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultAzureServiceReconcileTimeout) + ctx, cancel := context.WithTimeout(ctx, s.Scope.DefaultedAzureServiceReconcileTimeout()) defer cancel() specs := s.Scope.VnetPeeringSpecs() diff --git a/azure/services/vnetpeerings/vnetpeerings_test.go b/azure/services/vnetpeerings/vnetpeerings_test.go index b437c0eb8d0..736de69e43c 100644 --- a/azure/services/vnetpeerings/vnetpeerings_test.go +++ b/azure/services/vnetpeerings/vnetpeerings_test.go @@ -31,6 +31,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" "sigs.k8s.io/cluster-api-provider-azure/azure/services/vnetpeerings/mock_vnetpeerings" gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) var ( @@ -114,6 +115,7 @@ func TestReconcileVnetPeerings(t *testing.T) { name: "create one peering", expectedError: "", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs[:1]) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil) p.UpdatePutStatus(infrav1.VnetPeeringReadyCondition, ServiceName, nil) @@ -123,6 +125,7 @@ func TestReconcileVnetPeerings(t *testing.T) { name: "noop if no peering specs are found", expectedError: "", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return([]azure.ResourceSpecGetter{}) }, }, @@ -130,6 +133,7 @@ func TestReconcileVnetPeerings(t *testing.T) { name: "create even number of peerings", expectedError: "", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs[:2]) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(&fakePeering2To1, nil) @@ -140,6 +144,7 @@ func TestReconcileVnetPeerings(t *testing.T) { name: "create odd number of peerings", expectedError: "", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringExtraSpecs) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(&fakePeering2To1, nil) @@ -151,6 +156,7 @@ func TestReconcileVnetPeerings(t *testing.T) { name: "create multiple peerings on one vnet", expectedError: "", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(&fakePeering2To1, nil) @@ -165,6 +171,7 @@ func TestReconcileVnetPeerings(t *testing.T) { name: "error in creating peering", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(&fakePeering2To1, nil) @@ -179,6 +186,7 @@ func TestReconcileVnetPeerings(t *testing.T) { name: "not done error in creating is ignored", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil, internalError) @@ -193,6 +201,7 @@ func TestReconcileVnetPeerings(t *testing.T) { name: "not done error in creating is overwritten", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(&fakePeering2To1, nil) @@ -207,6 +216,7 @@ func TestReconcileVnetPeerings(t *testing.T) { name: "not done error in creating remains", expectedError: "operation type on Azure resource / is not done", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(&fakePeering1To2, nil) r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(&fakePeering2To1, nil) @@ -258,6 +268,7 @@ func TestDeleteVnetPeerings(t *testing.T) { name: "delete one peering", expectedError: "", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs[:1]) r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil) p.UpdateDeleteStatus(infrav1.VnetPeeringReadyCondition, ServiceName, nil) @@ -267,6 +278,7 @@ func TestDeleteVnetPeerings(t *testing.T) { name: "noop if no peering specs are found", expectedError: "", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return([]azure.ResourceSpecGetter{}) }, }, @@ -274,6 +286,7 @@ func TestDeleteVnetPeerings(t *testing.T) { name: "delete even number of peerings", expectedError: "", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs[:2]) r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil) r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil) @@ -284,6 +297,7 @@ func TestDeleteVnetPeerings(t *testing.T) { name: "delete odd number of peerings", expectedError: "", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringExtraSpecs) r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil) r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil) @@ -295,6 +309,7 @@ func TestDeleteVnetPeerings(t *testing.T) { name: "delete multiple peerings on one vnet", expectedError: "", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs) r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil) r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil) @@ -309,6 +324,7 @@ func TestDeleteVnetPeerings(t *testing.T) { name: "error in deleting peering", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs) r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil) r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil) @@ -323,6 +339,7 @@ func TestDeleteVnetPeerings(t *testing.T) { name: "not done error in deleting is ignored", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs) r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil) r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(internalError) @@ -337,6 +354,7 @@ func TestDeleteVnetPeerings(t *testing.T) { name: "not done error in deleting is overwritten", expectedError: "#: Internal Server Error: StatusCode=500", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs) r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil) r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil) @@ -351,6 +369,7 @@ func TestDeleteVnetPeerings(t *testing.T) { name: "not done error in deleting remains", expectedError: "operation type on Azure resource / is not done", expect: func(p *mock_vnetpeerings.MockVnetPeeringScopeMockRecorder, r *mock_async.MockReconcilerMockRecorder) { + p.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) p.VnetPeeringSpecs().Return(fakePeeringSpecs) r.DeleteResource(gomockinternal.AContext(), &fakePeering1To2, ServiceName).Return(nil) r.DeleteResource(gomockinternal.AContext(), &fakePeering2To1, ServiceName).Return(nil) diff --git a/controllers/asosecret_controller.go b/controllers/asosecret_controller.go index a7b1fe0fcde..7f6d41a08f5 100644 --- a/controllers/asosecret_controller.go +++ b/controllers/asosecret_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "time" asoconfig "github.com/Azure/azure-service-operator/v2/pkg/common/config" "github.com/pkg/errors" @@ -50,7 +49,7 @@ import ( type ASOSecretReconciler struct { client.Client Recorder record.EventRecorder - ReconcileTimeout time.Duration + Timeouts reconciler.Timeouts WatchFilterValue string } @@ -106,7 +105,7 @@ func (asos *ASOSecretReconciler) SetupWithManager(ctx context.Context, mgr ctrl. // Reconcile reconciles the ASO secrets associated with AzureCluster objects. func (asos *ASOSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(asos.ReconcileTimeout)) + ctx, cancel := context.WithTimeout(ctx, asos.Timeouts.DefaultedLoopTimeout()) defer cancel() ctx, log, done := tele.StartSpanWithLogger(ctx, "controllers.ASOSecret.Reconcile", @@ -181,6 +180,7 @@ func (asos *ASOSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request Client: asos.Client, Cluster: cluster, AzureCluster: ownerType, + Timeouts: asos.Timeouts, }) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create scope") @@ -206,6 +206,7 @@ func (asos *ASOSecretReconciler) Reconcile(ctx context.Context, req ctrl.Request Client: asos.Client, Cluster: cluster, ControlPlane: ownerType, + Timeouts: asos.Timeouts, }) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create scope") diff --git a/controllers/azurecluster_controller.go b/controllers/azurecluster_controller.go index b4dfa278a15..cd80b3202d4 100644 --- a/controllers/azurecluster_controller.go +++ b/controllers/azurecluster_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "time" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" @@ -48,7 +47,7 @@ import ( type AzureClusterReconciler struct { client.Client Recorder record.EventRecorder - ReconcileTimeout time.Duration + Timeouts reconciler.Timeouts WatchFilterValue string createAzureClusterService azureClusterServiceCreator } @@ -56,11 +55,11 @@ type AzureClusterReconciler struct { type azureClusterServiceCreator func(clusterScope *scope.ClusterScope) (*azureClusterService, error) // NewAzureClusterReconciler returns a new AzureClusterReconciler instance. -func NewAzureClusterReconciler(client client.Client, recorder record.EventRecorder, reconcileTimeout time.Duration, watchFilterValue string) *AzureClusterReconciler { +func NewAzureClusterReconciler(client client.Client, recorder record.EventRecorder, timeouts reconciler.Timeouts, watchFilterValue string) *AzureClusterReconciler { acr := &AzureClusterReconciler{ Client: client, Recorder: recorder, - ReconcileTimeout: reconcileTimeout, + Timeouts: timeouts, WatchFilterValue: watchFilterValue, } @@ -118,7 +117,7 @@ func (acr *AzureClusterReconciler) SetupWithManager(ctx context.Context, mgr ctr // Reconcile idempotently gets, creates, and updates a cluster. func (acr *AzureClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(acr.ReconcileTimeout)) + ctx, cancel := context.WithTimeout(ctx, acr.Timeouts.DefaultedLoopTimeout()) defer cancel() ctx, log, done := tele.StartSpanWithLogger( @@ -160,6 +159,7 @@ func (acr *AzureClusterReconciler) Reconcile(ctx context.Context, req ctrl.Reque Client: acr.Client, Cluster: cluster, AzureCluster: azureCluster, + Timeouts: acr.Timeouts, }) if err != nil { err = errors.Wrap(err, "failed to create scope") diff --git a/controllers/azurecluster_controller_test.go b/controllers/azurecluster_controller_test.go index ad3535672d4..3d2f72b503c 100644 --- a/controllers/azurecluster_controller_test.go +++ b/controllers/azurecluster_controller_test.go @@ -69,7 +69,7 @@ var _ = Describe("AzureClusterReconciler", func() { Context("Reconcile an AzureCluster", func() { It("should not error with minimal set up", func() { - reconciler := NewAzureClusterReconciler(testEnv, testEnv.GetEventRecorderFor("azurecluster-reconciler"), reconciler.DefaultLoopTimeout, "") + reconciler := NewAzureClusterReconciler(testEnv, testEnv.GetEventRecorderFor("azurecluster-reconciler"), reconciler.Timeouts{}, "") By("Calling reconcile") name := test.RandomName("foo", 10) instance := &infrav1.AzureCluster{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace}} @@ -276,7 +276,7 @@ func TestAzureClusterReconcilePaused(t *testing.T) { recorder := record.NewFakeRecorder(1) - reconciler := NewAzureClusterReconciler(c, recorder, reconciler.DefaultLoopTimeout, "") + reconciler := NewAzureClusterReconciler(c, recorder, reconciler.Timeouts{}, "") name := test.RandomName("paused", 10) namespace := namespace diff --git a/controllers/azureidentity_controller.go b/controllers/azureidentity_controller.go index 6668c6cc9f4..4d43b11219c 100644 --- a/controllers/azureidentity_controller.go +++ b/controllers/azureidentity_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "time" aadpodv1 "github.com/Azure/aad-pod-identity/pkg/apis/aadpodidentity/v1" "github.com/pkg/errors" @@ -47,7 +46,7 @@ import ( type AzureIdentityReconciler struct { client.Client Recorder record.EventRecorder - ReconcileTimeout time.Duration + Timeouts reconciler.Timeouts WatchFilterValue string } @@ -101,7 +100,7 @@ func (r *AzureIdentityReconciler) SetupWithManager(ctx context.Context, mgr ctrl // Reconcile reconciles the Azure identity. func (r *AzureIdentityReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) + ctx, cancel := context.WithTimeout(ctx, r.Timeouts.DefaultedLoopTimeout()) defer cancel() ctx, log, done := tele.StartSpanWithLogger(ctx, "controllers.AzureIdentityReconciler.Reconcile", diff --git a/controllers/azureidentity_controller_test.go b/controllers/azureidentity_controller_test.go index 446346e8f36..e0c6d478182 100644 --- a/controllers/azureidentity_controller_test.go +++ b/controllers/azureidentity_controller_test.go @@ -55,7 +55,7 @@ func TestAzureIdentityControllerReconcileAzureCluster(t *testing.T) { aiRec := &AzureIdentityReconciler{ Client: client, Recorder: record.NewFakeRecorder(42), - ReconcileTimeout: reconciler.DefaultLoopTimeout, + Timeouts: reconciler.Timeouts{}, WatchFilterValue: "fake", } _, err = aiRec.Reconcile(ctx, req) @@ -84,7 +84,7 @@ func TestAzureIdentityControllerReconcileAzureManagedControlPlane(t *testing.T) aiRec := &AzureIdentityReconciler{ Client: client, Recorder: record.NewFakeRecorder(42), - ReconcileTimeout: reconciler.DefaultLoopTimeout, + Timeouts: reconciler.Timeouts{}, WatchFilterValue: "fake", } _, err = aiRec.Reconcile(ctx, req) diff --git a/controllers/azurejson_machine_controller.go b/controllers/azurejson_machine_controller.go index bbe67fc4a30..6a49a3f8a08 100644 --- a/controllers/azurejson_machine_controller.go +++ b/controllers/azurejson_machine_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "time" "github.com/go-logr/logr" "github.com/pkg/errors" @@ -52,7 +51,7 @@ import ( type AzureJSONMachineReconciler struct { client.Client Recorder record.EventRecorder - ReconcileTimeout time.Duration + Timeouts reconciler.Timeouts WatchFilterValue string } @@ -128,7 +127,7 @@ func (f filterUnclonedMachinesPredicate) Generic(e event.GenericEvent) bool { // Reconcile reconciles the Azure json for a specific machine not in a machine deployment. func (r *AzureJSONMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) + ctx, cancel := context.WithTimeout(ctx, r.Timeouts.DefaultedLoopTimeout()) defer cancel() ctx, log, done := tele.StartSpanWithLogger( @@ -198,6 +197,7 @@ func (r *AzureJSONMachineReconciler) Reconcile(ctx context.Context, req ctrl.Req Client: r.Client, Cluster: cluster, AzureCluster: azureCluster, + Timeouts: r.Timeouts, }) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create scope") diff --git a/controllers/azurejson_machinepool_controller.go b/controllers/azurejson_machinepool_controller.go index d29ef70c48d..09d5af0773a 100644 --- a/controllers/azurejson_machinepool_controller.go +++ b/controllers/azurejson_machinepool_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "time" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" @@ -47,7 +46,7 @@ import ( type AzureJSONMachinePoolReconciler struct { client.Client Recorder record.EventRecorder - ReconcileTimeout time.Duration + Timeouts reconciler.Timeouts WatchFilterValue string } @@ -90,7 +89,7 @@ func (r *AzureJSONMachinePoolReconciler) SetupWithManager(ctx context.Context, m // Reconcile reconciles the Azure json for AzureMachinePool objects. func (r *AzureJSONMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) + ctx, cancel := context.WithTimeout(ctx, r.Timeouts.DefaultedLoopTimeout()) defer cancel() ctx, log, done := tele.StartSpanWithLogger( @@ -141,7 +140,7 @@ func (r *AzureJSONMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl return ctrl.Result{}, nil } - clusterScope, err := GetClusterScoper(ctx, log, r.Client, cluster) + clusterScope, err := GetClusterScoper(ctx, log, r.Client, cluster, r.Timeouts) if err != nil { return reconcile.Result{}, errors.Wrapf(err, "failed to create cluster scope for cluster %s/%s", cluster.Namespace, cluster.Name) } diff --git a/controllers/azurejson_machinepool_controller_test.go b/controllers/azurejson_machinepool_controller_test.go index 4ffbea3b016..4861f88a236 100644 --- a/controllers/azurejson_machinepool_controller_test.go +++ b/controllers/azurejson_machinepool_controller_test.go @@ -371,9 +371,9 @@ func TestAzureJSONPoolReconcilerUserAssignedIdentities(t *testing.T) { client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(azureMP, ownerMP, cluster, azureCluster, sec, fakeIdentity).Build() rec := AzureJSONMachinePoolReconciler{ - Client: client, - Recorder: record.NewFakeRecorder(42), - ReconcileTimeout: reconciler.DefaultLoopTimeout, + Client: client, + Recorder: record.NewFakeRecorder(42), + Timeouts: reconciler.Timeouts{}, } id := "fake-id" getClient = func(auth azure.Authorizer) (identities.Client, error) { diff --git a/controllers/azurejson_machinetemplate_controller.go b/controllers/azurejson_machinetemplate_controller.go index c7a408d5e59..359ae971a57 100644 --- a/controllers/azurejson_machinetemplate_controller.go +++ b/controllers/azurejson_machinetemplate_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "time" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" @@ -49,7 +48,7 @@ import ( type AzureJSONTemplateReconciler struct { client.Client Recorder record.EventRecorder - ReconcileTimeout time.Duration + Timeouts reconciler.Timeouts WatchFilterValue string } @@ -92,7 +91,7 @@ func (r *AzureJSONTemplateReconciler) SetupWithManager(ctx context.Context, mgr // Reconcile reconciles Azure json secrets for Azure machine templates. func (r *AzureJSONTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(r.ReconcileTimeout)) + ctx, cancel := context.WithTimeout(ctx, r.Timeouts.DefaultedLoopTimeout()) defer cancel() ctx, log, done := tele.StartSpanWithLogger(ctx, "controllers.AzureJSONTemplateReconciler.Reconcile", @@ -158,6 +157,7 @@ func (r *AzureJSONTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Re Client: r.Client, Cluster: cluster, AzureCluster: azureCluster, + Timeouts: r.Timeouts, }) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create scope") diff --git a/controllers/azuremachine_controller.go b/controllers/azuremachine_controller.go index c0846f15237..bb8e8ddf78c 100644 --- a/controllers/azuremachine_controller.go +++ b/controllers/azuremachine_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "time" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" @@ -49,7 +48,7 @@ import ( type AzureMachineReconciler struct { client.Client Recorder record.EventRecorder - ReconcileTimeout time.Duration + Timeouts reconciler.Timeouts WatchFilterValue string createAzureMachineService azureMachineServiceCreator } @@ -57,11 +56,11 @@ type AzureMachineReconciler struct { type azureMachineServiceCreator func(machineScope *scope.MachineScope) (*azureMachineService, error) // NewAzureMachineReconciler returns a new AzureMachineReconciler instance. -func NewAzureMachineReconciler(client client.Client, recorder record.EventRecorder, reconcileTimeout time.Duration, watchFilterValue string) *AzureMachineReconciler { +func NewAzureMachineReconciler(client client.Client, recorder record.EventRecorder, timeouts reconciler.Timeouts, watchFilterValue string) *AzureMachineReconciler { amr := &AzureMachineReconciler{ Client: client, Recorder: recorder, - ReconcileTimeout: reconcileTimeout, + Timeouts: timeouts, WatchFilterValue: watchFilterValue, } @@ -134,7 +133,7 @@ func (amr *AzureMachineReconciler) SetupWithManager(ctx context.Context, mgr ctr // Reconcile idempotently gets, creates, and updates a machine. func (amr *AzureMachineReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(amr.ReconcileTimeout)) + ctx, cancel := context.WithTimeout(ctx, amr.Timeouts.DefaultedLoopTimeout()) defer cancel() ctx, log, done := tele.StartSpanWithLogger( @@ -196,6 +195,7 @@ func (amr *AzureMachineReconciler) Reconcile(ctx context.Context, req ctrl.Reque Client: amr.Client, Cluster: cluster, AzureCluster: azureCluster, + Timeouts: amr.Timeouts, }) if err != nil { amr.Recorder.Eventf(azureCluster, corev1.EventTypeWarning, "Error creating the cluster scope", err.Error()) diff --git a/controllers/azuremachine_controller_test.go b/controllers/azuremachine_controller_test.go index 90a976b4084..53b81685daf 100644 --- a/controllers/azuremachine_controller_test.go +++ b/controllers/azuremachine_controller_test.go @@ -782,7 +782,7 @@ func TestConditions(t *testing.T) { g.Expect(fakeClient.Get(context.TODO(), key, resultIdentity)) recorder := record.NewFakeRecorder(10) - reconciler := NewAzureMachineReconciler(fakeClient, recorder, reconciler.DefaultLoopTimeout, "") + reconciler := NewAzureMachineReconciler(fakeClient, recorder, reconciler.Timeouts{}, "") clusterScope, err := scope.NewClusterScope(context.TODO(), scope.ClusterScopeParams{ Client: fakeClient, diff --git a/controllers/azuremanagedcluster_controller.go b/controllers/azuremanagedcluster_controller.go index 25cd3a51bc9..f38b69fa842 100644 --- a/controllers/azuremanagedcluster_controller.go +++ b/controllers/azuremanagedcluster_controller.go @@ -18,7 +18,6 @@ package controllers import ( "context" - "time" "github.com/pkg/errors" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -44,7 +43,7 @@ import ( type AzureManagedClusterReconciler struct { client.Client Recorder record.EventRecorder - ReconcileTimeout time.Duration + Timeouts reconciler.Timeouts WatchFilterValue string } @@ -101,7 +100,7 @@ func (amcr *AzureManagedClusterReconciler) SetupWithManager(ctx context.Context, // Reconcile idempotently gets, creates, and updates a managed cluster. func (amcr *AzureManagedClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(amcr.ReconcileTimeout)) + ctx, cancel := context.WithTimeout(ctx, amcr.Timeouts.DefaultedLoopTimeout()) defer cancel() ctx, log, done := tele.StartSpanWithLogger( diff --git a/controllers/azuremanagedcontrolplane_controller.go b/controllers/azuremanagedcontrolplane_controller.go index 48a47816a55..edc001b6031 100644 --- a/controllers/azuremanagedcontrolplane_controller.go +++ b/controllers/azuremanagedcontrolplane_controller.go @@ -19,7 +19,6 @@ package controllers import ( "context" "fmt" - "time" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" @@ -49,7 +48,7 @@ import ( type AzureManagedControlPlaneReconciler struct { client.Client Recorder record.EventRecorder - ReconcileTimeout time.Duration + Timeouts reconciler.Timeouts WatchFilterValue string getNewAzureManagedControlPlaneReconciler func(scope *scope.ManagedControlPlaneScope) (*azureManagedControlPlaneService, error) } @@ -122,7 +121,7 @@ func (amcpr *AzureManagedControlPlaneReconciler) SetupWithManager(ctx context.Co // Reconcile idempotently gets, creates, and updates a managed control plane. func (amcpr *AzureManagedControlPlaneReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(amcpr.ReconcileTimeout)) + ctx, cancel := context.WithTimeout(ctx, amcpr.Timeouts.DefaultedLoopTimeout()) defer cancel() ctx, log, done := tele.StartSpanWithLogger(ctx, "controllers.AzureManagedControlPlaneReconciler.Reconcile", @@ -185,6 +184,7 @@ func (amcpr *AzureManagedControlPlaneReconciler) Reconcile(ctx context.Context, Cluster: cluster, ControlPlane: azureControlPlane, ManagedMachinePools: pools, + Timeouts: amcpr.Timeouts, }) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create scope") diff --git a/controllers/azuremanagedcontrolplane_controller_test.go b/controllers/azuremanagedcontrolplane_controller_test.go index 624edd7beb0..93c601b0ac8 100644 --- a/controllers/azuremanagedcontrolplane_controller_test.go +++ b/controllers/azuremanagedcontrolplane_controller_test.go @@ -122,7 +122,7 @@ func TestAzureManagedControlPlaneReconcilePaused(t *testing.T) { reconciler := &AzureManagedControlPlaneReconciler{ Client: c, Recorder: recorder, - ReconcileTimeout: reconciler.DefaultLoopTimeout, + Timeouts: reconciler.Timeouts{}, WatchFilterValue: "", getNewAzureManagedControlPlaneReconciler: newAzureManagedControlPlaneReconciler, } diff --git a/controllers/azuremanagedmachinepool_controller.go b/controllers/azuremanagedmachinepool_controller.go index f9e3cd6bbbe..fc88c30b285 100644 --- a/controllers/azuremanagedmachinepool_controller.go +++ b/controllers/azuremanagedmachinepool_controller.go @@ -48,19 +48,19 @@ import ( type AzureManagedMachinePoolReconciler struct { client.Client Recorder record.EventRecorder - ReconcileTimeout time.Duration + Timeouts reconciler.Timeouts WatchFilterValue string createAzureManagedMachinePoolService azureManagedMachinePoolServiceCreator } -type azureManagedMachinePoolServiceCreator func(managedMachinePoolScope *scope.ManagedMachinePoolScope) (*azureManagedMachinePoolService, error) +type azureManagedMachinePoolServiceCreator func(managedMachinePoolScope *scope.ManagedMachinePoolScope, apiCallTimeout time.Duration) (*azureManagedMachinePoolService, error) // NewAzureManagedMachinePoolReconciler returns a new AzureManagedMachinePoolReconciler instance. -func NewAzureManagedMachinePoolReconciler(client client.Client, recorder record.EventRecorder, reconcileTimeout time.Duration, watchFilterValue string) *AzureManagedMachinePoolReconciler { +func NewAzureManagedMachinePoolReconciler(client client.Client, recorder record.EventRecorder, timeouts reconciler.Timeouts, watchFilterValue string) *AzureManagedMachinePoolReconciler { ampr := &AzureManagedMachinePoolReconciler{ Client: client, Recorder: recorder, - ReconcileTimeout: reconcileTimeout, + Timeouts: timeouts, WatchFilterValue: watchFilterValue, } @@ -135,7 +135,7 @@ func (ammpr *AzureManagedMachinePoolReconciler) SetupWithManager(ctx context.Con // Reconcile idempotently gets, creates, and updates a machine pool. func (ammpr *AzureManagedMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reterr error) { - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(ammpr.ReconcileTimeout)) + ctx, cancel := context.WithTimeout(ctx, ammpr.Timeouts.DefaultedLoopTimeout()) defer cancel() ctx, log, done := tele.StartSpanWithLogger(ctx, "controllers.AzureManagedMachinePoolReconciler.Reconcile", @@ -200,6 +200,7 @@ func (ammpr *AzureManagedMachinePoolReconciler) Reconcile(ctx context.Context, r Client: ammpr.Client, ControlPlane: controlPlane, Cluster: ownerCluster, + Timeouts: ammpr.Timeouts, }) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create ManagedControlPlane scope") @@ -261,7 +262,7 @@ func (ammpr *AzureManagedMachinePoolReconciler) reconcileNormal(ctx context.Cont } } - svc, err := ammpr.createAzureManagedMachinePoolService(scope) + svc, err := ammpr.createAzureManagedMachinePoolService(scope, ammpr.Timeouts.DefaultedAzureServiceReconcileTimeout()) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create an AzureManageMachinePoolService") } @@ -305,7 +306,7 @@ func (ammpr *AzureManagedMachinePoolReconciler) reconcilePause(ctx context.Conte log.Info("Reconciling AzureManagedMachinePool pause") - svc, err := ammpr.createAzureManagedMachinePoolService(scope) + svc, err := ammpr.createAzureManagedMachinePoolService(scope, ammpr.Timeouts.DefaultedAzureServiceReconcileTimeout()) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create an AzureManageMachinePoolService") } @@ -329,7 +330,7 @@ func (ammpr *AzureManagedMachinePoolReconciler) reconcileDelete(ctx context.Cont // So, remove the finalizer. controllerutil.RemoveFinalizer(scope.InfraMachinePool, infrav1.ClusterFinalizer) } else { - svc, err := ammpr.createAzureManagedMachinePoolService(scope) + svc, err := ammpr.createAzureManagedMachinePoolService(scope, ammpr.Timeouts.DefaultedAzureServiceReconcileTimeout()) if err != nil { return reconcile.Result{}, errors.Wrap(err, "failed to create an AzureManageMachinePoolService") } diff --git a/controllers/azuremanagedmachinepool_controller_test.go b/controllers/azuremanagedmachinepool_controller_test.go index 05c3c934831..6cc6ff80840 100644 --- a/controllers/azuremanagedmachinepool_controller_test.go +++ b/controllers/azuremanagedmachinepool_controller_test.go @@ -41,6 +41,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/services/agentpools" "sigs.k8s.io/cluster-api-provider-azure/azure/services/agentpools/mock_agentpools" gomock2 "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + reconcilerutils "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" @@ -183,8 +184,8 @@ func TestAzureManagedMachinePoolReconcile(t *testing.T) { defer mockCtrl.Finish() c.Setup(cb, reconciler, agentpools.EXPECT(), nodelister.EXPECT()) - controller := NewAzureManagedMachinePoolReconciler(cb.Build(), nil, 30*time.Second, "foo") - controller.createAzureManagedMachinePoolService = func(_ *scope.ManagedMachinePoolScope) (*azureManagedMachinePoolService, error) { + controller := NewAzureManagedMachinePoolReconciler(cb.Build(), nil, reconcilerutils.Timeouts{}, "foo") + controller.createAzureManagedMachinePoolService = func(_ *scope.ManagedMachinePoolScope, _ time.Duration) (*azureManagedMachinePoolService, error) { return &azureManagedMachinePoolService{ scope: agentpools, agentPoolsSvc: reconciler, diff --git a/controllers/azuremanagedmachinepool_reconciler.go b/controllers/azuremanagedmachinepool_reconciler.go index c9fe661c43c..0e081a0b588 100644 --- a/controllers/azuremanagedmachinepool_reconciler.go +++ b/controllers/azuremanagedmachinepool_reconciler.go @@ -74,12 +74,12 @@ func (a *AgentPoolVMSSNotFoundError) Is(target error) bool { } // newAzureManagedMachinePoolService populates all the services based on input scope. -func newAzureManagedMachinePoolService(scope *scope.ManagedMachinePoolScope) (*azureManagedMachinePoolService, error) { +func newAzureManagedMachinePoolService(scope *scope.ManagedMachinePoolScope, apiCallTimeout time.Duration) (*azureManagedMachinePoolService, error) { scaleSetAuthorizer, err := scaleSetAuthorizer(scope) if err != nil { return nil, err } - scaleSetsClient, err := scalesets.NewClient(scaleSetAuthorizer) + scaleSetsClient, err := scalesets.NewClient(scaleSetAuthorizer, apiCallTimeout) if err != nil { return nil, err } diff --git a/controllers/helpers.go b/controllers/helpers.go index 7038ad082b1..cff122e8f24 100644 --- a/controllers/helpers.go +++ b/controllers/helpers.go @@ -1077,7 +1077,7 @@ func ClusterPauseChangeAndInfrastructureReady(log logr.Logger) predicate.Funcs { } // GetClusterScoper returns a ClusterScoper for the given cluster using the infra ref pointing to either an AzureCluster or an AzureManagedCluster. -func GetClusterScoper(ctx context.Context, logger logr.Logger, c client.Client, cluster *clusterv1.Cluster) (ClusterScoper, error) { +func GetClusterScoper(ctx context.Context, logger logr.Logger, c client.Client, cluster *clusterv1.Cluster, timeouts reconciler.Timeouts) (ClusterScoper, error) { infraRef := cluster.Spec.InfrastructureRef switch infraRef.Kind { case "AzureCluster": @@ -1097,6 +1097,7 @@ func GetClusterScoper(ctx context.Context, logger logr.Logger, c client.Client, Client: c, Cluster: cluster, AzureCluster: azureCluster, + Timeouts: timeouts, }) case "AzureManagedCluster": @@ -1116,6 +1117,7 @@ func GetClusterScoper(ctx context.Context, logger logr.Logger, c client.Client, Client: c, Cluster: cluster, ControlPlane: azureManagedControlPlane, + Timeouts: timeouts, }) } diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 8b7629a06e3..e690875f066 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -44,10 +44,10 @@ func TestAPIs(t *testing.T) { var _ = BeforeSuite(func() { By("bootstrapping test environment") testEnv = env.NewTestEnvironment() - Expect(NewAzureClusterReconciler(testEnv, testEnv.GetEventRecorderFor("azurecluster-reconciler"), reconciler.DefaultLoopTimeout, ""). + Expect(NewAzureClusterReconciler(testEnv, testEnv.GetEventRecorderFor("azurecluster-reconciler"), reconciler.Timeouts{}, ""). SetupWithManager(context.Background(), testEnv.Manager, Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) - Expect(NewAzureMachineReconciler(testEnv, testEnv.GetEventRecorderFor("azuremachine-reconciler"), reconciler.DefaultLoopTimeout, ""). + Expect(NewAzureMachineReconciler(testEnv, testEnv.GetEventRecorderFor("azuremachine-reconciler"), reconciler.Timeouts{}, ""). SetupWithManager(context.Background(), testEnv.Manager, Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) Expect((&AzureManagedClusterReconciler{ @@ -61,7 +61,7 @@ var _ = BeforeSuite(func() { }).SetupWithManager(context.Background(), testEnv.Manager, Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) Expect(NewAzureManagedMachinePoolReconciler(testEnv, testEnv.GetEventRecorderFor("azuremanagedmachinepool-reconciler"), - reconciler.DefaultLoopTimeout, "").SetupWithManager(context.Background(), testEnv.Manager, Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) + reconciler.Timeouts{}, "").SetupWithManager(context.Background(), testEnv.Manager, Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) // +kubebuilder:scaffold:scheme diff --git a/exp/controllers/azuremachinepool_controller.go b/exp/controllers/azuremachinepool_controller.go index dd3453885eb..9f5fd94143d 100644 --- a/exp/controllers/azuremachinepool_controller.go +++ b/exp/controllers/azuremachinepool_controller.go @@ -57,7 +57,7 @@ type ( client.Client Scheme *runtime.Scheme Recorder record.EventRecorder - ReconcileTimeout time.Duration + Timeouts reconciler.Timeouts WatchFilterValue string createAzureMachinePoolService azureMachinePoolServiceCreator } @@ -72,11 +72,11 @@ type ( type azureMachinePoolServiceCreator func(machinePoolScope *scope.MachinePoolScope) (*azureMachinePoolService, error) // NewAzureMachinePoolReconciler returns a new AzureMachinePoolReconciler instance. -func NewAzureMachinePoolReconciler(client client.Client, recorder record.EventRecorder, reconcileTimeout time.Duration, watchFilterValue string) *AzureMachinePoolReconciler { +func NewAzureMachinePoolReconciler(client client.Client, recorder record.EventRecorder, timeouts reconciler.Timeouts, watchFilterValue string) *AzureMachinePoolReconciler { ampr := &AzureMachinePoolReconciler{ Client: client, Recorder: recorder, - ReconcileTimeout: reconcileTimeout, + Timeouts: timeouts, WatchFilterValue: watchFilterValue, } @@ -185,7 +185,7 @@ func (ampr *AzureMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl. tele.KVP("kind", infrav1.AzureMachinePoolKind), ) defer done() - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(ampr.ReconcileTimeout)) + ctx, cancel := context.WithTimeout(ctx, ampr.Timeouts.DefaultedLoopTimeout()) defer cancel() logger = logger.WithValues("namespace", req.Namespace, "azureMachinePool", req.Name) @@ -220,7 +220,7 @@ func (ampr *AzureMachinePoolReconciler) Reconcile(ctx context.Context, req ctrl. logger = logger.WithValues("cluster", cluster.Name) - clusterScope, err := infracontroller.GetClusterScoper(ctx, logger, ampr.Client, cluster) + clusterScope, err := infracontroller.GetClusterScoper(ctx, logger, ampr.Client, cluster, ampr.Timeouts) if err != nil { return reconcile.Result{}, errors.Wrapf(err, "failed to create cluster scope for cluster %s/%s", cluster.Namespace, cluster.Name) } diff --git a/exp/controllers/azuremachinepool_controller_test.go b/exp/controllers/azuremachinepool_controller_test.go index 707cb2e64ec..7247042f4a3 100644 --- a/exp/controllers/azuremachinepool_controller_test.go +++ b/exp/controllers/azuremachinepool_controller_test.go @@ -45,7 +45,7 @@ var _ = Describe("AzureMachinePoolReconciler", func() { Context("Reconcile an AzureMachinePool", func() { It("should not error with minimal set up", func() { reconciler := NewAzureMachinePoolReconciler(testEnv, testEnv.GetEventRecorderFor("azuremachinepool-reconciler"), - reconciler.DefaultLoopTimeout, "") + reconciler.Timeouts{}, "") By("Calling reconcile") instance := &infrav1exp.AzureMachinePool{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "default"}} result, err := reconciler.Reconcile(context.Background(), ctrl.Request{ @@ -81,7 +81,7 @@ func TestAzureMachinePoolReconcilePaused(t *testing.T) { recorder := record.NewFakeRecorder(1) - reconciler := NewAzureMachinePoolReconciler(c, recorder, reconciler.DefaultLoopTimeout, "") + reconciler := NewAzureMachinePoolReconciler(c, recorder, reconciler.Timeouts{}, "") name := test.RandomName("paused", 10) namespace := "default" diff --git a/exp/controllers/azuremachinepool_controller_unit_test.go b/exp/controllers/azuremachinepool_controller_unit_test.go index 8dc410e5b9b..c050ae16c05 100644 --- a/exp/controllers/azuremachinepool_controller_unit_test.go +++ b/exp/controllers/azuremachinepool_controller_unit_test.go @@ -55,6 +55,7 @@ func Test_newAzureMachinePoolService(t *testing.T) { clusterMock.EXPECT().HashKey().Return("fakeCluster") clusterMock.EXPECT().CloudEnvironment().AnyTimes() clusterMock.EXPECT().Token().AnyTimes() + clusterMock.EXPECT().DefaultedAzureCallTimeout().AnyTimes() mps := &scope.MachinePoolScope{ ClusterScoper: clusterMock, diff --git a/exp/controllers/azuremachinepoolmachine_controller.go b/exp/controllers/azuremachinepoolmachine_controller.go index 8fab7f3a795..4907b53eea2 100644 --- a/exp/controllers/azuremachinepoolmachine_controller.go +++ b/exp/controllers/azuremachinepoolmachine_controller.go @@ -57,7 +57,7 @@ type ( client.Client Scheme *runtime.Scheme Recorder record.EventRecorder - ReconcileTimeout time.Duration + Timeouts reconciler.Timeouts WatchFilterValue string reconcilerFactory azureMachinePoolMachineReconcilerFactory } @@ -69,11 +69,11 @@ type ( ) // NewAzureMachinePoolMachineController creates a new AzureMachinePoolMachineController to handle updates to Azure Machine Pool Machines. -func NewAzureMachinePoolMachineController(c client.Client, recorder record.EventRecorder, reconcileTimeout time.Duration, watchFilterValue string) *AzureMachinePoolMachineController { +func NewAzureMachinePoolMachineController(c client.Client, recorder record.EventRecorder, timeouts reconciler.Timeouts, watchFilterValue string) *AzureMachinePoolMachineController { return &AzureMachinePoolMachineController{ Client: c, Recorder: recorder, - ReconcileTimeout: reconcileTimeout, + Timeouts: timeouts, WatchFilterValue: watchFilterValue, reconcilerFactory: newAzureMachinePoolMachineReconciler, } @@ -146,7 +146,7 @@ func (ampmr *AzureMachinePoolMachineController) Reconcile(ctx context.Context, r logger = logger.WithValues("namespace", req.Namespace, "azureMachinePoolMachine", req.Name) - ctx, cancel := context.WithTimeout(ctx, reconciler.DefaultedLoopTimeout(ampmr.ReconcileTimeout)) + ctx, cancel := context.WithTimeout(ctx, ampmr.Timeouts.DefaultedLoopTimeout()) defer cancel() azureMachine := &infrav1exp.AzureMachinePoolMachine{} @@ -174,7 +174,7 @@ func (ampmr *AzureMachinePoolMachineController) Reconcile(ctx context.Context, r return ctrl.Result{}, nil } - clusterScope, err := infracontroller.GetClusterScoper(ctx, logger, ampmr.Client, cluster) + clusterScope, err := infracontroller.GetClusterScoper(ctx, logger, ampmr.Client, cluster, ampmr.Timeouts) if err != nil { return reconcile.Result{}, errors.Wrapf(err, "failed to create cluster scope for cluster %s/%s", cluster.Namespace, cluster.Name) } diff --git a/exp/controllers/azuremachinepoolmachine_controller_test.go b/exp/controllers/azuremachinepoolmachine_controller_test.go index 7c6d5e5e3ab..78ca2696782 100644 --- a/exp/controllers/azuremachinepoolmachine_controller_test.go +++ b/exp/controllers/azuremachinepoolmachine_controller_test.go @@ -36,6 +36,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/azure/scope" infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta1" gomock2 "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" + reconcilerutils "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" @@ -104,7 +105,7 @@ func TestAzureMachinePoolMachineReconciler_Reconcile(t *testing.T) { defer mockCtrl.Finish() c.Setup(cb, reconciler.EXPECT()) - controller := NewAzureMachinePoolMachineController(cb.Build(), nil, 30*time.Second, "foo") + controller := NewAzureMachinePoolMachineController(cb.Build(), nil, reconcilerutils.Timeouts{}, "foo") controller.reconcilerFactory = func(_ *scope.MachinePoolMachineScope) (azure.Reconciler, error) { return reconciler, nil } diff --git a/exp/controllers/suite_test.go b/exp/controllers/suite_test.go index 0752b1e2e09..6b43bc2ad87 100644 --- a/exp/controllers/suite_test.go +++ b/exp/controllers/suite_test.go @@ -54,10 +54,10 @@ var _ = BeforeSuite(func() { ctx = log.IntoContext(ctx, logr.New(testEnv.Log)) Expect(NewAzureMachinePoolReconciler(testEnv, testEnv.GetEventRecorderFor("azuremachinepool-reconciler"), - reconciler.DefaultLoopTimeout, "").SetupWithManager(ctx, testEnv.Manager, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) + reconciler.Timeouts{}, "").SetupWithManager(ctx, testEnv.Manager, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) Expect(NewAzureMachinePoolMachineController(testEnv, testEnv.GetEventRecorderFor("azuremachinepoolmachine-reconciler"), - reconciler.DefaultLoopTimeout, "").SetupWithManager(ctx, testEnv.Manager, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) + reconciler.Timeouts{}, "").SetupWithManager(ctx, testEnv.Manager, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: 1}})).To(Succeed()) // +kubebuilder:scaffold:scheme diff --git a/main.go b/main.go index ed8b6d7b7c9..24d1b0593fc 100644 --- a/main.go +++ b/main.go @@ -116,7 +116,7 @@ var ( webhookPort int webhookCertDir string diagnosticsOptions = DiagnosticsOptions{} - reconcileTimeout time.Duration + timeouts reconciler.Timeouts enableTracing bool ) @@ -227,10 +227,28 @@ func InitFlags(fs *pflag.FlagSet) { fs.StringVar(&webhookCertDir, "webhook-cert-dir", "/tmp/k8s-webhook-server/serving-certs/", "The webhook certificate directory, where the server should find the TLS certificate and key.") - fs.DurationVar(&reconcileTimeout, + fs.DurationVar(&timeouts.Loop, "reconcile-timeout", reconciler.DefaultLoopTimeout, - "The maximum duration a reconcile loop can run (e.g. 90m)", + "The maximum duration a reconcile loop can run (e.g. 10m)", + ) + + fs.DurationVar(&timeouts.AzureServiceReconcile, + "service-reconcile-timeout", + reconciler.DefaultAzureServiceReconcileTimeout, + "The maximum duration each Azure service reconcile can run (e.g. 90m)", + ) + + fs.DurationVar(&timeouts.AzureCall, + "api-call-timeout", + reconciler.DefaultAzureCallTimeout, + "The maximum duration CAPZ will wait for each Azure API request before it is considered long running and performed async (e.g. 10s)", + ) + + fs.DurationVar(&timeouts.Requeue, + "reconciler-requeue", + reconciler.DefaultReconcilerRequeue, + "The duration to wait before retrying after a transient reconcile error occurs (e.g. 15s)", ) fs.BoolVar( @@ -348,7 +366,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { } if err := controllers.NewAzureMachineReconciler(mgr.GetClient(), mgr.GetEventRecorderFor("azuremachine-reconciler"), - reconcileTimeout, + timeouts, watchFilterValue, ).SetupWithManager(ctx, mgr, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: azureMachineConcurrency}, Cache: machineCache}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureMachine") @@ -362,7 +380,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { if err := controllers.NewAzureClusterReconciler( mgr.GetClient(), mgr.GetEventRecorderFor("azurecluster-reconciler"), - reconcileTimeout, + timeouts, watchFilterValue, ).SetupWithManager(ctx, mgr, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}, Cache: clusterCache}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureCluster") @@ -372,7 +390,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { if err := (&controllers.AzureJSONTemplateReconciler{ Client: mgr.GetClient(), Recorder: mgr.GetEventRecorderFor("azurejsontemplate-reconciler"), - ReconcileTimeout: reconcileTimeout, + Timeouts: timeouts, WatchFilterValue: watchFilterValue, }).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureMachineConcurrency}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureJSONTemplate") @@ -382,7 +400,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { if err := (&controllers.AzureJSONMachineReconciler{ Client: mgr.GetClient(), Recorder: mgr.GetEventRecorderFor("azurejsonmachine-reconciler"), - ReconcileTimeout: reconcileTimeout, + Timeouts: timeouts, WatchFilterValue: watchFilterValue, }).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureMachineConcurrency}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureJSONMachine") @@ -392,7 +410,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { if err := (&controllers.AzureIdentityReconciler{ Client: mgr.GetClient(), Recorder: mgr.GetEventRecorderFor("azureidentity-reconciler"), - ReconcileTimeout: reconcileTimeout, + Timeouts: timeouts, WatchFilterValue: watchFilterValue, }).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureIdentity") @@ -402,7 +420,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { if err := (&controllers.ASOSecretReconciler{ Client: mgr.GetClient(), Recorder: mgr.GetEventRecorderFor("asosecret-reconciler"), - ReconcileTimeout: reconcileTimeout, + Timeouts: timeouts, WatchFilterValue: watchFilterValue, }).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "ASOSecret") @@ -420,7 +438,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { if err := infrav1controllersexp.NewAzureMachinePoolReconciler( mgr.GetClient(), mgr.GetEventRecorderFor("azuremachinepool-reconciler"), - reconcileTimeout, + timeouts, watchFilterValue, ).SetupWithManager(ctx, mgr, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: azureMachinePoolConcurrency}, Cache: mpCache}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureMachinePool") @@ -435,7 +453,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { if err := infrav1controllersexp.NewAzureMachinePoolMachineController( mgr.GetClient(), mgr.GetEventRecorderFor("azuremachinepoolmachine-reconciler"), - reconcileTimeout, + timeouts, watchFilterValue, ).SetupWithManager(ctx, mgr, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: azureMachinePoolMachineConcurrency}, Cache: mpmCache}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureMachinePoolMachine") @@ -445,7 +463,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { if err := (&controllers.AzureJSONMachinePoolReconciler{ Client: mgr.GetClient(), Recorder: mgr.GetEventRecorderFor("azurejsonmachinepool-reconciler"), - ReconcileTimeout: reconcileTimeout, + Timeouts: timeouts, WatchFilterValue: watchFilterValue, }).SetupWithManager(ctx, mgr, controller.Options{MaxConcurrentReconciles: azureMachinePoolConcurrency}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureJSONMachinePool") @@ -460,7 +478,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { if err := controllers.NewAzureManagedMachinePoolReconciler( mgr.GetClient(), mgr.GetEventRecorderFor("azuremanagedmachinepoolmachine-reconciler"), - reconcileTimeout, + timeouts, watchFilterValue, ).SetupWithManager(ctx, mgr, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: azureMachinePoolConcurrency}, Cache: mmpmCache}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureManagedMachinePool") @@ -475,7 +493,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { if err := (&controllers.AzureManagedClusterReconciler{ Client: mgr.GetClient(), Recorder: mgr.GetEventRecorderFor("azuremanagedcluster-reconciler"), - ReconcileTimeout: reconcileTimeout, + Timeouts: timeouts, WatchFilterValue: watchFilterValue, }).SetupWithManager(ctx, mgr, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}, Cache: mcCache}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureManagedCluster") @@ -490,7 +508,7 @@ func registerControllers(ctx context.Context, mgr manager.Manager) { if err := (&controllers.AzureManagedControlPlaneReconciler{ Client: mgr.GetClient(), Recorder: mgr.GetEventRecorderFor("azuremanagedcontrolplane-reconciler"), - ReconcileTimeout: reconcileTimeout, + Timeouts: timeouts, WatchFilterValue: watchFilterValue, }).SetupWithManager(ctx, mgr, controllers.Options{Options: controller.Options{MaxConcurrentReconciles: azureClusterConcurrency}, Cache: mcpCache}); err != nil { setupLog.Error(err, "unable to create controller", "controller", "AzureManagedControlPlane") diff --git a/util/reconciler/defaults.go b/util/reconciler/defaults.go index d6986619e82..faf16712a11 100644 --- a/util/reconciler/defaults.go +++ b/util/reconciler/defaults.go @@ -27,8 +27,6 @@ const ( DefaultMappingTimeout = 60 * time.Second // DefaultAzureServiceReconcileTimeout is the default timeout for an Azure service reconcile. DefaultAzureServiceReconcileTimeout = 12 * time.Second - // DefaultAKSServiceReconcileTimeout is the default timeout for an AKS service reconcile. - DefaultAKSServiceReconcileTimeout = 30 * time.Second // DefaultAzureCallTimeout is the default timeout for an Azure request after which an Azure operation is considered long running. DefaultAzureCallTimeout = 2 * time.Second // DefaultReconcilerRequeue is the default value for the reconcile retry. @@ -37,11 +35,50 @@ const ( DefaultHTTP429RetryAfter = 1 * time.Minute ) +// Timeouts defines the timeouts for a reconciler. +type Timeouts struct { + // Loop is the timeout for a reconcile loop (defaulted to the max ARM template duration). + Loop time.Duration + // AzureServiceReconcile is the timeout for an Azure service reconcile. + AzureServiceReconcile time.Duration + // AzureCall is the timeout for an Azure request after which an Azure operation is considered long-running. + AzureCall time.Duration + // Requeue is the value for the reconcile retry. + Requeue time.Duration +} + +// DefaultedAzureCallTimeout will default the timeout if it is zero-valued. +func (t Timeouts) DefaultedAzureCallTimeout() time.Duration { + if t.AzureCall <= 0 { + return DefaultAzureCallTimeout + } + + return t.AzureCall +} + +// DefaultedAzureServiceReconcileTimeout will default the timeout if it is zero-valued. +func (t Timeouts) DefaultedAzureServiceReconcileTimeout() time.Duration { + if t.AzureServiceReconcile <= 0 { + return DefaultAzureServiceReconcileTimeout + } + + return t.AzureServiceReconcile +} + +// DefaultedReconcilerRequeue will default the timeout if it is zero-valued. +func (t Timeouts) DefaultedReconcilerRequeue() time.Duration { + if t.Requeue <= 0 { + return DefaultReconcilerRequeue + } + + return t.Requeue +} + // DefaultedLoopTimeout will default the timeout if it is zero-valued. -func DefaultedLoopTimeout(timeout time.Duration) time.Duration { - if timeout <= 0 { +func (t Timeouts) DefaultedLoopTimeout() time.Duration { + if t.Loop <= 0 { return DefaultLoopTimeout } - return timeout + return t.Loop } diff --git a/util/reconciler/defaults_test.go b/util/reconciler/defaults_test.go index 30198ce680b..2e98931cfbe 100644 --- a/util/reconciler/defaults_test.go +++ b/util/reconciler/defaults_test.go @@ -24,7 +24,7 @@ import ( "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" ) -func TestDefaultedTimeout(t *testing.T) { +func TestDefaultedLoopTimeout(t *testing.T) { cases := []struct { Name string Subject time.Duration @@ -52,7 +52,118 @@ func TestDefaultedTimeout(t *testing.T) { t.Run(c.Name, func(t *testing.T) { t.Parallel() g := gomega.NewWithT(t) - g.Expect(reconciler.DefaultedLoopTimeout(c.Subject)).To(gomega.Equal(c.Expected)) + timeouts := reconciler.Timeouts{ + Loop: c.Subject, + } + g.Expect(timeouts.DefaultedLoopTimeout()).To(gomega.Equal(c.Expected)) + }) + } +} + +func TestDefaultedReconcilerRequeue(t *testing.T) { + cases := []struct { + Name string + Subject time.Duration + Expected time.Duration + }{ + { + Name: "WithZeroValueDefaults", + Subject: time.Duration(0), + Expected: reconciler.DefaultReconcilerRequeue, + }, + { + Name: "WithRealValue", + Subject: 2 * time.Hour, + Expected: 2 * time.Hour, + }, + { + Name: "WithNegativeValue", + Subject: time.Duration(-2), + Expected: reconciler.DefaultReconcilerRequeue, + }, + } + + for _, c := range cases { + c := c + t.Run(c.Name, func(t *testing.T) { + t.Parallel() + g := gomega.NewWithT(t) + timeouts := reconciler.Timeouts{ + Requeue: c.Subject, + } + g.Expect(timeouts.DefaultedReconcilerRequeue()).To(gomega.Equal(c.Expected)) + }) + } +} + +func TestDefaultedAzureCallTimeout(t *testing.T) { + cases := []struct { + Name string + Subject time.Duration + Expected time.Duration + }{ + { + Name: "WithZeroValueDefaults", + Subject: time.Duration(0), + Expected: reconciler.DefaultAzureCallTimeout, + }, + { + Name: "WithRealValue", + Subject: 2 * time.Hour, + Expected: 2 * time.Hour, + }, + { + Name: "WithNegativeValue", + Subject: time.Duration(-2), + Expected: reconciler.DefaultAzureCallTimeout, + }, + } + + for _, c := range cases { + c := c + t.Run(c.Name, func(t *testing.T) { + t.Parallel() + g := gomega.NewWithT(t) + timeouts := reconciler.Timeouts{ + AzureCall: c.Subject, + } + g.Expect(timeouts.DefaultedAzureCallTimeout()).To(gomega.Equal(c.Expected)) + }) + } +} + +func TestDefaultedAzureServiceReconcileTimeout(t *testing.T) { + cases := []struct { + Name string + Subject time.Duration + Expected time.Duration + }{ + { + Name: "WithZeroValueDefaults", + Subject: time.Duration(0), + Expected: reconciler.DefaultAzureServiceReconcileTimeout, + }, + { + Name: "WithRealValue", + Subject: 2 * time.Hour, + Expected: 2 * time.Hour, + }, + { + Name: "WithNegativeValue", + Subject: time.Duration(-2), + Expected: reconciler.DefaultAzureServiceReconcileTimeout, + }, + } + + for _, c := range cases { + c := c + t.Run(c.Name, func(t *testing.T) { + t.Parallel() + g := gomega.NewWithT(t) + timeouts := reconciler.Timeouts{ + AzureServiceReconcile: c.Subject, + } + g.Expect(timeouts.DefaultedAzureServiceReconcileTimeout()).To(gomega.Equal(c.Expected)) }) } }