github.com/jsoriano/terraform@v0.6.7-0.20151026070445-8b70867fdd95/builtin/providers/aws/provider.go (about)

     1  package aws
     2  
     3  import (
     4  	"net"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/aws/aws-sdk-go/aws/credentials"
     9  	"github.com/awslabs/aws-sdk-go/aws/credentials/ec2rolecreds"
    10  	"github.com/hashicorp/terraform/helper/hashcode"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  	"github.com/hashicorp/terraform/terraform"
    13  )
    14  
    15  // Provider returns a terraform.ResourceProvider.
    16  func Provider() terraform.ResourceProvider {
    17  	// TODO: Move the validation to this, requires conditional schemas
    18  	// TODO: Move the configuration to this, requires validation
    19  
    20  	// These variables are closed within the `getCreds` function below.
    21  	// This function is responsible for reading credentials from the
    22  	// environment in the case that they're not explicitly specified
    23  	// in the Terraform configuration.
    24  	//
    25  	// By using the getCreds function here instead of making the default
    26  	// empty, we avoid asking for input on credentials if they're available
    27  	// in the environment.
    28  	var credVal credentials.Value
    29  	var credErr error
    30  	var once sync.Once
    31  	getCreds := func() {
    32  		// Build the list of providers to look for creds in
    33  		providers := []credentials.Provider{
    34  			&credentials.EnvProvider{},
    35  			&credentials.SharedCredentialsProvider{},
    36  		}
    37  
    38  		// We only look in the EC2 metadata API if we can connect
    39  		// to the metadata service within a reasonable amount of time
    40  		conn, err := net.DialTimeout("tcp", "169.254.169.254:80", 100*time.Millisecond)
    41  		if err == nil {
    42  			conn.Close()
    43  			providers = append(providers, &ec2rolecreds.EC2RoleProvider{})
    44  		}
    45  
    46  		credVal, credErr = credentials.NewChainCredentials(providers).Get()
    47  
    48  		// If we didn't successfully find any credentials, just
    49  		// set the error to nil.
    50  		if credErr == credentials.ErrNoValidProvidersFoundInChain {
    51  			credErr = nil
    52  		}
    53  	}
    54  
    55  	// getCredDefault is a function used by DefaultFunc below to
    56  	// get the default value for various parts of the credentials.
    57  	// This function properly handles loading the credentials, checking
    58  	// for errors, etc.
    59  	getCredDefault := func(def interface{}, f func() string) (interface{}, error) {
    60  		once.Do(getCreds)
    61  
    62  		// If there was an error, that is always first
    63  		if credErr != nil {
    64  			return nil, credErr
    65  		}
    66  
    67  		// If the value is empty string, return nil (not set)
    68  		val := f()
    69  		if val == "" {
    70  			return def, nil
    71  		}
    72  
    73  		return val, nil
    74  	}
    75  
    76  	// The actual provider
    77  	return &schema.Provider{
    78  		Schema: map[string]*schema.Schema{
    79  			"access_key": &schema.Schema{
    80  				Type:     schema.TypeString,
    81  				Required: true,
    82  				DefaultFunc: func() (interface{}, error) {
    83  					return getCredDefault(nil, func() string {
    84  						return credVal.AccessKeyID
    85  					})
    86  				},
    87  				Description: descriptions["access_key"],
    88  			},
    89  
    90  			"secret_key": &schema.Schema{
    91  				Type:     schema.TypeString,
    92  				Required: true,
    93  				DefaultFunc: func() (interface{}, error) {
    94  					return getCredDefault(nil, func() string {
    95  						return credVal.SecretAccessKey
    96  					})
    97  				},
    98  				Description: descriptions["secret_key"],
    99  			},
   100  
   101  			"token": &schema.Schema{
   102  				Type:     schema.TypeString,
   103  				Optional: true,
   104  				DefaultFunc: func() (interface{}, error) {
   105  					return getCredDefault("", func() string {
   106  						return credVal.SessionToken
   107  					})
   108  				},
   109  				Description: descriptions["token"],
   110  			},
   111  
   112  			"region": &schema.Schema{
   113  				Type:     schema.TypeString,
   114  				Required: true,
   115  				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
   116  					"AWS_REGION",
   117  					"AWS_DEFAULT_REGION",
   118  				}, nil),
   119  				Description:  descriptions["region"],
   120  				InputDefault: "us-east-1",
   121  			},
   122  
   123  			"max_retries": &schema.Schema{
   124  				Type:        schema.TypeInt,
   125  				Optional:    true,
   126  				Default:     11,
   127  				Description: descriptions["max_retries"],
   128  			},
   129  
   130  			"allowed_account_ids": &schema.Schema{
   131  				Type:          schema.TypeSet,
   132  				Elem:          &schema.Schema{Type: schema.TypeString},
   133  				Optional:      true,
   134  				ConflictsWith: []string{"forbidden_account_ids"},
   135  				Set: func(v interface{}) int {
   136  					return hashcode.String(v.(string))
   137  				},
   138  			},
   139  
   140  			"forbidden_account_ids": &schema.Schema{
   141  				Type:          schema.TypeSet,
   142  				Elem:          &schema.Schema{Type: schema.TypeString},
   143  				Optional:      true,
   144  				ConflictsWith: []string{"allowed_account_ids"},
   145  				Set: func(v interface{}) int {
   146  					return hashcode.String(v.(string))
   147  				},
   148  			},
   149  
   150  			"dynamodb_endpoint": &schema.Schema{
   151  				Type:        schema.TypeString,
   152  				Optional:    true,
   153  				Default:     "",
   154  				Description: descriptions["dynamodb_endpoint"],
   155  			},
   156  		},
   157  
   158  		ResourcesMap: map[string]*schema.Resource{
   159  			"aws_ami":                          resourceAwsAmi(),
   160  			"aws_ami_copy":                     resourceAwsAmiCopy(),
   161  			"aws_ami_from_instance":            resourceAwsAmiFromInstance(),
   162  			"aws_app_cookie_stickiness_policy": resourceAwsAppCookieStickinessPolicy(),
   163  			"aws_autoscaling_group":            resourceAwsAutoscalingGroup(),
   164  			"aws_autoscaling_notification":     resourceAwsAutoscalingNotification(),
   165  			"aws_autoscaling_policy":           resourceAwsAutoscalingPolicy(),
   166  			"aws_cloudwatch_log_group":         resourceAwsCloudWatchLogGroup(),
   167  			"aws_autoscaling_lifecycle_hook":   resourceAwsAutoscalingLifecycleHook(),
   168  			"aws_cloudwatch_metric_alarm":      resourceAwsCloudWatchMetricAlarm(),
   169  			"aws_codedeploy_app":               resourceAwsCodeDeployApp(),
   170  			"aws_codedeploy_deployment_group":  resourceAwsCodeDeployDeploymentGroup(),
   171  			"aws_customer_gateway":             resourceAwsCustomerGateway(),
   172  			"aws_db_instance":                  resourceAwsDbInstance(),
   173  			"aws_db_parameter_group":           resourceAwsDbParameterGroup(),
   174  			"aws_db_security_group":            resourceAwsDbSecurityGroup(),
   175  			"aws_db_subnet_group":              resourceAwsDbSubnetGroup(),
   176  			"aws_directory_service_directory":  resourceAwsDirectoryServiceDirectory(),
   177  			"aws_dynamodb_table":               resourceAwsDynamoDbTable(),
   178  			"aws_ebs_volume":                   resourceAwsEbsVolume(),
   179  			"aws_ecs_cluster":                  resourceAwsEcsCluster(),
   180  			"aws_ecs_service":                  resourceAwsEcsService(),
   181  			"aws_ecs_task_definition":          resourceAwsEcsTaskDefinition(),
   182  			"aws_efs_file_system":              resourceAwsEfsFileSystem(),
   183  			"aws_efs_mount_target":             resourceAwsEfsMountTarget(),
   184  			"aws_eip":                          resourceAwsEip(),
   185  			"aws_elasticache_cluster":          resourceAwsElasticacheCluster(),
   186  			"aws_elasticache_parameter_group":  resourceAwsElasticacheParameterGroup(),
   187  			"aws_elasticache_security_group":   resourceAwsElasticacheSecurityGroup(),
   188  			"aws_elasticache_subnet_group":     resourceAwsElasticacheSubnetGroup(),
   189  			"aws_elasticsearch_domain":         resourceAwsElasticSearchDomain(),
   190  			"aws_elb":                          resourceAwsElb(),
   191  			"aws_flow_log":                     resourceAwsFlowLog(),
   192  			"aws_glacier_vault":                resourceAwsGlacierVault(),
   193  			"aws_iam_access_key":               resourceAwsIamAccessKey(),
   194  			"aws_iam_group_policy":             resourceAwsIamGroupPolicy(),
   195  			"aws_iam_group":                    resourceAwsIamGroup(),
   196  			"aws_iam_group_membership":         resourceAwsIamGroupMembership(),
   197  			"aws_iam_instance_profile":         resourceAwsIamInstanceProfile(),
   198  			"aws_iam_policy":                   resourceAwsIamPolicy(),
   199  			"aws_iam_policy_attachment":        resourceAwsIamPolicyAttachment(),
   200  			"aws_iam_role_policy":              resourceAwsIamRolePolicy(),
   201  			"aws_iam_role":                     resourceAwsIamRole(),
   202  			"aws_iam_saml_provider":            resourceAwsIamSamlProvider(),
   203  			"aws_iam_server_certificate":       resourceAwsIAMServerCertificate(),
   204  			"aws_iam_user_policy":              resourceAwsIamUserPolicy(),
   205  			"aws_iam_user":                     resourceAwsIamUser(),
   206  			"aws_instance":                     resourceAwsInstance(),
   207  			"aws_internet_gateway":             resourceAwsInternetGateway(),
   208  			"aws_key_pair":                     resourceAwsKeyPair(),
   209  			"aws_kinesis_stream":               resourceAwsKinesisStream(),
   210  			"aws_lambda_function":              resourceAwsLambdaFunction(),
   211  			"aws_launch_configuration":         resourceAwsLaunchConfiguration(),
   212  			"aws_lb_cookie_stickiness_policy":  resourceAwsLBCookieStickinessPolicy(),
   213  			"aws_main_route_table_association": resourceAwsMainRouteTableAssociation(),
   214  			"aws_network_acl":                  resourceAwsNetworkAcl(),
   215  			"aws_network_interface":            resourceAwsNetworkInterface(),
   216  			"aws_opsworks_stack":               resourceAwsOpsworksStack(),
   217  			"aws_opsworks_java_app_layer":      resourceAwsOpsworksJavaAppLayer(),
   218  			"aws_opsworks_haproxy_layer":       resourceAwsOpsworksHaproxyLayer(),
   219  			"aws_opsworks_static_web_layer":    resourceAwsOpsworksStaticWebLayer(),
   220  			"aws_opsworks_php_app_layer":       resourceAwsOpsworksPhpAppLayer(),
   221  			"aws_opsworks_rails_app_layer":     resourceAwsOpsworksRailsAppLayer(),
   222  			"aws_opsworks_nodejs_app_layer":    resourceAwsOpsworksNodejsAppLayer(),
   223  			"aws_opsworks_memcached_layer":     resourceAwsOpsworksMemcachedLayer(),
   224  			"aws_opsworks_mysql_layer":         resourceAwsOpsworksMysqlLayer(),
   225  			"aws_opsworks_ganglia_layer":       resourceAwsOpsworksGangliaLayer(),
   226  			"aws_opsworks_custom_layer":        resourceAwsOpsworksCustomLayer(),
   227  			"aws_placement_group":              resourceAwsPlacementGroup(),
   228  			"aws_proxy_protocol_policy":        resourceAwsProxyProtocolPolicy(),
   229  			"aws_rds_cluster":                  resourceAwsRDSCluster(),
   230  			"aws_rds_cluster_instance":         resourceAwsRDSClusterInstance(),
   231  			"aws_route53_delegation_set":       resourceAwsRoute53DelegationSet(),
   232  			"aws_route53_record":               resourceAwsRoute53Record(),
   233  			"aws_route53_zone_association":     resourceAwsRoute53ZoneAssociation(),
   234  			"aws_route53_zone":                 resourceAwsRoute53Zone(),
   235  			"aws_route53_health_check":         resourceAwsRoute53HealthCheck(),
   236  			"aws_route_table":                  resourceAwsRouteTable(),
   237  			"aws_route_table_association":      resourceAwsRouteTableAssociation(),
   238  			"aws_s3_bucket":                    resourceAwsS3Bucket(),
   239  			"aws_s3_bucket_object":             resourceAwsS3BucketObject(),
   240  			"aws_security_group":               resourceAwsSecurityGroup(),
   241  			"aws_security_group_rule":          resourceAwsSecurityGroupRule(),
   242  			"aws_spot_instance_request":        resourceAwsSpotInstanceRequest(),
   243  			"aws_sqs_queue":                    resourceAwsSqsQueue(),
   244  			"aws_sns_topic":                    resourceAwsSnsTopic(),
   245  			"aws_sns_topic_subscription":       resourceAwsSnsTopicSubscription(),
   246  			"aws_subnet":                       resourceAwsSubnet(),
   247  			"aws_volume_attachment":            resourceAwsVolumeAttachment(),
   248  			"aws_vpc_dhcp_options_association": resourceAwsVpcDhcpOptionsAssociation(),
   249  			"aws_vpc_dhcp_options":             resourceAwsVpcDhcpOptions(),
   250  			"aws_vpc_peering_connection":       resourceAwsVpcPeeringConnection(),
   251  			"aws_vpc":                          resourceAwsVpc(),
   252  			"aws_vpc_endpoint":                 resourceAwsVpcEndpoint(),
   253  			"aws_vpn_connection":               resourceAwsVpnConnection(),
   254  			"aws_vpn_connection_route":         resourceAwsVpnConnectionRoute(),
   255  			"aws_vpn_gateway":                  resourceAwsVpnGateway(),
   256  		},
   257  
   258  		ConfigureFunc: providerConfigure,
   259  	}
   260  }
   261  
   262  var descriptions map[string]string
   263  
   264  func init() {
   265  	descriptions = map[string]string{
   266  		"region": "The region where AWS operations will take place. Examples\n" +
   267  			"are us-east-1, us-west-2, etc.",
   268  
   269  		"access_key": "The access key for API operations. You can retrieve this\n" +
   270  			"from the 'Security & Credentials' section of the AWS console.",
   271  
   272  		"secret_key": "The secret key for API operations. You can retrieve this\n" +
   273  			"from the 'Security & Credentials' section of the AWS console.",
   274  
   275  		"token": "session token. A session token is only required if you are\n" +
   276  			"using temporary security credentials.",
   277  
   278  		"max_retries": "The maximum number of times an AWS API request is\n" +
   279  			"being executed. If the API request still fails, an error is\n" +
   280  			"thrown.",
   281  
   282  		"dynamodb_endpoint": "Use this to override the default endpoint URL constructed from the `region`.\n" +
   283  			"It's typically used to connect to dynamodb-local.",
   284  	}
   285  }
   286  
   287  func providerConfigure(d *schema.ResourceData) (interface{}, error) {
   288  	config := Config{
   289  		AccessKey:        d.Get("access_key").(string),
   290  		SecretKey:        d.Get("secret_key").(string),
   291  		Token:            d.Get("token").(string),
   292  		Region:           d.Get("region").(string),
   293  		MaxRetries:       d.Get("max_retries").(int),
   294  		DynamoDBEndpoint: d.Get("dynamodb_endpoint").(string),
   295  	}
   296  
   297  	if v, ok := d.GetOk("allowed_account_ids"); ok {
   298  		config.AllowedAccountIds = v.(*schema.Set).List()
   299  	}
   300  
   301  	if v, ok := d.GetOk("forbidden_account_ids"); ok {
   302  		config.ForbiddenAccountIds = v.(*schema.Set).List()
   303  	}
   304  
   305  	return config.Client()
   306  }