kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/backend/remote-state/azure/helpers_test.go (about) 1 package azure 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "os" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/Azure/azure-sdk-for-go/profiles/2017-03-09/resources/mgmt/resources" 13 armStorage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2021-01-01/storage" 14 "github.com/Azure/go-autorest/autorest" 15 sasStorage "github.com/hashicorp/go-azure-helpers/storage" 16 "github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/containers" 17 ) 18 19 const ( 20 // required for Azure Stack 21 sasSignedVersion = "2015-04-05" 22 ) 23 24 // verify that we are doing ACC tests or the Azure tests specifically 25 func testAccAzureBackend(t *testing.T) { 26 skip := os.Getenv("TF_ACC") == "" && os.Getenv("TF_AZURE_TEST") == "" 27 if skip { 28 t.Log("azure backend tests require setting TF_ACC or TF_AZURE_TEST") 29 t.Skip() 30 } 31 } 32 33 // these kind of tests can only run when within Azure (e.g. MSI) 34 func testAccAzureBackendRunningInAzure(t *testing.T) { 35 testAccAzureBackend(t) 36 37 if os.Getenv("TF_RUNNING_IN_AZURE") == "" { 38 t.Skip("Skipping test since not running in Azure") 39 } 40 } 41 42 func buildTestClient(t *testing.T, res resourceNames) *ArmClient { 43 subscriptionID := os.Getenv("ARM_SUBSCRIPTION_ID") 44 tenantID := os.Getenv("ARM_TENANT_ID") 45 clientID := os.Getenv("ARM_CLIENT_ID") 46 clientSecret := os.Getenv("ARM_CLIENT_SECRET") 47 msiEnabled := strings.EqualFold(os.Getenv("ARM_USE_MSI"), "true") 48 environment := os.Getenv("ARM_ENVIRONMENT") 49 50 hasCredentials := (clientID != "" && clientSecret != "") || msiEnabled 51 if !hasCredentials { 52 t.Fatal("Azure credentials missing or incomplete") 53 } 54 55 if subscriptionID == "" { 56 t.Fatalf("Missing ARM_SUBSCRIPTION_ID") 57 } 58 59 if tenantID == "" { 60 t.Fatalf("Missing ARM_TENANT_ID") 61 } 62 63 if environment == "" { 64 t.Fatalf("Missing ARM_ENVIRONMENT") 65 } 66 67 // location isn't used in this method, but is in the other test methods 68 location := os.Getenv("ARM_LOCATION") 69 if location == "" { 70 t.Fatalf("Missing ARM_LOCATION") 71 } 72 73 // Endpoint is optional (only for Stack) 74 endpoint := os.Getenv("ARM_ENDPOINT") 75 76 armClient, err := buildArmClient(context.TODO(), BackendConfig{ 77 SubscriptionID: subscriptionID, 78 TenantID: tenantID, 79 ClientID: clientID, 80 ClientSecret: clientSecret, 81 CustomResourceManagerEndpoint: endpoint, 82 Environment: environment, 83 ResourceGroupName: res.resourceGroup, 84 StorageAccountName: res.storageAccountName, 85 UseMsi: msiEnabled, 86 UseAzureADAuthentication: res.useAzureADAuth, 87 }) 88 if err != nil { 89 t.Fatalf("Failed to build ArmClient: %+v", err) 90 } 91 92 return armClient 93 } 94 95 func buildSasToken(accountName, accessKey string) (*string, error) { 96 // grant full access to Objects in the Blob Storage Account 97 permissions := "rwdlacup" // full control 98 resourceTypes := "sco" // service, container, object 99 services := "b" // blob 100 101 // Details on how to do this are here: 102 // https://docs.microsoft.com/en-us/rest/api/storageservices/Constructing-an-Account-SAS 103 signedProtocol := "https,http" 104 signedIp := "" 105 signedVersion := sasSignedVersion 106 107 utcNow := time.Now().UTC() 108 109 // account for servers being up to 5 minutes out 110 startDate := utcNow.Add(time.Minute * -5).Format(time.RFC3339) 111 endDate := utcNow.Add(time.Hour * 24).Format(time.RFC3339) 112 113 sasToken, err := sasStorage.ComputeAccountSASToken(accountName, accessKey, permissions, services, resourceTypes, 114 startDate, endDate, signedProtocol, signedIp, signedVersion) 115 if err != nil { 116 return nil, fmt.Errorf("Error computing SAS Token: %+v", err) 117 } 118 log.Printf("SAS Token should be %q", sasToken) 119 return &sasToken, nil 120 } 121 122 type resourceNames struct { 123 resourceGroup string 124 location string 125 storageAccountName string 126 storageContainerName string 127 storageKeyName string 128 storageAccountAccessKey string 129 useAzureADAuth bool 130 } 131 132 func testResourceNames(rString string, keyName string) resourceNames { 133 return resourceNames{ 134 resourceGroup: fmt.Sprintf("acctestRG-backend-%s-%s", strings.Replace(time.Now().Local().Format("060102150405.00"), ".", "", 1), rString), 135 location: os.Getenv("ARM_LOCATION"), 136 storageAccountName: fmt.Sprintf("acctestsa%s", rString), 137 storageContainerName: "acctestcont", 138 storageKeyName: keyName, 139 useAzureADAuth: false, 140 } 141 } 142 143 func (c *ArmClient) buildTestResources(ctx context.Context, names *resourceNames) error { 144 log.Printf("Creating Resource Group %q", names.resourceGroup) 145 _, err := c.groupsClient.CreateOrUpdate(ctx, names.resourceGroup, resources.Group{Location: &names.location}) 146 if err != nil { 147 return fmt.Errorf("failed to create test resource group: %s", err) 148 } 149 150 log.Printf("Creating Storage Account %q in Resource Group %q", names.storageAccountName, names.resourceGroup) 151 storageProps := armStorage.AccountCreateParameters{ 152 Sku: &armStorage.Sku{ 153 Name: armStorage.StandardLRS, 154 Tier: armStorage.Standard, 155 }, 156 Location: &names.location, 157 } 158 if names.useAzureADAuth { 159 allowSharedKeyAccess := false 160 storageProps.AccountPropertiesCreateParameters = &armStorage.AccountPropertiesCreateParameters{ 161 AllowSharedKeyAccess: &allowSharedKeyAccess, 162 } 163 } 164 future, err := c.storageAccountsClient.Create(ctx, names.resourceGroup, names.storageAccountName, storageProps) 165 if err != nil { 166 return fmt.Errorf("failed to create test storage account: %s", err) 167 } 168 169 err = future.WaitForCompletionRef(ctx, c.storageAccountsClient.Client) 170 if err != nil { 171 return fmt.Errorf("failed waiting for the creation of storage account: %s", err) 172 } 173 174 containersClient := containers.NewWithEnvironment(c.environment) 175 if names.useAzureADAuth { 176 containersClient.Client.Authorizer = *c.azureAdStorageAuth 177 } else { 178 log.Printf("fetching access key for storage account") 179 resp, err := c.storageAccountsClient.ListKeys(ctx, names.resourceGroup, names.storageAccountName, "") 180 if err != nil { 181 return fmt.Errorf("failed to list storage account keys %s:", err) 182 } 183 184 keys := *resp.Keys 185 accessKey := *keys[0].Value 186 names.storageAccountAccessKey = accessKey 187 188 storageAuth, err := autorest.NewSharedKeyAuthorizer(names.storageAccountName, accessKey, autorest.SharedKey) 189 if err != nil { 190 return fmt.Errorf("Error building Authorizer: %+v", err) 191 } 192 193 containersClient.Client.Authorizer = storageAuth 194 } 195 196 log.Printf("Creating Container %q in Storage Account %q (Resource Group %q)", names.storageContainerName, names.storageAccountName, names.resourceGroup) 197 _, err = containersClient.Create(ctx, names.storageAccountName, names.storageContainerName, containers.CreateInput{}) 198 if err != nil { 199 return fmt.Errorf("failed to create storage container: %s", err) 200 } 201 202 return nil 203 } 204 205 func (c ArmClient) destroyTestResources(ctx context.Context, resources resourceNames) error { 206 log.Printf("[DEBUG] Deleting Resource Group %q..", resources.resourceGroup) 207 future, err := c.groupsClient.Delete(ctx, resources.resourceGroup) 208 if err != nil { 209 return fmt.Errorf("Error deleting Resource Group: %+v", err) 210 } 211 212 log.Printf("[DEBUG] Waiting for deletion of Resource Group %q..", resources.resourceGroup) 213 err = future.WaitForCompletionRef(ctx, c.groupsClient.Client) 214 if err != nil { 215 return fmt.Errorf("Error waiting for the deletion of Resource Group: %+v", err) 216 } 217 218 return nil 219 }