diff --git a/pkg/cloudprovider/providers/azure/azure.go b/pkg/cloudprovider/providers/azure/azure.go index 170091cace9..5435036e6b8 100644 --- a/pkg/cloudprovider/providers/azure/azure.go +++ b/pkg/cloudprovider/providers/azure/azure.go @@ -176,20 +176,48 @@ type VirtualMachineScaleSetVMsClient interface { ListNextResults(lastResults compute.VirtualMachineScaleSetVMListResult) (result compute.VirtualMachineScaleSetVMListResult, err error) } +// RoutesClient defines needed functions for azure network.RoutesClient +type RoutesClient interface { + CreateOrUpdate(resourceGroupName string, routeTableName string, routeName string, routeParameters network.Route, cancel <-chan struct{}) (<-chan network.Route, <-chan error) + Delete(resourceGroupName string, routeTableName string, routeName string, cancel <-chan struct{}) (<-chan autorest.Response, <-chan error) +} + +// RouteTablesClient defines needed functions for azure network.RouteTablesClient +type RouteTablesClient interface { + CreateOrUpdate(resourceGroupName string, routeTableName string, parameters network.RouteTable, cancel <-chan struct{}) (<-chan network.RouteTable, <-chan error) + Get(resourceGroupName string, routeTableName string, expand string) (result network.RouteTable, err error) +} + +// StorageAccountClient defines needed functions for azure storage.AccountsClient +type StorageAccountClient interface { + Create(resourceGroupName string, accountName string, parameters storage.AccountCreateParameters, cancel <-chan struct{}) (<-chan storage.Account, <-chan error) + Delete(resourceGroupName string, accountName string) (result autorest.Response, err error) + ListKeys(resourceGroupName string, accountName string) (result storage.AccountListKeysResult, err error) + ListByResourceGroup(resourceGroupName string) (result storage.AccountListResult, err error) + GetProperties(resourceGroupName string, accountName string) (result storage.Account, err error) +} + +// DisksClient defines needed functions for azure disk.DisksClient +type DisksClient interface { + CreateOrUpdate(resourceGroupName string, diskName string, diskParameter disk.Model, cancel <-chan struct{}) (<-chan disk.Model, <-chan error) + Delete(resourceGroupName string, diskName string, cancel <-chan struct{}) (<-chan disk.OperationStatusResponse, <-chan error) + Get(resourceGroupName string, diskName string) (result disk.Model, err error) +} + // Cloud holds the config and clients type Cloud struct { Config Environment azure.Environment - RoutesClient network.RoutesClient + RoutesClient RoutesClient SubnetsClient SubnetsClient InterfacesClient InterfacesClient - RouteTablesClient network.RouteTablesClient + RouteTablesClient RouteTablesClient LoadBalancerClient LoadBalancersClient PublicIPAddressesClient PublicIPAddressesClient SecurityGroupsClient SecurityGroupsClient VirtualMachinesClient VirtualMachinesClient - StorageAccountClient storage.AccountsClient - DisksClient disk.DisksClient + StorageAccountClient StorageAccountClient + DisksClient DisksClient operationPollRateLimiter flowcontrol.RateLimiter resourceRequestBackoff wait.Backoff vmSet VMSet @@ -236,17 +264,19 @@ func NewCloud(configReader io.Reader) (cloudprovider.Interface, error) { configureUserAgent(&subnetsClient.Client) az.SubnetsClient = subnetsClient - az.RouteTablesClient = network.NewRouteTablesClient(az.SubscriptionID) - az.RouteTablesClient.BaseURI = az.Environment.ResourceManagerEndpoint - az.RouteTablesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - az.RouteTablesClient.PollingDelay = 5 * time.Second - configureUserAgent(&az.RouteTablesClient.Client) + routeTablesClient := network.NewRouteTablesClient(az.SubscriptionID) + routeTablesClient.BaseURI = az.Environment.ResourceManagerEndpoint + routeTablesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) + routeTablesClient.PollingDelay = 5 * time.Second + configureUserAgent(&routeTablesClient.Client) + az.RouteTablesClient = routeTablesClient - az.RoutesClient = network.NewRoutesClient(az.SubscriptionID) - az.RoutesClient.BaseURI = az.Environment.ResourceManagerEndpoint - az.RoutesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - az.RoutesClient.PollingDelay = 5 * time.Second - configureUserAgent(&az.RoutesClient.Client) + routesClient := network.NewRoutesClient(az.SubscriptionID) + routesClient.BaseURI = az.Environment.ResourceManagerEndpoint + routesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) + routesClient.PollingDelay = 5 * time.Second + configureUserAgent(&routesClient.Client) + az.RoutesClient = routesClient interfacesClient := network.NewInterfacesClient(az.SubscriptionID) interfacesClient.BaseURI = az.Environment.ResourceManagerEndpoint @@ -297,13 +327,19 @@ func NewCloud(configReader io.Reader) (cloudprovider.Interface, error) { configureUserAgent(&virtualMachineScaleSetsClient.Client) az.VirtualMachineScaleSetsClient = virtualMachineScaleSetsClient - az.StorageAccountClient = storage.NewAccountsClientWithBaseURI(az.Environment.ResourceManagerEndpoint, az.SubscriptionID) - az.StorageAccountClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - configureUserAgent(&az.StorageAccountClient.Client) + storageAccountClient := storage.NewAccountsClientWithBaseURI(az.Environment.ResourceManagerEndpoint, az.SubscriptionID) + storageAccountClient.BaseURI = az.Environment.ResourceManagerEndpoint + storageAccountClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) + storageAccountClient.PollingDelay = 5 * time.Second + configureUserAgent(&storageAccountClient.Client) + az.StorageAccountClient = storageAccountClient - az.DisksClient = disk.NewDisksClientWithBaseURI(az.Environment.ResourceManagerEndpoint, az.SubscriptionID) - az.DisksClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) - configureUserAgent(&az.DisksClient.Client) + disksClient := disk.NewDisksClientWithBaseURI(az.Environment.ResourceManagerEndpoint, az.SubscriptionID) + disksClient.BaseURI = az.Environment.ResourceManagerEndpoint + disksClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) + disksClient.PollingDelay = 5 * time.Second + configureUserAgent(&disksClient.Client) + az.DisksClient = disksClient // Conditionally configure rate limits if az.CloudProviderRateLimit { diff --git a/pkg/cloudprovider/providers/azure/azure_fakes.go b/pkg/cloudprovider/providers/azure/azure_fakes.go index 18e7281fa43..dd66d509f17 100644 --- a/pkg/cloudprovider/providers/azure/azure_fakes.go +++ b/pkg/cloudprovider/providers/azure/azure_fakes.go @@ -24,11 +24,12 @@ import ( "sync" "time" - "github.com/Azure/go-autorest/autorest/to" - "github.com/Azure/azure-sdk-for-go/arm/compute" + "github.com/Azure/azure-sdk-for-go/arm/disk" "github.com/Azure/azure-sdk-for-go/arm/network" + "github.com/Azure/azure-sdk-for-go/arm/storage" "github.com/Azure/go-autorest/autorest" + "github.com/Azure/go-autorest/autorest/to" ) type fakeAzureLBClient struct { @@ -785,3 +786,319 @@ func (fVMSSC fakeVirtualMachineScaleSetsClient) UpdateInstances(resourceGroupNam err = nil return resultChan, errChan } + +type fakeRoutesClient struct { + mutex *sync.Mutex + FakeStore map[string]map[string]network.Route +} + +func newFakeRoutesClient() fakeRoutesClient { + fRC := fakeRoutesClient{} + fRC.FakeStore = make(map[string]map[string]network.Route) + fRC.mutex = &sync.Mutex{} + return fRC +} + +func (fRC fakeRoutesClient) CreateOrUpdate(resourceGroupName string, routeTableName string, routeName string, routeParameters network.Route, cancel <-chan struct{}) (<-chan network.Route, <-chan error) { + fRC.mutex.Lock() + defer fRC.mutex.Unlock() + + resultChan := make(chan network.Route, 1) + errChan := make(chan error, 1) + var result network.Route + var err error + defer func() { + resultChan <- result + errChan <- err + close(resultChan) + close(errChan) + }() + + if _, ok := fRC.FakeStore[routeTableName]; !ok { + fRC.FakeStore[routeTableName] = make(map[string]network.Route) + } + fRC.FakeStore[routeTableName][routeName] = routeParameters + result = fRC.FakeStore[routeTableName][routeName] + result.Response.Response = &http.Response{ + StatusCode: http.StatusOK, + } + err = nil + return resultChan, errChan +} + +func (fRC fakeRoutesClient) Delete(resourceGroupName string, routeTableName string, routeName string, cancel <-chan struct{}) (<-chan autorest.Response, <-chan error) { + fRC.mutex.Lock() + defer fRC.mutex.Unlock() + + respChan := make(chan autorest.Response, 1) + errChan := make(chan error, 1) + var resp autorest.Response + var err error + defer func() { + respChan <- resp + errChan <- err + close(respChan) + close(errChan) + }() + if routes, ok := fRC.FakeStore[routeTableName]; ok { + if _, ok := routes[routeName]; ok { + delete(routes, routeName) + resp.Response = &http.Response{ + StatusCode: http.StatusAccepted, + } + + err = nil + return respChan, errChan + } + } + resp.Response = &http.Response{ + StatusCode: http.StatusNotFound, + } + err = autorest.DetailedError{ + StatusCode: http.StatusNotFound, + Message: "Not such Route", + } + return respChan, errChan +} + +type fakeRouteTablesClient struct { + mutex *sync.Mutex + FakeStore map[string]map[string]network.RouteTable +} + +func newFakeRouteTablesClient() fakeRouteTablesClient { + fRTC := fakeRouteTablesClient{} + fRTC.FakeStore = make(map[string]map[string]network.RouteTable) + fRTC.mutex = &sync.Mutex{} + return fRTC +} + +func (fRTC fakeRouteTablesClient) CreateOrUpdate(resourceGroupName string, routeTableName string, parameters network.RouteTable, cancel <-chan struct{}) (<-chan network.RouteTable, <-chan error) { + fRTC.mutex.Lock() + defer fRTC.mutex.Unlock() + + resultChan := make(chan network.RouteTable, 1) + errChan := make(chan error, 1) + var result network.RouteTable + var err error + defer func() { + resultChan <- result + errChan <- err + close(resultChan) + close(errChan) + }() + + if _, ok := fRTC.FakeStore[resourceGroupName]; !ok { + fRTC.FakeStore[resourceGroupName] = make(map[string]network.RouteTable) + } + fRTC.FakeStore[resourceGroupName][routeTableName] = parameters + result = fRTC.FakeStore[resourceGroupName][routeTableName] + result.Response.Response = &http.Response{ + StatusCode: http.StatusOK, + } + err = nil + return resultChan, errChan +} + +func (fRTC fakeRouteTablesClient) Get(resourceGroupName string, routeTableName string, expand string) (result network.RouteTable, err error) { + fRTC.mutex.Lock() + defer fRTC.mutex.Unlock() + if _, ok := fRTC.FakeStore[resourceGroupName]; ok { + if entity, ok := fRTC.FakeStore[resourceGroupName][routeTableName]; ok { + return entity, nil + } + } + return result, autorest.DetailedError{ + StatusCode: http.StatusNotFound, + Message: "Not such RouteTable", + } +} + +type fakeStorageAccountClient struct { + mutex *sync.Mutex + FakeStore map[string]map[string]storage.Account +} + +func newFakeStorageAccountClient() fakeStorageAccountClient { + fSAC := fakeStorageAccountClient{} + fSAC.FakeStore = make(map[string]map[string]storage.Account) + fSAC.mutex = &sync.Mutex{} + return fSAC +} + +func (fSAC fakeStorageAccountClient) Create(resourceGroupName string, accountName string, parameters storage.AccountCreateParameters, cancel <-chan struct{}) (<-chan storage.Account, <-chan error) { + fSAC.mutex.Lock() + defer fSAC.mutex.Unlock() + + resultChan := make(chan storage.Account, 1) + errChan := make(chan error, 1) + var result storage.Account + var err error + defer func() { + resultChan <- result + errChan <- err + close(resultChan) + close(errChan) + }() + + if _, ok := fSAC.FakeStore[resourceGroupName]; !ok { + fSAC.FakeStore[resourceGroupName] = make(map[string]storage.Account) + } + fSAC.FakeStore[resourceGroupName][accountName] = storage.Account{ + Name: &accountName, + Sku: parameters.Sku, + Kind: parameters.Kind, + Location: parameters.Location, + Identity: parameters.Identity, + Tags: parameters.Tags, + AccountProperties: &storage.AccountProperties{}, + } + result = fSAC.FakeStore[resourceGroupName][accountName] + result.Response.Response = &http.Response{ + StatusCode: http.StatusOK, + } + err = nil + return resultChan, errChan +} + +func (fSAC fakeStorageAccountClient) Delete(resourceGroupName string, accountName string) (result autorest.Response, err error) { + fSAC.mutex.Lock() + defer fSAC.mutex.Unlock() + + if rgAccounts, ok := fSAC.FakeStore[resourceGroupName]; ok { + if _, ok := rgAccounts[accountName]; ok { + delete(rgAccounts, accountName) + result.Response = &http.Response{ + StatusCode: http.StatusAccepted, + } + return result, nil + } + } + + result.Response = &http.Response{ + StatusCode: http.StatusNotFound, + } + err = autorest.DetailedError{ + StatusCode: http.StatusNotFound, + Message: "Not such StorageAccount", + } + return result, err +} + +func (fSAC fakeStorageAccountClient) ListKeys(resourceGroupName string, accountName string) (result storage.AccountListKeysResult, err error) { + return storage.AccountListKeysResult{}, nil +} + +func (fSAC fakeStorageAccountClient) ListByResourceGroup(resourceGroupName string) (result storage.AccountListResult, err error) { + return storage.AccountListResult{}, nil +} + +func (fSAC fakeStorageAccountClient) GetProperties(resourceGroupName string, accountName string) (result storage.Account, err error) { + fSAC.mutex.Lock() + defer fSAC.mutex.Unlock() + + if _, ok := fSAC.FakeStore[resourceGroupName]; ok { + if entity, ok := fSAC.FakeStore[resourceGroupName][accountName]; ok { + return entity, nil + } + } + + return result, autorest.DetailedError{ + StatusCode: http.StatusNotFound, + Message: "Not such StorageAccount", + } +} + +type fakeDisksClient struct { + mutex *sync.Mutex + FakeStore map[string]map[string]disk.Model +} + +func newFakeDisksClient() fakeDisksClient { + fDC := fakeDisksClient{} + fDC.FakeStore = make(map[string]map[string]disk.Model) + fDC.mutex = &sync.Mutex{} + return fDC +} + +func (fDC fakeDisksClient) CreateOrUpdate(resourceGroupName string, diskName string, diskParameter disk.Model, cancel <-chan struct{}) (<-chan disk.Model, <-chan error) { + fDC.mutex.Lock() + defer fDC.mutex.Unlock() + + resultChan := make(chan disk.Model, 1) + errChan := make(chan error, 1) + var result disk.Model + var err error + defer func() { + resultChan <- result + errChan <- err + close(resultChan) + close(errChan) + }() + + if _, ok := fDC.FakeStore[resourceGroupName]; !ok { + fDC.FakeStore[resourceGroupName] = make(map[string]disk.Model) + } + fDC.FakeStore[resourceGroupName][diskName] = diskParameter + result = fDC.FakeStore[resourceGroupName][diskName] + result.Response.Response = &http.Response{ + StatusCode: http.StatusOK, + } + err = nil + return resultChan, errChan +} + +func (fDC fakeDisksClient) Delete(resourceGroupName string, diskName string, cancel <-chan struct{}) (<-chan disk.OperationStatusResponse, <-chan error) { + fDC.mutex.Lock() + defer fDC.mutex.Unlock() + + respChan := make(chan disk.OperationStatusResponse, 1) + errChan := make(chan error, 1) + var resp disk.OperationStatusResponse + var err error + defer func() { + respChan <- resp + errChan <- err + close(respChan) + close(errChan) + }() + if rgDisks, ok := fDC.FakeStore[resourceGroupName]; ok { + if _, ok := rgDisks[diskName]; ok { + delete(rgDisks, diskName) + resp.Response = autorest.Response{ + Response: &http.Response{ + StatusCode: http.StatusAccepted, + }, + } + + err = nil + return respChan, errChan + } + } + resp.Response = autorest.Response{ + Response: &http.Response{ + StatusCode: http.StatusNotFound, + }, + } + err = autorest.DetailedError{ + StatusCode: http.StatusNotFound, + Message: "Not such Disk", + } + return respChan, errChan +} + +func (fDC fakeDisksClient) Get(resourceGroupName string, diskName string) (result disk.Model, err error) { + fDC.mutex.Lock() + defer fDC.mutex.Unlock() + + if _, ok := fDC.FakeStore[resourceGroupName]; ok { + if entity, ok := fDC.FakeStore[resourceGroupName][diskName]; ok { + return entity, nil + } + } + + return result, autorest.DetailedError{ + StatusCode: http.StatusNotFound, + Message: "Not such Disk", + } +}