2015-10-23 14:10:41 +00:00
package google
import (
"fmt"
2017-05-18 20:09:01 +00:00
"log"
"regexp"
2017-01-27 21:06:46 +00:00
"strings"
2018-04-03 21:44:18 +00:00
"time"
2015-10-23 14:10:41 +00:00
2018-06-20 22:02:25 +00:00
"github.com/hashicorp/terraform/helper/customdiff"
2016-01-08 16:54:55 +00:00
"github.com/hashicorp/terraform/helper/resource"
2015-10-23 14:10:41 +00:00
"github.com/hashicorp/terraform/helper/schema"
2017-07-07 19:48:29 +00:00
"github.com/hashicorp/terraform/helper/validation"
2015-10-23 14:10:41 +00:00
2015-11-13 20:36:03 +00:00
"google.golang.org/api/googleapi"
2019-01-08 00:44:54 +00:00
sqladmin "google.golang.org/api/sqladmin/v1beta4"
2015-10-23 14:10:41 +00:00
)
2018-12-13 22:47:51 +00:00
const privateNetworkLinkRegex = "projects/(" + ProjectRegex + ")/global/networks/((?:[a-z](?:[-a-z0-9]*[a-z0-9])?))$"
2017-11-13 20:51:15 +00:00
var sqlDatabaseAuthorizedNetWorkSchemaElem * schema . Resource = & schema . Resource {
Schema : map [ string ] * schema . Schema {
2018-12-14 20:51:11 +00:00
"expiration_time" : {
2017-11-13 20:51:15 +00:00
Type : schema . TypeString ,
Optional : true ,
} ,
2018-12-14 20:51:11 +00:00
"name" : {
2017-11-13 20:51:15 +00:00
Type : schema . TypeString ,
Optional : true ,
} ,
2018-12-14 20:51:11 +00:00
"value" : {
2017-11-13 20:51:15 +00:00
Type : schema . TypeString ,
Optional : true ,
} ,
} ,
}
2015-10-23 14:10:41 +00:00
func resourceSqlDatabaseInstance ( ) * schema . Resource {
return & schema . Resource {
Create : resourceSqlDatabaseInstanceCreate ,
Read : resourceSqlDatabaseInstanceRead ,
Update : resourceSqlDatabaseInstanceUpdate ,
Delete : resourceSqlDatabaseInstanceDelete ,
2017-06-22 17:25:26 +00:00
Importer : & schema . ResourceImporter {
2018-08-28 23:51:37 +00:00
State : resourceSqlDatabaseInstanceImport ,
2017-06-22 17:25:26 +00:00
} ,
2015-10-23 14:10:41 +00:00
2018-04-03 21:44:18 +00:00
Timeouts : & schema . ResourceTimeout {
Create : schema . DefaultTimeout ( 10 * time . Minute ) ,
Update : schema . DefaultTimeout ( 10 * time . Minute ) ,
Delete : schema . DefaultTimeout ( 10 * time . Minute ) ,
} ,
2018-06-20 22:02:25 +00:00
CustomizeDiff : customdiff . All (
customdiff . ForceNewIfChange ( "settings.0.disk_size" , isDiskShrinkage ) ) ,
2015-10-23 14:10:41 +00:00
Schema : map [ string ] * schema . Schema {
2018-12-14 20:51:11 +00:00
"region" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
2018-05-09 21:16:49 +00:00
Optional : true ,
2018-12-12 17:23:30 +00:00
Computed : true ,
2015-10-23 14:10:41 +00:00
ForceNew : true ,
} ,
2016-04-10 21:34:15 +00:00
2018-12-14 20:51:11 +00:00
"settings" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeList ,
Required : true ,
2017-05-18 20:09:01 +00:00
MaxItems : 1 ,
2015-10-23 14:10:41 +00:00
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2018-12-14 20:51:11 +00:00
"version" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeInt ,
Computed : true ,
} ,
2018-12-14 20:51:11 +00:00
"tier" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Required : true ,
} ,
2018-12-14 20:51:11 +00:00
"activation_policy" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
2017-08-01 20:13:09 +00:00
// Defaults differ between first and second gen instances
Computed : true ,
2015-10-23 14:10:41 +00:00
} ,
2018-12-14 20:51:11 +00:00
"authorized_gae_applications" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeList ,
Optional : true ,
Elem : & schema . Schema { Type : schema . TypeString } ,
} ,
2018-12-14 20:51:11 +00:00
"availability_type" : {
2018-01-24 17:23:48 +00:00
Type : schema . TypeString ,
Optional : true ,
DiffSuppressFunc : suppressFirstGen ,
// Set computed instead of default because this property is for second-gen
// only. The default when not provided is ZONAL, which means no explicit HA
// configuration.
Computed : true ,
ValidateFunc : validation . StringInSlice ( [ ] string { "REGIONAL" , "ZONAL" } , false ) ,
} ,
2018-12-14 20:51:11 +00:00
"backup_configuration" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeList ,
Optional : true ,
2017-08-01 20:13:09 +00:00
Computed : true ,
MaxItems : 1 ,
2015-10-23 14:10:41 +00:00
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2018-12-14 20:51:11 +00:00
"binary_log_enabled" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeBool ,
Optional : true ,
} ,
2018-12-14 20:51:11 +00:00
"enabled" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeBool ,
Optional : true ,
} ,
2018-12-14 20:51:11 +00:00
"start_time" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
2017-08-01 20:13:09 +00:00
// start_time is randomly assigned if not set
Computed : true ,
2015-10-23 14:10:41 +00:00
} ,
} ,
} ,
} ,
2018-12-14 20:51:11 +00:00
"crash_safe_replication" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeBool ,
Optional : true ,
2017-01-27 21:06:46 +00:00
Computed : true ,
2015-10-23 14:10:41 +00:00
} ,
2018-12-14 20:51:11 +00:00
"database_flags" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeList ,
Optional : true ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2018-12-14 20:51:11 +00:00
"value" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
} ,
2018-12-14 20:51:11 +00:00
"name" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
} ,
} ,
} ,
} ,
2018-12-14 20:51:11 +00:00
"disk_autoresize" : {
2017-05-18 20:09:01 +00:00
Type : schema . TypeBool ,
Optional : true ,
2017-11-29 23:51:00 +00:00
Default : true ,
2017-05-18 20:09:01 +00:00
DiffSuppressFunc : suppressFirstGen ,
2017-02-01 16:20:31 +00:00
} ,
2018-12-14 20:51:11 +00:00
"disk_size" : {
2017-02-01 16:20:31 +00:00
Type : schema . TypeInt ,
Optional : true ,
2017-08-01 20:13:09 +00:00
// Defaults differ between first and second gen instances
Computed : true ,
2017-02-01 16:20:31 +00:00
} ,
2018-12-14 20:51:11 +00:00
"disk_type" : {
2017-02-01 16:20:31 +00:00
Type : schema . TypeString ,
Optional : true ,
2017-08-01 20:13:09 +00:00
// Set computed instead of default because this property is for second-gen only.
Computed : true ,
2017-02-01 16:20:31 +00:00
} ,
2018-12-14 20:51:11 +00:00
"ip_configuration" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeList ,
Optional : true ,
2017-08-01 20:13:09 +00:00
Computed : true ,
MaxItems : 1 ,
2015-10-23 14:10:41 +00:00
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2018-12-14 20:51:11 +00:00
"authorized_networks" : {
2017-11-13 20:51:15 +00:00
Type : schema . TypeSet ,
2015-10-23 14:10:41 +00:00
Optional : true ,
2017-11-13 20:51:15 +00:00
Set : schema . HashResource ( sqlDatabaseAuthorizedNetWorkSchemaElem ) ,
Elem : sqlDatabaseAuthorizedNetWorkSchemaElem ,
2015-10-23 14:10:41 +00:00
} ,
2018-12-14 20:51:11 +00:00
"ipv4_enabled" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeBool ,
Optional : true ,
2017-08-01 20:13:09 +00:00
// Defaults differ between first and second gen instances
Computed : true ,
2015-10-23 14:10:41 +00:00
} ,
2018-12-14 20:51:11 +00:00
"require_ssl" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeBool ,
Optional : true ,
} ,
2018-12-14 20:51:11 +00:00
"private_network" : {
2018-12-13 22:47:51 +00:00
Type : schema . TypeString ,
Optional : true ,
2019-02-20 19:06:20 +00:00
ValidateFunc : orEmpty ( validateRegexp ( privateNetworkLinkRegex ) ) ,
2018-12-13 22:47:51 +00:00
DiffSuppressFunc : compareSelfLinkRelativePaths ,
} ,
2015-10-23 14:10:41 +00:00
} ,
} ,
} ,
2018-12-14 20:51:11 +00:00
"location_preference" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeList ,
Optional : true ,
2017-08-01 20:13:09 +00:00
MaxItems : 1 ,
Computed : true ,
2015-10-23 14:10:41 +00:00
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2018-12-14 20:51:11 +00:00
"follow_gae_application" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
} ,
2018-12-14 20:51:11 +00:00
"zone" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
} ,
} ,
} ,
} ,
2018-12-14 20:51:11 +00:00
"maintenance_window" : {
2017-02-17 23:33:47 +00:00
Type : schema . TypeList ,
Optional : true ,
MaxItems : 1 ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2018-12-14 20:51:11 +00:00
"day" : {
2017-07-07 19:48:29 +00:00
Type : schema . TypeInt ,
Optional : true ,
ValidateFunc : validation . IntBetween ( 1 , 7 ) ,
2017-02-17 23:33:47 +00:00
} ,
2018-12-14 20:51:11 +00:00
"hour" : {
2017-07-07 19:48:29 +00:00
Type : schema . TypeInt ,
Optional : true ,
ValidateFunc : validation . IntBetween ( 0 , 23 ) ,
2017-02-17 23:33:47 +00:00
} ,
2018-12-14 20:51:11 +00:00
"update_track" : {
2017-02-17 23:33:47 +00:00
Type : schema . TypeString ,
Optional : true ,
} ,
} ,
} ,
} ,
2018-12-14 20:51:11 +00:00
"pricing_plan" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
2017-08-01 20:13:09 +00:00
Default : "PER_USE" ,
2015-10-23 14:10:41 +00:00
} ,
2018-12-14 20:51:11 +00:00
"replication_type" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
2017-08-01 20:13:09 +00:00
Default : "SYNCHRONOUS" ,
2015-10-23 14:10:41 +00:00
} ,
2018-12-14 20:51:11 +00:00
"user_labels" : {
2018-05-30 22:32:11 +00:00
Type : schema . TypeMap ,
Optional : true ,
Elem : & schema . Schema { Type : schema . TypeString } ,
} ,
2015-10-23 14:10:41 +00:00
} ,
} ,
} ,
2016-04-10 21:34:15 +00:00
2018-12-14 20:51:11 +00:00
"connection_name" : {
2017-09-12 15:04:13 +00:00
Type : schema . TypeString ,
Computed : true ,
} ,
2018-12-14 20:51:11 +00:00
"database_version" : {
2016-04-10 21:34:15 +00:00
Type : schema . TypeString ,
Optional : true ,
2016-10-27 23:11:08 +00:00
Default : "MYSQL_5_6" ,
2016-04-10 21:34:15 +00:00
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"ip_address" : {
2016-02-22 15:34:51 +00:00
Type : schema . TypeList ,
Computed : true ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2018-12-14 20:51:11 +00:00
"ip_address" : {
2016-02-22 15:34:51 +00:00
Type : schema . TypeString ,
Computed : true ,
} ,
2018-12-14 20:51:11 +00:00
"type" : {
2018-11-21 18:43:17 +00:00
Type : schema . TypeString ,
Computed : true ,
} ,
2018-12-14 20:51:11 +00:00
"time_to_retire" : {
2016-02-22 15:34:51 +00:00
Type : schema . TypeString ,
Computed : true ,
} ,
} ,
} ,
} ,
2016-04-10 21:34:15 +00:00
2018-12-14 20:51:11 +00:00
"first_ip_address" : {
2018-03-02 01:12:33 +00:00
Type : schema . TypeString ,
Computed : true ,
} ,
2019-02-20 19:06:20 +00:00
"public_ip_address" : {
Type : schema . TypeString ,
Computed : true ,
} ,
"private_ip_address" : {
Type : schema . TypeString ,
Computed : true ,
} ,
2018-12-14 20:51:11 +00:00
"name" : {
2016-04-10 21:34:15 +00:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"master_instance_name" : {
2016-04-10 21:34:15 +00:00
Type : schema . TypeString ,
Optional : true ,
2017-06-22 17:25:26 +00:00
Computed : true ,
2016-04-10 21:34:15 +00:00
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"project" : {
2016-04-10 21:34:15 +00:00
Type : schema . TypeString ,
Optional : true ,
2017-11-28 00:32:20 +00:00
Computed : true ,
2016-04-10 21:34:15 +00:00
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"replica_configuration" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeList ,
Optional : true ,
2017-05-22 21:04:28 +00:00
MaxItems : 1 ,
2017-08-01 20:13:09 +00:00
// Returned from API on all replicas
Computed : true ,
2015-10-23 14:10:41 +00:00
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2018-12-14 20:51:11 +00:00
"ca_certificate" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"client_certificate" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"client_key" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"connect_retry_interval" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeInt ,
Optional : true ,
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"dump_file_path" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"failover_target" : {
2017-05-22 20:44:25 +00:00
Type : schema . TypeBool ,
Optional : true ,
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"master_heartbeat_period" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeInt ,
Optional : true ,
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"password" : {
2018-05-10 22:31:07 +00:00
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
Sensitive : true ,
2015-10-23 14:10:41 +00:00
} ,
2018-12-14 20:51:11 +00:00
"ssl_cipher" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"username" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
} ,
2018-12-14 20:51:11 +00:00
"verify_server_certificate" : {
2015-10-23 14:10:41 +00:00
Type : schema . TypeBool ,
Optional : true ,
ForceNew : true ,
} ,
} ,
} ,
} ,
2018-12-14 20:51:11 +00:00
"server_ca_cert" : {
2018-01-29 21:53:54 +00:00
Type : schema . TypeList ,
Computed : true ,
MaxItems : 1 ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2018-12-14 20:51:11 +00:00
"cert" : {
2018-01-29 21:53:54 +00:00
Type : schema . TypeString ,
Computed : true ,
} ,
2018-12-14 20:51:11 +00:00
"common_name" : {
2018-01-29 21:53:54 +00:00
Type : schema . TypeString ,
Computed : true ,
} ,
2018-12-14 20:51:11 +00:00
"create_time" : {
2018-01-29 21:53:54 +00:00
Type : schema . TypeString ,
Computed : true ,
} ,
2018-12-14 20:51:11 +00:00
"expiration_time" : {
2018-01-29 21:53:54 +00:00
Type : schema . TypeString ,
Computed : true ,
} ,
2018-12-14 20:51:11 +00:00
"sha1_fingerprint" : {
2018-01-29 21:53:54 +00:00
Type : schema . TypeString ,
Computed : true ,
} ,
} ,
} ,
} ,
2018-12-14 20:51:11 +00:00
"service_account_email_address" : {
2018-09-12 22:43:47 +00:00
Type : schema . TypeString ,
Computed : true ,
} ,
2018-12-14 20:51:11 +00:00
"self_link" : {
2016-04-10 16:59:57 +00:00
Type : schema . TypeString ,
2016-04-10 21:34:15 +00:00
Computed : true ,
2016-04-10 16:59:57 +00:00
} ,
2015-10-23 14:10:41 +00:00
} ,
}
}
2018-01-24 17:23:48 +00:00
// Suppress diff with any attribute value that is not supported on 1st Generation
// Instances
2017-05-18 20:09:01 +00:00
func suppressFirstGen ( k , old , new string , d * schema . ResourceData ) bool {
2018-01-24 17:23:48 +00:00
if isFirstGen ( d ) {
log . Printf ( "[DEBUG] suppressing diff on %s due to 1st gen instance type" , k )
2017-05-18 20:09:01 +00:00
return true
}
2018-01-24 17:23:48 +00:00
2017-05-18 20:09:01 +00:00
return false
}
2018-01-24 17:23:48 +00:00
// Detects whether a database is 1st Generation by inspecting the tier name
func isFirstGen ( d * schema . ResourceData ) bool {
settingsList := d . Get ( "settings" ) . ( [ ] interface { } )
settings := settingsList [ 0 ] . ( map [ string ] interface { } )
tier := settings [ "tier" ] . ( string )
// 1st Generation databases have tiers like 'D0', as opposed to 2nd Generation which are
// prefixed with 'db'
return ! regexp . MustCompile ( "db*" ) . Match ( [ ] byte ( tier ) )
}
2015-10-23 14:10:41 +00:00
func resourceSqlDatabaseInstanceCreate ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
2016-04-10 16:59:57 +00:00
project , err := getProject ( d , config )
if err != nil {
return err
}
2018-05-09 21:16:49 +00:00
region , err := getRegion ( d , config )
if err != nil {
return err
}
2015-10-23 14:10:41 +00:00
2018-10-03 14:59:07 +00:00
var name string
2016-01-08 16:54:55 +00:00
if v , ok := d . GetOk ( "name" ) ; ok {
2018-10-03 14:59:07 +00:00
name = v . ( string )
2016-01-08 16:54:55 +00:00
} else {
2018-10-03 14:59:07 +00:00
name = resource . UniqueId ( )
2016-01-08 16:54:55 +00:00
}
2018-10-03 14:59:07 +00:00
d . Set ( "name" , name )
2015-10-23 14:10:41 +00:00
2018-10-03 14:59:07 +00:00
instance := & sqladmin . DatabaseInstance {
Name : name ,
Region : region ,
Settings : expandSqlDatabaseInstanceSettings ( d . Get ( "settings" ) . ( [ ] interface { } ) , ! isFirstGen ( d ) ) ,
DatabaseVersion : d . Get ( "database_version" ) . ( string ) ,
MasterInstanceName : d . Get ( "master_instance_name" ) . ( string ) ,
ReplicaConfiguration : expandReplicaConfiguration ( d . Get ( "replica_configuration" ) . ( [ ] interface { } ) ) ,
}
// Modifying a replica during Create can cause problems if the master is
// modified at the same time. Lock the master until we're done in order
// to prevent that.
if ! sqlDatabaseIsMaster ( d ) {
2018-07-24 22:32:18 +00:00
mutexKV . Lock ( instanceMutexKey ( project , instance . MasterInstanceName ) )
defer mutexKV . Unlock ( instanceMutexKey ( project , instance . MasterInstanceName ) )
2015-10-23 14:10:41 +00:00
}
2016-04-10 16:59:57 +00:00
op , err := config . clientSqlAdmin . Instances . Insert ( project , instance ) . Do ( )
2015-10-23 14:10:41 +00:00
if err != nil {
2019-04-11 18:13:12 +00:00
if gerr , ok := err . ( * googleapi . Error ) ; ok && gerr . Code == 409 {
return fmt . Errorf ( "Error, failed to create instance %s with error code 409: %s. This may be due to a name collision - SQL instance names cannot be reused within a week." , instance . Name , err )
}
2019-03-22 17:24:05 +00:00
return fmt . Errorf ( "Error, failed to create instance %s: %s" , instance . Name , err )
2015-10-23 14:10:41 +00:00
}
2017-08-01 20:13:09 +00:00
d . SetId ( instance . Name )
2018-04-03 21:44:18 +00:00
err = sqladminOperationWaitTime ( config , op , project , "Create Instance" , int ( d . Timeout ( schema . TimeoutCreate ) . Minutes ( ) ) )
2015-10-23 14:10:41 +00:00
if err != nil {
2017-08-01 20:13:09 +00:00
d . SetId ( "" )
2015-10-23 14:10:41 +00:00
return err
}
2017-02-01 06:21:11 +00:00
err = resourceSqlDatabaseInstanceRead ( d , meta )
if err != nil {
return err
}
2018-10-03 14:59:07 +00:00
// If a default root user was created with a wildcard ('%') hostname, delete it.
// Users in a replica instance are inherited from the master instance and should be left alone.
if sqlDatabaseIsMaster ( d ) {
2017-10-03 19:41:04 +00:00
var users * sqladmin . UsersListResponse
2018-03-23 18:19:39 +00:00
err = retryTime ( func ( ) error {
2017-10-03 19:41:04 +00:00
users , err = config . clientSqlAdmin . Users . List ( project , instance . Name ) . Do ( )
return err
2018-04-25 19:24:52 +00:00
} , 5 )
2017-09-07 19:44:17 +00:00
if err != nil {
return fmt . Errorf ( "Error, attempting to list users associated with instance %s: %s" , instance . Name , err )
}
for _ , u := range users . Items {
if u . Name == "root" && u . Host == "%" {
2017-10-03 19:41:04 +00:00
err = retry ( func ( ) error {
op , err = config . clientSqlAdmin . Users . Delete ( project , instance . Name , u . Host , u . Name ) . Do ( )
if err == nil {
2018-04-03 21:44:18 +00:00
err = sqladminOperationWaitTime ( config , op , project , "Delete default root User" , int ( d . Timeout ( schema . TimeoutCreate ) . Minutes ( ) ) )
2017-10-03 19:41:04 +00:00
}
return err
} )
2017-09-07 19:44:17 +00:00
if err != nil {
return fmt . Errorf ( "Error, failed to delete default 'root'@'*' user, but the database was created successfully: %s" , err )
}
2017-02-01 06:21:11 +00:00
}
}
}
return nil
2015-10-23 14:10:41 +00:00
}
2018-10-03 14:59:07 +00:00
func expandSqlDatabaseInstanceSettings ( configured [ ] interface { } , secondGen bool ) * sqladmin . Settings {
2018-10-11 16:37:31 +00:00
if len ( configured ) == 0 || configured [ 0 ] == nil {
2018-10-03 14:59:07 +00:00
return nil
}
_settings := configured [ 0 ] . ( map [ string ] interface { } )
settings := & sqladmin . Settings {
2018-10-11 17:07:50 +00:00
// Version is unset in Create but is set during update
SettingsVersion : int64 ( _settings [ "version" ] . ( int ) ) ,
2018-10-03 14:59:07 +00:00
Tier : _settings [ "tier" ] . ( string ) ,
ForceSendFields : [ ] string { "StorageAutoResize" } ,
ActivationPolicy : _settings [ "activation_policy" ] . ( string ) ,
AvailabilityType : _settings [ "availability_type" ] . ( string ) ,
CrashSafeReplicationEnabled : _settings [ "crash_safe_replication" ] . ( bool ) ,
DataDiskSizeGb : int64 ( _settings [ "disk_size" ] . ( int ) ) ,
DataDiskType : _settings [ "disk_type" ] . ( string ) ,
PricingPlan : _settings [ "pricing_plan" ] . ( string ) ,
ReplicationType : _settings [ "replication_type" ] . ( string ) ,
UserLabels : convertStringMap ( _settings [ "user_labels" ] . ( map [ string ] interface { } ) ) ,
BackupConfiguration : expandBackupConfiguration ( _settings [ "backup_configuration" ] . ( [ ] interface { } ) ) ,
DatabaseFlags : expandDatabaseFlags ( _settings [ "database_flags" ] . ( [ ] interface { } ) ) ,
AuthorizedGaeApplications : expandAuthorizedGaeApplications ( _settings [ "authorized_gae_applications" ] . ( [ ] interface { } ) ) ,
IpConfiguration : expandIpConfiguration ( _settings [ "ip_configuration" ] . ( [ ] interface { } ) ) ,
LocationPreference : expandLocationPreference ( _settings [ "location_preference" ] . ( [ ] interface { } ) ) ,
MaintenanceWindow : expandMaintenanceWindow ( _settings [ "maintenance_window" ] . ( [ ] interface { } ) ) ,
}
// 1st Generation instances don't support the disk_autoresize parameter
// and it defaults to true - so we shouldn't set it if this is first gen
if secondGen {
settings . StorageAutoResize = googleapi . Bool ( _settings [ "disk_autoresize" ] . ( bool ) )
}
return settings
}
func expandReplicaConfiguration ( configured [ ] interface { } ) * sqladmin . ReplicaConfiguration {
2018-10-11 16:37:31 +00:00
if len ( configured ) == 0 || configured [ 0 ] == nil {
2018-10-03 14:59:07 +00:00
return nil
}
_replicaConfiguration := configured [ 0 ] . ( map [ string ] interface { } )
return & sqladmin . ReplicaConfiguration {
FailoverTarget : _replicaConfiguration [ "failover_target" ] . ( bool ) ,
// MysqlReplicaConfiguration has been flattened in the TF schema, so
// we'll keep it flat here instead of another expand method.
MysqlReplicaConfiguration : & sqladmin . MySqlReplicaConfiguration {
CaCertificate : _replicaConfiguration [ "ca_certificate" ] . ( string ) ,
ClientCertificate : _replicaConfiguration [ "client_certificate" ] . ( string ) ,
ClientKey : _replicaConfiguration [ "client_key" ] . ( string ) ,
ConnectRetryInterval : int64 ( _replicaConfiguration [ "connect_retry_interval" ] . ( int ) ) ,
DumpFilePath : _replicaConfiguration [ "dump_file_path" ] . ( string ) ,
MasterHeartbeatPeriod : int64 ( _replicaConfiguration [ "master_heartbeat_period" ] . ( int ) ) ,
Password : _replicaConfiguration [ "password" ] . ( string ) ,
SslCipher : _replicaConfiguration [ "ssl_cipher" ] . ( string ) ,
Username : _replicaConfiguration [ "username" ] . ( string ) ,
VerifyServerCertificate : _replicaConfiguration [ "verify_server_certificate" ] . ( bool ) ,
} ,
}
}
func expandMaintenanceWindow ( configured [ ] interface { } ) * sqladmin . MaintenanceWindow {
2018-10-11 16:37:31 +00:00
if len ( configured ) == 0 || configured [ 0 ] == nil {
2018-10-03 14:59:07 +00:00
return nil
}
window := configured [ 0 ] . ( map [ string ] interface { } )
return & sqladmin . MaintenanceWindow {
2018-12-12 00:04:14 +00:00
Day : int64 ( window [ "day" ] . ( int ) ) ,
Hour : int64 ( window [ "hour" ] . ( int ) ) ,
UpdateTrack : window [ "update_track" ] . ( string ) ,
ForceSendFields : [ ] string { "Hour" } ,
2018-10-03 14:59:07 +00:00
}
}
func expandLocationPreference ( configured [ ] interface { } ) * sqladmin . LocationPreference {
2018-10-11 16:37:31 +00:00
if len ( configured ) == 0 || configured [ 0 ] == nil {
2018-10-03 14:59:07 +00:00
return nil
}
_locationPreference := configured [ 0 ] . ( map [ string ] interface { } )
return & sqladmin . LocationPreference {
FollowGaeApplication : _locationPreference [ "follow_gae_application" ] . ( string ) ,
Zone : _locationPreference [ "zone" ] . ( string ) ,
}
}
func expandIpConfiguration ( configured [ ] interface { } ) * sqladmin . IpConfiguration {
2018-10-11 16:37:31 +00:00
if len ( configured ) == 0 || configured [ 0 ] == nil {
2018-10-03 14:59:07 +00:00
return nil
}
_ipConfiguration := configured [ 0 ] . ( map [ string ] interface { } )
2018-11-21 18:43:17 +00:00
2018-10-03 14:59:07 +00:00
return & sqladmin . IpConfiguration {
Ipv4Enabled : _ipConfiguration [ "ipv4_enabled" ] . ( bool ) ,
RequireSsl : _ipConfiguration [ "require_ssl" ] . ( bool ) ,
2018-12-13 22:47:51 +00:00
PrivateNetwork : _ipConfiguration [ "private_network" ] . ( string ) ,
2018-10-03 14:59:07 +00:00
AuthorizedNetworks : expandAuthorizedNetworks ( _ipConfiguration [ "authorized_networks" ] . ( * schema . Set ) . List ( ) ) ,
2018-12-12 00:04:14 +00:00
ForceSendFields : [ ] string { "Ipv4Enabled" , "RequireSsl" } ,
2018-10-03 14:59:07 +00:00
}
}
func expandAuthorizedNetworks ( configured [ ] interface { } ) [ ] * sqladmin . AclEntry {
an := make ( [ ] * sqladmin . AclEntry , 0 , len ( configured ) )
for _ , _acl := range configured {
_entry := _acl . ( map [ string ] interface { } )
an = append ( an , & sqladmin . AclEntry {
ExpirationTime : _entry [ "expiration_time" ] . ( string ) ,
Name : _entry [ "name" ] . ( string ) ,
Value : _entry [ "value" ] . ( string ) ,
} )
}
return an
}
func expandAuthorizedGaeApplications ( configured [ ] interface { } ) [ ] string {
aga := make ( [ ] string , 0 , len ( configured ) )
for _ , app := range configured {
aga = append ( aga , app . ( string ) )
}
return aga
}
func expandDatabaseFlags ( configured [ ] interface { } ) [ ] * sqladmin . DatabaseFlags {
databaseFlags := make ( [ ] * sqladmin . DatabaseFlags , 0 , len ( configured ) )
for _ , _flag := range configured {
_entry := _flag . ( map [ string ] interface { } )
databaseFlags = append ( databaseFlags , & sqladmin . DatabaseFlags {
Name : _entry [ "name" ] . ( string ) ,
Value : _entry [ "value" ] . ( string ) ,
} )
}
return databaseFlags
}
func expandBackupConfiguration ( configured [ ] interface { } ) * sqladmin . BackupConfiguration {
2018-10-11 16:37:31 +00:00
if len ( configured ) == 0 || configured [ 0 ] == nil {
2018-10-03 14:59:07 +00:00
return nil
}
_backupConfiguration := configured [ 0 ] . ( map [ string ] interface { } )
return & sqladmin . BackupConfiguration {
BinaryLogEnabled : _backupConfiguration [ "binary_log_enabled" ] . ( bool ) ,
Enabled : _backupConfiguration [ "enabled" ] . ( bool ) ,
StartTime : _backupConfiguration [ "start_time" ] . ( string ) ,
}
}
2015-10-23 14:10:41 +00:00
func resourceSqlDatabaseInstanceRead ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
2016-04-10 16:59:57 +00:00
project , err := getProject ( d , config )
if err != nil {
return err
}
2019-04-03 20:27:44 +00:00
var instance * sqladmin . DatabaseInstance
err = retry (
func ( ) error {
instance , err = config . clientSqlAdmin . Instances . Get ( project , d . Id ( ) ) . Do ( )
return err
} ,
)
2015-10-23 14:10:41 +00:00
if err != nil {
2017-05-09 23:00:47 +00:00
return handleNotFoundError ( err , d , fmt . Sprintf ( "SQL Database Instance %q" , d . Get ( "name" ) . ( string ) ) )
2015-10-23 14:10:41 +00:00
}
2017-06-22 17:25:26 +00:00
d . Set ( "name" , instance . Name )
d . Set ( "region" , instance . Region )
d . Set ( "database_version" , instance . DatabaseVersion )
2017-09-12 15:04:13 +00:00
d . Set ( "connection_name" , instance . ConnectionName )
2018-09-12 22:43:47 +00:00
d . Set ( "service_account_email_address" , instance . ServiceAccountEmailAddress )
2015-10-23 14:10:41 +00:00
2017-08-01 20:13:09 +00:00
if err := d . Set ( "settings" , flattenSettings ( instance . Settings ) ) ; err != nil {
log . Printf ( "[WARN] Failed to set SQL Database Instance Settings" )
2015-10-23 14:10:41 +00:00
}
2018-03-02 01:12:33 +00:00
2018-07-24 22:32:18 +00:00
if err := d . Set ( "replica_configuration" , flattenReplicaConfiguration ( instance . ReplicaConfiguration , d ) ) ; err != nil {
2017-08-01 20:13:09 +00:00
log . Printf ( "[WARN] Failed to set SQL Database Instance Replica Configuration" )
2015-10-23 14:10:41 +00:00
}
2018-03-02 01:12:33 +00:00
ipAddresses := flattenIpAddresses ( instance . IpAddresses )
if err := d . Set ( "ip_address" , ipAddresses ) ; err != nil {
2017-08-01 20:13:09 +00:00
log . Printf ( "[WARN] Failed to set SQL Database Instance IP Addresses" )
2017-02-01 16:20:31 +00:00
}
2018-03-02 01:12:33 +00:00
if len ( ipAddresses ) > 0 {
2018-10-11 17:07:50 +00:00
d . Set ( "first_ip_address" , ipAddresses [ 0 ] [ "ip_address" ] )
2018-03-02 01:12:33 +00:00
}
2019-02-20 19:06:20 +00:00
publicIpAddress := ""
privateIpAddress := ""
for _ , ip := range instance . IpAddresses {
if publicIpAddress == "" && ip . Type == "PRIMARY" {
publicIpAddress = ip . IpAddress
}
if privateIpAddress == "" && ip . Type == "PRIVATE" {
privateIpAddress = ip . IpAddress
}
}
d . Set ( "public_ip_address" , publicIpAddress )
d . Set ( "private_ip_address" , privateIpAddress )
2018-01-29 21:53:54 +00:00
if err := d . Set ( "server_ca_cert" , flattenServerCaCert ( instance . ServerCaCert ) ) ; err != nil {
log . Printf ( "[WARN] Failed to set SQL Database CA Certificate" )
}
2017-06-22 17:25:26 +00:00
d . Set ( "master_instance_name" , strings . TrimPrefix ( instance . MasterInstanceName , project + ":" ) )
2017-11-28 00:32:20 +00:00
d . Set ( "project" , project )
2015-10-23 14:10:41 +00:00
d . Set ( "self_link" , instance . SelfLink )
d . SetId ( instance . Name )
return nil
}
func resourceSqlDatabaseInstanceUpdate ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
2016-04-10 16:59:57 +00:00
project , err := getProject ( d , config )
if err != nil {
return err
}
2018-10-11 17:07:50 +00:00
// Update only updates the settings, so they are all we need to set.
instance := & sqladmin . DatabaseInstance {
Settings : expandSqlDatabaseInstanceSettings ( d . Get ( "settings" ) . ( [ ] interface { } ) , ! isFirstGen ( d ) ) ,
2015-10-23 14:10:41 +00:00
}
2018-07-24 22:32:18 +00:00
// Lock on the master_instance_name just in case updating any replica
// settings causes operations on the master.
if v , ok := d . GetOk ( "master_instance_name" ) ; ok {
mutexKV . Lock ( instanceMutexKey ( project , v . ( string ) ) )
defer mutexKV . Unlock ( instanceMutexKey ( project , v . ( string ) ) )
}
2018-10-11 17:07:50 +00:00
op , err := config . clientSqlAdmin . Instances . Update ( project , d . Get ( "name" ) . ( string ) , instance ) . Do ( )
2015-10-23 14:10:41 +00:00
if err != nil {
2018-10-11 17:07:50 +00:00
return fmt . Errorf ( "Error, failed to update instance settings for %s: %s" , instance . Name , err )
2015-10-23 14:10:41 +00:00
}
2018-04-03 21:44:18 +00:00
err = sqladminOperationWaitTime ( config , op , project , "Update Instance" , int ( d . Timeout ( schema . TimeoutUpdate ) . Minutes ( ) ) )
2015-10-23 14:10:41 +00:00
if err != nil {
return err
}
return resourceSqlDatabaseInstanceRead ( d , meta )
}
func resourceSqlDatabaseInstanceDelete ( d * schema . ResourceData , meta interface { } ) error {
config := meta . ( * Config )
2016-04-10 16:59:57 +00:00
project , err := getProject ( d , config )
if err != nil {
return err
}
2018-07-24 22:32:18 +00:00
// Lock on the master_instance_name just in case deleting a replica causes
// operations on the master.
if v , ok := d . GetOk ( "master_instance_name" ) ; ok {
mutexKV . Lock ( instanceMutexKey ( project , v . ( string ) ) )
defer mutexKV . Unlock ( instanceMutexKey ( project , v . ( string ) ) )
}
2019-01-08 00:44:54 +00:00
var op * sqladmin . Operation
err = retryTimeDuration ( func ( ) error {
op , err = config . clientSqlAdmin . Instances . Delete ( project , d . Get ( "name" ) . ( string ) ) . Do ( )
return err
} , d . Timeout ( schema . TimeoutDelete ) )
2015-10-23 14:10:41 +00:00
if err != nil {
return fmt . Errorf ( "Error, failed to delete instance %s: %s" , d . Get ( "name" ) . ( string ) , err )
}
2018-04-03 21:44:18 +00:00
err = sqladminOperationWaitTime ( config , op , project , "Delete Instance" , int ( d . Timeout ( schema . TimeoutDelete ) . Minutes ( ) ) )
2015-10-23 14:10:41 +00:00
if err != nil {
return err
}
return nil
}
2017-02-17 23:33:47 +00:00
2018-08-28 23:51:37 +00:00
func resourceSqlDatabaseInstanceImport ( d * schema . ResourceData , meta interface { } ) ( [ ] * schema . ResourceData , error ) {
config := meta . ( * Config )
2019-02-15 00:00:35 +00:00
if err := parseImportId ( [ ] string {
2018-08-28 23:51:37 +00:00
"projects/(?P<project>[^/]+)/instances/(?P<name>[^/]+)" ,
"(?P<project>[^/]+)/(?P<name>[^/]+)" ,
2019-02-15 00:00:35 +00:00
"(?P<name>[^/]+)" } , d , config ) ; err != nil {
return nil , err
}
2018-08-28 23:51:37 +00:00
// Replace import id for the resource id
id , err := replaceVars ( d , config , "{{name}}" )
if err != nil {
return nil , fmt . Errorf ( "Error constructing id: %s" , err )
}
d . SetId ( id )
return [ ] * schema . ResourceData { d } , nil
}
2017-08-01 20:13:09 +00:00
func flattenSettings ( settings * sqladmin . Settings ) [ ] map [ string ] interface { } {
data := map [ string ] interface { } {
"version" : settings . SettingsVersion ,
"tier" : settings . Tier ,
"activation_policy" : settings . ActivationPolicy ,
"authorized_gae_applications" : settings . AuthorizedGaeApplications ,
2018-01-24 17:23:48 +00:00
"availability_type" : settings . AvailabilityType ,
2017-08-01 20:13:09 +00:00
"crash_safe_replication" : settings . CrashSafeReplicationEnabled ,
"disk_type" : settings . DataDiskType ,
"disk_size" : settings . DataDiskSizeGb ,
"pricing_plan" : settings . PricingPlan ,
"replication_type" : settings . ReplicationType ,
2018-05-30 22:32:11 +00:00
"user_labels" : settings . UserLabels ,
2017-08-01 20:13:09 +00:00
}
if settings . BackupConfiguration != nil {
data [ "backup_configuration" ] = flattenBackupConfiguration ( settings . BackupConfiguration )
}
if settings . DatabaseFlags != nil {
data [ "database_flags" ] = flattenDatabaseFlags ( settings . DatabaseFlags )
}
if settings . IpConfiguration != nil {
data [ "ip_configuration" ] = flattenIpConfiguration ( settings . IpConfiguration )
}
if settings . LocationPreference != nil {
data [ "location_preference" ] = flattenLocationPreference ( settings . LocationPreference )
}
2018-01-24 17:23:48 +00:00
2017-08-01 20:13:09 +00:00
if settings . MaintenanceWindow != nil {
data [ "maintenance_window" ] = flattenMaintenanceWindow ( settings . MaintenanceWindow )
}
2018-01-24 17:23:48 +00:00
if settings . StorageAutoResize != nil {
data [ "disk_autoresize" ] = * settings . StorageAutoResize
}
2018-05-30 22:32:11 +00:00
if settings . UserLabels != nil {
data [ "user_labels" ] = settings . UserLabels
}
2017-08-01 20:13:09 +00:00
return [ ] map [ string ] interface { } { data }
}
func flattenBackupConfiguration ( backupConfiguration * sqladmin . BackupConfiguration ) [ ] map [ string ] interface { } {
data := map [ string ] interface { } {
"binary_log_enabled" : backupConfiguration . BinaryLogEnabled ,
"enabled" : backupConfiguration . Enabled ,
"start_time" : backupConfiguration . StartTime ,
}
return [ ] map [ string ] interface { } { data }
}
func flattenDatabaseFlags ( databaseFlags [ ] * sqladmin . DatabaseFlags ) [ ] map [ string ] interface { } {
flags := make ( [ ] map [ string ] interface { } , 0 , len ( databaseFlags ) )
for _ , flag := range databaseFlags {
data := map [ string ] interface { } {
"name" : flag . Name ,
"value" : flag . Value ,
}
flags = append ( flags , data )
}
return flags
}
func flattenIpConfiguration ( ipConfiguration * sqladmin . IpConfiguration ) interface { } {
data := map [ string ] interface { } {
2018-12-13 22:47:51 +00:00
"ipv4_enabled" : ipConfiguration . Ipv4Enabled ,
"private_network" : ipConfiguration . PrivateNetwork ,
"require_ssl" : ipConfiguration . RequireSsl ,
2017-08-01 20:13:09 +00:00
}
if ipConfiguration . AuthorizedNetworks != nil {
data [ "authorized_networks" ] = flattenAuthorizedNetworks ( ipConfiguration . AuthorizedNetworks )
}
return [ ] map [ string ] interface { } { data }
}
func flattenAuthorizedNetworks ( entries [ ] * sqladmin . AclEntry ) interface { } {
2017-11-13 20:51:15 +00:00
networks := schema . NewSet ( schema . HashResource ( sqlDatabaseAuthorizedNetWorkSchemaElem ) , [ ] interface { } { } )
2017-08-01 20:13:09 +00:00
for _ , entry := range entries {
data := map [ string ] interface { } {
"expiration_time" : entry . ExpirationTime ,
"name" : entry . Name ,
"value" : entry . Value ,
}
2017-11-13 20:51:15 +00:00
networks . Add ( data )
2017-08-01 20:13:09 +00:00
}
return networks
}
func flattenLocationPreference ( locationPreference * sqladmin . LocationPreference ) interface { } {
data := map [ string ] interface { } {
"follow_gae_application" : locationPreference . FollowGaeApplication ,
2018-09-05 22:24:22 +00:00
"zone" : locationPreference . Zone ,
2017-08-01 20:13:09 +00:00
}
return [ ] map [ string ] interface { } { data }
}
func flattenMaintenanceWindow ( maintenanceWindow * sqladmin . MaintenanceWindow ) interface { } {
data := map [ string ] interface { } {
"day" : maintenanceWindow . Day ,
"hour" : maintenanceWindow . Hour ,
"update_track" : maintenanceWindow . UpdateTrack ,
}
return [ ] map [ string ] interface { } { data }
}
2018-07-24 22:32:18 +00:00
func flattenReplicaConfiguration ( replicaConfiguration * sqladmin . ReplicaConfiguration , d * schema . ResourceData ) [ ] map [ string ] interface { } {
2017-08-01 20:13:09 +00:00
rc := [ ] map [ string ] interface { } { }
if replicaConfiguration != nil {
data := map [ string ] interface { } {
"failover_target" : replicaConfiguration . FailoverTarget ,
// Don't attempt to assign anything from replicaConfiguration.MysqlReplicaConfiguration,
// since those fields are set on create and then not stored. See description at
2018-07-24 22:32:18 +00:00
// https://cloud.google.com/sql/docs/mysql/admin-api/v1beta4/instances.
// Instead, set them to the values they previously had so we don't set them all to zero.
"ca_certificate" : d . Get ( "replica_configuration.0.ca_certificate" ) ,
"client_certificate" : d . Get ( "replica_configuration.0.client_certificate" ) ,
"client_key" : d . Get ( "replica_configuration.0.client_key" ) ,
"connect_retry_interval" : d . Get ( "replica_configuration.0.connect_retry_interval" ) ,
"dump_file_path" : d . Get ( "replica_configuration.0.dump_file_path" ) ,
"master_heartbeat_period" : d . Get ( "replica_configuration.0.master_heartbeat_period" ) ,
"password" : d . Get ( "replica_configuration.0.password" ) ,
"ssl_cipher" : d . Get ( "replica_configuration.0.ssl_cipher" ) ,
"username" : d . Get ( "replica_configuration.0.username" ) ,
"verify_server_certificate" : d . Get ( "replica_configuration.0.verify_server_certificate" ) ,
2017-08-01 20:13:09 +00:00
}
rc = append ( rc , data )
}
return rc
}
func flattenIpAddresses ( ipAddresses [ ] * sqladmin . IpMapping ) [ ] map [ string ] interface { } {
2017-08-25 16:13:37 +00:00
var ips [ ] map [ string ] interface { }
2017-08-01 20:13:09 +00:00
for _ , ip := range ipAddresses {
data := map [ string ] interface { } {
"ip_address" : ip . IpAddress ,
2018-11-21 18:43:17 +00:00
"type" : ip . Type ,
2017-08-01 20:13:09 +00:00
"time_to_retire" : ip . TimeToRetire ,
}
ips = append ( ips , data )
}
return ips
}
2018-01-29 21:53:54 +00:00
func flattenServerCaCert ( caCert * sqladmin . SslCert ) [ ] map [ string ] interface { } {
var cert [ ] map [ string ] interface { }
if caCert != nil {
data := map [ string ] interface { } {
"cert" : caCert . Cert ,
"common_name" : caCert . CommonName ,
"create_time" : caCert . CreateTime ,
"expiration_time" : caCert . ExpirationTime ,
"sha1_fingerprint" : caCert . Sha1Fingerprint ,
}
cert = append ( cert , data )
}
return cert
}
2017-05-31 19:19:27 +00:00
func instanceMutexKey ( project , instance_name string ) string {
return fmt . Sprintf ( "google-sql-database-instance-%s-%s" , project , instance_name )
}
2017-09-07 19:44:17 +00:00
2018-10-03 14:59:07 +00:00
// sqlDatabaseIsMaster returns true if the provided schema.ResourceData represents a
// master SQL Instance, and false if it is a replica.
func sqlDatabaseIsMaster ( d * schema . ResourceData ) bool {
2017-09-07 19:44:17 +00:00
_ , ok := d . GetOk ( "master_instance_name" )
2018-10-03 14:59:07 +00:00
return ! ok
2017-09-07 19:44:17 +00:00
}