terraform/builtin/providers/azurerm/provider.go

272 lines
9.7 KiB
Go
Raw Normal View History

package azurerm
import (
"fmt"
"reflect"
"strings"
"sync"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform/helper/mutexkv"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
riviera "github.com/jen20/riviera/azure"
)
// Provider returns a terraform.ResourceProvider.
func Provider() terraform.ResourceProvider {
var p *schema.Provider
p = &schema.Provider{
Schema: map[string]*schema.Schema{
"subscription_id": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("ARM_SUBSCRIPTION_ID", ""),
},
"client_id": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_ID", ""),
},
"client_secret": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("ARM_CLIENT_SECRET", ""),
},
"tenant_id": {
Type: schema.TypeString,
Required: true,
DefaultFunc: schema.EnvDefaultFunc("ARM_TENANT_ID", ""),
},
},
DataSourcesMap: map[string]*schema.Resource{
"azurerm_client_config": dataSourceArmClientConfig(),
},
ResourcesMap: map[string]*schema.Resource{
// These resources use the Azure ARM SDK
provider/azurerm: Add Load Balancer resources (#9199) * provider/azurerm: Add AzureRM Loadbalancer resource Adds support for the elusive Azure LoadBalancer * [x] `azurerm_lb` * [x] `azurerm_lb_backend_address_pool` * [x] `azurerm_lb_rule` * [x] `azurerm_lb_nat_rule` * [x] `azurerm_lb_probe` * [x] `azurerm_lb_nat_pool` Test Results: ``` make testacc TEST=./builtin/providers/azurerm TESTARGS='-run=TestAccAzureRMLoadbalancer' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) TF_ACC=1 go test ./builtin/providers/azurerm -v -run=TestAccAzureRMLoadbalancer -timeout 120m === RUN TestAccAzureRMLoadbalancerBackEndAddressPool_basic --- PASS: TestAccAzureRMLoadbalancerBackEndAddressPool_basic (207.26s) === RUN TestAccAzureRMLoadbalancerBackEndAddressPool_removal --- PASS: TestAccAzureRMLoadbalancerBackEndAddressPool_removal (165.89s) === RUN TestAccAzureRMLoadbalancerNatRule_basic --- PASS: TestAccAzureRMLoadbalancerNatRule_basic (179.30s) === RUN TestAccAzureRMLoadbalancerNatRule_removal --- PASS: TestAccAzureRMLoadbalancerNatRule_removal (180.73s) === RUN TestAccAzureRMLoadbalancerRule_basic --- PASS: TestAccAzureRMLoadbalancerRule_basic (170.40s) === RUN TestAccAzureRMLoadbalancerRule_removal --- PASS: TestAccAzureRMLoadbalancerRule_removal (204.23s) === RUN TestAccAzureRMLoadbalancer_basic --- PASS: TestAccAzureRMLoadbalancer_basic (136.03s) === RUN TestAccAzureRMLoadbalancer_frontEndConfig --- PASS: TestAccAzureRMLoadbalancer_frontEndConfig (214.47s) === RUN TestAccAzureRMLoadbalancer_tags --- PASS: TestAccAzureRMLoadbalancer_tags (215.52s) === RUN TestAccAzureRMLoadbalancerProbe_basic --- PASS: TestAccAzureRMLoadbalancerProbe_basic (183.36s) === RUN TestAccAzureRMLoadbalancerProbe_removal --- PASS: TestAccAzureRMLoadbalancerProbe_removal (185.86s) === RUN TestAccAzureRMLoadbalancerNatPool_basic --- PASS: TestAccAzureRMLoadbalancerNatPool_basic (161.47s) === RUN TestAccAzureRMLoadbalancerNatPool_removal --- PASS: TestAccAzureRMLoadbalancerNatPool_removal (167.38s) PASS ok github.com/hashicorp/terraform/builtin/providers/azurerm 1673.852s ``` * provider/azurerm: Documentation for the ARM LB resources
2016-10-07 20:14:26 +02:00
"azurerm_availability_set": resourceArmAvailabilitySet(),
"azurerm_cdn_endpoint": resourceArmCdnEndpoint(),
"azurerm_cdn_profile": resourceArmCdnProfile(),
"azurerm_eventhub": resourceArmEventHub(),
"azurerm_eventhub_namespace": resourceArmEventHubNamespace(),
provider/azurerm: Add Load Balancer resources (#9199) * provider/azurerm: Add AzureRM Loadbalancer resource Adds support for the elusive Azure LoadBalancer * [x] `azurerm_lb` * [x] `azurerm_lb_backend_address_pool` * [x] `azurerm_lb_rule` * [x] `azurerm_lb_nat_rule` * [x] `azurerm_lb_probe` * [x] `azurerm_lb_nat_pool` Test Results: ``` make testacc TEST=./builtin/providers/azurerm TESTARGS='-run=TestAccAzureRMLoadbalancer' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) TF_ACC=1 go test ./builtin/providers/azurerm -v -run=TestAccAzureRMLoadbalancer -timeout 120m === RUN TestAccAzureRMLoadbalancerBackEndAddressPool_basic --- PASS: TestAccAzureRMLoadbalancerBackEndAddressPool_basic (207.26s) === RUN TestAccAzureRMLoadbalancerBackEndAddressPool_removal --- PASS: TestAccAzureRMLoadbalancerBackEndAddressPool_removal (165.89s) === RUN TestAccAzureRMLoadbalancerNatRule_basic --- PASS: TestAccAzureRMLoadbalancerNatRule_basic (179.30s) === RUN TestAccAzureRMLoadbalancerNatRule_removal --- PASS: TestAccAzureRMLoadbalancerNatRule_removal (180.73s) === RUN TestAccAzureRMLoadbalancerRule_basic --- PASS: TestAccAzureRMLoadbalancerRule_basic (170.40s) === RUN TestAccAzureRMLoadbalancerRule_removal --- PASS: TestAccAzureRMLoadbalancerRule_removal (204.23s) === RUN TestAccAzureRMLoadbalancer_basic --- PASS: TestAccAzureRMLoadbalancer_basic (136.03s) === RUN TestAccAzureRMLoadbalancer_frontEndConfig --- PASS: TestAccAzureRMLoadbalancer_frontEndConfig (214.47s) === RUN TestAccAzureRMLoadbalancer_tags --- PASS: TestAccAzureRMLoadbalancer_tags (215.52s) === RUN TestAccAzureRMLoadbalancerProbe_basic --- PASS: TestAccAzureRMLoadbalancerProbe_basic (183.36s) === RUN TestAccAzureRMLoadbalancerProbe_removal --- PASS: TestAccAzureRMLoadbalancerProbe_removal (185.86s) === RUN TestAccAzureRMLoadbalancerNatPool_basic --- PASS: TestAccAzureRMLoadbalancerNatPool_basic (161.47s) === RUN TestAccAzureRMLoadbalancerNatPool_removal --- PASS: TestAccAzureRMLoadbalancerNatPool_removal (167.38s) PASS ok github.com/hashicorp/terraform/builtin/providers/azurerm 1673.852s ``` * provider/azurerm: Documentation for the ARM LB resources
2016-10-07 20:14:26 +02:00
"azurerm_lb": resourceArmLoadBalancer(),
"azurerm_lb_backend_address_pool": resourceArmLoadBalancerBackendAddressPool(),
"azurerm_lb_nat_rule": resourceArmLoadBalancerNatRule(),
"azurerm_lb_nat_pool": resourceArmLoadBalancerNatPool(),
"azurerm_lb_probe": resourceArmLoadBalancerProbe(),
"azurerm_lb_rule": resourceArmLoadBalancerRule(),
"azurerm_key_vault": resourceArmKeyVault(),
"azurerm_local_network_gateway": resourceArmLocalNetworkGateway(),
"azurerm_network_interface": resourceArmNetworkInterface(),
"azurerm_network_security_group": resourceArmNetworkSecurityGroup(),
"azurerm_network_security_rule": resourceArmNetworkSecurityRule(),
"azurerm_public_ip": resourceArmPublicIp(),
"azurerm_route": resourceArmRoute(),
"azurerm_route_table": resourceArmRouteTable(),
"azurerm_servicebus_namespace": resourceArmServiceBusNamespace(),
"azurerm_servicebus_subscription": resourceArmServiceBusSubscription(),
"azurerm_servicebus_topic": resourceArmServiceBusTopic(),
"azurerm_storage_account": resourceArmStorageAccount(),
"azurerm_storage_blob": resourceArmStorageBlob(),
"azurerm_storage_container": resourceArmStorageContainer(),
"azurerm_storage_share": resourceArmStorageShare(),
"azurerm_storage_queue": resourceArmStorageQueue(),
"azurerm_storage_table": resourceArmStorageTable(),
"azurerm_subnet": resourceArmSubnet(),
"azurerm_template_deployment": resourceArmTemplateDeployment(),
provider/azurerm: add traffic manager resources (#7826) * provider/azurerm: vendor arm/trafficmanager package * provider/azurerm: add azurerm_traffic_manager_profile resource * provider/azurerm: add azurerm_traffic_manager_endpoint resource * provider/azurerm: document traffic manager resources * provider/azurerm: use short type argument for traffic manager endpoint The resource now takes the short type for example azureEndpoints instead of the long form Microsoft.Network/TrafficManagerProfiles/azureEndpoints. ``` TF_ACC=1 go test ./builtin/providers/azurerm -v -run TestAccAzureRMTrafficManagerEndpoint -timeout 120m === RUN TestAccAzureRMTrafficManagerEndpoint_basic --- PASS: TestAccAzureRMTrafficManagerEndpoint_basic (179.72s) === RUN TestAccAzureRMTrafficManagerEndpoint_basicDisableExternal --- PASS: TestAccAzureRMTrafficManagerEndpoint_basicDisableExternal (171.36s) === RUN TestAccAzureRMTrafficManagerEndpoint_updateWeight --- PASS: TestAccAzureRMTrafficManagerEndpoint_updateWeight (167.24s) === RUN TestAccAzureRMTrafficManagerEndpoint_updatePriority --- PASS: TestAccAzureRMTrafficManagerEndpoint_updatePriority (192.91s) === RUN TestAccAzureRMTrafficManagerEndpoint_nestedEndpoints --- PASS: TestAccAzureRMTrafficManagerEndpoint_nestedEndpoints (111.18s) PASS ok github.com/hashicorp/terraform/builtin/providers/azurerm 822.534s ``` * provider/azurerm: remove unnecesary dereferences in traffic manager resources ``` TF_ACC=1 go test ./builtin/providers/azurerm -v -run TestAccAzureRMTrafficManager -timeout 120m === RUN TestAccAzureRMTrafficManagerEndpoint_basic --- PASS: TestAccAzureRMTrafficManagerEndpoint_basic (176.08s) === RUN TestAccAzureRMTrafficManagerEndpoint_basicDisableExternal --- PASS: TestAccAzureRMTrafficManagerEndpoint_basicDisableExternal (172.28s) === RUN TestAccAzureRMTrafficManagerEndpoint_updateWeight --- PASS: TestAccAzureRMTrafficManagerEndpoint_updateWeight (148.97s) === RUN TestAccAzureRMTrafficManagerEndpoint_updatePriority --- PASS: TestAccAzureRMTrafficManagerEndpoint_updatePriority (101.18s) === RUN TestAccAzureRMTrafficManagerEndpoint_nestedEndpoints --- PASS: TestAccAzureRMTrafficManagerEndpoint_nestedEndpoints (88.33s) === RUN TestAccAzureRMTrafficManagerProfile_weighted --- PASS: TestAccAzureRMTrafficManagerProfile_weighted (80.92s) === RUN TestAccAzureRMTrafficManagerProfile_performance --- PASS: TestAccAzureRMTrafficManagerProfile_performance (82.98s) === RUN TestAccAzureRMTrafficManagerProfile_priority --- PASS: TestAccAzureRMTrafficManagerProfile_priority (81.07s) === RUN TestAccAzureRMTrafficManagerProfile_withTags --- PASS: TestAccAzureRMTrafficManagerProfile_withTags (102.50s) PASS ok github.com/hashicorp/terraform/builtin/providers/azurerm 1034.458s ```
2016-08-01 00:46:15 +02:00
"azurerm_traffic_manager_endpoint": resourceArmTrafficManagerEndpoint(),
"azurerm_traffic_manager_profile": resourceArmTrafficManagerProfile(),
"azurerm_virtual_machine_extension": resourceArmVirtualMachineExtensions(),
"azurerm_virtual_machine": resourceArmVirtualMachine(),
"azurerm_virtual_machine_scale_set": resourceArmVirtualMachineScaleSet(),
"azurerm_virtual_network": resourceArmVirtualNetwork(),
"azurerm_virtual_network_peering": resourceArmVirtualNetworkPeering(),
// These resources use the Riviera SDK
"azurerm_dns_a_record": resourceArmDnsARecord(),
"azurerm_dns_aaaa_record": resourceArmDnsAAAARecord(),
"azurerm_dns_cname_record": resourceArmDnsCNameRecord(),
"azurerm_dns_mx_record": resourceArmDnsMxRecord(),
"azurerm_dns_ns_record": resourceArmDnsNsRecord(),
"azurerm_dns_srv_record": resourceArmDnsSrvRecord(),
"azurerm_dns_txt_record": resourceArmDnsTxtRecord(),
"azurerm_dns_zone": resourceArmDnsZone(),
"azurerm_resource_group": resourceArmResourceGroup(),
"azurerm_search_service": resourceArmSearchService(),
"azurerm_sql_database": resourceArmSqlDatabase(),
"azurerm_sql_firewall_rule": resourceArmSqlFirewallRule(),
"azurerm_sql_server": resourceArmSqlServer(),
},
}
p.ConfigureFunc = providerConfigure(p)
return p
}
// Config is the configuration structure used to instantiate a
// new Azure management client.
type Config struct {
ManagementURL string
SubscriptionID string
ClientID string
ClientSecret string
TenantID string
validateCredentialsOnce sync.Once
}
func (c *Config) validate() error {
var err *multierror.Error
if c.SubscriptionID == "" {
err = multierror.Append(err, fmt.Errorf("Subscription ID must be configured for the AzureRM provider"))
}
if c.ClientID == "" {
err = multierror.Append(err, fmt.Errorf("Client ID must be configured for the AzureRM provider"))
}
if c.ClientSecret == "" {
err = multierror.Append(err, fmt.Errorf("Client Secret must be configured for the AzureRM provider"))
}
if c.TenantID == "" {
err = multierror.Append(err, fmt.Errorf("Tenant ID must be configured for the AzureRM provider"))
}
return err.ErrorOrNil()
}
func providerConfigure(p *schema.Provider) schema.ConfigureFunc {
return func(d *schema.ResourceData) (interface{}, error) {
config := &Config{
SubscriptionID: d.Get("subscription_id").(string),
ClientID: d.Get("client_id").(string),
ClientSecret: d.Get("client_secret").(string),
TenantID: d.Get("tenant_id").(string),
}
if err := config.validate(); err != nil {
return nil, err
}
client, err := config.getArmClient()
if err != nil {
return nil, err
}
client.StopContext = p.StopContext()
err = registerAzureResourceProvidersWithSubscription(client.rivieraClient)
if err != nil {
return nil, err
}
return client, nil
}
}
func registerProviderWithSubscription(providerName string, client *riviera.Client) error {
request := client.NewRequest()
request.Command = riviera.RegisterResourceProvider{
Namespace: providerName,
}
response, err := request.Execute()
if err != nil {
return fmt.Errorf("Cannot request provider registration for Azure Resource Manager: %s.", err)
}
if !response.IsSuccessful() {
return fmt.Errorf("Credentials for accessing 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 nil
}
var providerRegistrationOnce sync.Once
// registerAzureResourceProvidersWithSubscription uses the providers client to register
// all Azure resource providers which the Terraform provider may require (regardless of
// whether they are actually used by the configuration or not). It was confirmed by Microsoft
// that this is the approach their own internal tools also take.
func registerAzureResourceProvidersWithSubscription(client *riviera.Client) error {
var err error
providerRegistrationOnce.Do(func() {
// We register Microsoft.Compute during client initialization
providers := []string{"Microsoft.Network", "Microsoft.Cdn", "Microsoft.Storage", "Microsoft.Sql", "Microsoft.Search", "Microsoft.Resources", "Microsoft.ServiceBus", "Microsoft.KeyVault", "Microsoft.EventHub"}
var wg sync.WaitGroup
wg.Add(len(providers))
for _, providerName := range providers {
go func(p string) {
defer wg.Done()
if innerErr := registerProviderWithSubscription(p, client); err != nil {
err = innerErr
}
}(providerName)
}
wg.Wait()
})
return err
}
// azureRMNormalizeLocation is a function which normalises human-readable region/location
// names (e.g. "West US") to the values used and returned by the Azure API (e.g. "westus").
// In state we track the API internal version as it is easier to go from the human form
// to the canonical form than the other way around.
func azureRMNormalizeLocation(location interface{}) string {
input := location.(string)
return strings.Replace(strings.ToLower(input), " ", "", -1)
}
// armMutexKV is the instance of MutexKV for ARM resources
var armMutexKV = mutexkv.NewMutexKV()
func azureStateRefreshFunc(resourceURI string, client *ArmClient, command riviera.APICall) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
req := client.rivieraClient.NewRequestForURI(resourceURI)
req.Command = command
res, err := req.Execute()
if err != nil {
return nil, "", fmt.Errorf("Error executing %T command in azureStateRefreshFunc", req.Command)
}
var value reflect.Value
if reflect.ValueOf(res.Parsed).Kind() == reflect.Ptr {
value = reflect.ValueOf(res.Parsed).Elem()
} else {
value = reflect.ValueOf(res.Parsed)
}
for i := 0; i < value.NumField(); i++ { // iterates through every struct type field
tag := value.Type().Field(i).Tag // returns the tag string
tagValue := tag.Get("mapstructure")
if tagValue == "provisioningState" {
return res.Parsed, value.Field(i).Elem().String(), nil
}
}
panic(fmt.Errorf("azureStateRefreshFunc called on structure %T with no mapstructure:provisioningState tag. This is a bug", res.Parsed))
}
}
// Resource group names can be capitalised, but we store them in lowercase.
// Use a custom diff function to avoid creation of new resources.
func resourceAzurermResourceGroupNameDiffSuppress(k, old, new string, d *schema.ResourceData) bool {
return strings.ToLower(old) == strings.ToLower(new)
}