github.com/sixgill/terraform@v0.9.0-beta2.0.20170316214032-033f6226ae50/builtin/providers/google/provider.go (about)

     1  package google
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/hashicorp/terraform/helper/schema"
     9  	"github.com/hashicorp/terraform/terraform"
    10  	"google.golang.org/api/compute/v1"
    11  	"google.golang.org/api/googleapi"
    12  )
    13  
    14  // Provider returns a terraform.ResourceProvider.
    15  func Provider() terraform.ResourceProvider {
    16  	return &schema.Provider{
    17  		Schema: map[string]*schema.Schema{
    18  			"credentials": &schema.Schema{
    19  				Type:     schema.TypeString,
    20  				Optional: true,
    21  				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
    22  					"GOOGLE_CREDENTIALS",
    23  					"GOOGLE_CLOUD_KEYFILE_JSON",
    24  					"GCLOUD_KEYFILE_JSON",
    25  				}, nil),
    26  				ValidateFunc: validateCredentials,
    27  			},
    28  
    29  			"project": &schema.Schema{
    30  				Type:     schema.TypeString,
    31  				Optional: true,
    32  				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
    33  					"GOOGLE_PROJECT",
    34  					"GCLOUD_PROJECT",
    35  					"CLOUDSDK_CORE_PROJECT",
    36  				}, nil),
    37  			},
    38  
    39  			"region": &schema.Schema{
    40  				Type:     schema.TypeString,
    41  				Required: true,
    42  				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
    43  					"GOOGLE_REGION",
    44  					"GCLOUD_REGION",
    45  					"CLOUDSDK_COMPUTE_REGION",
    46  				}, nil),
    47  			},
    48  		},
    49  
    50  		DataSourcesMap: map[string]*schema.Resource{
    51  			"google_iam_policy":    dataSourceGoogleIamPolicy(),
    52  			"google_compute_zones": dataSourceGoogleComputeZones(),
    53  		},
    54  
    55  		ResourcesMap: map[string]*schema.Resource{
    56  			"google_compute_autoscaler":             resourceComputeAutoscaler(),
    57  			"google_compute_address":                resourceComputeAddress(),
    58  			"google_compute_backend_service":        resourceComputeBackendService(),
    59  			"google_compute_disk":                   resourceComputeDisk(),
    60  			"google_compute_firewall":               resourceComputeFirewall(),
    61  			"google_compute_forwarding_rule":        resourceComputeForwardingRule(),
    62  			"google_compute_global_address":         resourceComputeGlobalAddress(),
    63  			"google_compute_global_forwarding_rule": resourceComputeGlobalForwardingRule(),
    64  			"google_compute_health_check":           resourceComputeHealthCheck(),
    65  			"google_compute_http_health_check":      resourceComputeHttpHealthCheck(),
    66  			"google_compute_https_health_check":     resourceComputeHttpsHealthCheck(),
    67  			"google_compute_image":                  resourceComputeImage(),
    68  			"google_compute_instance":               resourceComputeInstance(),
    69  			"google_compute_instance_group":         resourceComputeInstanceGroup(),
    70  			"google_compute_instance_group_manager": resourceComputeInstanceGroupManager(),
    71  			"google_compute_instance_template":      resourceComputeInstanceTemplate(),
    72  			"google_compute_network":                resourceComputeNetwork(),
    73  			"google_compute_project_metadata":       resourceComputeProjectMetadata(),
    74  			"google_compute_region_backend_service": resourceComputeRegionBackendService(),
    75  			"google_compute_route":                  resourceComputeRoute(),
    76  			"google_compute_ssl_certificate":        resourceComputeSslCertificate(),
    77  			"google_compute_subnetwork":             resourceComputeSubnetwork(),
    78  			"google_compute_target_http_proxy":      resourceComputeTargetHttpProxy(),
    79  			"google_compute_target_https_proxy":     resourceComputeTargetHttpsProxy(),
    80  			"google_compute_target_pool":            resourceComputeTargetPool(),
    81  			"google_compute_url_map":                resourceComputeUrlMap(),
    82  			"google_compute_vpn_gateway":            resourceComputeVpnGateway(),
    83  			"google_compute_vpn_tunnel":             resourceComputeVpnTunnel(),
    84  			"google_container_cluster":              resourceContainerCluster(),
    85  			"google_container_node_pool":            resourceContainerNodePool(),
    86  			"google_dns_managed_zone":               resourceDnsManagedZone(),
    87  			"google_dns_record_set":                 resourceDnsRecordSet(),
    88  			"google_sql_database":                   resourceSqlDatabase(),
    89  			"google_sql_database_instance":          resourceSqlDatabaseInstance(),
    90  			"google_sql_user":                       resourceSqlUser(),
    91  			"google_project":                        resourceGoogleProject(),
    92  			"google_project_iam_policy":             resourceGoogleProjectIamPolicy(),
    93  			"google_project_services":               resourceGoogleProjectServices(),
    94  			"google_pubsub_topic":                   resourcePubsubTopic(),
    95  			"google_pubsub_subscription":            resourcePubsubSubscription(),
    96  			"google_service_account":                resourceGoogleServiceAccount(),
    97  			"google_storage_bucket":                 resourceStorageBucket(),
    98  			"google_storage_bucket_acl":             resourceStorageBucketAcl(),
    99  			"google_storage_bucket_object":          resourceStorageBucketObject(),
   100  			"google_storage_object_acl":             resourceStorageObjectAcl(),
   101  		},
   102  
   103  		ConfigureFunc: providerConfigure,
   104  	}
   105  }
   106  
   107  func providerConfigure(d *schema.ResourceData) (interface{}, error) {
   108  	credentials := d.Get("credentials").(string)
   109  	config := Config{
   110  		Credentials: credentials,
   111  		Project:     d.Get("project").(string),
   112  		Region:      d.Get("region").(string),
   113  	}
   114  
   115  	if err := config.loadAndValidate(); err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	return &config, nil
   120  }
   121  
   122  func validateCredentials(v interface{}, k string) (warnings []string, errors []error) {
   123  	if v == nil || v.(string) == "" {
   124  		return
   125  	}
   126  	creds := v.(string)
   127  	var account accountFile
   128  	if err := json.Unmarshal([]byte(creds), &account); err != nil {
   129  		errors = append(errors,
   130  			fmt.Errorf("credentials are not valid JSON '%s': %s", creds, err))
   131  	}
   132  
   133  	return
   134  }
   135  
   136  // getRegionFromZone returns the region from a zone for Google cloud.
   137  func getRegionFromZone(zone string) string {
   138  	if zone != "" && len(zone) > 2 {
   139  		region := zone[:len(zone)-2]
   140  		return region
   141  	}
   142  	return ""
   143  }
   144  
   145  // getRegion reads the "region" field from the given resource data and falls
   146  // back to the provider's value if not given. If the provider's value is not
   147  // given, an error is returned.
   148  func getRegion(d *schema.ResourceData, config *Config) (string, error) {
   149  	res, ok := d.GetOk("region")
   150  	if !ok {
   151  		if config.Region != "" {
   152  			return config.Region, nil
   153  		}
   154  		return "", fmt.Errorf("%q: required field is not set", "region")
   155  	}
   156  	return res.(string), nil
   157  }
   158  
   159  // getProject reads the "project" field from the given resource data and falls
   160  // back to the provider's value if not given. If the provider's value is not
   161  // given, an error is returned.
   162  func getProject(d *schema.ResourceData, config *Config) (string, error) {
   163  	res, ok := d.GetOk("project")
   164  	if !ok {
   165  		if config.Project != "" {
   166  			return config.Project, nil
   167  		}
   168  		return "", fmt.Errorf("%q: required field is not set", "project")
   169  	}
   170  	return res.(string), nil
   171  }
   172  
   173  func getZonalResourceFromRegion(getResource func(string) (interface{}, error), region string, compute *compute.Service, project string) (interface{}, error) {
   174  	zoneList, err := compute.Zones.List(project).Do()
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  	var resource interface{}
   179  	for _, zone := range zoneList.Items {
   180  		if strings.Contains(zone.Name, region) {
   181  			resource, err = getResource(zone.Name)
   182  			if err != nil {
   183  				if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
   184  					// Resource was not found in this zone
   185  					continue
   186  				}
   187  				return nil, fmt.Errorf("Error reading Resource: %s", err)
   188  			}
   189  			// Resource was found
   190  			return resource, nil
   191  		}
   192  	}
   193  	// Resource does not exist in this region
   194  	return nil, nil
   195  }
   196  
   197  // getNetworkLink reads the "network" field from the given resource data and if the value:
   198  // - is a resource URL, returns the string unchanged
   199  // - is the network name only, then looks up the resource URL using the google client
   200  func getNetworkLink(d *schema.ResourceData, config *Config, field string) (string, error) {
   201  	if v, ok := d.GetOk(field); ok {
   202  		network := v.(string)
   203  
   204  		project, err := getProject(d, config)
   205  		if err != nil {
   206  			return "", err
   207  		}
   208  
   209  		if !strings.HasPrefix(network, "https://www.googleapis.com/compute/") {
   210  			// Network value provided is just the name, lookup the network SelfLink
   211  			networkData, err := config.clientCompute.Networks.Get(
   212  				project, network).Do()
   213  			if err != nil {
   214  				return "", fmt.Errorf("Error reading network: %s", err)
   215  			}
   216  			network = networkData.SelfLink
   217  		}
   218  
   219  		return network, nil
   220  
   221  	} else {
   222  		return "", nil
   223  	}
   224  }
   225  
   226  // getNetworkName reads the "network" field from the given resource data and if the value:
   227  // - is a resource URL, extracts the network name from the URL and returns it
   228  // - is the network name only (i.e not prefixed with http://www.googleapis.com/compute/...), is returned unchanged
   229  func getNetworkName(d *schema.ResourceData, field string) (string, error) {
   230  	if v, ok := d.GetOk(field); ok {
   231  		network := v.(string)
   232  		return getNetworkNameFromSelfLink(network)
   233  	}
   234  	return "", nil
   235  }
   236  
   237  func getNetworkNameFromSelfLink(network string) (string, error) {
   238  	if strings.HasPrefix(network, "https://www.googleapis.com/compute/") {
   239  		// extract the network name from SelfLink URL
   240  		networkName := network[strings.LastIndex(network, "/")+1:]
   241  		if networkName == "" {
   242  			return "", fmt.Errorf("network url not valid")
   243  		}
   244  		return networkName, nil
   245  	}
   246  
   247  	return network, nil
   248  }