Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Database Instance Auth #552

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions google/resource_sql_database_instance.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package google

import (
"bytes"
"fmt"
"log"
"regexp"
"strings"

"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"

"google.golang.org/api/googleapi"
"google.golang.org/api/sqladmin/v1beta4"
sqladmin "google.golang.org/api/sqladmin/v1beta4"
)

func resourceSqlDatabaseInstance() *schema.Resource {
Expand All @@ -23,6 +25,8 @@ func resourceSqlDatabaseInstance() *schema.Resource {
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
SchemaVersion: 1,
MigrateState: resourceSqlDatabaseInstanceMigrateState,

Schema: map[string]*schema.Schema{
"region": &schema.Schema{
Expand Down Expand Up @@ -128,8 +132,9 @@ func resourceSqlDatabaseInstance() *schema.Resource {
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"authorized_networks": &schema.Schema{
Type: schema.TypeList,
Type: schema.TypeSet,
Optional: true,
Set: resourceSqlDatabaseInstanceAuthNetworkHash,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"expiration_time": &schema.Schema{
Expand Down Expand Up @@ -975,6 +980,27 @@ func resourceSqlDatabaseInstanceDelete(d *schema.ResourceData, meta interface{})
return nil
}

func resourceSqlDatabaseInstanceAuthNetworkHash(v interface{}) int {
if v == nil {
return 0
}

var buf bytes.Buffer
m := v.(map[string]interface{})

if v, ok := m["expiration_time"]; ok {
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
}
if v, ok := m["name"]; ok {
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
}
if v, ok := m["value"]; ok {
buf.WriteString(fmt.Sprintf("%s-", v.(string)))
}

return hashcode.String(buf.String())
}

func flattenSettings(settings *sqladmin.Settings) []map[string]interface{} {
data := map[string]interface{}{
"version": settings.SettingsVersion,
Expand Down
97 changes: 97 additions & 0 deletions google/resource_sql_database_instance_migrate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package google

import (
"fmt"
"log"
"sort"
"strconv"
"strings"

"github.com/hashicorp/terraform/terraform"
)

func resourceSqlDatabaseInstanceMigrateState(
v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
if is.Empty() {
log.Println("[DEBUG] Empty InstanceState; nothing to migrate.")
return is, nil
}

switch v {
case 0:
log.Println("[INFO] Found SQL Database Instance State v0; migrating to v1")
is, err := migrateSqlDatabaseInstanceStateV0toV1(is)
if err != nil {
return is, err
}
return is, nil
default:
return is, fmt.Errorf("Unexpected schema version: %d", v)
}
}

func migrateSqlDatabaseInstanceStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) {
log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes)
idx := 0
networkCount := 0
newNetworks := make(map[string]string)
keys := make([]string, len(is.Attributes))
for k, _ := range is.Attributes {
keys[idx] = k
idx++

}
sort.Strings(keys)
for _, k := range keys {
if !strings.HasPrefix(k, "settings.0.ip_configuration.0.authorized_networks.") {
continue
}

if k == "settings.0.ip_configuration.0.authorized_networks.#" {
continue
}

// We have a key that looks like "settings.0.ip_configuration.0.authorized_networks.<listn>" and we know it's not
// settings.0.ip_configuration.0.authorized_networks.# because we deleted it above, so it must be
// settings.0.ip_configuration.0.authorized_networks.<listn>
// All that's left is to convert the list to a hash.
kParts := strings.Split(k, ".")

// Sanity check: all seven parts should be there and <listn> should be a number
badFormat := false
if len(kParts) != 7 {
badFormat = true
} else if _, err := strconv.Atoi(kParts[5]); err != nil {
badFormat = true
}

if badFormat {
return is, fmt.Errorf(
"migration error: found network key in unexpected format: %s", k)
}

// Get the values for all items in the set that make up the hash.
vTime := is.Attributes[fmt.Sprintf("settings.0.ip_configuration.0.authorized_networks.%s.expiration_time", kParts[5])]
vName := is.Attributes[fmt.Sprintf("settings.0.ip_configuration.0.authorized_networks.%s.name", kParts[5])]
vValue := is.Attributes[fmt.Sprintf("settings.0.ip_configuration.0.authorized_networks.%s.value", kParts[5])]

// Generate the hash based on the expected values using the actual hash function.
networkHash := resourceSqlDatabaseInstanceAuthNetworkHash(map[string]interface{}{
"expiration_time": vTime,
"name": vName,
"value": vValue,
})

newK := fmt.Sprintf("settings.0.ip_configuration.0.authorized_networks.%d.%s", networkHash, kParts[6])
networkCount++
newNetworks[newK] = is.Attributes[k]
delete(is.Attributes, k)
}

for k, v := range newNetworks {
is.Attributes[k] = v
}

log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes)
return is, nil
}
80 changes: 40 additions & 40 deletions google/resource_sql_database_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import (
"strings"
"testing"

sqladmin "google.golang.org/api/sqladmin/v1beta4"

"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"

"google.golang.org/api/sqladmin/v1beta4"
)

func init() {
Expand Down Expand Up @@ -196,7 +196,7 @@ func TestAccGoogleSqlDatabaseInstance_dontDeleteDefaultUserOnReplica(t *testing.
// 1. Create an instance.
// 2. Add a root@'%' user.
// 3. Create a replica and assert it succeeds (it'll fail if we try to delete the root user thinking it's a
// default user)
// default user)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Expand Down Expand Up @@ -706,53 +706,53 @@ resource "google_sql_database_instance" "instance" {

func testGoogleSqlDatabaseInstanceConfig_withoutReplica(instanceName string) string {
return fmt.Sprintf(`resource "google_sql_database_instance" "instance" {
name = "%s"
region = "us-central1"
database_version = "MYSQL_5_7"

settings {
tier = "db-n1-standard-1"

backup_configuration {
binary_log_enabled = "true"
enabled = "true"
start_time = "18:00"
}
}
name = "%s"
region = "us-central1"
database_version = "MYSQL_5_7"

settings {
tier = "db-n1-standard-1"

backup_configuration {
binary_log_enabled = "true"
enabled = "true"
start_time = "18:00"
}
}
}`, instanceName)
}

func testGoogleSqlDatabaseInstanceConfig_withReplica(instanceName, failoverName string) string {
return fmt.Sprintf(`
resource "google_sql_database_instance" "instance" {
name = "%s"
region = "us-central1"
database_version = "MYSQL_5_7"
name = "%s"
region = "us-central1"
database_version = "MYSQL_5_7"

settings {
tier = "db-n1-standard-1"
settings {
tier = "db-n1-standard-1"

backup_configuration {
binary_log_enabled = "true"
enabled = "true"
start_time = "18:00"
}
}
backup_configuration {
binary_log_enabled = "true"
enabled = "true"
start_time = "18:00"
}
}
}

resource "google_sql_database_instance" "instance-failover" {
name = "%s"
region = "us-central1"
database_version = "MYSQL_5_7"
master_instance_name = "${google_sql_database_instance.instance.name}"
name = "%s"
region = "us-central1"
database_version = "MYSQL_5_7"
master_instance_name = "${google_sql_database_instance.instance.name}"

replica_configuration {
failover_target = "true"
}
replica_configuration {
failover_target = "true"
}

settings {
tier = "db-n1-standard-1"
}
settings {
tier = "db-n1-standard-1"
}
}
`, instanceName, failoverName)
}
Expand Down Expand Up @@ -883,10 +883,10 @@ resource "google_sql_database_instance" "instance" {
tier = "db-f1-micro"

maintenance_window {
day = 7
hour = 3
day = 7
hour = 3
update_track = "canary"
}
}
}
}
`
Expand Down