github.com/ns1/terraform@v0.7.10-0.20161109153551-8949419bef40/state/remote/azure.go (about) 1 package remote 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "os" 8 9 "github.com/Azure/azure-sdk-for-go/arm/storage" 10 mainStorage "github.com/Azure/azure-sdk-for-go/storage" 11 "github.com/Azure/go-autorest/autorest/azure" 12 riviera "github.com/jen20/riviera/azure" 13 ) 14 15 func azureFactory(conf map[string]string) (Client, error) { 16 storageAccountName, ok := conf["storage_account_name"] 17 if !ok { 18 return nil, fmt.Errorf("missing 'storage_account_name' configuration") 19 } 20 containerName, ok := conf["container_name"] 21 if !ok { 22 return nil, fmt.Errorf("missing 'container_name' configuration") 23 } 24 keyName, ok := conf["key"] 25 if !ok { 26 return nil, fmt.Errorf("missing 'key' configuration") 27 } 28 29 accessKey, ok := confOrEnv(conf, "access_key", "ARM_ACCESS_KEY") 30 if !ok { 31 resourceGroupName, ok := conf["resource_group_name"] 32 if !ok { 33 return nil, fmt.Errorf("missing 'resource_group' configuration") 34 } 35 36 var err error 37 accessKey, err = getStorageAccountAccessKey(conf, resourceGroupName, storageAccountName) 38 if err != nil { 39 return nil, fmt.Errorf("Couldn't read access key from storage account: %s.", err) 40 } 41 } 42 43 storageClient, err := mainStorage.NewBasicClient(storageAccountName, accessKey) 44 if err != nil { 45 return nil, fmt.Errorf("Error creating storage client for storage account %q: %s", storageAccountName, err) 46 } 47 48 blobClient := storageClient.GetBlobService() 49 50 return &AzureClient{ 51 blobClient: &blobClient, 52 containerName: containerName, 53 keyName: keyName, 54 }, nil 55 } 56 57 func getStorageAccountAccessKey(conf map[string]string, resourceGroupName, storageAccountName string) (string, error) { 58 creds, err := getCredentialsFromConf(conf) 59 if err != nil { 60 return "", err 61 } 62 63 oauthConfig, err := azure.PublicCloud.OAuthConfigForTenant(creds.TenantID) 64 if err != nil { 65 return "", err 66 } 67 if oauthConfig == nil { 68 return "", fmt.Errorf("Unable to configure OAuthConfig for tenant %s", creds.TenantID) 69 } 70 71 spt, err := azure.NewServicePrincipalToken(*oauthConfig, creds.ClientID, creds.ClientSecret, azure.PublicCloud.ResourceManagerEndpoint) 72 if err != nil { 73 return "", err 74 } 75 76 accountsClient := storage.NewAccountsClient(creds.SubscriptionID) 77 accountsClient.Authorizer = spt 78 79 keys, err := accountsClient.ListKeys(resourceGroupName, storageAccountName) 80 if err != nil { 81 return "", fmt.Errorf("Error retrieving keys for storage account %q: %s", storageAccountName, err) 82 } 83 84 if keys.Keys == nil { 85 return "", fmt.Errorf("Nil key returned for storage account %q", storageAccountName) 86 } 87 88 accessKeys := *keys.Keys 89 return *accessKeys[0].KeyName, nil 90 } 91 92 func getCredentialsFromConf(conf map[string]string) (*riviera.AzureResourceManagerCredentials, error) { 93 subscriptionID, ok := confOrEnv(conf, "arm_subscription_id", "ARM_SUBSCRIPTION_ID") 94 if !ok { 95 return nil, fmt.Errorf("missing 'arm_subscription_id' configuration") 96 } 97 clientID, ok := confOrEnv(conf, "arm_client_id", "ARM_CLIENT_ID") 98 if !ok { 99 return nil, fmt.Errorf("missing 'arm_client_id' configuration") 100 } 101 clientSecret, ok := confOrEnv(conf, "arm_client_secret", "ARM_CLIENT_SECRET") 102 if !ok { 103 return nil, fmt.Errorf("missing 'arm_client_secret' configuration") 104 } 105 tenantID, ok := confOrEnv(conf, "arm_tenant_id", "ARM_TENANT_ID") 106 if !ok { 107 return nil, fmt.Errorf("missing 'arm_tenant_id' configuration") 108 } 109 110 return &riviera.AzureResourceManagerCredentials{ 111 SubscriptionID: subscriptionID, 112 ClientID: clientID, 113 ClientSecret: clientSecret, 114 TenantID: tenantID, 115 }, nil 116 } 117 118 func confOrEnv(conf map[string]string, confKey, envVar string) (string, bool) { 119 value, ok := conf[confKey] 120 if ok { 121 return value, true 122 } 123 124 value = os.Getenv(envVar) 125 126 return value, value != "" 127 } 128 129 type AzureClient struct { 130 blobClient *mainStorage.BlobStorageClient 131 containerName string 132 keyName string 133 } 134 135 func (c *AzureClient) Get() (*Payload, error) { 136 blob, err := c.blobClient.GetBlob(c.containerName, c.keyName) 137 if err != nil { 138 if storErr, ok := err.(mainStorage.AzureStorageServiceError); ok { 139 if storErr.Code == "BlobNotFound" { 140 return nil, nil 141 } 142 } 143 return nil, err 144 } 145 146 defer blob.Close() 147 148 data, err := ioutil.ReadAll(blob) 149 if err != nil { 150 return nil, err 151 } 152 153 payload := &Payload{ 154 Data: data, 155 } 156 157 // If there was no data, then return nil 158 if len(payload.Data) == 0 { 159 return nil, nil 160 } 161 162 return payload, nil 163 } 164 165 func (c *AzureClient) Put(data []byte) error { 166 return c.blobClient.CreateBlockBlobFromReader( 167 c.containerName, 168 c.keyName, 169 uint64(len(data)), 170 bytes.NewReader(data), 171 map[string]string{ 172 "Content-Type": "application/json", 173 }, 174 ) 175 } 176 177 func (c *AzureClient) Delete() error { 178 return c.blobClient.DeleteBlob(c.containerName, c.keyName, nil) 179 }