Obtaining the current metadata before setting it
This commit is contained in:
parent
a10d23dd95
commit
d074b0da29
|
@ -101,6 +101,17 @@ type Backend struct {
|
|||
leaseID string
|
||||
}
|
||||
|
||||
type BackendConfig struct {
|
||||
AccessKey string
|
||||
Environment string
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
ResourceGroupName string
|
||||
StorageAccountName string
|
||||
SubscriptionID string
|
||||
TenantID string
|
||||
}
|
||||
|
||||
func (b *Backend) configure(ctx context.Context) error {
|
||||
if b.containerName != "" {
|
||||
return nil
|
||||
|
@ -112,7 +123,18 @@ func (b *Backend) configure(ctx context.Context) error {
|
|||
b.containerName = data.Get("container_name").(string)
|
||||
b.keyName = data.Get("key").(string)
|
||||
|
||||
blobClient, err := getBlobClient(data)
|
||||
config := BackendConfig{
|
||||
AccessKey: data.Get("access_key").(string),
|
||||
ClientID: data.Get("arm_client_id").(string),
|
||||
ClientSecret: data.Get("arm_client_secret").(string),
|
||||
Environment: data.Get("environment").(string),
|
||||
ResourceGroupName: data.Get("resource_group_name").(string),
|
||||
StorageAccountName: data.Get("storage_account_name").(string),
|
||||
SubscriptionID: data.Get("arm_subscription_id").(string),
|
||||
TenantID: data.Get("arm_tenant_id").(string),
|
||||
}
|
||||
|
||||
blobClient, err := getBlobClient(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -121,65 +143,63 @@ func (b *Backend) configure(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getBlobClient(d *schema.ResourceData) (storage.BlobStorageClient, error) {
|
||||
func getBlobClient(config BackendConfig) (storage.BlobStorageClient, error) {
|
||||
var client storage.BlobStorageClient
|
||||
|
||||
env, err := getAzureEnvironment(d.Get("environment").(string))
|
||||
env, err := getAzureEnvironment(config.Environment)
|
||||
if err != nil {
|
||||
return client, err
|
||||
}
|
||||
|
||||
storageAccountName := d.Get("storage_account_name").(string)
|
||||
|
||||
accessKey, err := getAccessKey(d, storageAccountName, env)
|
||||
accessKey, err := getAccessKey(config, env)
|
||||
if err != nil {
|
||||
return client, err
|
||||
}
|
||||
|
||||
storageClient, err := storage.NewClient(storageAccountName, accessKey, env.StorageEndpointSuffix,
|
||||
storageClient, err := storage.NewClient(config.StorageAccountName, accessKey, env.StorageEndpointSuffix,
|
||||
storage.DefaultAPIVersion, true)
|
||||
if err != nil {
|
||||
return client, fmt.Errorf("Error creating storage client for storage account %q: %s", storageAccountName, err)
|
||||
return client, fmt.Errorf("Error creating storage client for storage account %q: %s", config.StorageAccountName, err)
|
||||
}
|
||||
|
||||
client = storageClient.GetBlobService()
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func getAccessKey(d *schema.ResourceData, storageAccountName string, env azure.Environment) (string, error) {
|
||||
if key, ok := d.GetOk("access_key"); ok {
|
||||
return key.(string), nil
|
||||
func getAccessKey(config BackendConfig, env azure.Environment) (string, error) {
|
||||
if config.AccessKey != "" {
|
||||
return config.AccessKey, nil
|
||||
}
|
||||
|
||||
resourceGroupName, rgOk := d.GetOk("resource_group_name")
|
||||
subscriptionID, subOk := d.GetOk("arm_subscription_id")
|
||||
clientID, clientIDOk := d.GetOk("arm_client_id")
|
||||
clientSecret, clientSecretOK := d.GetOk("arm_client_secret")
|
||||
tenantID, tenantIDOk := d.GetOk("arm_tenant_id")
|
||||
rgOk := config.ResourceGroupName != ""
|
||||
subOk := config.SubscriptionID != ""
|
||||
clientIDOk := config.ClientID != ""
|
||||
clientSecretOK := config.ClientSecret != ""
|
||||
tenantIDOk := config.TenantID != ""
|
||||
if !rgOk || !subOk || !clientIDOk || !clientSecretOK || !tenantIDOk {
|
||||
return "", fmt.Errorf("resource_group_name and credentials must be provided when access_key is absent")
|
||||
}
|
||||
|
||||
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, tenantID.(string))
|
||||
oauthConfig, err := adal.NewOAuthConfig(env.ActiveDirectoryEndpoint, config.TenantID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
spt, err := adal.NewServicePrincipalToken(*oauthConfig, clientID.(string), clientSecret.(string), env.ResourceManagerEndpoint)
|
||||
spt, err := adal.NewServicePrincipalToken(*oauthConfig, config.ClientID, config.ClientSecret, env.ResourceManagerEndpoint)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
accountsClient := armStorage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, subscriptionID.(string))
|
||||
accountsClient := armStorage.NewAccountsClientWithBaseURI(env.ResourceManagerEndpoint, config.SubscriptionID)
|
||||
accountsClient.Authorizer = autorest.NewBearerAuthorizer(spt)
|
||||
|
||||
keys, err := accountsClient.ListKeys(resourceGroupName.(string), storageAccountName)
|
||||
keys, err := accountsClient.ListKeys(config.ResourceGroupName, config.StorageAccountName)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error retrieving keys for storage account %q: %s", storageAccountName, err)
|
||||
return "", fmt.Errorf("Error retrieving keys for storage account %q: %s", config.StorageAccountName, err)
|
||||
}
|
||||
|
||||
if keys.Keys == nil {
|
||||
return "", fmt.Errorf("Nil key returned for storage account %q", storageAccountName)
|
||||
return "", fmt.Errorf("Nil key returned for storage account %q", config.StorageAccountName)
|
||||
}
|
||||
|
||||
accessKeys := *keys.Keys
|
||||
|
|
|
@ -33,6 +33,11 @@ func (c *RemoteClient) Get() (*remote.Payload, error) {
|
|||
containerReference := c.blobClient.GetContainerReference(c.containerName)
|
||||
blobReference := containerReference.GetBlobReference(c.keyName)
|
||||
options := &storage.GetBlobOptions{}
|
||||
|
||||
if c.leaseID != "" {
|
||||
options.LeaseID = c.leaseID
|
||||
}
|
||||
|
||||
blob, err := blobReference.Get(options)
|
||||
if err != nil {
|
||||
if storErr, ok := err.(storage.AzureStorageServiceError); ok {
|
||||
|
@ -63,6 +68,7 @@ func (c *RemoteClient) Get() (*remote.Payload, error) {
|
|||
}
|
||||
|
||||
func (c *RemoteClient) Put(data []byte) error {
|
||||
getOptions := &storage.GetBlobMetadataOptions{}
|
||||
setOptions := &storage.SetBlobPropertiesOptions{}
|
||||
putOptions := &storage.PutBlobOptions{}
|
||||
|
||||
|
@ -73,13 +79,26 @@ func (c *RemoteClient) Put(data []byte) error {
|
|||
blobReference.Properties.ContentLength = int64(len(data))
|
||||
|
||||
if c.leaseID != "" {
|
||||
getOptions.LeaseID = c.leaseID
|
||||
setOptions.LeaseID = c.leaseID
|
||||
putOptions.LeaseID = c.leaseID
|
||||
}
|
||||
|
||||
exists, err := blobReference.Exists()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if exists {
|
||||
err = blobReference.GetMetadata(getOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(data)
|
||||
|
||||
err := blobReference.CreateBlockBlobFromReader(reader, putOptions)
|
||||
err = blobReference.CreateBlockBlobFromReader(reader, putOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -177,7 +196,7 @@ func (c *RemoteClient) getLockInfo() (*state.LockInfo, error) {
|
|||
|
||||
raw := blobReference.Metadata[lockInfoMetaKey]
|
||||
if raw == "" {
|
||||
return nil, fmt.Errorf("blob metadata %s was empty", lockInfoMetaKey)
|
||||
return nil, fmt.Errorf("blob metadata %q was empty", lockInfoMetaKey)
|
||||
}
|
||||
|
||||
data, err := base64.StdEncoding.DecodeString(raw)
|
||||
|
@ -198,7 +217,9 @@ func (c *RemoteClient) getLockInfo() (*state.LockInfo, error) {
|
|||
func (c *RemoteClient) writeLockInfo(info *state.LockInfo) error {
|
||||
containerReference := c.blobClient.GetContainerReference(c.containerName)
|
||||
blobReference := containerReference.GetBlobReference(c.keyName)
|
||||
err := blobReference.GetMetadata(&storage.GetBlobMetadataOptions{})
|
||||
err := blobReference.GetMetadata(&storage.GetBlobMetadataOptions{
|
||||
LeaseID: c.leaseID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -214,7 +235,6 @@ func (c *RemoteClient) writeLockInfo(info *state.LockInfo) error {
|
|||
LeaseID: c.leaseID,
|
||||
}
|
||||
return blobReference.SetMetadata(opts)
|
||||
|
||||
}
|
||||
|
||||
func (c *RemoteClient) Unlock(id string) error {
|
||||
|
|
|
@ -3,7 +3,9 @@ package azure
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/storage"
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/state/remote"
|
||||
)
|
||||
|
||||
|
@ -67,3 +69,75 @@ func TestRemoteClientLocks(t *testing.T) {
|
|||
|
||||
remote.TestRemoteLocks(t, s1.(*remote.State).Client, s2.(*remote.State).Client)
|
||||
}
|
||||
|
||||
func TestPutMaintainsMetaData(t *testing.T) {
|
||||
testACC(t)
|
||||
|
||||
keyName := "testState"
|
||||
headerName := "acceptancetest"
|
||||
expectedValue := "f3b56bad-33ad-4b93-a600-7a66e9cbd1eb"
|
||||
res := setupResources(t, keyName)
|
||||
defer destroyResources(t, res.resourceGroupName)
|
||||
|
||||
config := getBackendConfig(t, res)
|
||||
blobClient, err := getBlobClient(config)
|
||||
if err != nil {
|
||||
t.Fatalf("Error getting Blob Client: %+v", err)
|
||||
}
|
||||
|
||||
containerReference := blobClient.GetContainerReference(res.containerName)
|
||||
blobReference := containerReference.GetBlobReference(keyName)
|
||||
|
||||
err = blobReference.CreateBlockBlob(&storage.PutBlobOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Error Creating Block Blob: %+v", err)
|
||||
}
|
||||
|
||||
err = blobReference.GetMetadata(&storage.GetBlobMetadataOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Error loading MetaData: %+v", err)
|
||||
}
|
||||
|
||||
blobReference.Metadata[headerName] = expectedValue
|
||||
err = blobReference.SetMetadata(&storage.SetBlobMetadataOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Error setting MetaData: %+v", err)
|
||||
}
|
||||
|
||||
// update the metadata using the Backend
|
||||
remoteClient := RemoteClient{
|
||||
keyName: res.keyName,
|
||||
containerName: res.containerName,
|
||||
blobClient: blobClient,
|
||||
}
|
||||
|
||||
bytes := []byte(acctest.RandString(20))
|
||||
err = remoteClient.Put(bytes)
|
||||
if err != nil {
|
||||
t.Fatalf("Error putting data: %+v", err)
|
||||
}
|
||||
|
||||
// Verify it still exists
|
||||
err = blobReference.GetMetadata(&storage.GetBlobMetadataOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("Error loading MetaData: %+v", err)
|
||||
}
|
||||
|
||||
if blobReference.Metadata[headerName] != expectedValue {
|
||||
t.Fatalf("%q was not set to %q in the MetaData: %+v", headerName, expectedValue, blobReference.Metadata)
|
||||
}
|
||||
}
|
||||
|
||||
func getBackendConfig(t *testing.T, res testResources) BackendConfig {
|
||||
clients := getTestClient(t)
|
||||
return BackendConfig{
|
||||
ClientID: clients.clientID,
|
||||
ClientSecret: clients.clientSecret,
|
||||
Environment: clients.environment.Name,
|
||||
SubscriptionID: clients.subscriptionID,
|
||||
TenantID: clients.tenantID,
|
||||
|
||||
ResourceGroupName: res.resourceGroupName,
|
||||
StorageAccountName: res.storageAccountName,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ func TestBackendConfig(t *testing.T, b Backend, c map[string]interface{}) Backen
|
|||
// error ErrNamedStatesNotSupported, then it will not test that.
|
||||
//
|
||||
// If you want to test locking, two backends must be given. If b2 is nil,
|
||||
// then state lockign won't be tested.
|
||||
// then state locking won't be tested.
|
||||
func TestBackend(t *testing.T, b1, b2 Backend) {
|
||||
t.Helper()
|
||||
|
||||
|
|
Loading…
Reference in New Issue