Azure backend: support snapshots/versioning (#24069)

* Azure backend: support snapshots/versioning

Co-authored-by: Reda Ahdjoudj <reda.ahdjoudj@gmail.com>
Co-authored-by: Patrick F. Marques <patrickfmarques@gmail.com>

* Azure backend: Versioning -> Snapshot

Co-authored-by: Reda Ahdjoudj <reda.ahdjoudj@gmail.com>
Co-authored-by: Patrick F. Marques <patrickfmarques@gmail.com>
This commit is contained in:
Even Holthe 2020-06-25 11:50:16 +02:00 committed by GitHub
parent f1ea705dbe
commit 0f85b283b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 33 additions and 1 deletions

View File

@ -51,6 +51,13 @@ func New() backend.Backend {
DefaultFunc: schema.EnvDefaultFunc("ARM_SAS_TOKEN", ""), DefaultFunc: schema.EnvDefaultFunc("ARM_SAS_TOKEN", ""),
}, },
"snapshot": {
Type: schema.TypeBool,
Optional: true,
Description: "Enable/Disable automatic blob snapshotting",
DefaultFunc: schema.EnvDefaultFunc("ARM_SNAPSHOT", false),
},
"resource_group_name": { "resource_group_name": {
Type: schema.TypeString, Type: schema.TypeString,
Optional: true, Optional: true,
@ -150,6 +157,7 @@ type Backend struct {
containerName string containerName string
keyName string keyName string
accountName string accountName string
snapshot bool
} }
type BackendConfig struct { type BackendConfig struct {
@ -180,6 +188,7 @@ func (b *Backend) configure(ctx context.Context) error {
b.containerName = data.Get("container_name").(string) b.containerName = data.Get("container_name").(string)
b.accountName = data.Get("storage_account_name").(string) b.accountName = data.Get("storage_account_name").(string)
b.keyName = data.Get("key").(string) b.keyName = data.Get("key").(string)
b.snapshot = data.Get("snapshot").(bool)
// support for previously deprecated fields // support for previously deprecated fields
clientId := valueFromDeprecatedField(data, "client_id", "arm_client_id") clientId := valueFromDeprecatedField(data, "client_id", "arm_client_id")

View File

@ -90,6 +90,7 @@ func (b *Backend) StateMgr(name string) (state.State, error) {
containerName: b.containerName, containerName: b.containerName,
keyName: b.path(name), keyName: b.path(name),
accountName: b.accountName, accountName: b.accountName,
snapshot: b.snapshot,
} }
stateMgr := &remote.State{Client: client} stateMgr := &remote.State{Client: client}

View File

@ -21,6 +21,7 @@ func TestBackendConfig(t *testing.T) {
"storage_account_name": "tfaccount", "storage_account_name": "tfaccount",
"container_name": "tfcontainer", "container_name": "tfcontainer",
"key": "state", "key": "state",
"snapshot": false,
// Access Key must be Base64 // Access Key must be Base64
"access_key": "QUNDRVNTX0tFWQ0K", "access_key": "QUNDRVNTX0tFWQ0K",
} }
@ -33,6 +34,9 @@ func TestBackendConfig(t *testing.T) {
if b.keyName != "state" { if b.keyName != "state" {
t.Fatalf("Incorrect keyName was populated") t.Fatalf("Incorrect keyName was populated")
} }
if b.snapshot != false {
t.Fatalf("Incorrect snapshot was populated")
}
} }
func TestBackendAccessKeyBasic(t *testing.T) { func TestBackendAccessKeyBasic(t *testing.T) {

View File

@ -5,11 +5,14 @@ import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-uuid" "github.com/hashicorp/go-uuid"
"github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/blobs"
"github.com/hashicorp/terraform/state" "github.com/hashicorp/terraform/state"
"github.com/hashicorp/terraform/state/remote" "github.com/hashicorp/terraform/state/remote"
"github.com/tombuildsstuff/giovanni/storage/2018-11-09/blob/blobs"
) )
const ( const (
@ -24,6 +27,7 @@ type RemoteClient struct {
containerName string containerName string
keyName string keyName string
leaseID string leaseID string
snapshot bool
} }
func (c *RemoteClient) Get() (*remote.Payload, error) { func (c *RemoteClient) Get() (*remote.Payload, error) {
@ -67,6 +71,18 @@ func (c *RemoteClient) Put(data []byte) error {
} }
ctx := context.TODO() ctx := context.TODO()
if c.snapshot {
snapshotInput := blobs.SnapshotInput{LeaseID: options.LeaseID}
log.Printf("[DEBUG] Snapshotting existing Blob %q (Container %q / Account %q)", c.keyName, c.containerName, c.accountName)
if _, err := c.giovanniBlobClient.Snapshot(ctx, c.accountName, c.containerName, c.keyName, snapshotInput); err != nil {
return fmt.Errorf("error snapshotting Blob %q (Container %q / Account %q): %+v", c.keyName, c.containerName, c.accountName, err)
}
log.Print("[DEBUG] Created blob snapshot")
}
blob, err := c.giovanniBlobClient.GetProperties(ctx, c.accountName, c.containerName, c.keyName, getOptions) blob, err := c.giovanniBlobClient.GetProperties(ctx, c.accountName, c.containerName, c.keyName, getOptions)
if err != nil { if err != nil {
if blob.StatusCode != 404 { if blob.StatusCode != 404 {

View File

@ -154,6 +154,8 @@ The following configuration options are supported:
* `environment` - (Optional) The Azure Environment which should be used. This can also be sourced from the `ARM_ENVIRONMENT` environment variable. Possible values are `public`, `china`, `german`, `stack` and `usgovernment`. Defaults to `public`. * `environment` - (Optional) The Azure Environment which should be used. This can also be sourced from the `ARM_ENVIRONMENT` environment variable. Possible values are `public`, `china`, `german`, `stack` and `usgovernment`. Defaults to `public`.
* `snapshot` - (Optional) Should the Blob used to store the Terraform Statefile be snapshotted before use? Defaults to `false`. This value can also be sourced from the `ARM_SNAPSHOT` environment variable.
* `endpoint` - (Optional) The Custom Endpoint for Azure Resource Manager. This can also be sourced from the `ARM_ENDPOINT` environment variable. * `endpoint` - (Optional) The Custom Endpoint for Azure Resource Manager. This can also be sourced from the `ARM_ENDPOINT` environment variable.
~> **NOTE:** An `endpoint` should only be configured when using Azure Stack. ~> **NOTE:** An `endpoint` should only be configured when using Azure Stack.