2014-08-25 18:48:20 +00:00
package google
import (
2015-07-27 19:35:52 +00:00
"encoding/json"
"fmt"
2016-08-04 20:14:43 +00:00
"strings"
2015-07-27 19:35:52 +00:00
2015-11-12 22:13:07 +00:00
"github.com/hashicorp/terraform/helper/pathorcontents"
2014-08-25 18:48:20 +00:00
"github.com/hashicorp/terraform/helper/schema"
2014-09-28 18:51:39 +00:00
"github.com/hashicorp/terraform/terraform"
2016-08-04 20:14:43 +00:00
"google.golang.org/api/compute/v1"
"google.golang.org/api/googleapi"
2014-08-25 18:48:20 +00:00
)
// Provider returns a terraform.ResourceProvider.
2014-09-28 18:51:39 +00:00
func Provider ( ) terraform . ResourceProvider {
2014-08-25 18:48:20 +00:00
return & schema . Provider {
Schema : map [ string ] * schema . Schema {
"account_file" : & schema . Schema {
2015-07-27 19:35:52 +00:00
Type : schema . TypeString ,
2015-10-19 19:27:41 +00:00
Optional : true ,
2015-07-27 19:35:52 +00:00
DefaultFunc : schema . EnvDefaultFunc ( "GOOGLE_ACCOUNT_FILE" , nil ) ,
ValidateFunc : validateAccountFile ,
2017-03-14 04:58:39 +00:00
Removed : "Use the credentials field instead" ,
2015-11-12 22:13:07 +00:00
} ,
"credentials" : & schema . Schema {
2016-04-04 21:56:35 +00:00
Type : schema . TypeString ,
Optional : true ,
DefaultFunc : schema . MultiEnvDefaultFunc ( [ ] string {
"GOOGLE_CREDENTIALS" ,
"GOOGLE_CLOUD_KEYFILE_JSON" ,
2016-04-10 23:31:40 +00:00
"GCLOUD_KEYFILE_JSON" ,
2016-04-04 21:56:35 +00:00
} , nil ) ,
2015-11-12 22:13:07 +00:00
ValidateFunc : validateCredentials ,
2015-07-23 20:53:44 +00:00
} ,
2014-08-25 19:55:08 +00:00
"project" : & schema . Schema {
2016-04-10 23:31:40 +00:00
Type : schema . TypeString ,
Optional : true ,
DefaultFunc : schema . MultiEnvDefaultFunc ( [ ] string {
"GOOGLE_PROJECT" ,
"GCLOUD_PROJECT" ,
"CLOUDSDK_CORE_PROJECT" ,
} , nil ) ,
2014-08-25 19:55:08 +00:00
} ,
"region" : & schema . Schema {
2016-04-10 23:31:40 +00:00
Type : schema . TypeString ,
Required : true ,
DefaultFunc : schema . MultiEnvDefaultFunc ( [ ] string {
"GOOGLE_REGION" ,
"GCLOUD_REGION" ,
"CLOUDSDK_COMPUTE_REGION" ,
} , nil ) ,
2014-08-25 19:55:08 +00:00
} ,
2014-08-25 18:48:20 +00:00
} ,
2016-08-10 04:44:53 +00:00
DataSourcesMap : map [ string ] * schema . Resource {
2017-02-14 23:35:17 +00:00
"google_iam_policy" : dataSourceGoogleIamPolicy ( ) ,
"google_compute_zones" : dataSourceGoogleComputeZones ( ) ,
2016-08-10 04:44:53 +00:00
} ,
2014-08-25 18:48:20 +00:00
ResourcesMap : map [ string ] * schema . Resource {
2015-08-14 11:06:06 +00:00
"google_compute_autoscaler" : resourceComputeAutoscaler ( ) ,
"google_compute_address" : resourceComputeAddress ( ) ,
2015-08-20 19:52:30 +00:00
"google_compute_backend_service" : resourceComputeBackendService ( ) ,
2015-08-14 11:06:06 +00:00
"google_compute_disk" : resourceComputeDisk ( ) ,
"google_compute_firewall" : resourceComputeFirewall ( ) ,
"google_compute_forwarding_rule" : resourceComputeForwardingRule ( ) ,
2015-10-30 20:14:36 +00:00
"google_compute_global_address" : resourceComputeGlobalAddress ( ) ,
2015-10-30 20:34:14 +00:00
"google_compute_global_forwarding_rule" : resourceComputeGlobalForwardingRule ( ) ,
2016-11-18 16:08:26 +00:00
"google_compute_health_check" : resourceComputeHealthCheck ( ) ,
2015-08-14 11:06:06 +00:00
"google_compute_http_health_check" : resourceComputeHttpHealthCheck ( ) ,
2015-11-12 15:48:26 +00:00
"google_compute_https_health_check" : resourceComputeHttpsHealthCheck ( ) ,
2016-08-12 02:35:33 +00:00
"google_compute_image" : resourceComputeImage ( ) ,
2015-08-14 11:06:06 +00:00
"google_compute_instance" : resourceComputeInstance ( ) ,
2016-02-26 18:41:35 +00:00
"google_compute_instance_group" : resourceComputeInstanceGroup ( ) ,
2015-10-30 21:27:12 +00:00
"google_compute_instance_group_manager" : resourceComputeInstanceGroupManager ( ) ,
2015-08-14 11:06:06 +00:00
"google_compute_instance_template" : resourceComputeInstanceTemplate ( ) ,
"google_compute_network" : resourceComputeNetwork ( ) ,
2015-08-20 19:18:41 +00:00
"google_compute_project_metadata" : resourceComputeProjectMetadata ( ) ,
2016-11-18 16:08:26 +00:00
"google_compute_region_backend_service" : resourceComputeRegionBackendService ( ) ,
2015-08-14 11:06:06 +00:00
"google_compute_route" : resourceComputeRoute ( ) ,
2015-11-02 15:15:19 +00:00
"google_compute_ssl_certificate" : resourceComputeSslCertificate ( ) ,
2016-02-14 22:27:17 +00:00
"google_compute_subnetwork" : resourceComputeSubnetwork ( ) ,
2015-11-01 15:39:08 +00:00
"google_compute_target_http_proxy" : resourceComputeTargetHttpProxy ( ) ,
2015-11-02 19:32:07 +00:00
"google_compute_target_https_proxy" : resourceComputeTargetHttpsProxy ( ) ,
2015-08-14 11:06:06 +00:00
"google_compute_target_pool" : resourceComputeTargetPool ( ) ,
2015-10-30 21:27:12 +00:00
"google_compute_url_map" : resourceComputeUrlMap ( ) ,
2015-09-04 20:54:18 +00:00
"google_compute_vpn_gateway" : resourceComputeVpnGateway ( ) ,
"google_compute_vpn_tunnel" : resourceComputeVpnTunnel ( ) ,
2015-08-14 11:06:06 +00:00
"google_container_cluster" : resourceContainerCluster ( ) ,
2017-03-06 22:59:24 +00:00
"google_container_node_pool" : resourceContainerNodePool ( ) ,
2015-08-14 11:06:06 +00:00
"google_dns_managed_zone" : resourceDnsManagedZone ( ) ,
"google_dns_record_set" : resourceDnsRecordSet ( ) ,
2015-10-23 14:10:41 +00:00
"google_sql_database" : resourceSqlDatabase ( ) ,
"google_sql_database_instance" : resourceSqlDatabaseInstance ( ) ,
2016-01-13 21:33:08 +00:00
"google_sql_user" : resourceSqlUser ( ) ,
2016-08-10 04:44:53 +00:00
"google_project" : resourceGoogleProject ( ) ,
2016-11-23 06:55:40 +00:00
"google_project_iam_policy" : resourceGoogleProjectIamPolicy ( ) ,
"google_project_services" : resourceGoogleProjectServices ( ) ,
2015-12-11 17:59:13 +00:00
"google_pubsub_topic" : resourcePubsubTopic ( ) ,
"google_pubsub_subscription" : resourcePubsubSubscription ( ) ,
2016-11-08 07:27:32 +00:00
"google_service_account" : resourceGoogleServiceAccount ( ) ,
2015-08-14 11:06:06 +00:00
"google_storage_bucket" : resourceStorageBucket ( ) ,
2015-09-16 18:46:46 +00:00
"google_storage_bucket_acl" : resourceStorageBucketAcl ( ) ,
2015-09-03 18:47:51 +00:00
"google_storage_bucket_object" : resourceStorageBucketObject ( ) ,
2015-09-16 18:46:46 +00:00
"google_storage_object_acl" : resourceStorageObjectAcl ( ) ,
2014-08-25 18:48:20 +00:00
} ,
ConfigureFunc : providerConfigure ,
}
}
func providerConfigure ( d * schema . ResourceData ) ( interface { } , error ) {
2015-11-12 22:13:07 +00:00
credentials := d . Get ( "credentials" ) . ( string )
2014-08-25 18:48:20 +00:00
config := Config {
2015-11-12 22:13:07 +00:00
Credentials : credentials ,
2015-07-27 19:35:52 +00:00
Project : d . Get ( "project" ) . ( string ) ,
Region : d . Get ( "region" ) . ( string ) ,
2014-08-25 18:48:20 +00:00
}
if err := config . loadAndValidate ( ) ; err != nil {
return nil , err
}
2014-08-25 19:55:08 +00:00
return & config , nil
2014-08-25 18:48:20 +00:00
}
2015-07-27 19:35:52 +00:00
func validateAccountFile ( v interface { } , k string ) ( warnings [ ] string , errors [ ] error ) {
2015-10-19 19:27:41 +00:00
if v == nil {
return
}
2015-07-27 19:35:52 +00:00
value := v . ( string )
if value == "" {
return
}
2015-11-12 22:13:07 +00:00
contents , wasPath , err := pathorcontents . Read ( value )
if err != nil {
errors = append ( errors , fmt . Errorf ( "Error loading Account File: %s" , err ) )
}
if wasPath {
2017-03-14 04:58:39 +00:00
errors = append ( errors , fmt . Errorf ( ` Error loading credentials; they were provided as a path instead of file contents. Please use $ { file("%s")} instead. ` , value ) )
2015-11-12 22:13:07 +00:00
}
2015-07-27 19:35:52 +00:00
var account accountFile
2015-11-12 22:13:07 +00:00
if err := json . Unmarshal ( [ ] byte ( contents ) , & account ) ; err != nil {
errors = append ( errors ,
fmt . Errorf ( "account_file not valid JSON '%s': %s" , contents , err ) )
2015-07-27 19:35:52 +00:00
}
2015-11-12 22:13:07 +00:00
return
}
func validateCredentials ( v interface { } , k string ) ( warnings [ ] string , errors [ ] error ) {
if v == nil || v . ( string ) == "" {
return
}
creds := v . ( string )
var account accountFile
if err := json . Unmarshal ( [ ] byte ( creds ) , & account ) ; err != nil {
2015-07-27 21:07:38 +00:00
errors = append ( errors ,
2015-11-12 22:13:07 +00:00
fmt . Errorf ( "credentials are not valid JSON '%s': %s" , creds , err ) )
2015-07-27 19:35:52 +00:00
}
return
}
2016-02-15 03:17:55 +00:00
2016-02-18 16:23:20 +00:00
// getRegionFromZone returns the region from a zone for Google cloud.
2016-02-15 03:17:55 +00:00
func getRegionFromZone ( zone string ) string {
if zone != "" && len ( zone ) > 2 {
region := zone [ : len ( zone ) - 2 ]
return region
}
return ""
}
2016-04-10 16:59:57 +00:00
// getRegion reads the "region" field from the given resource data and falls
// back to the provider's value if not given. If the provider's value is not
// given, an error is returned.
func getRegion ( d * schema . ResourceData , config * Config ) ( string , error ) {
res , ok := d . GetOk ( "region" )
if ! ok {
if config . Region != "" {
return config . Region , nil
}
return "" , fmt . Errorf ( "%q: required field is not set" , "region" )
}
return res . ( string ) , nil
}
// getProject reads the "project" field from the given resource data and falls
// back to the provider's value if not given. If the provider's value is not
// given, an error is returned.
func getProject ( d * schema . ResourceData , config * Config ) ( string , error ) {
res , ok := d . GetOk ( "project" )
if ! ok {
if config . Project != "" {
return config . Project , nil
}
return "" , fmt . Errorf ( "%q: required field is not set" , "project" )
}
return res . ( string ) , nil
}
2016-08-04 20:14:43 +00:00
func getZonalResourceFromRegion ( getResource func ( string ) ( interface { } , error ) , region string , compute * compute . Service , project string ) ( interface { } , error ) {
zoneList , err := compute . Zones . List ( project ) . Do ( )
if err != nil {
return nil , err
}
var resource interface { }
for _ , zone := range zoneList . Items {
if strings . Contains ( zone . Name , region ) {
resource , err = getResource ( zone . Name )
if err != nil {
if gerr , ok := err . ( * googleapi . Error ) ; ok && gerr . Code == 404 {
// Resource was not found in this zone
continue
}
return nil , fmt . Errorf ( "Error reading Resource: %s" , err )
}
// Resource was found
return resource , nil
}
}
// Resource does not exist in this region
return nil , nil
}
2016-09-03 09:51:20 +00:00
// getNetworkLink reads the "network" field from the given resource data and if the value:
// - is a resource URL, returns the string unchanged
// - is the network name only, then looks up the resource URL using the google client
func getNetworkLink ( d * schema . ResourceData , config * Config , field string ) ( string , error ) {
if v , ok := d . GetOk ( field ) ; ok {
network := v . ( string )
project , err := getProject ( d , config )
if err != nil {
return "" , err
}
if ! strings . HasPrefix ( network , "https://www.googleapis.com/compute/" ) {
// Network value provided is just the name, lookup the network SelfLink
networkData , err := config . clientCompute . Networks . Get (
project , network ) . Do ( )
if err != nil {
return "" , fmt . Errorf ( "Error reading network: %s" , err )
}
network = networkData . SelfLink
}
return network , nil
} else {
return "" , nil
}
}
// getNetworkName reads the "network" field from the given resource data and if the value:
// - is a resource URL, extracts the network name from the URL and returns it
// - is the network name only (i.e not prefixed with http://www.googleapis.com/compute/...), is returned unchanged
func getNetworkName ( d * schema . ResourceData , field string ) ( string , error ) {
if v , ok := d . GetOk ( field ) ; ok {
network := v . ( string )
if strings . HasPrefix ( network , "https://www.googleapis.com/compute/" ) {
// extract the network name from SelfLink URL
networkName := network [ strings . LastIndex ( network , "/" ) + 1 : ]
if networkName == "" {
return "" , fmt . Errorf ( "network url not valid" )
}
return networkName , nil
}
return network , nil
}
return "" , nil
}