github.com/koding/terraform@v0.6.4-0.20170608090606-5d7e0339779d/builtin/providers/google/resource_sql_database_instance.go (about)

     1  package google
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"regexp"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/terraform/helper/resource"
    10  	"github.com/hashicorp/terraform/helper/schema"
    11  
    12  	"google.golang.org/api/googleapi"
    13  	"google.golang.org/api/sqladmin/v1beta4"
    14  )
    15  
    16  func resourceSqlDatabaseInstance() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceSqlDatabaseInstanceCreate,
    19  		Read:   resourceSqlDatabaseInstanceRead,
    20  		Update: resourceSqlDatabaseInstanceUpdate,
    21  		Delete: resourceSqlDatabaseInstanceDelete,
    22  
    23  		Schema: map[string]*schema.Schema{
    24  			"region": &schema.Schema{
    25  				Type:     schema.TypeString,
    26  				Required: true,
    27  				ForceNew: true,
    28  			},
    29  
    30  			"settings": &schema.Schema{
    31  				Type:     schema.TypeList,
    32  				Required: true,
    33  				MaxItems: 1,
    34  				Elem: &schema.Resource{
    35  					Schema: map[string]*schema.Schema{
    36  						"version": &schema.Schema{
    37  							Type:     schema.TypeInt,
    38  							Computed: true,
    39  						},
    40  						"tier": &schema.Schema{
    41  							Type:     schema.TypeString,
    42  							Required: true,
    43  						},
    44  						"activation_policy": &schema.Schema{
    45  							Type:     schema.TypeString,
    46  							Optional: true,
    47  						},
    48  						"authorized_gae_applications": &schema.Schema{
    49  							Type:     schema.TypeList,
    50  							Optional: true,
    51  							Elem:     &schema.Schema{Type: schema.TypeString},
    52  						},
    53  						"backup_configuration": &schema.Schema{
    54  							Type:     schema.TypeList,
    55  							Optional: true,
    56  							Elem: &schema.Resource{
    57  								Schema: map[string]*schema.Schema{
    58  									"binary_log_enabled": &schema.Schema{
    59  										Type:     schema.TypeBool,
    60  										Optional: true,
    61  									},
    62  									"enabled": &schema.Schema{
    63  										Type:     schema.TypeBool,
    64  										Optional: true,
    65  									},
    66  									"start_time": &schema.Schema{
    67  										Type:     schema.TypeString,
    68  										Optional: true,
    69  									},
    70  								},
    71  							},
    72  						},
    73  						"crash_safe_replication": &schema.Schema{
    74  							Type:     schema.TypeBool,
    75  							Optional: true,
    76  							Computed: true,
    77  						},
    78  						"database_flags": &schema.Schema{
    79  							Type:     schema.TypeList,
    80  							Optional: true,
    81  							Elem: &schema.Resource{
    82  								Schema: map[string]*schema.Schema{
    83  									"value": &schema.Schema{
    84  										Type:     schema.TypeString,
    85  										Optional: true,
    86  									},
    87  									"name": &schema.Schema{
    88  										Type:     schema.TypeString,
    89  										Optional: true,
    90  									},
    91  								},
    92  							},
    93  						},
    94  						"disk_autoresize": &schema.Schema{
    95  							Type:             schema.TypeBool,
    96  							Default:          true,
    97  							Optional:         true,
    98  							DiffSuppressFunc: suppressFirstGen,
    99  						},
   100  						"disk_size": &schema.Schema{
   101  							Type:     schema.TypeInt,
   102  							Optional: true,
   103  						},
   104  						"disk_type": &schema.Schema{
   105  							Type:     schema.TypeString,
   106  							Optional: true,
   107  						},
   108  						"ip_configuration": &schema.Schema{
   109  							Type:     schema.TypeList,
   110  							Optional: true,
   111  							Elem: &schema.Resource{
   112  								Schema: map[string]*schema.Schema{
   113  									"authorized_networks": &schema.Schema{
   114  										Type:     schema.TypeList,
   115  										Optional: true,
   116  										Elem: &schema.Resource{
   117  											Schema: map[string]*schema.Schema{
   118  												"expiration_time": &schema.Schema{
   119  													Type:     schema.TypeString,
   120  													Optional: true,
   121  												},
   122  												"name": &schema.Schema{
   123  													Type:     schema.TypeString,
   124  													Optional: true,
   125  												},
   126  												"value": &schema.Schema{
   127  													Type:     schema.TypeString,
   128  													Optional: true,
   129  												},
   130  											},
   131  										},
   132  									},
   133  									"ipv4_enabled": &schema.Schema{
   134  										Type:     schema.TypeBool,
   135  										Optional: true,
   136  									},
   137  									"require_ssl": &schema.Schema{
   138  										Type:     schema.TypeBool,
   139  										Optional: true,
   140  									},
   141  								},
   142  							},
   143  						},
   144  						"location_preference": &schema.Schema{
   145  							Type:     schema.TypeList,
   146  							Optional: true,
   147  							Elem: &schema.Resource{
   148  								Schema: map[string]*schema.Schema{
   149  									"follow_gae_application": &schema.Schema{
   150  										Type:     schema.TypeString,
   151  										Optional: true,
   152  									},
   153  									"zone": &schema.Schema{
   154  										Type:     schema.TypeString,
   155  										Optional: true,
   156  									},
   157  								},
   158  							},
   159  						},
   160  						"maintenance_window": &schema.Schema{
   161  							Type:     schema.TypeList,
   162  							Optional: true,
   163  							MaxItems: 1,
   164  							Elem: &schema.Resource{
   165  								Schema: map[string]*schema.Schema{
   166  									"day": &schema.Schema{
   167  										Type:     schema.TypeInt,
   168  										Optional: true,
   169  										ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
   170  											return validateNumericRange(v, k, 1, 7)
   171  										},
   172  									},
   173  									"hour": &schema.Schema{
   174  										Type:     schema.TypeInt,
   175  										Optional: true,
   176  										ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
   177  											return validateNumericRange(v, k, 0, 23)
   178  										},
   179  									},
   180  									"update_track": &schema.Schema{
   181  										Type:     schema.TypeString,
   182  										Optional: true,
   183  									},
   184  								},
   185  							},
   186  						},
   187  						"pricing_plan": &schema.Schema{
   188  							Type:     schema.TypeString,
   189  							Optional: true,
   190  						},
   191  						"replication_type": &schema.Schema{
   192  							Type:     schema.TypeString,
   193  							Optional: true,
   194  						},
   195  					},
   196  				},
   197  			},
   198  
   199  			"database_version": &schema.Schema{
   200  				Type:     schema.TypeString,
   201  				Optional: true,
   202  				Default:  "MYSQL_5_6",
   203  				ForceNew: true,
   204  			},
   205  
   206  			"ip_address": &schema.Schema{
   207  				Type:     schema.TypeList,
   208  				Computed: true,
   209  				Elem: &schema.Resource{
   210  					Schema: map[string]*schema.Schema{
   211  						"ip_address": &schema.Schema{
   212  							Type:     schema.TypeString,
   213  							Computed: true,
   214  						},
   215  						"time_to_retire": &schema.Schema{
   216  							Type:     schema.TypeString,
   217  							Optional: true,
   218  							Computed: true,
   219  						},
   220  					},
   221  				},
   222  			},
   223  
   224  			"name": &schema.Schema{
   225  				Type:     schema.TypeString,
   226  				Optional: true,
   227  				Computed: true,
   228  				ForceNew: true,
   229  			},
   230  
   231  			"master_instance_name": &schema.Schema{
   232  				Type:     schema.TypeString,
   233  				Optional: true,
   234  				ForceNew: true,
   235  			},
   236  
   237  			"project": &schema.Schema{
   238  				Type:     schema.TypeString,
   239  				Optional: true,
   240  				ForceNew: true,
   241  			},
   242  
   243  			"replica_configuration": &schema.Schema{
   244  				Type:     schema.TypeList,
   245  				Optional: true,
   246  				MaxItems: 1,
   247  				Elem: &schema.Resource{
   248  					Schema: map[string]*schema.Schema{
   249  						"ca_certificate": &schema.Schema{
   250  							Type:     schema.TypeString,
   251  							Optional: true,
   252  							ForceNew: true,
   253  						},
   254  						"client_certificate": &schema.Schema{
   255  							Type:     schema.TypeString,
   256  							Optional: true,
   257  							ForceNew: true,
   258  						},
   259  						"client_key": &schema.Schema{
   260  							Type:     schema.TypeString,
   261  							Optional: true,
   262  							ForceNew: true,
   263  						},
   264  						"connect_retry_interval": &schema.Schema{
   265  							Type:     schema.TypeInt,
   266  							Optional: true,
   267  							ForceNew: true,
   268  						},
   269  						"dump_file_path": &schema.Schema{
   270  							Type:     schema.TypeString,
   271  							Optional: true,
   272  							ForceNew: true,
   273  						},
   274  						"failover_target": &schema.Schema{
   275  							Type:     schema.TypeBool,
   276  							Optional: true,
   277  							ForceNew: true,
   278  						},
   279  						"master_heartbeat_period": &schema.Schema{
   280  							Type:     schema.TypeInt,
   281  							Optional: true,
   282  							ForceNew: true,
   283  						},
   284  						"password": &schema.Schema{
   285  							Type:     schema.TypeString,
   286  							Optional: true,
   287  							ForceNew: true,
   288  						},
   289  						"ssl_cipher": &schema.Schema{
   290  							Type:     schema.TypeString,
   291  							Optional: true,
   292  							ForceNew: true,
   293  						},
   294  						"username": &schema.Schema{
   295  							Type:     schema.TypeString,
   296  							Optional: true,
   297  							ForceNew: true,
   298  						},
   299  						"verify_server_certificate": &schema.Schema{
   300  							Type:     schema.TypeBool,
   301  							Optional: true,
   302  							ForceNew: true,
   303  						},
   304  					},
   305  				},
   306  			},
   307  
   308  			"self_link": &schema.Schema{
   309  				Type:     schema.TypeString,
   310  				Computed: true,
   311  			},
   312  		},
   313  	}
   314  }
   315  
   316  // Suppress diff with any disk_autoresize value on 1st Generation Instances
   317  func suppressFirstGen(k, old, new string, d *schema.ResourceData) bool {
   318  	settingsList := d.Get("settings").([]interface{})
   319  
   320  	settings := settingsList[0].(map[string]interface{})
   321  	tier := settings["tier"].(string)
   322  	matched, err := regexp.MatchString("db*", tier)
   323  	if err != nil {
   324  		log.Printf("[ERR] error with regex in diff supression for disk_autoresize: %s", err)
   325  	}
   326  	if !matched {
   327  		log.Printf("[DEBUG] suppressing diff on disk_autoresize due to 1st gen instance type")
   328  		return true
   329  	}
   330  	return false
   331  }
   332  
   333  func resourceSqlDatabaseInstanceCreate(d *schema.ResourceData, meta interface{}) error {
   334  	config := meta.(*Config)
   335  
   336  	project, err := getProject(d, config)
   337  	if err != nil {
   338  		return err
   339  	}
   340  
   341  	region := d.Get("region").(string)
   342  	databaseVersion := d.Get("database_version").(string)
   343  
   344  	_settingsList := d.Get("settings").([]interface{})
   345  
   346  	_settings := _settingsList[0].(map[string]interface{})
   347  	settings := &sqladmin.Settings{
   348  		Tier:            _settings["tier"].(string),
   349  		ForceSendFields: []string{"StorageAutoResize"},
   350  	}
   351  
   352  	if v, ok := _settings["activation_policy"]; ok {
   353  		settings.ActivationPolicy = v.(string)
   354  	}
   355  
   356  	if v, ok := _settings["authorized_gae_applications"]; ok {
   357  		settings.AuthorizedGaeApplications = make([]string, 0)
   358  		for _, app := range v.([]interface{}) {
   359  			settings.AuthorizedGaeApplications = append(settings.AuthorizedGaeApplications,
   360  				app.(string))
   361  		}
   362  	}
   363  
   364  	if v, ok := _settings["backup_configuration"]; ok {
   365  		_backupConfigurationList := v.([]interface{})
   366  		if len(_backupConfigurationList) > 1 {
   367  			return fmt.Errorf("At most one backup_configuration block is allowed")
   368  		}
   369  
   370  		if len(_backupConfigurationList) == 1 && _backupConfigurationList[0] != nil {
   371  			settings.BackupConfiguration = &sqladmin.BackupConfiguration{}
   372  			_backupConfiguration := _backupConfigurationList[0].(map[string]interface{})
   373  
   374  			if vp, okp := _backupConfiguration["binary_log_enabled"]; okp {
   375  				settings.BackupConfiguration.BinaryLogEnabled = vp.(bool)
   376  			}
   377  
   378  			if vp, okp := _backupConfiguration["enabled"]; okp {
   379  				settings.BackupConfiguration.Enabled = vp.(bool)
   380  			}
   381  
   382  			if vp, okp := _backupConfiguration["start_time"]; okp {
   383  				settings.BackupConfiguration.StartTime = vp.(string)
   384  			}
   385  		}
   386  	}
   387  
   388  	if v, ok := _settings["crash_safe_replication"]; ok {
   389  		settings.CrashSafeReplicationEnabled = v.(bool)
   390  	}
   391  
   392  	settings.StorageAutoResize = _settings["disk_autoresize"].(bool)
   393  
   394  	if v, ok := _settings["disk_size"]; ok && v.(int) > 0 {
   395  		settings.DataDiskSizeGb = int64(v.(int))
   396  	}
   397  
   398  	if v, ok := _settings["disk_type"]; ok && len(v.(string)) > 0 {
   399  		settings.DataDiskType = v.(string)
   400  	}
   401  
   402  	if v, ok := _settings["database_flags"]; ok {
   403  		settings.DatabaseFlags = make([]*sqladmin.DatabaseFlags, 0)
   404  		_databaseFlagsList := v.([]interface{})
   405  		for _, _flag := range _databaseFlagsList {
   406  			_entry := _flag.(map[string]interface{})
   407  			flag := &sqladmin.DatabaseFlags{}
   408  			if vp, okp := _entry["name"]; okp {
   409  				flag.Name = vp.(string)
   410  			}
   411  
   412  			if vp, okp := _entry["value"]; okp {
   413  				flag.Value = vp.(string)
   414  			}
   415  
   416  			settings.DatabaseFlags = append(settings.DatabaseFlags, flag)
   417  		}
   418  	}
   419  
   420  	if v, ok := _settings["ip_configuration"]; ok {
   421  		_ipConfigurationList := v.([]interface{})
   422  		if len(_ipConfigurationList) > 1 {
   423  			return fmt.Errorf("At most one ip_configuration block is allowed")
   424  		}
   425  
   426  		if len(_ipConfigurationList) == 1 && _ipConfigurationList[0] != nil {
   427  			settings.IpConfiguration = &sqladmin.IpConfiguration{}
   428  			_ipConfiguration := _ipConfigurationList[0].(map[string]interface{})
   429  
   430  			if vp, okp := _ipConfiguration["ipv4_enabled"]; okp {
   431  				settings.IpConfiguration.Ipv4Enabled = vp.(bool)
   432  			}
   433  
   434  			if vp, okp := _ipConfiguration["require_ssl"]; okp {
   435  				settings.IpConfiguration.RequireSsl = vp.(bool)
   436  			}
   437  
   438  			if vp, okp := _ipConfiguration["authorized_networks"]; okp {
   439  				settings.IpConfiguration.AuthorizedNetworks = make([]*sqladmin.AclEntry, 0)
   440  				_authorizedNetworksList := vp.([]interface{})
   441  				for _, _acl := range _authorizedNetworksList {
   442  					_entry := _acl.(map[string]interface{})
   443  					entry := &sqladmin.AclEntry{}
   444  
   445  					if vpp, okpp := _entry["expiration_time"]; okpp {
   446  						entry.ExpirationTime = vpp.(string)
   447  					}
   448  
   449  					if vpp, okpp := _entry["name"]; okpp {
   450  						entry.Name = vpp.(string)
   451  					}
   452  
   453  					if vpp, okpp := _entry["value"]; okpp {
   454  						entry.Value = vpp.(string)
   455  					}
   456  
   457  					settings.IpConfiguration.AuthorizedNetworks = append(
   458  						settings.IpConfiguration.AuthorizedNetworks, entry)
   459  				}
   460  			}
   461  		}
   462  	}
   463  
   464  	if v, ok := _settings["location_preference"]; ok {
   465  		_locationPreferenceList := v.([]interface{})
   466  		if len(_locationPreferenceList) > 1 {
   467  			return fmt.Errorf("At most one location_preference block is allowed")
   468  		}
   469  
   470  		if len(_locationPreferenceList) == 1 && _locationPreferenceList[0] != nil {
   471  			settings.LocationPreference = &sqladmin.LocationPreference{}
   472  			_locationPreference := _locationPreferenceList[0].(map[string]interface{})
   473  
   474  			if vp, okp := _locationPreference["follow_gae_application"]; okp {
   475  				settings.LocationPreference.FollowGaeApplication = vp.(string)
   476  			}
   477  
   478  			if vp, okp := _locationPreference["zone"]; okp {
   479  				settings.LocationPreference.Zone = vp.(string)
   480  			}
   481  		}
   482  	}
   483  
   484  	if v, ok := _settings["maintenance_window"]; ok && len(v.([]interface{})) > 0 {
   485  		settings.MaintenanceWindow = &sqladmin.MaintenanceWindow{}
   486  		_maintenanceWindow := v.([]interface{})[0].(map[string]interface{})
   487  
   488  		if vp, okp := _maintenanceWindow["day"]; okp {
   489  			settings.MaintenanceWindow.Day = int64(vp.(int))
   490  		}
   491  
   492  		if vp, okp := _maintenanceWindow["hour"]; okp {
   493  			settings.MaintenanceWindow.Hour = int64(vp.(int))
   494  		}
   495  
   496  		if vp, ok := _maintenanceWindow["update_track"]; ok {
   497  			if len(vp.(string)) > 0 {
   498  				settings.MaintenanceWindow.UpdateTrack = vp.(string)
   499  			}
   500  		}
   501  	}
   502  
   503  	if v, ok := _settings["pricing_plan"]; ok {
   504  		settings.PricingPlan = v.(string)
   505  	}
   506  
   507  	if v, ok := _settings["replication_type"]; ok {
   508  		settings.ReplicationType = v.(string)
   509  	}
   510  
   511  	instance := &sqladmin.DatabaseInstance{
   512  		Region:          region,
   513  		Settings:        settings,
   514  		DatabaseVersion: databaseVersion,
   515  	}
   516  
   517  	if v, ok := d.GetOk("name"); ok {
   518  		instance.Name = v.(string)
   519  	} else {
   520  		instance.Name = resource.UniqueId()
   521  		d.Set("name", instance.Name)
   522  	}
   523  
   524  	if v, ok := d.GetOk("replica_configuration"); ok {
   525  		_replicaConfigurationList := v.([]interface{})
   526  
   527  		if len(_replicaConfigurationList) == 1 && _replicaConfigurationList[0] != nil {
   528  			replicaConfiguration := &sqladmin.ReplicaConfiguration{}
   529  			mySqlReplicaConfiguration := &sqladmin.MySqlReplicaConfiguration{}
   530  			_replicaConfiguration := _replicaConfigurationList[0].(map[string]interface{})
   531  
   532  			if vp, okp := _replicaConfiguration["failover_target"]; okp {
   533  				replicaConfiguration.FailoverTarget = vp.(bool)
   534  			}
   535  
   536  			if vp, okp := _replicaConfiguration["ca_certificate"]; okp {
   537  				mySqlReplicaConfiguration.CaCertificate = vp.(string)
   538  			}
   539  
   540  			if vp, okp := _replicaConfiguration["client_certificate"]; okp {
   541  				mySqlReplicaConfiguration.ClientCertificate = vp.(string)
   542  			}
   543  
   544  			if vp, okp := _replicaConfiguration["client_key"]; okp {
   545  				mySqlReplicaConfiguration.ClientKey = vp.(string)
   546  			}
   547  
   548  			if vp, okp := _replicaConfiguration["connect_retry_interval"]; okp {
   549  				mySqlReplicaConfiguration.ConnectRetryInterval = int64(vp.(int))
   550  			}
   551  
   552  			if vp, okp := _replicaConfiguration["dump_file_path"]; okp {
   553  				mySqlReplicaConfiguration.DumpFilePath = vp.(string)
   554  			}
   555  
   556  			if vp, okp := _replicaConfiguration["master_heartbeat_period"]; okp {
   557  				mySqlReplicaConfiguration.MasterHeartbeatPeriod = int64(vp.(int))
   558  			}
   559  
   560  			if vp, okp := _replicaConfiguration["password"]; okp {
   561  				mySqlReplicaConfiguration.Password = vp.(string)
   562  			}
   563  
   564  			if vp, okp := _replicaConfiguration["ssl_cipher"]; okp {
   565  				mySqlReplicaConfiguration.SslCipher = vp.(string)
   566  			}
   567  
   568  			if vp, okp := _replicaConfiguration["username"]; okp {
   569  				mySqlReplicaConfiguration.Username = vp.(string)
   570  			}
   571  
   572  			if vp, okp := _replicaConfiguration["verify_server_certificate"]; okp {
   573  				mySqlReplicaConfiguration.VerifyServerCertificate = vp.(bool)
   574  			}
   575  
   576  			replicaConfiguration.MysqlReplicaConfiguration = mySqlReplicaConfiguration
   577  			instance.ReplicaConfiguration = replicaConfiguration
   578  		}
   579  	}
   580  
   581  	if v, ok := d.GetOk("master_instance_name"); ok {
   582  		instance.MasterInstanceName = v.(string)
   583  	}
   584  
   585  	op, err := config.clientSqlAdmin.Instances.Insert(project, instance).Do()
   586  	if err != nil {
   587  		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 409 {
   588  			return fmt.Errorf("Error, the name %s is unavailable because it was used recently", instance.Name)
   589  		} else {
   590  			return fmt.Errorf("Error, failed to create instance %s: %s", instance.Name, err)
   591  		}
   592  	}
   593  
   594  	err = sqladminOperationWait(config, op, "Create Instance")
   595  	if err != nil {
   596  		return err
   597  	}
   598  
   599  	err = resourceSqlDatabaseInstanceRead(d, meta)
   600  	if err != nil {
   601  		return err
   602  	}
   603  
   604  	// If a root user exists with a wildcard ('%') hostname, delete it.
   605  	users, err := config.clientSqlAdmin.Users.List(project, instance.Name).Do()
   606  	if err != nil {
   607  		return fmt.Errorf("Error, attempting to list users associated with instance %s: %s", instance.Name, err)
   608  	}
   609  	for _, u := range users.Items {
   610  		if u.Name == "root" && u.Host == "%" {
   611  			op, err = config.clientSqlAdmin.Users.Delete(project, instance.Name, u.Host, u.Name).Do()
   612  			if err != nil {
   613  				return fmt.Errorf("Error, failed to delete default 'root'@'*' user, but the database was created successfully: %s", err)
   614  			}
   615  			err = sqladminOperationWait(config, op, "Delete default root User")
   616  			if err != nil {
   617  				return err
   618  			}
   619  		}
   620  	}
   621  
   622  	return nil
   623  }
   624  
   625  func resourceSqlDatabaseInstanceRead(d *schema.ResourceData, meta interface{}) error {
   626  	config := meta.(*Config)
   627  
   628  	project, err := getProject(d, config)
   629  	if err != nil {
   630  		return err
   631  	}
   632  
   633  	instance, err := config.clientSqlAdmin.Instances.Get(project,
   634  		d.Get("name").(string)).Do()
   635  
   636  	if err != nil {
   637  		return handleNotFoundError(err, d, fmt.Sprintf("SQL Database Instance %q", d.Get("name").(string)))
   638  	}
   639  
   640  	_settingsList := d.Get("settings").([]interface{})
   641  	_settings := _settingsList[0].(map[string]interface{})
   642  
   643  	settings := instance.Settings
   644  	_settings["version"] = settings.SettingsVersion
   645  	_settings["tier"] = settings.Tier
   646  
   647  	// Take care to only update attributes that the user has defined explicitly
   648  	if v, ok := _settings["activation_policy"]; ok && len(v.(string)) > 0 {
   649  		_settings["activation_policy"] = settings.ActivationPolicy
   650  	}
   651  
   652  	if v, ok := _settings["authorized_gae_applications"]; ok && len(v.([]interface{})) > 0 {
   653  		_authorized_gae_applications := make([]interface{}, 0)
   654  		for _, app := range settings.AuthorizedGaeApplications {
   655  			_authorized_gae_applications = append(_authorized_gae_applications, app)
   656  		}
   657  		_settings["authorized_gae_applications"] = _authorized_gae_applications
   658  	}
   659  
   660  	if v, ok := _settings["backup_configuration"]; ok {
   661  		_backupConfigurationList := v.([]interface{})
   662  		if len(_backupConfigurationList) > 1 {
   663  			return fmt.Errorf("At most one backup_configuration block is allowed")
   664  		}
   665  
   666  		if len(_backupConfigurationList) == 1 && _backupConfigurationList[0] != nil {
   667  			_backupConfiguration := _backupConfigurationList[0].(map[string]interface{})
   668  
   669  			if vp, okp := _backupConfiguration["binary_log_enabled"]; okp && vp != nil {
   670  				_backupConfiguration["binary_log_enabled"] = settings.BackupConfiguration.BinaryLogEnabled
   671  			}
   672  
   673  			if vp, okp := _backupConfiguration["enabled"]; okp && vp != nil {
   674  				_backupConfiguration["enabled"] = settings.BackupConfiguration.Enabled
   675  			}
   676  
   677  			if vp, okp := _backupConfiguration["start_time"]; okp && len(vp.(string)) > 0 {
   678  				_backupConfiguration["start_time"] = settings.BackupConfiguration.StartTime
   679  			}
   680  
   681  			_backupConfigurationList[0] = _backupConfiguration
   682  			_settings["backup_configuration"] = _backupConfigurationList
   683  		}
   684  	}
   685  
   686  	if v, ok := _settings["crash_safe_replication"]; ok && v != nil {
   687  		_settings["crash_safe_replication"] = settings.CrashSafeReplicationEnabled
   688  	}
   689  
   690  	_settings["disk_autoresize"] = settings.StorageAutoResize
   691  
   692  	if v, ok := _settings["disk_size"]; ok && v != nil {
   693  		if v.(int) > 0 && settings.DataDiskSizeGb < int64(v.(int)) {
   694  			_settings["disk_size"] = settings.DataDiskSizeGb
   695  		}
   696  	}
   697  
   698  	if v, ok := _settings["disk_type"]; ok && v != nil {
   699  		if len(v.(string)) > 0 {
   700  			_settings["disk_type"] = settings.DataDiskType
   701  		}
   702  	}
   703  
   704  	if v, ok := _settings["database_flags"]; ok && len(v.([]interface{})) > 0 {
   705  		_flag_map := make(map[string]string)
   706  		// First keep track of localy defined flag pairs
   707  		for _, _flag := range _settings["database_flags"].([]interface{}) {
   708  			_entry := _flag.(map[string]interface{})
   709  			_flag_map[_entry["name"].(string)] = _entry["value"].(string)
   710  		}
   711  
   712  		_database_flags := make([]interface{}, 0)
   713  		// Next read the flag pairs from the server, and reinsert those that
   714  		// correspond to ones defined locally
   715  		for _, entry := range settings.DatabaseFlags {
   716  			if _, okp := _flag_map[entry.Name]; okp {
   717  				_entry := make(map[string]interface{})
   718  				_entry["name"] = entry.Name
   719  				_entry["value"] = entry.Value
   720  				_database_flags = append(_database_flags, _entry)
   721  			}
   722  		}
   723  		_settings["database_flags"] = _database_flags
   724  	}
   725  
   726  	if v, ok := _settings["ip_configuration"]; ok {
   727  		_ipConfigurationList := v.([]interface{})
   728  		if len(_ipConfigurationList) > 1 {
   729  			return fmt.Errorf("At most one ip_configuration block is allowed")
   730  		}
   731  
   732  		if len(_ipConfigurationList) == 1 && _ipConfigurationList[0] != nil {
   733  			_ipConfiguration := _ipConfigurationList[0].(map[string]interface{})
   734  
   735  			if vp, okp := _ipConfiguration["ipv4_enabled"]; okp && vp != nil {
   736  				_ipConfiguration["ipv4_enabled"] = settings.IpConfiguration.Ipv4Enabled
   737  			}
   738  
   739  			if vp, okp := _ipConfiguration["require_ssl"]; okp && vp != nil {
   740  				_ipConfiguration["require_ssl"] = settings.IpConfiguration.RequireSsl
   741  			}
   742  
   743  			if vp, okp := _ipConfiguration["authorized_networks"]; okp && vp != nil {
   744  				_authorizedNetworksList := vp.([]interface{})
   745  				_ipc_map := make(map[string]interface{})
   746  				// First keep track of locally defined ip configurations
   747  				for _, _ipc := range _authorizedNetworksList {
   748  					if _ipc == nil {
   749  						continue
   750  					}
   751  					_entry := _ipc.(map[string]interface{})
   752  					if _entry["value"] == nil {
   753  						continue
   754  					}
   755  					_value := make(map[string]interface{})
   756  					_value["name"] = _entry["name"]
   757  					_value["expiration_time"] = _entry["expiration_time"]
   758  					// We key on value, since that is the only required part of
   759  					// this 3-tuple
   760  					_ipc_map[_entry["value"].(string)] = _value
   761  				}
   762  				_authorized_networks := make([]interface{}, 0)
   763  				// Next read the network tuples from the server, and reinsert those that
   764  				// correspond to ones defined locally
   765  				for _, entry := range settings.IpConfiguration.AuthorizedNetworks {
   766  					if _, okp := _ipc_map[entry.Value]; okp {
   767  						_entry := make(map[string]interface{})
   768  						_entry["value"] = entry.Value
   769  						_entry["name"] = entry.Name
   770  						_entry["expiration_time"] = entry.ExpirationTime
   771  						_authorized_networks = append(_authorized_networks, _entry)
   772  					}
   773  				}
   774  				_ipConfiguration["authorized_networks"] = _authorized_networks
   775  			}
   776  			_ipConfigurationList[0] = _ipConfiguration
   777  			_settings["ip_configuration"] = _ipConfigurationList
   778  		}
   779  	}
   780  
   781  	if v, ok := _settings["location_preference"]; ok && len(v.([]interface{})) > 0 {
   782  		_locationPreferenceList := v.([]interface{})
   783  		if len(_locationPreferenceList) > 1 {
   784  			return fmt.Errorf("At most one location_preference block is allowed")
   785  		}
   786  
   787  		if len(_locationPreferenceList) == 1 && _locationPreferenceList[0] != nil &&
   788  			settings.LocationPreference != nil {
   789  			_locationPreference := _locationPreferenceList[0].(map[string]interface{})
   790  
   791  			if vp, okp := _locationPreference["follow_gae_application"]; okp && vp != nil {
   792  				_locationPreference["follow_gae_application"] =
   793  					settings.LocationPreference.FollowGaeApplication
   794  			}
   795  
   796  			if vp, okp := _locationPreference["zone"]; okp && vp != nil {
   797  				_locationPreference["zone"] = settings.LocationPreference.Zone
   798  			}
   799  
   800  			_locationPreferenceList[0] = _locationPreference
   801  			_settings["location_preference"] = _locationPreferenceList[0]
   802  		}
   803  	}
   804  
   805  	if v, ok := _settings["maintenance_window"]; ok && len(v.([]interface{})) > 0 &&
   806  		settings.MaintenanceWindow != nil {
   807  		_maintenanceWindow := v.([]interface{})[0].(map[string]interface{})
   808  
   809  		if vp, okp := _maintenanceWindow["day"]; okp && vp != nil {
   810  			_maintenanceWindow["day"] = settings.MaintenanceWindow.Day
   811  		}
   812  
   813  		if vp, okp := _maintenanceWindow["hour"]; okp && vp != nil {
   814  			_maintenanceWindow["hour"] = settings.MaintenanceWindow.Hour
   815  		}
   816  
   817  		if vp, ok := _maintenanceWindow["update_track"]; ok && vp != nil {
   818  			if len(vp.(string)) > 0 {
   819  				_maintenanceWindow["update_track"] = settings.MaintenanceWindow.UpdateTrack
   820  			}
   821  		}
   822  	}
   823  
   824  	if v, ok := _settings["pricing_plan"]; ok && len(v.(string)) > 0 {
   825  		_settings["pricing_plan"] = settings.PricingPlan
   826  	}
   827  
   828  	if v, ok := _settings["replication_type"]; ok && len(v.(string)) > 0 {
   829  		_settings["replication_type"] = settings.ReplicationType
   830  	}
   831  
   832  	_settingsList[0] = _settings
   833  	d.Set("settings", _settingsList)
   834  
   835  	if v, ok := d.GetOk("replica_configuration"); ok && v != nil {
   836  		_replicaConfigurationList := v.([]interface{})
   837  		if len(_replicaConfigurationList) == 1 && _replicaConfigurationList[0] != nil {
   838  			_replicaConfiguration := _replicaConfigurationList[0].(map[string]interface{})
   839  
   840  			if vp, okp := _replicaConfiguration["failover_target"]; okp && vp != nil {
   841  				_replicaConfiguration["failover_target"] = instance.ReplicaConfiguration.FailoverTarget
   842  			}
   843  
   844  			// Don't attempt to assign anything from instance.ReplicaConfiguration.MysqlReplicaConfiguration,
   845  			// since those fields are set on create and then not stored. See description at
   846  			// https://cloud.google.com/sql/docs/mysql/admin-api/v1beta4/instances
   847  
   848  			_replicaConfigurationList[0] = _replicaConfiguration
   849  			d.Set("replica_configuration", _replicaConfigurationList)
   850  		}
   851  	}
   852  
   853  	_ipAddresses := make([]interface{}, len(instance.IpAddresses))
   854  
   855  	for i, ip := range instance.IpAddresses {
   856  		_ipAddress := make(map[string]interface{})
   857  
   858  		_ipAddress["ip_address"] = ip.IpAddress
   859  		_ipAddress["time_to_retire"] = ip.TimeToRetire
   860  
   861  		_ipAddresses[i] = _ipAddress
   862  	}
   863  
   864  	d.Set("ip_address", _ipAddresses)
   865  
   866  	if v, ok := d.GetOk("master_instance_name"); ok && v != nil {
   867  		d.Set("master_instance_name", strings.TrimPrefix(instance.MasterInstanceName, project+":"))
   868  	}
   869  
   870  	d.Set("self_link", instance.SelfLink)
   871  	d.SetId(instance.Name)
   872  
   873  	return nil
   874  }
   875  
   876  func resourceSqlDatabaseInstanceUpdate(d *schema.ResourceData, meta interface{}) error {
   877  	config := meta.(*Config)
   878  
   879  	project, err := getProject(d, config)
   880  	if err != nil {
   881  		return err
   882  	}
   883  
   884  	d.Partial(true)
   885  
   886  	instance, err := config.clientSqlAdmin.Instances.Get(project,
   887  		d.Get("name").(string)).Do()
   888  
   889  	if err != nil {
   890  		return fmt.Errorf("Error retrieving instance %s: %s",
   891  			d.Get("name").(string), err)
   892  	}
   893  
   894  	if d.HasChange("settings") {
   895  		_oListCast, _settingsListCast := d.GetChange("settings")
   896  		_oList := _oListCast.([]interface{})
   897  		_o := _oList[0].(map[string]interface{})
   898  		_settingsList := _settingsListCast.([]interface{})
   899  
   900  		_settings := _settingsList[0].(map[string]interface{})
   901  		settings := &sqladmin.Settings{
   902  			Tier:            _settings["tier"].(string),
   903  			SettingsVersion: instance.Settings.SettingsVersion,
   904  			ForceSendFields: []string{"StorageAutoResize"},
   905  		}
   906  
   907  		if v, ok := _settings["activation_policy"]; ok {
   908  			settings.ActivationPolicy = v.(string)
   909  		}
   910  
   911  		if v, ok := _settings["authorized_gae_applications"]; ok {
   912  			settings.AuthorizedGaeApplications = make([]string, 0)
   913  			for _, app := range v.([]interface{}) {
   914  				settings.AuthorizedGaeApplications = append(settings.AuthorizedGaeApplications,
   915  					app.(string))
   916  			}
   917  		}
   918  
   919  		if v, ok := _settings["backup_configuration"]; ok {
   920  			_backupConfigurationList := v.([]interface{})
   921  			if len(_backupConfigurationList) > 1 {
   922  				return fmt.Errorf("At most one backup_configuration block is allowed")
   923  			}
   924  
   925  			if len(_backupConfigurationList) == 1 && _backupConfigurationList[0] != nil {
   926  				settings.BackupConfiguration = &sqladmin.BackupConfiguration{}
   927  				_backupConfiguration := _backupConfigurationList[0].(map[string]interface{})
   928  
   929  				if vp, okp := _backupConfiguration["binary_log_enabled"]; okp {
   930  					settings.BackupConfiguration.BinaryLogEnabled = vp.(bool)
   931  				}
   932  
   933  				if vp, okp := _backupConfiguration["enabled"]; okp {
   934  					settings.BackupConfiguration.Enabled = vp.(bool)
   935  				}
   936  
   937  				if vp, okp := _backupConfiguration["start_time"]; okp {
   938  					settings.BackupConfiguration.StartTime = vp.(string)
   939  				}
   940  			}
   941  		}
   942  
   943  		if v, ok := _settings["crash_safe_replication"]; ok {
   944  			settings.CrashSafeReplicationEnabled = v.(bool)
   945  		}
   946  
   947  		settings.StorageAutoResize = _settings["disk_autoresize"].(bool)
   948  
   949  		if v, ok := _settings["disk_size"]; ok {
   950  			if v.(int) > 0 && int64(v.(int)) > instance.Settings.DataDiskSizeGb {
   951  				settings.DataDiskSizeGb = int64(v.(int))
   952  			}
   953  		}
   954  
   955  		if v, ok := _settings["disk_type"]; ok && len(v.(string)) > 0 {
   956  			settings.DataDiskType = v.(string)
   957  		}
   958  
   959  		_oldDatabaseFlags := make([]interface{}, 0)
   960  		if ov, ook := _o["database_flags"]; ook {
   961  			_oldDatabaseFlags = ov.([]interface{})
   962  		}
   963  
   964  		if v, ok := _settings["database_flags"]; ok || len(_oldDatabaseFlags) > 0 {
   965  			oldDatabaseFlags := settings.DatabaseFlags
   966  			settings.DatabaseFlags = make([]*sqladmin.DatabaseFlags, 0)
   967  			_databaseFlagsList := make([]interface{}, 0)
   968  			if v != nil {
   969  				_databaseFlagsList = v.([]interface{})
   970  			}
   971  
   972  			_odbf_map := make(map[string]interface{})
   973  			for _, _dbf := range _oldDatabaseFlags {
   974  				_entry := _dbf.(map[string]interface{})
   975  				_odbf_map[_entry["name"].(string)] = true
   976  			}
   977  
   978  			// First read the flags from the server, and reinsert those that
   979  			// were not previously defined
   980  			for _, entry := range oldDatabaseFlags {
   981  				_, ok_old := _odbf_map[entry.Name]
   982  				if !ok_old {
   983  					settings.DatabaseFlags = append(
   984  						settings.DatabaseFlags, entry)
   985  				}
   986  			}
   987  			// finally, insert only those that were previously defined
   988  			// and are still defined.
   989  			for _, _flag := range _databaseFlagsList {
   990  				_entry := _flag.(map[string]interface{})
   991  				flag := &sqladmin.DatabaseFlags{}
   992  				if vp, okp := _entry["name"]; okp {
   993  					flag.Name = vp.(string)
   994  				}
   995  
   996  				if vp, okp := _entry["value"]; okp {
   997  					flag.Value = vp.(string)
   998  				}
   999  
  1000  				settings.DatabaseFlags = append(settings.DatabaseFlags, flag)
  1001  			}
  1002  		}
  1003  
  1004  		if v, ok := _settings["ip_configuration"]; ok {
  1005  			_ipConfigurationList := v.([]interface{})
  1006  			if len(_ipConfigurationList) > 1 {
  1007  				return fmt.Errorf("At most one ip_configuration block is allowed")
  1008  			}
  1009  
  1010  			if len(_ipConfigurationList) == 1 && _ipConfigurationList[0] != nil {
  1011  				settings.IpConfiguration = &sqladmin.IpConfiguration{}
  1012  				_ipConfiguration := _ipConfigurationList[0].(map[string]interface{})
  1013  
  1014  				if vp, okp := _ipConfiguration["ipv4_enabled"]; okp {
  1015  					settings.IpConfiguration.Ipv4Enabled = vp.(bool)
  1016  				}
  1017  
  1018  				if vp, okp := _ipConfiguration["require_ssl"]; okp {
  1019  					settings.IpConfiguration.RequireSsl = vp.(bool)
  1020  				}
  1021  
  1022  				_oldAuthorizedNetworkList := make([]interface{}, 0)
  1023  				if ov, ook := _o["ip_configuration"]; ook {
  1024  					_oldIpConfList := ov.([]interface{})
  1025  					if len(_oldIpConfList) > 0 {
  1026  						_oldIpConf := _oldIpConfList[0].(map[string]interface{})
  1027  						if ovp, ookp := _oldIpConf["authorized_networks"]; ookp {
  1028  							_oldAuthorizedNetworkList = ovp.([]interface{})
  1029  						}
  1030  					}
  1031  				}
  1032  
  1033  				if vp, okp := _ipConfiguration["authorized_networks"]; okp || len(_oldAuthorizedNetworkList) > 0 {
  1034  					oldAuthorizedNetworks := instance.Settings.IpConfiguration.AuthorizedNetworks
  1035  					settings.IpConfiguration.AuthorizedNetworks = make([]*sqladmin.AclEntry, 0)
  1036  
  1037  					_authorizedNetworksList := make([]interface{}, 0)
  1038  					if vp != nil {
  1039  						_authorizedNetworksList = vp.([]interface{})
  1040  					}
  1041  					_oipc_map := make(map[string]interface{})
  1042  					for _, _ipc := range _oldAuthorizedNetworkList {
  1043  						_entry := _ipc.(map[string]interface{})
  1044  						_oipc_map[_entry["value"].(string)] = true
  1045  					}
  1046  					// Next read the network tuples from the server, and reinsert those that
  1047  					// were not previously defined
  1048  					for _, entry := range oldAuthorizedNetworks {
  1049  						_, ok_old := _oipc_map[entry.Value]
  1050  						if !ok_old {
  1051  							settings.IpConfiguration.AuthorizedNetworks = append(
  1052  								settings.IpConfiguration.AuthorizedNetworks, entry)
  1053  						}
  1054  					}
  1055  					// finally, update old entries and insert new ones
  1056  					// and are still defined.
  1057  					for _, _ipc := range _authorizedNetworksList {
  1058  						_entry := _ipc.(map[string]interface{})
  1059  						entry := &sqladmin.AclEntry{}
  1060  
  1061  						if vpp, okpp := _entry["expiration_time"]; okpp {
  1062  							entry.ExpirationTime = vpp.(string)
  1063  						}
  1064  
  1065  						if vpp, okpp := _entry["name"]; okpp {
  1066  							entry.Name = vpp.(string)
  1067  						}
  1068  
  1069  						if vpp, okpp := _entry["value"]; okpp {
  1070  							entry.Value = vpp.(string)
  1071  						}
  1072  
  1073  						settings.IpConfiguration.AuthorizedNetworks = append(
  1074  							settings.IpConfiguration.AuthorizedNetworks, entry)
  1075  					}
  1076  				}
  1077  			}
  1078  		}
  1079  
  1080  		if v, ok := _settings["location_preference"]; ok {
  1081  			_locationPreferenceList := v.([]interface{})
  1082  			if len(_locationPreferenceList) > 1 {
  1083  				return fmt.Errorf("At most one location_preference block is allowed")
  1084  			}
  1085  
  1086  			if len(_locationPreferenceList) == 1 && _locationPreferenceList[0] != nil {
  1087  				settings.LocationPreference = &sqladmin.LocationPreference{}
  1088  				_locationPreference := _locationPreferenceList[0].(map[string]interface{})
  1089  
  1090  				if vp, okp := _locationPreference["follow_gae_application"]; okp {
  1091  					settings.LocationPreference.FollowGaeApplication = vp.(string)
  1092  				}
  1093  
  1094  				if vp, okp := _locationPreference["zone"]; okp {
  1095  					settings.LocationPreference.Zone = vp.(string)
  1096  				}
  1097  			}
  1098  		}
  1099  
  1100  		if v, ok := _settings["maintenance_window"]; ok && len(v.([]interface{})) > 0 {
  1101  			settings.MaintenanceWindow = &sqladmin.MaintenanceWindow{}
  1102  			_maintenanceWindow := v.([]interface{})[0].(map[string]interface{})
  1103  
  1104  			if vp, okp := _maintenanceWindow["day"]; okp {
  1105  				settings.MaintenanceWindow.Day = int64(vp.(int))
  1106  			}
  1107  
  1108  			if vp, okp := _maintenanceWindow["hour"]; okp {
  1109  				settings.MaintenanceWindow.Hour = int64(vp.(int))
  1110  			}
  1111  
  1112  			if vp, ok := _maintenanceWindow["update_track"]; ok {
  1113  				if len(vp.(string)) > 0 {
  1114  					settings.MaintenanceWindow.UpdateTrack = vp.(string)
  1115  				}
  1116  			}
  1117  		}
  1118  
  1119  		if v, ok := _settings["pricing_plan"]; ok {
  1120  			settings.PricingPlan = v.(string)
  1121  		}
  1122  
  1123  		if v, ok := _settings["replication_type"]; ok {
  1124  			settings.ReplicationType = v.(string)
  1125  		}
  1126  
  1127  		instance.Settings = settings
  1128  	}
  1129  
  1130  	d.Partial(false)
  1131  
  1132  	op, err := config.clientSqlAdmin.Instances.Update(project, instance.Name, instance).Do()
  1133  	if err != nil {
  1134  		return fmt.Errorf("Error, failed to update instance %s: %s", instance.Name, err)
  1135  	}
  1136  
  1137  	err = sqladminOperationWait(config, op, "Create Instance")
  1138  	if err != nil {
  1139  		return err
  1140  	}
  1141  
  1142  	return resourceSqlDatabaseInstanceRead(d, meta)
  1143  }
  1144  
  1145  func resourceSqlDatabaseInstanceDelete(d *schema.ResourceData, meta interface{}) error {
  1146  	config := meta.(*Config)
  1147  
  1148  	project, err := getProject(d, config)
  1149  	if err != nil {
  1150  		return err
  1151  	}
  1152  
  1153  	op, err := config.clientSqlAdmin.Instances.Delete(project, d.Get("name").(string)).Do()
  1154  
  1155  	if err != nil {
  1156  		return fmt.Errorf("Error, failed to delete instance %s: %s", d.Get("name").(string), err)
  1157  	}
  1158  
  1159  	err = sqladminOperationWait(config, op, "Delete Instance")
  1160  	if err != nil {
  1161  		return err
  1162  	}
  1163  
  1164  	return nil
  1165  }
  1166  
  1167  func validateNumericRange(v interface{}, k string, min int, max int) (ws []string, errors []error) {
  1168  	value := v.(int)
  1169  	if min > value || value > max {
  1170  		errors = append(errors, fmt.Errorf(
  1171  			"%q outside range %d-%d.", k, min, max))
  1172  	}
  1173  	return
  1174  }
  1175  
  1176  func instanceMutexKey(project, instance_name string) string {
  1177  	return fmt.Sprintf("google-sql-database-instance-%s-%s", project, instance_name)
  1178  }