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()