provider/google-cloud: Add maintenance window (#12042)

* provider/google-cloud: Add maintenance window

Allows specification of the `maintenance_window` within the `settings`
block. This controls when Google will restart a database in order to
apply updates. It is also possible to select an `update_track` to
relatively control updating between instances in the same project.

* Adjustments as suggested in code review.
This commit is contained in:
Mike Fowler 2017-02-17 23:33:47 +00:00 committed by Paul Stack
parent a2682bc94b
commit bfdeae0e33
3 changed files with 164 additions and 0 deletions

View File

@ -153,6 +153,33 @@ func resourceSqlDatabaseInstance() *schema.Resource {
},
},
},
"maintenance_window": &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"day": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
return validateNumericRange(v, k, 1, 7)
},
},
"hour": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
return validateNumericRange(v, k, 0, 23)
},
},
"update_track": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
},
},
},
"pricing_plan": &schema.Schema{
Type: schema.TypeString,
Optional: true,
@ -431,6 +458,25 @@ func resourceSqlDatabaseInstanceCreate(d *schema.ResourceData, meta interface{})
}
}
if v, ok := _settings["maintenance_window"]; ok && len(v.([]interface{})) > 0 {
settings.MaintenanceWindow = &sqladmin.MaintenanceWindow{}
_maintenanceWindow := v.([]interface{})[0].(map[string]interface{})
if vp, okp := _maintenanceWindow["day"]; okp {
settings.MaintenanceWindow.Day = int64(vp.(int))
}
if vp, okp := _maintenanceWindow["hour"]; okp {
settings.MaintenanceWindow.Hour = int64(vp.(int))
}
if vp, ok := _maintenanceWindow["update_track"]; ok {
if len(vp.(string)) > 0 {
settings.MaintenanceWindow.UpdateTrack = vp.(string)
}
}
}
if v, ok := _settings["pricing_plan"]; ok {
settings.PricingPlan = v.(string)
}
@ -745,6 +791,25 @@ func resourceSqlDatabaseInstanceRead(d *schema.ResourceData, meta interface{}) e
}
}
if v, ok := _settings["maintenance_window"]; ok && len(v.([]interface{})) > 0 &&
settings.MaintenanceWindow != nil {
_maintenanceWindow := v.([]interface{})[0].(map[string]interface{})
if vp, okp := _maintenanceWindow["day"]; okp && vp != nil {
_maintenanceWindow["day"] = settings.MaintenanceWindow.Day
}
if vp, okp := _maintenanceWindow["hour"]; okp && vp != nil {
_maintenanceWindow["hour"] = settings.MaintenanceWindow.Hour
}
if vp, ok := _maintenanceWindow["update_track"]; ok && vp != nil {
if len(vp.(string)) > 0 {
_maintenanceWindow["update_track"] = settings.MaintenanceWindow.UpdateTrack
}
}
}
if v, ok := _settings["pricing_plan"]; ok && len(v.(string)) > 0 {
_settings["pricing_plan"] = settings.PricingPlan
}
@ -1062,6 +1127,25 @@ func resourceSqlDatabaseInstanceUpdate(d *schema.ResourceData, meta interface{})
}
}
if v, ok := _settings["maintenance_window"]; ok && len(v.([]interface{})) > 0 {
settings.MaintenanceWindow = &sqladmin.MaintenanceWindow{}
_maintenanceWindow := v.([]interface{})[0].(map[string]interface{})
if vp, okp := _maintenanceWindow["day"]; okp {
settings.MaintenanceWindow.Day = int64(vp.(int))
}
if vp, okp := _maintenanceWindow["hour"]; okp {
settings.MaintenanceWindow.Hour = int64(vp.(int))
}
if vp, ok := _maintenanceWindow["update_track"]; ok {
if len(vp.(string)) > 0 {
settings.MaintenanceWindow.UpdateTrack = vp.(string)
}
}
}
if v, ok := _settings["pricing_plan"]; ok {
settings.PricingPlan = v.(string)
}
@ -1109,3 +1193,12 @@ func resourceSqlDatabaseInstanceDelete(d *schema.ResourceData, meta interface{})
return nil
}
func validateNumericRange(v interface{}, k string, min int, max int) (ws []string, errors []error) {
value := v.(int)
if min > value || value > max {
errors = append(errors, fmt.Errorf(
"%q outside range %d-%d.", k, min, max))
}
return
}

View File

@ -162,6 +162,29 @@ func TestAccGoogleSqlDatabaseInstance_diskspecs(t *testing.T) {
})
}
func TestAccGoogleSqlDatabaseInstance_maintenance(t *testing.T) {
var instance sqladmin.DatabaseInstance
masterID := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccGoogleSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_maintenance, masterID),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleSqlDatabaseInstanceExists(
"google_sql_database_instance.instance", &instance),
testAccCheckGoogleSqlDatabaseInstanceEquals(
"google_sql_database_instance.instance", &instance),
),
},
},
})
}
func TestAccGoogleSqlDatabaseInstance_settings_upgrade(t *testing.T) {
var instance sqladmin.DatabaseInstance
databaseID := acctest.RandInt()
@ -359,6 +382,26 @@ func testAccCheckGoogleSqlDatabaseInstanceEquals(n string,
}
}
if instance.Settings.MaintenanceWindow != nil {
server = strconv.FormatInt(instance.Settings.MaintenanceWindow.Day, 10)
local = attributes["settings.0.maintenance_window.0.day"]
if server != local && len(server) > 0 && len(local) > 0 {
return fmt.Errorf("Error settings.maintenance_window.day mismatch, (%s, %s)", server, local)
}
server = strconv.FormatInt(instance.Settings.MaintenanceWindow.Hour, 10)
local = attributes["settings.0.maintenance_window.0.hour"]
if server != local && len(server) > 0 && len(local) > 0 {
return fmt.Errorf("Error settings.maintenance_window.hour mismatch, (%s, %s)", server, local)
}
server = instance.Settings.MaintenanceWindow.UpdateTrack
local = attributes["settings.0.maintenance_window.0.update_track"]
if server != local && len(server) > 0 && len(local) > 0 {
return fmt.Errorf("Error settings.maintenance_window.update_track mismatch, (%s, %s)", server, local)
}
}
server = instance.Settings.PricingPlan
local = attributes["settings.0.pricing_plan"]
if server != local && len(server) > 0 && len(local) > 0 {
@ -639,6 +682,23 @@ resource "google_sql_database_instance" "instance" {
}
`
var testGoogleSqlDatabaseInstance_maintenance = `
resource "google_sql_database_instance" "instance" {
name = "tf-lw-%d"
region = "us-central1"
settings {
tier = "db-f1-micro"
maintenance_window {
day = 7
hour = 3
update_track = "canary"
}
}
}
`
var testGoogleSqlDatabaseInstance_authNets_step1 = `
resource "google_sql_database_instance" "instance" {
name = "tf-lw-%d"

View File

@ -134,6 +134,17 @@ The optional `settings.location_preference` subblock supports:
* `zone` - (Optional) The preferred compute engine
[zone](https://cloud.google.com/compute/docs/zones?hl=en).
The optional `settings.maintenance_window` subblock for Second Generation
instances declares a one-hour [maintenance window](https://cloud.google.com/sql/docs/instance-settings?hl=en#maintenance-window-2ndgen)
when an Instance can automatically restart to apply updates. It supports:
* `day` - (Optional) Day of week (`1-7`), starting on Monday
* `hour` - (Optional) Hour of day (`0-23`), ignored if `day` not set
* `update_track` - (Optional) Receive updates earlier (`canary`) or later
(`stable`)
The optional `replica_configuration` block must have `master_instance_name` set
to work, cannot be updated, and supports: