Merge pull request #15841 from hashicorp/jbardin/azurerm-backend
Rename the azure backend to azurerm
This commit is contained in:
commit
0da6b95ef8
|
@ -42,7 +42,8 @@ func init() {
|
||||||
"inmem": func() backend.Backend { return backendinmem.New() },
|
"inmem": func() backend.Backend { return backendinmem.New() },
|
||||||
"swift": func() backend.Backend { return backendSwift.New() },
|
"swift": func() backend.Backend { return backendSwift.New() },
|
||||||
"s3": func() backend.Backend { return backendS3.New() },
|
"s3": func() backend.Backend { return backendS3.New() },
|
||||||
"azure": func() backend.Backend { return backendAzure.New() },
|
"azure": deprecateBackend(backendAzure.New(),
|
||||||
|
`Warning: "azure" name is deprecated, please use "azurerm"`),
|
||||||
"azurerm": func() backend.Backend { return backendAzure.New() },
|
"azurerm": func() backend.Backend { return backendAzure.New() },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,235 +0,0 @@
|
||||||
package remote
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/Azure/azure-sdk-for-go/arm/storage"
|
|
||||||
mainStorage "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"
|
|
||||||
riviera "github.com/jen20/riviera/azure"
|
|
||||||
)
|
|
||||||
|
|
||||||
func azureFactory(conf map[string]string) (Client, error) {
|
|
||||||
storageAccountName, ok := conf["storage_account_name"]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("missing 'storage_account_name' configuration")
|
|
||||||
}
|
|
||||||
containerName, ok := conf["container_name"]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("missing 'container_name' configuration")
|
|
||||||
}
|
|
||||||
keyName, ok := conf["key"]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("missing 'key' configuration")
|
|
||||||
}
|
|
||||||
|
|
||||||
env, err := getAzureEnvironmentFromConf(conf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
accessKey, ok := confOrEnv(conf, "access_key", "ARM_ACCESS_KEY")
|
|
||||||
if !ok {
|
|
||||||
resourceGroupName, ok := conf["resource_group_name"]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("missing 'resource_group_name' configuration")
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
accessKey, err = getStorageAccountAccessKey(conf, resourceGroupName, storageAccountName, env)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Couldn't read access key from storage account: %s.", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
storageClient, err := mainStorage.NewClient(storageAccountName, accessKey, env.StorageEndpointSuffix,
|
|
||||||
mainStorage.DefaultAPIVersion, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error creating storage client for storage account %q: %s", storageAccountName, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
blobClient := storageClient.GetBlobService()
|
|
||||||
leaseID, _ := confOrEnv(conf, "lease_id", "ARM_LEASE_ID")
|
|
||||||
|
|
||||||
return &AzureClient{
|
|
||||||
blobClient: &blobClient,
|
|
||||||
containerName: containerName,
|
|
||||||
keyName: keyName,
|
|
||||||
leaseID: leaseID,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getStorageAccountAccessKey(conf map[string]string, resourceGroupName, storageAccountName string, env azure.Environment) (string, error) {
|
|
||||||
creds, err := getCredentialsFromConf(conf, env)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, creds.TenantID)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if oauthConfig == nil {
|
|
||||||
return "", fmt.Errorf("Unable to configure OAuthConfig for tenant %s", creds.TenantID)
|
|
||||||
}
|
|
||||||
|
|
||||||
spt, err := adal.NewServicePrincipalToken(*oauthConfig, creds.ClientID, creds.ClientSecret, env.ResourceManagerEndpoint)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
accountsClient := storage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, creds.SubscriptionID)
|
|
||||||
accountsClient.Authorizer = autorest.NewBearerAuthorizer(spt)
|
|
||||||
|
|
||||||
keys, err := accountsClient.ListKeys(resourceGroupName, storageAccountName)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("Error retrieving keys for storage account %q: %s", storageAccountName, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if keys.Keys == nil {
|
|
||||||
return "", fmt.Errorf("Nil key returned for storage account %q", storageAccountName)
|
|
||||||
}
|
|
||||||
|
|
||||||
accessKeys := *keys.Keys
|
|
||||||
return *accessKeys[0].Value, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCredentialsFromConf(conf map[string]string, env azure.Environment) (*riviera.AzureResourceManagerCredentials, error) {
|
|
||||||
subscriptionID, ok := confOrEnv(conf, "arm_subscription_id", "ARM_SUBSCRIPTION_ID")
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("missing 'arm_subscription_id' configuration")
|
|
||||||
}
|
|
||||||
clientID, ok := confOrEnv(conf, "arm_client_id", "ARM_CLIENT_ID")
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("missing 'arm_client_id' configuration")
|
|
||||||
}
|
|
||||||
clientSecret, ok := confOrEnv(conf, "arm_client_secret", "ARM_CLIENT_SECRET")
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("missing 'arm_client_secret' configuration")
|
|
||||||
}
|
|
||||||
tenantID, ok := confOrEnv(conf, "arm_tenant_id", "ARM_TENANT_ID")
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("missing 'arm_tenant_id' configuration")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &riviera.AzureResourceManagerCredentials{
|
|
||||||
SubscriptionID: subscriptionID,
|
|
||||||
ClientID: clientID,
|
|
||||||
ClientSecret: clientSecret,
|
|
||||||
TenantID: tenantID,
|
|
||||||
ActiveDirectoryEndpoint: env.ActiveDirectoryEndpoint,
|
|
||||||
ResourceManagerEndpoint: env.ResourceManagerEndpoint,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAzureEnvironmentFromConf(conf map[string]string) (azure.Environment, error) {
|
|
||||||
envName, ok := confOrEnv(conf, "environment", "ARM_ENVIRONMENT")
|
|
||||||
if !ok {
|
|
||||||
return azure.PublicCloud, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
env, err := azure.EnvironmentFromName(envName)
|
|
||||||
if err != nil {
|
|
||||||
// try again with wrapped value to support readable values like german instead of AZUREGERMANCLOUD
|
|
||||||
var innerErr error
|
|
||||||
env, innerErr = azure.EnvironmentFromName(fmt.Sprintf("AZURE%sCLOUD", envName))
|
|
||||||
if innerErr != nil {
|
|
||||||
return env, fmt.Errorf("invalid 'environment' configuration: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return env, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func confOrEnv(conf map[string]string, confKey, envVar string) (string, bool) {
|
|
||||||
value, ok := conf[confKey]
|
|
||||||
if ok {
|
|
||||||
return value, true
|
|
||||||
}
|
|
||||||
|
|
||||||
value = os.Getenv(envVar)
|
|
||||||
|
|
||||||
return value, value != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type AzureClient struct {
|
|
||||||
blobClient *mainStorage.BlobStorageClient
|
|
||||||
containerName string
|
|
||||||
keyName string
|
|
||||||
leaseID string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *AzureClient) Get() (*Payload, error) {
|
|
||||||
containerReference := c.blobClient.GetContainerReference(c.containerName)
|
|
||||||
blobReference := containerReference.GetBlobReference(c.keyName)
|
|
||||||
options := &mainStorage.GetBlobOptions{}
|
|
||||||
blob, err := blobReference.Get(options)
|
|
||||||
if err != nil {
|
|
||||||
if storErr, ok := err.(mainStorage.AzureStorageServiceError); ok {
|
|
||||||
if storErr.Code == "BlobNotFound" {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer blob.Close()
|
|
||||||
|
|
||||||
data, err := ioutil.ReadAll(blob)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
payload := &Payload{
|
|
||||||
Data: data,
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there was no data, then return nil
|
|
||||||
if len(payload.Data) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return payload, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *AzureClient) Put(data []byte) error {
|
|
||||||
setOptions := &mainStorage.SetBlobPropertiesOptions{}
|
|
||||||
putOptions := &mainStorage.PutBlobOptions{}
|
|
||||||
|
|
||||||
containerReference := c.blobClient.GetContainerReference(c.containerName)
|
|
||||||
blobReference := containerReference.GetBlobReference(c.keyName)
|
|
||||||
|
|
||||||
blobReference.Properties.ContentType = "application/json"
|
|
||||||
blobReference.Properties.ContentLength = int64(len(data))
|
|
||||||
|
|
||||||
if c.leaseID != "" {
|
|
||||||
setOptions.LeaseID = c.leaseID
|
|
||||||
putOptions.LeaseID = c.leaseID
|
|
||||||
}
|
|
||||||
|
|
||||||
reader := bytes.NewReader(data)
|
|
||||||
|
|
||||||
err := blobReference.CreateBlockBlobFromReader(reader, putOptions)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return blobReference.SetProperties(setOptions)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *AzureClient) Delete() error {
|
|
||||||
containerReference := c.blobClient.GetContainerReference(c.containerName)
|
|
||||||
blobReference := containerReference.GetBlobReference(c.keyName)
|
|
||||||
options := &mainStorage.DeleteBlobOptions{}
|
|
||||||
|
|
||||||
if c.leaseID != "" {
|
|
||||||
options.LeaseID = c.leaseID
|
|
||||||
}
|
|
||||||
|
|
||||||
return blobReference.Delete(options)
|
|
||||||
}
|
|
|
@ -1,231 +0,0 @@
|
||||||
package remote
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
mainStorage "github.com/Azure/azure-sdk-for-go/storage"
|
|
||||||
"github.com/hashicorp/terraform/helper/acctest"
|
|
||||||
riviera "github.com/jen20/riviera/azure"
|
|
||||||
"github.com/jen20/riviera/storage"
|
|
||||||
"github.com/satori/uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAzureClient_impl(t *testing.T) {
|
|
||||||
var _ Client = new(AzureClient)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This test creates a bucket in Azure and populates it.
|
|
||||||
// It may incur costs, so it will only run if Azure credential environment
|
|
||||||
// variables are present.
|
|
||||||
func TestAzureClient(t *testing.T) {
|
|
||||||
config := getAzureConfig(t)
|
|
||||||
|
|
||||||
setup(t, config)
|
|
||||||
defer teardown(t, config)
|
|
||||||
|
|
||||||
client, err := azureFactory(config)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error for valid config: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
testClient(t, client)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This test is the same as TestAzureClient with the addition of passing an
|
|
||||||
// empty string in the lease_id, we expect the client to pass tests
|
|
||||||
func TestAzureClientEmptyLease(t *testing.T) {
|
|
||||||
config := getAzureConfig(t)
|
|
||||||
config["lease_id"] = ""
|
|
||||||
|
|
||||||
setup(t, config)
|
|
||||||
defer teardown(t, config)
|
|
||||||
|
|
||||||
client, err := azureFactory(config)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error for valid config: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
testClient(t, client)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This test is the same as TestAzureClient with the addition of using the
|
|
||||||
// lease_id config option
|
|
||||||
func TestAzureClientLease(t *testing.T) {
|
|
||||||
leaseID := uuid.NewV4().String()
|
|
||||||
config := getAzureConfig(t)
|
|
||||||
config["lease_id"] = leaseID
|
|
||||||
|
|
||||||
setup(t, config)
|
|
||||||
defer teardown(t, config)
|
|
||||||
|
|
||||||
client, err := azureFactory(config)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error for valid config: %v", err)
|
|
||||||
}
|
|
||||||
azureClient := client.(*AzureClient)
|
|
||||||
|
|
||||||
containerReference := azureClient.blobClient.GetContainerReference(azureClient.containerName)
|
|
||||||
blobReference := containerReference.GetBlobReference(azureClient.keyName)
|
|
||||||
|
|
||||||
// put empty blob so we can acquire lease against it
|
|
||||||
options := &mainStorage.PutBlobOptions{}
|
|
||||||
err = blobReference.CreateBlockBlob(options)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error creating blob for leasing: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
leaseOptions := &mainStorage.LeaseOptions{}
|
|
||||||
_, err = blobReference.AcquireLease(-1, leaseID, leaseOptions)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error acquiring lease: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// no need to release lease as blob is deleted in testing
|
|
||||||
testClient(t, client)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAzureConfig(t *testing.T) map[string]string {
|
|
||||||
config := map[string]string{
|
|
||||||
"arm_subscription_id": os.Getenv("ARM_SUBSCRIPTION_ID"),
|
|
||||||
"arm_client_id": os.Getenv("ARM_CLIENT_ID"),
|
|
||||||
"arm_client_secret": os.Getenv("ARM_CLIENT_SECRET"),
|
|
||||||
"arm_tenant_id": os.Getenv("ARM_TENANT_ID"),
|
|
||||||
"environment": os.Getenv("ARM_ENVIRONMENT"),
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range config {
|
|
||||||
if v == "" {
|
|
||||||
t.Skipf("skipping; %s must be set", strings.ToUpper(k))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rs := acctest.RandString(8)
|
|
||||||
|
|
||||||
config["resource_group_name"] = fmt.Sprintf("terraform-%s", rs)
|
|
||||||
config["storage_account_name"] = fmt.Sprintf("terraform%s", rs)
|
|
||||||
config["container_name"] = "terraform"
|
|
||||||
config["key"] = "test.tfstate"
|
|
||||||
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
func setup(t *testing.T, conf map[string]string) {
|
|
||||||
env, err := getAzureEnvironmentFromConf(conf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error getting Azure environment from conf: %v", err)
|
|
||||||
}
|
|
||||||
creds, err := getCredentialsFromConf(conf, env)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error getting credentials from conf: %v", err)
|
|
||||||
}
|
|
||||||
rivieraClient, err := getRivieraClient(creds)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error instantiating the riviera client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create resource group
|
|
||||||
r := rivieraClient.NewRequest()
|
|
||||||
r.Command = riviera.CreateResourceGroup{
|
|
||||||
Name: conf["resource_group_name"],
|
|
||||||
Location: riviera.WestUS,
|
|
||||||
}
|
|
||||||
response, err := r.Execute()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error creating a resource group: %v", err)
|
|
||||||
}
|
|
||||||
if !response.IsSuccessful() {
|
|
||||||
t.Fatalf("Error creating a resource group: %v", response.Error.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create storage account
|
|
||||||
r = rivieraClient.NewRequest()
|
|
||||||
r.Command = storage.CreateStorageAccount{
|
|
||||||
ResourceGroupName: conf["resource_group_name"],
|
|
||||||
Name: conf["storage_account_name"],
|
|
||||||
AccountType: riviera.String("Standard_LRS"),
|
|
||||||
Location: riviera.WestUS,
|
|
||||||
}
|
|
||||||
response, err = r.Execute()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error creating a storage account: %v", err)
|
|
||||||
}
|
|
||||||
if !response.IsSuccessful() {
|
|
||||||
t.Fatalf("Error creating a storage account: %v", response.Error.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create container
|
|
||||||
accessKey, err := getStorageAccountAccessKey(conf, conf["resource_group_name"], conf["storage_account_name"], env)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error creating a storage account: %v", err)
|
|
||||||
}
|
|
||||||
storageClient, err := mainStorage.NewClient(conf["storage_account_name"], accessKey, env.StorageEndpointSuffix,
|
|
||||||
mainStorage.DefaultAPIVersion, true)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error creating storage client for storage account %q: %s", conf["storage_account_name"], err)
|
|
||||||
}
|
|
||||||
blobClient := storageClient.GetBlobService()
|
|
||||||
containerName := conf["container_name"]
|
|
||||||
containerReference := blobClient.GetContainerReference(containerName)
|
|
||||||
options := &mainStorage.CreateContainerOptions{
|
|
||||||
Access: mainStorage.ContainerAccessTypePrivate,
|
|
||||||
}
|
|
||||||
_, err = containerReference.CreateIfNotExists(options)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Couldn't create container with name %s: %s.", conf["container_name"], err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func teardown(t *testing.T, conf map[string]string) {
|
|
||||||
env, err := getAzureEnvironmentFromConf(conf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error getting Azure environment from conf: %v", err)
|
|
||||||
}
|
|
||||||
creds, err := getCredentialsFromConf(conf, env)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error getting credentials from conf: %v", err)
|
|
||||||
}
|
|
||||||
rivieraClient, err := getRivieraClient(creds)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error instantiating the riviera client: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
r := rivieraClient.NewRequest()
|
|
||||||
r.Command = riviera.DeleteResourceGroup{
|
|
||||||
Name: conf["resource_group_name"],
|
|
||||||
}
|
|
||||||
response, err := r.Execute()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error deleting the resource group: %v", err)
|
|
||||||
}
|
|
||||||
if !response.IsSuccessful() {
|
|
||||||
t.Fatalf("Error deleting the resource group: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRivieraClient(credentials *riviera.AzureResourceManagerCredentials) (*riviera.Client, error) {
|
|
||||||
rivieraClient, err := riviera.NewClient(credentials)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Error creating Riviera client: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
request := rivieraClient.NewRequest()
|
|
||||||
request.Command = riviera.RegisterResourceProvider{
|
|
||||||
Namespace: "Microsoft.Storage",
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err := request.Execute()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Cannot request provider registration for Azure Resource Manager: %s.", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !response.IsSuccessful() {
|
|
||||||
return nil, fmt.Errorf("Credentials for acessing the Azure Resource Manager API are likely " +
|
|
||||||
"to be incorrect, or\n the service principal does not have permission to use " +
|
|
||||||
"the Azure Service Management\n API.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return rivieraClient, nil
|
|
||||||
}
|
|
|
@ -1,12 +1,12 @@
|
||||||
---
|
---
|
||||||
layout: "backend-types"
|
layout: "backend-types"
|
||||||
page_title: "Backend Type: azure"
|
page_title: "Backend Type: azurerm"
|
||||||
sidebar_current: "docs-backends-types-standard-azure"
|
sidebar_current: "docs-backends-types-standard-azurerm"
|
||||||
description: |-
|
description: |-
|
||||||
Terraform can store state remotely in Azure Storage.
|
Terraform can store state remotely in Azure Storage.
|
||||||
---
|
---
|
||||||
|
|
||||||
# azure
|
# azurerm
|
||||||
|
|
||||||
**Kind: Standard (with state locking)**
|
**Kind: Standard (with state locking)**
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ Stores the state as a given key in a given bucket on [Microsoft Azure Storage](h
|
||||||
|
|
||||||
```hcl
|
```hcl
|
||||||
terraform {
|
terraform {
|
||||||
backend "azure" {
|
backend "azurerm" {
|
||||||
storage_account_name = "abcd1234"
|
storage_account_name = "abcd1234"
|
||||||
container_name = "tfstate"
|
container_name = "tfstate"
|
||||||
key = "prod.terraform.tfstate"
|
key = "prod.terraform.tfstate"
|
||||||
|
@ -31,7 +31,7 @@ Note that for the access credentials we recommend using a
|
||||||
|
|
||||||
```hcl
|
```hcl
|
||||||
data "terraform_remote_state" "foo" {
|
data "terraform_remote_state" "foo" {
|
||||||
backend = "azure"
|
backend = "azurerm"
|
||||||
config {
|
config {
|
||||||
storage_account_name = "terraform123abc"
|
storage_account_name = "terraform123abc"
|
||||||
container_name = "terraform-state"
|
container_name = "terraform-state"
|
|
@ -26,8 +26,8 @@
|
||||||
<li<%= sidebar_current("docs-backends-types-standard-artifactory") %>>
|
<li<%= sidebar_current("docs-backends-types-standard-artifactory") %>>
|
||||||
<a href="/docs/backends/types/artifactory.html">artifactory</a>
|
<a href="/docs/backends/types/artifactory.html">artifactory</a>
|
||||||
</li>
|
</li>
|
||||||
<li<%= sidebar_current("docs-backends-types-standard-azure") %>>
|
<li<%= sidebar_current("docs-backends-types-standard-azurerm") %>>
|
||||||
<a href="/docs/backends/types/azure.html">azure</a>
|
<a href="/docs/backends/types/azurerm.html">azure</a>
|
||||||
</li>
|
</li>
|
||||||
<li<%= sidebar_current("docs-backends-types-standard-consul") %>>
|
<li<%= sidebar_current("docs-backends-types-standard-consul") %>>
|
||||||
<a href="/docs/backends/types/consul.html">consul</a>
|
<a href="/docs/backends/types/consul.html">consul</a>
|
||||||
|
|
Loading…
Reference in New Issue