terraform-provider-google/google/resource_sql_database_instance_test.go
The Magician 00568c1d73 Sql database port (#3639)
Signed-off-by: Modular Magician <magic-modules@google.com>
2019-05-17 11:15:18 -07:00

966 lines
23 KiB
Go

package google
import (
"fmt"
"log"
"strings"
"testing"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
sqladmin "google.golang.org/api/sqladmin/v1beta4"
)
// Fields that should be ignored in import tests because they aren't returned
// from GCP (and thus can't be imported)
var ignoredReplicaConfigurationFields = []string{
"replica_configuration.0.ca_certificate",
"replica_configuration.0.client_certificate",
"replica_configuration.0.client_key",
"replica_configuration.0.connect_retry_interval",
"replica_configuration.0.dump_file_path",
"replica_configuration.0.master_heartbeat_period",
"replica_configuration.0.password",
"replica_configuration.0.ssl_cipher",
"replica_configuration.0.username",
"replica_configuration.0.verify_server_certificate",
}
func init() {
resource.AddTestSweepers("gcp_sql_db_instance", &resource.Sweeper{
Name: "gcp_sql_db_instance",
F: testSweepDatabases,
})
}
func testSweepDatabases(region string) error {
config, err := sharedConfigForRegion(region)
if err != nil {
return fmt.Errorf("error getting shared config for region: %s", err)
}
err = config.LoadAndValidate()
if err != nil {
log.Fatalf("error loading: %s", err)
}
found, err := config.clientSqlAdmin.Instances.List(config.Project).Do()
if err != nil {
log.Fatalf("error listing databases: %s", err)
}
if len(found.Items) == 0 {
log.Printf("No databases found")
return nil
}
running := map[string]struct{}{}
for _, d := range found.Items {
var testDbInstance bool
for _, testName := range []string{"tf-lw-", "sqldatabasetest"} {
// only destroy instances we know to fit our test naming pattern
if strings.HasPrefix(d.Name, testName) {
testDbInstance = true
}
}
if !testDbInstance {
continue
}
if d.State != "RUNNABLE" {
continue
}
running[d.Name] = struct{}{}
}
for _, d := range found.Items {
// don't delete replicas, we'll take care of that
// when deleting the database they replicate
if d.ReplicaConfiguration != nil {
continue
}
log.Printf("Destroying SQL Instance (%s)", d.Name)
// replicas need to be stopped and destroyed before destroying a master
// instance. The ordering slice tracks replica databases for a given master
// and we call destroy on them before destroying the master
var ordering []string
for _, replicaName := range d.ReplicaNames {
// don't try to stop replicas that aren't running
if _, ok := running[replicaName]; !ok {
ordering = append(ordering, replicaName)
continue
}
// need to stop replication before being able to destroy a database
op, err := config.clientSqlAdmin.Instances.StopReplica(config.Project, replicaName).Do()
if err != nil {
return fmt.Errorf("error, failed to stop replica instance (%s) for instance (%s): %s", replicaName, d.Name, err)
}
err = sqlAdminOperationWait(config.clientSqlAdmin, op, config.Project, "Stop Replica")
if err != nil {
if strings.Contains(err.Error(), "does not exist") {
log.Printf("Replication operation not found")
} else {
return err
}
}
ordering = append(ordering, replicaName)
}
// ordering has a list of replicas (or none), now add the primary to the end
ordering = append(ordering, d.Name)
for _, db := range ordering {
// destroy instances, replicas first
op, err := config.clientSqlAdmin.Instances.Delete(config.Project, db).Do()
if err != nil {
if strings.Contains(err.Error(), "409") {
// the GCP api can return a 409 error after the delete operation
// reaches a successful end
log.Printf("Operation not found, got 409 response")
continue
}
return fmt.Errorf("Error, failed to delete instance %s: %s", db, err)
}
err = sqlAdminOperationWait(config.clientSqlAdmin, op, config.Project, "Delete Instance")
if err != nil {
if strings.Contains(err.Error(), "does not exist") {
log.Printf("SQL instance not found")
continue
}
return err
}
}
}
return nil
}
func TestAccSqlDatabaseInstance_basicFirstGen(t *testing.T) {
t.Parallel()
instanceID := acctest.RandInt()
instanceName := fmt.Sprintf("tf-lw-%d", instanceID)
resourceName := "google_sql_database_instance.instance"
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(testGoogleSqlDatabaseInstance_basic, instanceID),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
ResourceName: resourceName,
ImportStateId: fmt.Sprintf("projects/%s/instances/%s", getTestProjectFromEnv(), instanceName),
ImportState: true,
ImportStateVerify: true,
},
{
ResourceName: resourceName,
ImportStateId: fmt.Sprintf("%s/%s", getTestProjectFromEnv(), instanceName),
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccSqlDatabaseInstance_basicInferredName(t *testing.T) {
t.Parallel()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testGoogleSqlDatabaseInstance_basic2,
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccSqlDatabaseInstance_basicSecondGen(t *testing.T) {
t.Parallel()
databaseName := "tf-test-" + acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_basic3, databaseName),
Check: testAccCheckGoogleSqlDatabaseRootUserDoesNotExist(databaseName),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccSqlDatabaseInstance_dontDeleteDefaultUserOnReplica(t *testing.T) {
t.Parallel()
databaseName := "sql-instance-test-" + acctest.RandString(10)
failoverName := "sql-instance-test-failover-" + acctest.RandString(10)
// 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)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testGoogleSqlDatabaseInstanceConfig_withoutReplica(databaseName),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
{
PreConfig: func() {
// Add a root user
config := testAccProvider.Meta().(*Config)
user := sqladmin.User{
Name: "root",
Host: "%",
Password: acctest.RandString(26),
}
op, err := config.clientSqlAdmin.Users.Insert(config.Project, databaseName, &user).Do()
if err != nil {
t.Errorf("Error while inserting root@%% user: %s", err)
return
}
err = sqlAdminOperationWait(config.clientSqlAdmin, op, config.Project, "Waiting for user to insert")
if err != nil {
t.Errorf("Error while waiting for user insert operation to complete: %s", err.Error())
}
// User was created, now create replica
},
Config: testGoogleSqlDatabaseInstanceConfig_withReplica(databaseName, failoverName),
},
},
})
}
func TestAccSqlDatabaseInstance_settings_basic(t *testing.T) {
t.Parallel()
databaseID := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_settings, databaseID),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccSqlDatabaseInstance_replica(t *testing.T) {
t.Parallel()
databaseID := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_replica, databaseID, databaseID, databaseID),
},
{
ResourceName: "google_sql_database_instance.instance_master",
ImportState: true,
ImportStateVerify: true,
},
{
ResourceName: "google_sql_database_instance.replica1",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: ignoredReplicaConfigurationFields,
},
{
ResourceName: "google_sql_database_instance.replica2",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: ignoredReplicaConfigurationFields,
},
},
})
}
func TestAccSqlDatabaseInstance_slave(t *testing.T) {
t.Parallel()
masterID := acctest.RandInt()
slaveID := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_slave, masterID, slaveID),
},
{
ResourceName: "google_sql_database_instance.instance_master",
ImportState: true,
ImportStateVerify: true,
},
{
ResourceName: "google_sql_database_instance.instance_slave",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccSqlDatabaseInstance_highAvailability(t *testing.T) {
t.Parallel()
instanceID := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_highAvailability, instanceID),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccSqlDatabaseInstance_diskspecs(t *testing.T) {
t.Parallel()
masterID := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_diskspecs, masterID),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccSqlDatabaseInstance_maintenance(t *testing.T) {
t.Parallel()
masterID := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_maintenance, masterID),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccSqlDatabaseInstance_settings_upgrade(t *testing.T) {
t.Parallel()
databaseID := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_basic, databaseID),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_settings, databaseID),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccSqlDatabaseInstance_settingsDowngrade(t *testing.T) {
t.Parallel()
databaseID := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_settings, databaseID),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_basic, databaseID),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
// GH-4222
func TestAccSqlDatabaseInstance_authNets(t *testing.T) {
t.Parallel()
databaseID := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_authNets_step1, databaseID),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_authNets_step2, databaseID),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_authNets_step1, databaseID),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
// Tests that a SQL instance can be referenced from more than one other resource without
// throwing an error during provisioning, see #9018.
func TestAccSqlDatabaseInstance_multipleOperations(t *testing.T) {
t.Parallel()
databaseID, instanceID, userID := acctest.RandString(8), acctest.RandString(8), acctest.RandString(8)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_multipleOperations, databaseID, instanceID, userID),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func TestAccSqlDatabaseInstance_basic_with_user_labels(t *testing.T) {
t.Parallel()
databaseName := "tf-test-" + acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccSqlDatabaseInstanceDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_basic_with_user_labels, databaseName),
Check: testAccCheckGoogleSqlDatabaseRootUserDoesNotExist(databaseName),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
{
Config: fmt.Sprintf(
testGoogleSqlDatabaseInstance_basic_with_user_labels_update, databaseName),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
},
},
})
}
func testAccSqlDatabaseInstanceDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
config := testAccProvider.Meta().(*Config)
if rs.Type != "google_sql_database_instance" {
continue
}
_, err := config.clientSqlAdmin.Instances.Get(config.Project,
rs.Primary.Attributes["name"]).Do()
if err == nil {
return fmt.Errorf("Database Instance still exists")
}
}
return nil
}
func testAccCheckGoogleSqlDatabaseRootUserDoesNotExist(instance string) resource.TestCheckFunc {
return func(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
users, err := config.clientSqlAdmin.Users.List(config.Project, instance).Do()
if err != nil {
return fmt.Errorf("Could not list database users for %q: %s", instance, err)
}
for _, u := range users.Items {
if u.Name == "root" && u.Host == "%" {
return fmt.Errorf("%v@%v user still exists", u.Name, u.Host)
}
}
return nil
}
}
var testGoogleSqlDatabaseInstance_basic = `
resource "google_sql_database_instance" "instance" {
name = "tf-lw-%d"
region = "us-central"
settings {
tier = "D0"
crash_safe_replication = false
}
}
`
var testGoogleSqlDatabaseInstance_basic2 = `
resource "google_sql_database_instance" "instance" {
region = "us-central"
settings {
tier = "D0"
crash_safe_replication = false
}
}
`
var testGoogleSqlDatabaseInstance_basic3 = `
resource "google_sql_database_instance" "instance" {
name = "%s"
region = "us-central1"
settings {
tier = "db-f1-micro"
}
}
`
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"
}
}
}`, 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"
settings {
tier = "db-n1-standard-1"
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}"
replica_configuration {
failover_target = "true"
}
settings {
tier = "db-n1-standard-1"
}
}
`, instanceName, failoverName)
}
var testGoogleSqlDatabaseInstance_settings = `
resource "google_sql_database_instance" "instance" {
name = "tf-lw-%d"
region = "us-central"
settings {
tier = "D0"
crash_safe_replication = false
replication_type = "ASYNCHRONOUS"
location_preference {
zone = "us-central1-f"
}
ip_configuration {
ipv4_enabled = "true"
authorized_networks {
value = "108.12.12.12"
name = "misc"
expiration_time = "2050-11-15T16:19:00.094Z"
}
}
backup_configuration {
enabled = "true"
start_time = "19:19"
}
activation_policy = "ON_DEMAND"
}
}
`
var testGoogleSqlDatabaseInstance_replica = `
resource "google_sql_database_instance" "instance_master" {
name = "tf-lw-%d"
database_version = "MYSQL_5_6"
region = "us-central1"
settings {
tier = "db-n1-standard-1"
backup_configuration {
enabled = true
start_time = "00:00"
binary_log_enabled = true
}
}
}
resource "google_sql_database_instance" "replica1" {
name = "tf-lw-%d-1"
database_version = "MYSQL_5_6"
region = "us-central1"
settings {
tier = "db-n1-standard-1"
}
master_instance_name = "${google_sql_database_instance.instance_master.name}"
replica_configuration {
connect_retry_interval = 100
master_heartbeat_period = 10000
password = "password"
username = "username"
ssl_cipher = "ALL"
verify_server_certificate = false
}
}
resource "google_sql_database_instance" "replica2" {
name = "tf-lw-%d-2"
database_version = "MYSQL_5_6"
region = "us-central1"
settings {
tier = "db-n1-standard-1"
}
master_instance_name = "${google_sql_database_instance.instance_master.name}"
replica_configuration {
connect_retry_interval = 100
master_heartbeat_period = 10000
password = "password"
username = "username"
ssl_cipher = "ALL"
verify_server_certificate = false
}
}
`
var testGoogleSqlDatabaseInstance_slave = `
resource "google_sql_database_instance" "instance_master" {
name = "tf-lw-%d"
region = "us-central1"
settings {
tier = "db-f1-micro"
backup_configuration {
enabled = true
binary_log_enabled = true
}
}
}
resource "google_sql_database_instance" "instance_slave" {
name = "tf-lw-%d"
region = "us-central1"
master_instance_name = "${google_sql_database_instance.instance_master.name}"
settings {
tier = "db-f1-micro"
}
}
`
var testGoogleSqlDatabaseInstance_highAvailability = `
resource "google_sql_database_instance" "instance" {
name = "tf-lw-%d"
region = "us-central1"
database_version = "POSTGRES_9_6"
settings {
tier = "db-f1-micro"
availability_type = "REGIONAL"
backup_configuration {
enabled = true
}
}
}
`
var testGoogleSqlDatabaseInstance_diskspecs = `
resource "google_sql_database_instance" "instance" {
name = "tf-lw-%d"
region = "us-central1"
settings {
tier = "db-f1-micro"
disk_autoresize = true
disk_size = 15
disk_type = "PD_HDD"
}
}
`
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"
region = "us-central"
settings {
tier = "D0"
crash_safe_replication = false
ip_configuration {
ipv4_enabled = "true"
authorized_networks {
value = "108.12.12.12"
name = "misc"
expiration_time = "2050-11-15T16:19:00.094Z"
}
}
}
}
`
var testGoogleSqlDatabaseInstance_authNets_step2 = `
resource "google_sql_database_instance" "instance" {
name = "tf-lw-%d"
region = "us-central"
settings {
tier = "D0"
crash_safe_replication = false
ip_configuration {
ipv4_enabled = "true"
}
}
}
`
var testGoogleSqlDatabaseInstance_multipleOperations = `
resource "google_sql_database_instance" "instance" {
name = "tf-test-%s"
region = "us-central"
settings {
tier = "D0"
crash_safe_replication = false
}
}
resource "google_sql_database" "database" {
name = "tf-test-%s"
instance = "${google_sql_database_instance.instance.name}"
}
resource "google_sql_user" "user" {
name = "tf-test-%s"
instance = "${google_sql_database_instance.instance.name}"
host = "google.com"
password = "hunter2"
}
`
var testGoogleSqlDatabaseInstance_basic_with_user_labels = `
resource "google_sql_database_instance" "instance" {
name = "%s"
region = "us-central1"
settings {
tier = "db-f1-micro"
user_labels = {
track = "production"
location = "western-division"
}
}
}
`
var testGoogleSqlDatabaseInstance_basic_with_user_labels_update = `
resource "google_sql_database_instance" "instance" {
name = "%s"
region = "us-central1"
settings {
tier = "db-f1-micro"
user_labels = {
track = "production"
}
}
}
`