terraform/backend/remote-state/azure/backend_test.go

232 lines
7.0 KiB
Go

package azure
import (
"fmt"
"os"
"testing"
"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
armStorage "github.com/Azure/azure-sdk-for-go/arm/storage"
"github.com/Azure/azure-sdk-for-go/storage"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/go-autorest/autorest/azure"
"github.com/hashicorp/terraform/backend"
"github.com/hashicorp/terraform/helper/acctest"
)
// verify that we are doing ACC tests or the Azure tests specifically
func testACC(t *testing.T) {
skip := os.Getenv("TF_ACC") == "" && os.Getenv("TF_AZURE_TEST") == ""
if skip {
t.Log("azure backend tests require setting TF_ACC or TF_AZURE_TEST")
t.Skip()
}
}
func TestBackend_impl(t *testing.T) {
var _ backend.Backend = new(Backend)
}
func TestBackendConfig(t *testing.T) {
// This test just instantiates the client. Shouldn't make any actual
// requests nor incur any costs.
config := map[string]interface{}{
"storage_account_name": "tfaccount",
"container_name": "tfcontainer",
"key": "state",
// Access Key must be Base64
"access_key": "QUNDRVNTX0tFWQ0K",
}
b := backend.TestBackendConfig(t, New(), config).(*Backend)
if b.containerName != "tfcontainer" {
t.Fatalf("Incorrect bucketName was populated")
}
if b.keyName != "state" {
t.Fatalf("Incorrect keyName was populated")
}
}
func TestBackend(t *testing.T) {
testACC(t)
keyName := "testState"
res := setupResources(t, keyName)
defer destroyResources(t, res.resourceGroupName)
b := backend.TestBackendConfig(t, New(), map[string]interface{}{
"storage_account_name": res.storageAccountName,
"container_name": res.containerName,
"key": keyName,
"access_key": res.accessKey,
}).(*Backend)
backend.TestBackend(t, b, nil)
}
func TestBackendLocked(t *testing.T) {
testACC(t)
keyName := "testState"
res := setupResources(t, keyName)
defer destroyResources(t, res.resourceGroupName)
b1 := backend.TestBackendConfig(t, New(), map[string]interface{}{
"storage_account_name": res.storageAccountName,
"container_name": res.containerName,
"key": keyName,
"access_key": res.accessKey,
}).(*Backend)
b2 := backend.TestBackendConfig(t, New(), map[string]interface{}{
"storage_account_name": res.storageAccountName,
"container_name": res.containerName,
"key": keyName,
"access_key": res.accessKey,
}).(*Backend)
backend.TestBackend(t, b1, b2)
}
type testResources struct {
resourceGroupName string
storageAccountName string
containerName string
keyName string
accessKey string
}
func setupResources(t *testing.T, keyName string) testResources {
clients := getTestClient(t)
ri := acctest.RandInt()
rs := acctest.RandString(4)
res := testResources{
resourceGroupName: fmt.Sprintf("terraform-backend-testing-%d", ri),
storageAccountName: fmt.Sprintf("tfbackendtesting%s", rs),
containerName: "terraform",
keyName: keyName,
}
location := os.Getenv("ARM_LOCATION")
if location == "" {
location = "westus"
}
t.Logf("creating resource group %s", res.resourceGroupName)
_, err := clients.groupsClient.CreateOrUpdate(res.resourceGroupName, resources.Group{Location: &location})
if err != nil {
t.Fatalf("failed to create test resource group: %s", err)
}
t.Logf("creating storage account %s", res.storageAccountName)
_, createError := clients.storageAccountsClient.Create(res.resourceGroupName, res.storageAccountName, armStorage.AccountCreateParameters{
Sku: &armStorage.Sku{
Name: armStorage.StandardLRS,
Tier: armStorage.Standard,
},
Location: &location,
}, make(chan struct{}))
createErr := <-createError
if createErr != nil {
destroyResources(t, res.resourceGroupName)
t.Fatalf("failed to create test storage account: %s", err)
}
t.Log("fetching access key for storage account")
resp, err := clients.storageAccountsClient.ListKeys(res.resourceGroupName, res.storageAccountName)
if err != nil {
destroyResources(t, res.resourceGroupName)
t.Fatalf("failed to list storage account keys %s:", err)
}
keys := *resp.Keys
res.accessKey = *keys[0].Value
storageClient, err := storage.NewClient(res.storageAccountName, res.accessKey,
clients.environment.StorageEndpointSuffix, storage.DefaultAPIVersion, true)
if err != nil {
destroyResources(t, res.resourceGroupName)
t.Fatalf("failed to list storage account keys %s:", err)
}
t.Logf("creating container %s", res.containerName)
blobService := storageClient.GetBlobService()
container := blobService.GetContainerReference(res.containerName)
err = container.Create(&storage.CreateContainerOptions{})
if err != nil {
destroyResources(t, res.resourceGroupName)
t.Fatalf("failed to create storage container: %s", err)
}
return res
}
func destroyResources(t *testing.T, resourceGroupName string) {
warning := "WARNING: Failed to delete the test Azure resources. They may incur charges. (error was %s)"
clients := getTestClient(t)
t.Log("destroying created resources")
// destroying is simple as deleting the resource group will destroy everything else
_, deleteErr := clients.groupsClient.Delete(resourceGroupName, make(chan struct{}))
err := <-deleteErr
if err != nil {
t.Logf(warning, err)
return
}
t.Log("Azure resources destroyed")
}
type testClient struct {
subscriptionID string
tenantID string
clientID string
clientSecret string
environment azure.Environment
groupsClient resources.GroupsClient
storageAccountsClient armStorage.AccountsClient
}
func getTestClient(t *testing.T) testClient {
client := testClient{
subscriptionID: os.Getenv("ARM_SUBSCRIPTION_ID"),
tenantID: os.Getenv("ARM_TENANT_ID"),
clientID: os.Getenv("ARM_CLIENT_ID"),
clientSecret: os.Getenv("ARM_CLIENT_SECRET"),
}
if client.subscriptionID == "" || client.tenantID == "" || client.clientID == "" || client.clientSecret == "" {
t.Fatal("Azure credentials missing or incomplete")
}
env, err := getAzureEnvironment(os.Getenv("ARM_ENVIRONMENT"))
if err != nil {
t.Fatalf("Failed to detect Azure environment from ARM_ENVIRONMENT value: %s", os.Getenv("ARM_ENVIRONMENT"))
}
client.environment = env
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, client.tenantID)
if err != nil {
t.Fatalf("Failed to get OAuth config: %s", err)
}
spt, err := adal.NewServicePrincipalToken(*oauthConfig, client.clientID, client.clientSecret, env.ResourceManagerEndpoint)
if err != nil {
t.Fatalf("Failed to create Service Principal Token: %s", err)
}
client.groupsClient = resources.NewGroupsClientWithBaseURI(env.ResourceManagerEndpoint, client.subscriptionID)
client.groupsClient.Authorizer = autorest.NewBearerAuthorizer(spt)
client.storageAccountsClient = armStorage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, client.subscriptionID)
client.storageAccountsClient.Authorizer = autorest.NewBearerAuthorizer(spt)
return client
}