github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/builtin/providers/aws/provider.go (about)

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