github.com/danrjohnson/terraform@v0.7.0-rc2.0.20160627135212-d0fc1fa086ff/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.Key1 == nil { 85 return "", fmt.Errorf("Nil key returned for storage account %q", storageAccountName) 86 } 87 88 return *keys.Key1, nil 89 } 90 91 func getCredentialsFromConf(conf map[string]string) (*riviera.AzureResourceManagerCredentials, error) { 92 subscriptionID, ok := confOrEnv(conf, "arm_subscription_id", "ARM_SUBSCRIPTION_ID") 93 if !ok { 94 return nil, fmt.Errorf("missing 'arm_subscription_id' configuration") 95 } 96 clientID, ok := confOrEnv(conf, "arm_client_id", "ARM_CLIENT_ID") 97 if !ok { 98 return nil, fmt.Errorf("missing 'arm_client_id' configuration") 99 } 100 clientSecret, ok := confOrEnv(conf, "arm_client_secret", "ARM_CLIENT_SECRET") 101 if !ok { 102 return nil, fmt.Errorf("missing 'arm_client_secret' configuration") 103 } 104 tenantID, ok := confOrEnv(conf, "arm_tenant_id", "ARM_TENANT_ID") 105 if !ok { 106 return nil, fmt.Errorf("missing 'arm_tenant_id' configuration") 107 } 108 109 return &riviera.AzureResourceManagerCredentials{ 110 SubscriptionID: subscriptionID, 111 ClientID: clientID, 112 ClientSecret: clientSecret, 113 TenantID: tenantID, 114 }, nil 115 } 116 117 func confOrEnv(conf map[string]string, confKey, envVar string) (string, bool) { 118 value, ok := conf[confKey] 119 if ok { 120 return value, true 121 } 122 123 value = os.Getenv(envVar) 124 125 return value, value != "" 126 } 127 128 type AzureClient struct { 129 blobClient *mainStorage.BlobStorageClient 130 containerName string 131 keyName string 132 } 133 134 func (c *AzureClient) Get() (*Payload, error) { 135 blob, err := c.blobClient.GetBlob(c.containerName, c.keyName) 136 if err != nil { 137 if storErr, ok := err.(mainStorage.AzureStorageServiceError); ok { 138 if storErr.Code == "BlobNotFound" { 139 return nil, nil 140 } 141 } 142 return nil, err 143 } 144 145 defer blob.Close() 146 147 data, err := ioutil.ReadAll(blob) 148 if err != nil { 149 return nil, err 150 } 151 152 payload := &Payload{ 153 Data: data, 154 } 155 156 // If there was no data, then return nil 157 if len(payload.Data) == 0 { 158 return nil, nil 159 } 160 161 return payload, nil 162 } 163 164 func (c *AzureClient) Put(data []byte) error { 165 return c.blobClient.CreateBlockBlobFromReader( 166 c.containerName, 167 c.keyName, 168 uint64(len(data)), 169 bytes.NewReader(data), 170 map[string]string{ 171 "Content-Type": "application/json", 172 }, 173 ) 174 } 175 176 func (c *AzureClient) Delete() error { 177 return c.blobClient.DeleteBlob(c.containerName, c.keyName, nil) 178 }