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 }