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  }