github.com/daveadams/terraform@v0.6.4-0.20160830094355-13ce74975936/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/pathorcontents"
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  	"github.com/hashicorp/terraform/terraform"
    11  	"google.golang.org/api/compute/v1"
    12  	"google.golang.org/api/googleapi"
    13  )
    14  
    15  // Provider returns a terraform.ResourceProvider.
    16  func Provider() terraform.ResourceProvider {
    17  	return &schema.Provider{
    18  		Schema: map[string]*schema.Schema{
    19  			"account_file": &schema.Schema{
    20  				Type:         schema.TypeString,
    21  				Optional:     true,
    22  				DefaultFunc:  schema.EnvDefaultFunc("GOOGLE_ACCOUNT_FILE", nil),
    23  				ValidateFunc: validateAccountFile,
    24  				Deprecated:   "Use the credentials field instead",
    25  			},
    26  
    27  			"credentials": &schema.Schema{
    28  				Type:     schema.TypeString,
    29  				Optional: true,
    30  				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
    31  					"GOOGLE_CREDENTIALS",
    32  					"GOOGLE_CLOUD_KEYFILE_JSON",
    33  					"GCLOUD_KEYFILE_JSON",
    34  				}, nil),
    35  				ValidateFunc: validateCredentials,
    36  			},
    37  
    38  			"project": &schema.Schema{
    39  				Type:     schema.TypeString,
    40  				Optional: true,
    41  				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
    42  					"GOOGLE_PROJECT",
    43  					"GCLOUD_PROJECT",
    44  					"CLOUDSDK_CORE_PROJECT",
    45  				}, nil),
    46  			},
    47  
    48  			"region": &schema.Schema{
    49  				Type:     schema.TypeString,
    50  				Required: true,
    51  				DefaultFunc: schema.MultiEnvDefaultFunc([]string{
    52  					"GOOGLE_REGION",
    53  					"GCLOUD_REGION",
    54  					"CLOUDSDK_COMPUTE_REGION",
    55  				}, nil),
    56  			},
    57  		},
    58  
    59  		ResourcesMap: map[string]*schema.Resource{
    60  			"google_compute_autoscaler":             resourceComputeAutoscaler(),
    61  			"google_compute_address":                resourceComputeAddress(),
    62  			"google_compute_backend_service":        resourceComputeBackendService(),
    63  			"google_compute_disk":                   resourceComputeDisk(),
    64  			"google_compute_firewall":               resourceComputeFirewall(),
    65  			"google_compute_forwarding_rule":        resourceComputeForwardingRule(),
    66  			"google_compute_global_address":         resourceComputeGlobalAddress(),
    67  			"google_compute_global_forwarding_rule": resourceComputeGlobalForwardingRule(),
    68  			"google_compute_http_health_check":      resourceComputeHttpHealthCheck(),
    69  			"google_compute_https_health_check":     resourceComputeHttpsHealthCheck(),
    70  			"google_compute_image":                  resourceComputeImage(),
    71  			"google_compute_instance":               resourceComputeInstance(),
    72  			"google_compute_instance_group":         resourceComputeInstanceGroup(),
    73  			"google_compute_instance_group_manager": resourceComputeInstanceGroupManager(),
    74  			"google_compute_instance_template":      resourceComputeInstanceTemplate(),
    75  			"google_compute_network":                resourceComputeNetwork(),
    76  			"google_compute_project_metadata":       resourceComputeProjectMetadata(),
    77  			"google_compute_route":                  resourceComputeRoute(),
    78  			"google_compute_ssl_certificate":        resourceComputeSslCertificate(),
    79  			"google_compute_subnetwork":             resourceComputeSubnetwork(),
    80  			"google_compute_target_http_proxy":      resourceComputeTargetHttpProxy(),
    81  			"google_compute_target_https_proxy":     resourceComputeTargetHttpsProxy(),
    82  			"google_compute_target_pool":            resourceComputeTargetPool(),
    83  			"google_compute_url_map":                resourceComputeUrlMap(),
    84  			"google_compute_vpn_gateway":            resourceComputeVpnGateway(),
    85  			"google_compute_vpn_tunnel":             resourceComputeVpnTunnel(),
    86  			"google_container_cluster":              resourceContainerCluster(),
    87  			"google_dns_managed_zone":               resourceDnsManagedZone(),
    88  			"google_dns_record_set":                 resourceDnsRecordSet(),
    89  			"google_sql_database":                   resourceSqlDatabase(),
    90  			"google_sql_database_instance":          resourceSqlDatabaseInstance(),
    91  			"google_sql_user":                       resourceSqlUser(),
    92  			"google_pubsub_topic":                   resourcePubsubTopic(),
    93  			"google_pubsub_subscription":            resourcePubsubSubscription(),
    94  			"google_storage_bucket":                 resourceStorageBucket(),
    95  			"google_storage_bucket_acl":             resourceStorageBucketAcl(),
    96  			"google_storage_bucket_object":          resourceStorageBucketObject(),
    97  			"google_storage_object_acl":             resourceStorageObjectAcl(),
    98  		},
    99  
   100  		ConfigureFunc: providerConfigure,
   101  	}
   102  }
   103  
   104  func providerConfigure(d *schema.ResourceData) (interface{}, error) {
   105  	credentials := d.Get("credentials").(string)
   106  	if credentials == "" {
   107  		credentials = d.Get("account_file").(string)
   108  	}
   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 validateAccountFile(v interface{}, k string) (warnings []string, errors []error) {
   123  	if v == nil {
   124  		return
   125  	}
   126  
   127  	value := v.(string)
   128  
   129  	if value == "" {
   130  		return
   131  	}
   132  
   133  	contents, wasPath, err := pathorcontents.Read(value)
   134  	if err != nil {
   135  		errors = append(errors, fmt.Errorf("Error loading Account File: %s", err))
   136  	}
   137  	if wasPath {
   138  		warnings = append(warnings, `account_file was provided as a path instead of
   139  as file contents. This support will be removed in the future. Please update
   140  your configuration to use ${file("filename.json")} instead.`)
   141  	}
   142  
   143  	var account accountFile
   144  	if err := json.Unmarshal([]byte(contents), &account); err != nil {
   145  		errors = append(errors,
   146  			fmt.Errorf("account_file not valid JSON '%s': %s", contents, err))
   147  	}
   148  
   149  	return
   150  }
   151  
   152  func validateCredentials(v interface{}, k string) (warnings []string, errors []error) {
   153  	if v == nil || v.(string) == "" {
   154  		return
   155  	}
   156  	creds := v.(string)
   157  	var account accountFile
   158  	if err := json.Unmarshal([]byte(creds), &account); err != nil {
   159  		errors = append(errors,
   160  			fmt.Errorf("credentials are not valid JSON '%s': %s", creds, err))
   161  	}
   162  
   163  	return
   164  }
   165  
   166  // getRegionFromZone returns the region from a zone for Google cloud.
   167  func getRegionFromZone(zone string) string {
   168  	if zone != "" && len(zone) > 2 {
   169  		region := zone[:len(zone)-2]
   170  		return region
   171  	}
   172  	return ""
   173  }
   174  
   175  // getRegion reads the "region" field from the given resource data and falls
   176  // back to the provider's value if not given. If the provider's value is not
   177  // given, an error is returned.
   178  func getRegion(d *schema.ResourceData, config *Config) (string, error) {
   179  	res, ok := d.GetOk("region")
   180  	if !ok {
   181  		if config.Region != "" {
   182  			return config.Region, nil
   183  		}
   184  		return "", fmt.Errorf("%q: required field is not set", "region")
   185  	}
   186  	return res.(string), nil
   187  }
   188  
   189  // getProject reads the "project" field from the given resource data and falls
   190  // back to the provider's value if not given. If the provider's value is not
   191  // given, an error is returned.
   192  func getProject(d *schema.ResourceData, config *Config) (string, error) {
   193  	res, ok := d.GetOk("project")
   194  	if !ok {
   195  		if config.Project != "" {
   196  			return config.Project, nil
   197  		}
   198  		return "", fmt.Errorf("%q: required field is not set", "project")
   199  	}
   200  	return res.(string), nil
   201  }
   202  
   203  func getZonalResourceFromRegion(getResource func(string) (interface{}, error), region string, compute *compute.Service, project string) (interface{}, error) {
   204  	zoneList, err := compute.Zones.List(project).Do()
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  	var resource interface{}
   209  	for _, zone := range zoneList.Items {
   210  		if strings.Contains(zone.Name, region) {
   211  			resource, err = getResource(zone.Name)
   212  			if err != nil {
   213  				if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
   214  					// Resource was not found in this zone
   215  					continue
   216  				}
   217  				return nil, fmt.Errorf("Error reading Resource: %s", err)
   218  			}
   219  			// Resource was found
   220  			return resource, nil
   221  		}
   222  	}
   223  	// Resource does not exist in this region
   224  	return nil, nil
   225  }