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