github.com/hugorut/terraform@v1.1.3/src/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 UseMicrosoftGraph: res.useMicrosoftGraph, 88 }) 89 if err != nil { 90 t.Fatalf("Failed to build ArmClient: %+v", err) 91 } 92 93 return armClient 94 } 95 96 func buildSasToken(accountName, accessKey string) (*string, error) { 97 // grant full access to Objects in the Blob Storage Account 98 permissions := "rwdlacup" // full control 99 resourceTypes := "sco" // service, container, object 100 services := "b" // blob 101 102 // Details on how to do this are here: 103 // https://docs.microsoft.com/en-us/rest/api/storageservices/Constructing-an-Account-SAS 104 signedProtocol := "https,http" 105 signedIp := "" 106 signedVersion := sasSignedVersion 107 108 utcNow := time.Now().UTC() 109 110 // account for servers being up to 5 minutes out 111 startDate := utcNow.Add(time.Minute * -5).Format(time.RFC3339) 112 endDate := utcNow.Add(time.Hour * 24).Format(time.RFC3339) 113 114 sasToken, err := sasStorage.ComputeAccountSASToken(accountName, accessKey, permissions, services, resourceTypes, 115 startDate, endDate, signedProtocol, signedIp, signedVersion) 116 if err != nil { 117 return nil, fmt.Errorf("Error computing SAS Token: %+v", err) 118 } 119 log.Printf("SAS Token should be %q", sasToken) 120 return &sasToken, nil 121 } 122 123 type resourceNames struct { 124 resourceGroup string 125 location string 126 storageAccountName string 127 storageContainerName string 128 storageKeyName string 129 storageAccountAccessKey string 130 useAzureADAuth bool 131 useMicrosoftGraph bool 132 } 133 134 func testResourceNames(rString string, keyName string) resourceNames { 135 return resourceNames{ 136 resourceGroup: fmt.Sprintf("acctestRG-backend-%s-%s", strings.Replace(time.Now().Local().Format("060102150405.00"), ".", "", 1), rString), 137 location: os.Getenv("ARM_LOCATION"), 138 storageAccountName: fmt.Sprintf("acctestsa%s", rString), 139 storageContainerName: "acctestcont", 140 storageKeyName: keyName, 141 useAzureADAuth: false, 142 } 143 } 144 145 func (c *ArmClient) buildTestResources(ctx context.Context, names *resourceNames) error { 146 log.Printf("Creating Resource Group %q", names.resourceGroup) 147 _, err := c.groupsClient.CreateOrUpdate(ctx, names.resourceGroup, resources.Group{Location: &names.location}) 148 if err != nil { 149 return fmt.Errorf("failed to create test resource group: %s", err) 150 } 151 152 log.Printf("Creating Storage Account %q in Resource Group %q", names.storageAccountName, names.resourceGroup) 153 storageProps := armStorage.AccountCreateParameters{ 154 Sku: &armStorage.Sku{ 155 Name: armStorage.StandardLRS, 156 Tier: armStorage.Standard, 157 }, 158 Location: &names.location, 159 } 160 if names.useAzureADAuth { 161 allowSharedKeyAccess := false 162 storageProps.AccountPropertiesCreateParameters = &armStorage.AccountPropertiesCreateParameters{ 163 AllowSharedKeyAccess: &allowSharedKeyAccess, 164 } 165 } 166 future, err := c.storageAccountsClient.Create(ctx, names.resourceGroup, names.storageAccountName, storageProps) 167 if err != nil { 168 return fmt.Errorf("failed to create test storage account: %s", err) 169 } 170 171 err = future.WaitForCompletionRef(ctx, c.storageAccountsClient.Client) 172 if err != nil { 173 return fmt.Errorf("failed waiting for the creation of storage account: %s", err) 174 } 175 176 containersClient := containers.NewWithEnvironment(c.environment) 177 if names.useAzureADAuth { 178 containersClient.Client.Authorizer = *c.azureAdStorageAuth 179 } else { 180 log.Printf("fetching access key for storage account") 181 resp, err := c.storageAccountsClient.ListKeys(ctx, names.resourceGroup, names.storageAccountName, "") 182 if err != nil { 183 return fmt.Errorf("failed to list storage account keys %s:", err) 184 } 185 186 keys := *resp.Keys 187 accessKey := *keys[0].Value 188 names.storageAccountAccessKey = accessKey 189 190 storageAuth, err := autorest.NewSharedKeyAuthorizer(names.storageAccountName, accessKey, autorest.SharedKey) 191 if err != nil { 192 return fmt.Errorf("Error building Authorizer: %+v", err) 193 } 194 195 containersClient.Client.Authorizer = storageAuth 196 } 197 198 log.Printf("Creating Container %q in Storage Account %q (Resource Group %q)", names.storageContainerName, names.storageAccountName, names.resourceGroup) 199 _, err = containersClient.Create(ctx, names.storageAccountName, names.storageContainerName, containers.CreateInput{}) 200 if err != nil { 201 return fmt.Errorf("failed to create storage container: %s", err) 202 } 203 204 return nil 205 } 206 207 func (c ArmClient) destroyTestResources(ctx context.Context, resources resourceNames) error { 208 log.Printf("[DEBUG] Deleting Resource Group %q..", resources.resourceGroup) 209 future, err := c.groupsClient.Delete(ctx, resources.resourceGroup) 210 if err != nil { 211 return fmt.Errorf("Error deleting Resource Group: %+v", err) 212 } 213 214 log.Printf("[DEBUG] Waiting for deletion of Resource Group %q..", resources.resourceGroup) 215 err = future.WaitForCompletionRef(ctx, c.groupsClient.Client) 216 if err != nil { 217 return fmt.Errorf("Error waiting for the deletion of Resource Group: %+v", err) 218 } 219 220 return nil 221 }