pkg/armhelpers/azureclient.go (146 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. package armhelpers import ( "context" "fmt" "net/http" "strings" "time" "github.com/Azure/aks-engine-azurestack/pkg/helpers/to" "github.com/Azure/aks-engine-azurestack/pkg/kubernetes" authorization "github.com/Azure/azure-sdk-for-go/profile/p20200901/resourcemanager/authorization/armauthorization" compute "github.com/Azure/azure-sdk-for-go/profile/p20200901/resourcemanager/compute/armcompute" network "github.com/Azure/azure-sdk-for-go/profile/p20200901/resourcemanager/network/armnetwork" resources "github.com/Azure/azure-sdk-for-go/profile/p20200901/resourcemanager/resources/armresources" storage "github.com/Azure/azure-sdk-for-go/profile/p20200901/resourcemanager/storage/armstorage" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob" "github.com/pkg/errors" log "github.com/sirupsen/logrus" ) var ( // RequiredResourceProviders is the list of Azure Resource Providers needed for AKS Engine to function RequiredResourceProviders = []string{"Microsoft.Compute", "Microsoft.Storage", "Microsoft.Network"} ) // AzureClient implements the `AKSEngineClient` interface. // This client is backed by real Azure clients talking to an ARM endpoint. type AzureClient struct { acceptLanguageHeader http.Header authorizationClient *authorization.RoleAssignmentsClient deploymentsClient *resources.DeploymentsClient deploymentOperationsClient *resources.DeploymentOperationsClient storageAccountsClient *storage.AccountsClient storageBlobClientFactory func(key, blobURI string) (*azblob.Client, error) interfacesClient *network.InterfacesClient groupsClient *resources.ResourceGroupsClient providersClient *resources.ProvidersClient virtualMachinesClient *compute.VirtualMachinesClient disksClient *compute.DisksClient availabilitySetsClient *compute.AvailabilitySetsClient virtualMachineImagesClient *compute.VirtualMachineImagesClient } // GetKubernetesClient returns a KubernetesClient hooked up to the api server at the apiserverURL. func (az *AzureClient) GetKubernetesClient(apiserverURL, kubeConfig string, interval, timeout time.Duration) (kubernetes.Client, error) { return kubernetes.NewClient(apiserverURL, kubeConfig, interval, timeout) } // NewAzureClientWithClientSecret returns an AzureClient via client_id and client_secret func NewAzureClient(subscriptionID string, credential azcore.TokenCredential, options *arm.ClientOptions) (*AzureClient, error) { var err error c := &AzureClient{} c.authorizationClient, err = authorization.NewRoleAssignmentsClient(subscriptionID, credential, options) if err != nil { return nil, errors.Wrap(err, "failed to create role assignments client") } c.deploymentsClient, err = resources.NewDeploymentsClient(subscriptionID, credential, options) if err != nil { return nil, errors.Wrap(err, "failed to create deployments client") } c.deploymentOperationsClient, err = resources.NewDeploymentOperationsClient(subscriptionID, credential, options) if err != nil { return nil, errors.Wrap(err, "failed to create deployment operations client") } c.storageAccountsClient, err = storage.NewAccountsClient(subscriptionID, credential, options) if err != nil { return nil, errors.Wrap(err, "failed to create storage accounts client") } c.interfacesClient, err = network.NewInterfacesClient(subscriptionID, credential, options) if err != nil { return nil, errors.Wrap(err, "failed to create network interfaces client") } c.groupsClient, err = resources.NewResourceGroupsClient(subscriptionID, credential, options) if err != nil { return nil, errors.Wrap(err, "failed to create resource groups client") } c.providersClient, err = resources.NewProvidersClient(subscriptionID, credential, options) if err != nil { return nil, errors.Wrap(err, "failed to create providers client") } c.virtualMachinesClient, err = compute.NewVirtualMachinesClient(subscriptionID, credential, options) if err != nil { return nil, errors.Wrap(err, "failed to create virtual machines client") } c.disksClient, err = compute.NewDisksClient(subscriptionID, credential, options) if err != nil { return nil, errors.Wrap(err, "failed to create disks client") } c.availabilitySetsClient, err = compute.NewAvailabilitySetsClient(subscriptionID, credential, options) if err != nil { return nil, errors.Wrap(err, "failed to create availability sets client") } c.virtualMachineImagesClient, err = compute.NewVirtualMachineImagesClient(subscriptionID, credential, options) if err != nil { return nil, errors.Wrap(err, "failed to create virtual machine images client") } c.storageBlobClientFactory = keysBlobClient() return c, nil } // EnsureProvidersRegistered checks if the AzureClient is registered to required resource providers and, if not, register subscription to providers func (az *AzureClient) EnsureProvidersRegistered(subscriptionID string) error { ctx, cancel := context.WithTimeout(context.Background(), DefaultARMOperationTimeout) ctx = policy.WithHTTPHeader(ctx, az.acceptLanguageHeader) defer cancel() pager := az.providersClient.NewListPager(nil) providers := []*resources.Provider{} for pager.More() { page, err := pager.NextPage(ctx) if err != nil { return errors.Errorf("Error listing registered providers for subscription %s", subscriptionID) } providers = append(providers, page.Value...) } m := make(map[string]bool) for _, provider := range providers { m[strings.ToLower(to.String(provider.Namespace))] = to.String(provider.RegistrationState) == "Registered" } for _, provider := range RequiredResourceProviders { registered, ok := m[strings.ToLower(provider)] if !ok { return errors.Errorf("Unknown resource provider %q", provider) } if registered { log.Debugf("Already registered for %q", provider) } else { log.Infof("Registering subscription to resource provider. provider=%q subscription=%q", provider, subscriptionID) if _, err := az.providersClient.Register(ctx, provider, nil); err != nil { return err } } } return nil } func keysBlobClient() func(key, blobURI string) (*azblob.Client, error) { return func(key, blobURI string) (*azblob.Client, error) { parts, err := azblob.ParseURL(blobURI) if err != nil { return nil, err } name := strings.Split(parts.Host, ".")[0] sas, err := azblob.NewSharedKeyCredential(name, key) if err != nil { return nil, err } return azblob.NewClientWithSharedKeyCredential(fmt.Sprintf("%s%s", parts.Scheme, parts.Host), sas, nil) } } func (az *AzureClient) AddAcceptLanguages(languages []string) { acceptLanguageHeader := http.Header{} for _, language := range languages { acceptLanguageHeader.Add("Accept-Language", language) } az.acceptLanguageHeader = acceptLanguageHeader }