providers/aws/aws_provider.go (296 lines of code) (raw):
// Copyright 2018 The Terraformer Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package aws
import (
"os"
"strconv"
"github.com/GoogleCloudPlatform/terraformer/terraformutils"
"github.com/pkg/errors"
"github.com/zclconf/go-cty/cty"
)
type AWSProvider struct { //nolint
terraformutils.Provider
region string
profile string
}
const GlobalRegion = "aws-global"
const MainRegionPublicPartition = "us-east-1"
const NoRegion = ""
// SupportedGlobalResources should be bound to a default region. AWS doesn't specify in which region default services are
// placed (see https://docs.aws.amazon.com/general/latest/gr/rande.html), so we shouldn't assume any region as well
var SupportedGlobalResources = []string{
"budgets",
"cloudfront",
"ecrpublic",
"iam",
"organization",
"route53",
"waf",
}
// SupportedEastOnlyResources should be bound to us-east-1 region only, and does not work in any other region.
var SupportedEastOnlyResources = []string{
"wafv2_cloudfront",
}
func (p AWSProvider) GetResourceConnections() map[string]map[string][]string {
return map[string]map[string][]string{
"alb": {
"sg": []string{"security_groups", "id"},
"subnet": []string{"subnets", "id"},
"alb": []string{
"load_balancer_arn", "id",
"listener_arn", "id",
// TF ALB TG attachment logic doesn't work well with references (doesn't interpolate)
},
},
"auto_scaling": {
"sg": []string{"security_groups", "id"},
"subnet": []string{"vpc_zone_identifier", "id"},
},
"ec2_instance": {
"sg": []string{"vpc_security_group_ids", "id"},
"subnet": []string{"subnet_id", "id"},
"ebs": []string{"ebs_block_device", "id"},
},
"elasticache": {
"vpc": []string{"vpc_id", "id"},
"subnet": []string{"subnet_ids", "id"},
"sg": []string{"security_group_ids", "id"},
},
"ebs": {
// TF EBS attachment logic doesn't work well with references (doesn't interpolate)
},
"ecs": {
// ECS is not able anymore to support references (doesn't interpolate)
"subnet": []string{"network_configuration.subnets", "id"},
"sg": []string{"network_configuration.security_groups", "id"},
},
"eks": {
"subnet": []string{"vpc_config.subnet_ids", "id"},
"sg": []string{"vpc_config.security_group_ids", "id"},
},
"elb": {
"sg": []string{"security_groups", "id"},
"subnet": []string{"subnets", "id"},
},
"igw": {"vpc": []string{"vpc_id", "id"}},
"identitystore": {
"identitystore": []string{
"group_id", "id",
"member_id", "id",
},
},
"msk": {
"subnet": []string{"broker_node_group_info.client_subnets", "id"},
"sg": []string{"broker_node_group_info.security_groups", "id"},
},
"nacl": {
"subnet": []string{"subnet_ids", "id"},
"vpc": []string{"vpc_id", "id"},
},
"organization": {
"organization": []string{
"policy_id", "id",
"parent_id", "id",
"target_id", "id",
},
},
"rds": {
"subnet": []string{"subnet_ids", "id"},
"sg": []string{"vpc_security_group_ids", "id"},
},
"route_table": {
"route_table": []string{"route_table_id", "id"},
"subnet": []string{"subnet_id", "id"},
"vpc": []string{"vpc_id", "id"},
},
"sns": {
"sns": []string{"topic_arn", "id"},
"sqs": []string{"endpoint", "arn"},
},
"sg": {
"sg": []string{
"egress.security_groups", "id",
"ingress.security_groups", "id",
"security_group_id", "id",
"source_security_group_id", "id",
},
},
"subnet": {"vpc": []string{"vpc_id", "id"}},
"transit_gateway": {
"vpc": []string{"vpc_id", "id"},
"transit_gateway": []string{"transit_gateway_id", "id"},
"subnet": []string{"subnet_ids", "id"},
"vpn_connection": []string{"vpn_connection_id", "id"},
},
"vpn_gateway": {"vpc": []string{"vpc_id", "id"}},
"vpn_connection": {
"customer_gateway": []string{"customer_gateway_id", "id"},
"vpn_gateway": []string{"vpn_gateway_id", "id"},
},
}
}
func (p AWSProvider) GetProviderData(arg ...string) map[string]interface{} {
awsConfig := map[string]interface{}{}
if p.region == GlobalRegion {
awsConfig["region"] = MainRegionPublicPartition // For TF to workaround terraform-providers/terraform-provider-aws#1043
} else if p.region != NoRegion {
awsConfig["region"] = p.region
}
return map[string]interface{}{
"provider": map[string]interface{}{
"aws": awsConfig,
},
}
}
func (p *AWSProvider) GetConfig() cty.Value {
if p.region != GlobalRegion {
return cty.ObjectVal(map[string]cty.Value{
"region": cty.StringVal(p.region),
"skip_region_validation": cty.True,
})
}
return cty.ObjectVal(map[string]cty.Value{
"region": cty.StringVal(""),
"skip_region_validation": cty.True,
})
}
func (p *AWSProvider) GetBasicConfig() cty.Value {
return p.GetConfig()
}
// check projectName in env params
func (p *AWSProvider) Init(args []string) error {
p.region = args[0]
p.profile = args[1]
// Terraformer accepts region and profile configuration, so we must detect what env variables to adjust to make Go SDK rely on them. AWS_SDK_LOAD_CONFIG here must be checked to determine correct variable to set.
enableSharedConfig, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG"))
var err error
if p.region != GlobalRegion && p.region != NoRegion {
if enableSharedConfig {
err = os.Setenv("AWS_DEFAULT_REGION", p.region)
} else {
err = os.Setenv("AWS_REGION", p.region)
}
if err != nil {
return err
}
}
if p.profile != "" && p.profile != "default" {
envVar := "AWS_PROFILE"
if enableSharedConfig {
envVar = "AWS_DEFAULT_PROFILE"
}
if err := os.Setenv(envVar, p.profile); err != nil {
return err
}
}
return nil
}
func (p *AWSProvider) GetName() string {
return "aws"
}
func (p *AWSProvider) InitService(serviceName string, verbose bool) error {
var isSupported bool
if _, isSupported = p.GetSupportedService()[serviceName]; !isSupported {
return errors.New("aws: " + serviceName + " not supported service")
}
p.Service = p.GetSupportedService()[serviceName]
p.Service.SetName(serviceName)
p.Service.SetVerbose(verbose)
p.Service.SetProviderName(p.GetName())
p.Service.SetArgs(map[string]interface{}{
"region": p.region,
"profile": p.profile,
"skip_region_validation": true,
})
return nil
}
// GetAWSSupportService return map of support service for AWS
func (p *AWSProvider) GetSupportedService() map[string]terraformutils.ServiceGenerator {
return map[string]terraformutils.ServiceGenerator{
"accessanalyzer": &AwsFacade{service: &AccessAnalyzerGenerator{}},
"acm": &AwsFacade{service: &ACMGenerator{}},
"alb": &AwsFacade{service: &AlbGenerator{}},
"api_gateway": &AwsFacade{service: &APIGatewayGenerator{}},
"api_gatewayv2": &AwsFacade{service: &APIGatewayV2Generator{}},
"appsync": &AwsFacade{service: &AppSyncGenerator{}},
"auto_scaling": &AwsFacade{service: &AutoScalingGenerator{}},
"batch": &AwsFacade{service: &BatchGenerator{}},
"budgets": &AwsFacade{service: &BudgetsGenerator{}},
"cloud9": &AwsFacade{service: &Cloud9Generator{}},
"cloudformation": &AwsFacade{service: &CloudFormationGenerator{}},
"cloudfront": &AwsFacade{service: &CloudFrontGenerator{}},
"cloudhsm": &AwsFacade{service: &CloudHsmGenerator{}},
"cloudtrail": &AwsFacade{service: &CloudTrailGenerator{}},
"cloudwatch": &AwsFacade{service: &CloudWatchGenerator{}},
"codebuild": &AwsFacade{service: &CodeBuildGenerator{}},
"codecommit": &AwsFacade{service: &CodeCommitGenerator{}},
"codedeploy": &AwsFacade{service: &CodeDeployGenerator{}},
"codepipeline": &AwsFacade{service: &CodePipelineGenerator{}},
"cognito": &AwsFacade{service: &CognitoGenerator{}},
"config": &AwsFacade{service: &ConfigGenerator{}},
"customer_gateway": &AwsFacade{service: &CustomerGatewayGenerator{}},
"datapipeline": &AwsFacade{service: &DataPipelineGenerator{}},
"devicefarm": &AwsFacade{service: &DeviceFarmGenerator{}},
"docdb": &AwsFacade{service: &DocDBGenerator{}},
"dx": &AwsFacade{service: &DirectConnectGenerator{}},
"dynamodb": &AwsFacade{service: &DynamoDbGenerator{}},
"ebs": &AwsFacade{service: &EbsGenerator{}},
"ec2_instance": &AwsFacade{service: &Ec2Generator{}},
"ecr": &AwsFacade{service: &EcrGenerator{}},
"ecrpublic": &AwsFacade{service: &EcrPublicGenerator{}},
"ecs": &AwsFacade{service: &EcsGenerator{}},
"efs": &AwsFacade{service: &EfsGenerator{}},
"eks": &AwsFacade{service: &EksGenerator{}},
"eip": &AwsFacade{service: &ElasticIPGenerator{}},
"elasticache": &AwsFacade{service: &ElastiCacheGenerator{}},
"elastic_beanstalk": &AwsFacade{service: &BeanstalkGenerator{}},
"elb": &AwsFacade{service: &ElbGenerator{}},
"emr": &AwsFacade{service: &EmrGenerator{}},
"eni": &AwsFacade{service: &EniGenerator{}},
"es": &AwsFacade{service: &EsGenerator{}},
"firehose": &AwsFacade{service: &FirehoseGenerator{}},
"glue": &AwsFacade{service: &GlueGenerator{}},
"iam": &AwsFacade{service: &IamGenerator{}},
"identitystore": &AwsFacade{service: &IdentityStoreGenerator{}},
"igw": &AwsFacade{service: &IgwGenerator{}},
"iot": &AwsFacade{service: &IotGenerator{}},
"kinesis": &AwsFacade{service: &KinesisGenerator{}},
"kms": &AwsFacade{service: &KmsGenerator{}},
"lambda": &AwsFacade{service: &LambdaGenerator{}},
"logs": &AwsFacade{service: &LogsGenerator{}},
"media_package": &AwsFacade{service: &MediaPackageGenerator{}},
"media_store": &AwsFacade{service: &MediaStoreGenerator{}},
"medialive": &AwsFacade{service: &MediaLiveGenerator{}},
"mq": &AwsFacade{service: &MQGenerator{}},
"msk": &AwsFacade{service: &MskGenerator{}},
"nacl": &AwsFacade{service: &NaclGenerator{}},
"nat": &AwsFacade{service: &NatGatewayGenerator{}},
"opsworks": &AwsFacade{service: &OpsworksGenerator{}},
"organization": &AwsFacade{service: &OrganizationGenerator{}},
"qldb": &AwsFacade{service: &QLDBGenerator{}},
"rds": &AwsFacade{service: &RDSGenerator{}},
"redshift": &AwsFacade{service: &RedshiftGenerator{}},
"resourcegroups": &AwsFacade{service: &ResourceGroupsGenerator{}},
"route53": &AwsFacade{service: &Route53Generator{}},
"route_table": &AwsFacade{service: &RouteTableGenerator{}},
"s3": &AwsFacade{service: &S3Generator{}},
"secretsmanager": &AwsFacade{service: &SecretsManagerGenerator{}},
"securityhub": &AwsFacade{service: &SecurityhubGenerator{}},
"servicecatalog": &AwsFacade{service: &ServiceCatalogGenerator{}},
"ses": &AwsFacade{service: &SesGenerator{}},
"sfn": &AwsFacade{service: &SfnGenerator{}},
"sg": &AwsFacade{service: &SecurityGenerator{}},
"sqs": &AwsFacade{service: &SqsGenerator{}},
"sns": &AwsFacade{service: &SnsGenerator{}},
"ssm": &AwsFacade{service: &SsmGenerator{}},
"subnet": &AwsFacade{service: &SubnetGenerator{}},
"swf": &AwsFacade{service: &SWFGenerator{}},
"transit_gateway": &AwsFacade{service: &TransitGatewayGenerator{}},
"waf": &AwsFacade{service: &WafGenerator{}},
"waf_regional": &AwsFacade{service: &WafRegionalGenerator{}},
"wafv2_cloudfront": &AwsFacade{service: NewWafv2CloudfrontGenerator()},
"wafv2_regional": &AwsFacade{service: NewWafv2RegionalGenerator()},
"vpc": &AwsFacade{service: &VpcGenerator{}},
"vpc_endpoint": &AwsFacade{service: &VpcEndpointGenerator{}},
"vpc_peering": &AwsFacade{service: &VpcPeeringConnectionGenerator{}},
"vpn_connection": &AwsFacade{service: &VpnConnectionGenerator{}},
"vpn_gateway": &AwsFacade{service: &VpnGatewayGenerator{}},
"workspaces": &AwsFacade{service: &WorkspacesGenerator{}},
"xray": &AwsFacade{service: &XrayGenerator{}},
}
}
func StringValue(value *string) string {
if value != nil {
return *value
}
return ""
}