diff --git a/aws/resource_aws_db_instance.go b/aws/resource_aws_db_instance.go index 9100d9518dd..fc3a25947fc 100644 --- a/aws/resource_aws_db_instance.go +++ b/aws/resource_aws_db_instance.go @@ -407,6 +407,16 @@ func resourceAwsDbInstance() *schema.Resource { }, }, + "domain": { + Type: schema.TypeString, + Optional: true, + }, + + "domain_iam_role_name": { + Type: schema.TypeString, + Optional: true, + }, + "tags": tagsSchema(), }, } @@ -777,6 +787,14 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error opts.DBSubnetGroupName = aws.String(attr.(string)) } + if attr, ok := d.GetOk("domain"); ok { + opts.Domain = aws.String(attr.(string)) + } + + if attr, ok := d.GetOk("domain_iam_role_name"); ok { + opts.DomainIAMRoleName = aws.String(attr.(string)) + } + if attr, ok := d.GetOk("enabled_cloudwatch_logs_exports"); ok && len(attr.([]interface{})) > 0 { opts.EnableCloudwatchLogsExports = expandStringList(attr.([]interface{})) } @@ -1003,6 +1021,14 @@ func resourceAwsDbInstanceCreate(d *schema.ResourceData, meta interface{}) error opts.EnableIAMDatabaseAuthentication = aws.Bool(attr.(bool)) } + if attr, ok := d.GetOk("domain"); ok { + opts.Domain = aws.String(attr.(string)) + } + + if attr, ok := d.GetOk("domain_iam_role_name"); ok { + opts.DomainIAMRoleName = aws.String(attr.(string)) + } + log.Printf("[DEBUG] DB Instance create configuration: %#v", opts) var err error err = resource.Retry(5*time.Minute, func() *resource.RetryError { @@ -1153,6 +1179,13 @@ func resourceAwsDbInstanceRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error setting enabled_cloudwatch_logs_exports: %s", err) } + d.Set("domain", "") + d.Set("domain_iam_role_name", "") + if len(v.DomainMemberships) > 0 && v.DomainMemberships[0] != nil { + d.Set("domain", v.DomainMemberships[0].Domain) + d.Set("domain_iam_role_name", v.DomainMemberships[0].IAMRoleName) + } + // list tags for resource // set tags conn := meta.(*AWSClient).rdsconn @@ -1412,6 +1445,14 @@ func resourceAwsDbInstanceUpdate(d *schema.ResourceData, meta interface{}) error requestUpdate = true } + if d.HasChange("domain") || d.HasChange("domain_iam_role_name") { + d.SetPartial("domain") + d.SetPartial("domain_iam_role_name") + req.Domain = aws.String(d.Get("domain").(string)) + req.DomainIAMRoleName = aws.String(d.Get("domain_iam_role_name").(string)) + requestUpdate = true + } + log.Printf("[DEBUG] Send DB Instance Modification request: %t", requestUpdate) if requestUpdate { log.Printf("[DEBUG] DB Instance Modification request: %s", req) diff --git a/aws/resource_aws_db_instance_test.go b/aws/resource_aws_db_instance_test.go index 7e2f8cbba8d..90eaecda9a1 100644 --- a/aws/resource_aws_db_instance_test.go +++ b/aws/resource_aws_db_instance_test.go @@ -1236,6 +1236,66 @@ func TestAccAWSDBInstance_MSSQL_TZ(t *testing.T) { }) } +func TestAccAWSDBInstance_MSSQL_Domain(t *testing.T) { + var vBefore, vAfter rds.DBInstance + rInt := acctest.RandInt() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDBInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDBMSSQLDomain(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists("aws_db_instance.mssql", &vBefore), + testAccCheckAWSDBInstanceDomainAttributes("foo.somedomain.com", &vBefore), + resource.TestCheckResourceAttrSet( + "aws_db_instance.mssql", "domain"), + resource.TestCheckResourceAttrSet( + "aws_db_instance.mssql", "domain_iam_role_name"), + ), + }, + { + Config: testAccAWSDBMSSQLUpdateDomain(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists("aws_db_instance.mssql", &vAfter), + testAccCheckAWSDBInstanceDomainAttributes("bar.somedomain.com", &vAfter), + resource.TestCheckResourceAttrSet( + "aws_db_instance.mssql", "domain"), + resource.TestCheckResourceAttrSet( + "aws_db_instance.mssql", "domain_iam_role_name"), + ), + }, + }, + }) +} + +func TestAccAWSDBInstance_MSSQL_DomainSnapshotRestore(t *testing.T) { + var v, vRestoredInstance rds.DBInstance + rInt := acctest.RandInt() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSDBInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSDBMSSQLDomainSnapshotRestore(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSDBInstanceExists("aws_db_instance.mssql_restore", &vRestoredInstance), + testAccCheckAWSDBInstanceExists("aws_db_instance.mssql", &v), + testAccCheckAWSDBInstanceDomainAttributes("foo.somedomain.com", &vRestoredInstance), + resource.TestCheckResourceAttrSet( + "aws_db_instance.mssql_restore", "domain"), + resource.TestCheckResourceAttrSet( + "aws_db_instance.mssql_restore", "domain_iam_role_name"), + ), + }, + }, + }) +} + func TestAccAWSDBInstance_MinorVersion(t *testing.T) { var v rds.DBInstance @@ -1478,6 +1538,20 @@ func testAccCheckAWSDBInstanceAttributes_MSSQL(v *rds.DBInstance, tz string) res } } +func testAccCheckAWSDBInstanceDomainAttributes(domain string, v *rds.DBInstance) resource.TestCheckFunc { + return func(s *terraform.State) error { + for _, dm := range v.DomainMemberships { + if *dm.FQDN != domain { + continue + } + + return nil + } + + return fmt.Errorf("Domain %s not found in domain memberships", domain) + } +} + func testAccCheckAWSDBInstanceParameterApplyStatusInSync(dbInstance *rds.DBInstance) resource.TestCheckFunc { return func(s *terraform.State) error { for _, dbParameterGroup := range dbInstance.DBParameterGroups { @@ -2416,6 +2490,378 @@ resource "aws_security_group_rule" "rds-mssql-1" { `, rInt, rInt, rInt) } +func testAccAWSDBMSSQLDomain(rInt int) string { + return fmt.Sprintf(` +resource "aws_vpc" "foo" { + cidr_block = "10.1.0.0/16" + enable_dns_hostnames = true + tags { + Name = "terraform-testacc-db-instance-mssql-domain" + } +} + +resource "aws_db_subnet_group" "rds_one" { + name = "tf_acc_test_%d" + description = "db subnets for rds_one" + + subnet_ids = ["${aws_subnet.main.id}", "${aws_subnet.other.id}"] +} + +resource "aws_subnet" "main" { + vpc_id = "${aws_vpc.foo.id}" + availability_zone = "us-west-2a" + cidr_block = "10.1.1.0/24" + tags { + Name = "tf-acc-db-instance-mssql-domain-main" + } +} + +resource "aws_subnet" "other" { + vpc_id = "${aws_vpc.foo.id}" + availability_zone = "us-west-2b" + cidr_block = "10.1.2.0/24" + tags { + Name = "tf-acc-db-instance-mssql-domain-other" + } +} + +resource "aws_db_instance" "mssql" { + identifier = "tf-test-mssql-%d" + + db_subnet_group_name = "${aws_db_subnet_group.rds_one.name}" + + instance_class = "db.t2.micro" + allocated_storage = 20 + username = "somecrazyusername" + password = "somecrazypassword" + engine = "sqlserver-ex" + backup_retention_period = 0 + skip_final_snapshot = true + + domain = "${aws_directory_service_directory.foo.id}" + domain_iam_role_name = "${aws_iam_role.role.name}" + + vpc_security_group_ids = ["${aws_security_group.rds-mssql.id}"] +} + +resource "aws_security_group" "rds-mssql" { + name = "tf-rds-mssql-test-%d" + + description = "TF Testing" + vpc_id = "${aws_vpc.foo.id}" +} + +resource "aws_security_group_rule" "rds-mssql-1" { + type = "egress" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + + security_group_id = "${aws_security_group.rds-mssql.id}" +} + +resource "aws_directory_service_directory" "foo" { + name = "foo.somedomain.com" + password = "SuperSecretPassw0rd" + type = "MicrosoftAD" + edition = "Standard" + + vpc_settings { + vpc_id = "${aws_vpc.foo.id}" + subnet_ids = ["${aws_subnet.main.id}", "${aws_subnet.other.id}"] + } +} + +resource "aws_directory_service_directory" "bar" { + name = "bar.somedomain.com" + password = "SuperSecretPassw0rd" + type = "MicrosoftAD" + edition = "Standard" + + vpc_settings { + vpc_id = "${aws_vpc.foo.id}" + subnet_ids = ["${aws_subnet.main.id}", "${aws_subnet.other.id}"] + } +} + +resource "aws_iam_role" "role" { + name = "tf-acc-db-instance-mssql-domain-role-%d" + + assume_role_policy = <