Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
162ec2f
Terraform changes for enabling cross project clone
gsa725 Feb 26, 2026
5aab141
Updated test params for testAccSqlDatabaseInstance_crossProjectClone …
gsa725 Feb 26, 2026
4d9ce82
Updating resource name in testAccSqlDatabaseInstance_crossProjectClone
gsa725 Feb 26, 2026
b35a579
Added testAccSqlDatabaseInstanceImportStateIdFunc to also import proj…
gsa725 Feb 26, 2026
eb5c9b2
Nitpicking changes
gsa725 Feb 27, 2026
cac58bf
Revert testAccSqlDatabaseInstanceDestroyProducer changes
gsa725 Feb 27, 2026
56ae306
Updated resource meta yaml for new clone field
gsa725 Feb 27, 2026
2f4585b
Creating bootstrap project for cross project clone instead of taking …
gsa725 Mar 2, 2026
eb2c06c
Release cross project clone changes for beta only
gsa725 Mar 2, 2026
a662755
Run test in VCR mode
gsa725 Mar 2, 2026
99b2e33
Fix test issue
gsa725 Mar 2, 2026
993f994
Version related changes
gsa725 Mar 2, 2026
186cf89
Nitpicking changes
gsa725 Mar 2, 2026
d6b0dc6
Data fix
gsa725 Mar 2, 2026
55a369d
Beta only
gsa725 Mar 2, 2026
385553c
Beta provider changes only
gsa725 Mar 3, 2026
e206ebf
Addressing comment
gsa725 Mar 3, 2026
154447c
Switching cloneDestinationProject and cloneSourceProject to verify th…
gsa725 Mar 3, 2026
fa26cfc
Fixing compile issue
gsa725 Mar 3, 2026
6a5b028
Update project id for the source instance
gsa725 Mar 3, 2026
15ec72f
Fix changes
gsa725 Mar 4, 2026
797c57d
Addressing PR comments
gsa725 Mar 4, 2026
8bc0750
Trying random fix
gsa725 Mar 4, 2026
713b89b
Remove output.txt file
gsa725 Mar 4, 2026
d81697d
Update to beta factories
gsa725 Mar 4, 2026
aa569ad
Using env. variables for dest project
gsa725 Mar 5, 2026
869eb28
Compile fix
gsa725 Mar 5, 2026
db570ea
Small bug fix
gsa725 Mar 5, 2026
a5965bb
Addressing PR comments
gsa725 Mar 9, 2026
da61a09
Adding documentation
gsa725 Mar 9, 2026
bb75fef
Remove extra file
gsa725 Mar 9, 2026
6ed0a3d
Small bug fix
gsa725 Mar 9, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -1381,6 +1381,13 @@ API (for read pools, effective_availability_type may differ from availability_ty
Required: true,
Description: `The name of the instance from which the point in time should be restored.`,
},
{{- if ne $.TargetVersionName "ga" }}
"source_project": {
Type: schema.TypeString,
Optional: true,
Description: `The project ID of the source project`,
},
{{- end }}
"point_in_time": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -1561,7 +1568,14 @@ func resourceSqlDatabaseInstanceCreate(d *schema.ResourceData, meta interface{})
ReplicaConfiguration: expandReplicaConfiguration(d.Get("replica_configuration").([]interface{})),
}

cloneContext, cloneSource := expandCloneContext(d.Get("clone").([]interface{}))
cloneContext, cloneSourceInstance := expandCloneContext(d.Get("clone").([]interface{}))

{{- if ne $.TargetVersionName "ga" }}
cloneSourceProject := expandCloneSourceProject(d.Get("clone").([]interface{}))
if cloneSourceProject == "" {
cloneSourceProject = project
}
{{- end }}
pointInTimeRestoreContext := expandPointInTimeRestoreContext(d.Get("point_in_time_restore_context").([]interface{}))

if valueI, ok := d.GetOk("settings.0.auto_upgrade_enabled"); ok && !(valueI.(bool)) {
Expand Down Expand Up @@ -1623,8 +1637,19 @@ func resourceSqlDatabaseInstanceCreate(d *schema.ResourceData, meta interface{})
RetryFunc: func() (operr error) {
if cloneContext != nil {
cloneContext.DestinationInstanceName = name
{{- if ne $.TargetVersionName "ga" }}
// if cloneSourceProject isn't equal to the project, then it's a cross project clone request.
if (cloneSourceProject != project) {
cloneContext.DestinationProject = project
cloneContext.DestinationNetwork = network
}
{{- end }}
clodeReq := sqladmin.InstancesCloneRequest{CloneContext: cloneContext}
op, operr = config.NewSqlAdminClient(userAgent).Instances.Clone(project, cloneSource, &clodeReq).Do()
{{- if ne $.TargetVersionName "ga" }}
op, operr = config.NewSqlAdminClient(userAgent).Instances.Clone(cloneSourceProject, cloneSourceInstance, &clodeReq).Do()
Comment thread
zli82016 marked this conversation as resolved.
{{- else }}
op, operr = config.NewSqlAdminClient(userAgent).Instances.Clone(project, cloneSourceInstance, &clodeReq).Do()
{{- end }}
Comment thread
gsa725 marked this conversation as resolved.
} else if pointInTimeRestoreContext != nil {
parent := fmt.Sprintf("projects/%s", project)
op, operr = config.NewSqlAdminClient(userAgent).Instances.PointInTimeRestore(parent, pointInTimeRestoreContext).Do()
Expand Down Expand Up @@ -1872,6 +1897,16 @@ func expandCloneContext(configured []interface{}) (*sqladmin.CloneContext, strin
}, _cloneConfiguration["source_instance_name"].(string)
}

{{- if ne $.TargetVersionName "ga" }}
func expandCloneSourceProject(configured []interface{}) (string) {
if len(configured) == 0 || configured[0] == nil {
return ""
}
_cloneConfiguration := configured[0].(map[string]interface{})
return _cloneConfiguration["source_project"].(string)
}
{{- end }}

func expandMaintenanceWindow(configured []interface{}) *sqladmin.MaintenanceWindow {
if len(configured) == 0 || configured[0] == nil {
return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ fields:
- field: 'clone.preferred_zone'
- field: 'clone.source_instance_deletion_time'
- field: 'clone.source_instance_name'
{{- if ne $.TargetVersionName "ga" }}
- field: 'clone.source_project'
{{- end }}
- api_field: 'connectionName'
- api_field: 'databaseVersion'
- field: 'deletion_protection'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

package sql_test

import (
Expand Down Expand Up @@ -1718,6 +1719,49 @@ func TestAccSqlDatabaseInstance_basicClone(t *testing.T) {
})
}

{{- if ne $.TargetVersionName "ga" }}
func TestAccSqlDatabaseInstance_crossProjectClone(t *testing.T) {
t.Parallel()

context := map[string]interface{}{
"random_suffix": acctest.RandString(t, 10),
"orgId": envvar.GetTestOrgFromEnv(t),
"billingAccount": envvar.GetTestBillingAccountFromEnv(t),
"cloneSourceProject": envvar.GetTestProjectFromEnv(),
}

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t),
ExternalProviders: map[string]resource.ExternalProvider{
"time": {},
},
Steps: []resource.TestStep{
{
Config: testAccSqlDatabaseInstance_crossProjectClone(context),
},
{
ResourceName: "google_sql_database_instance.instance",
ImportState: true,
ImportStateVerify: true,
ImportStateIdFunc: testAccSqlDatabaseInstanceImportStateIdFunc("google_sql_database_instance.instance"),
Comment thread
zli82016 marked this conversation as resolved.
ImportStateVerifyIgnore: []string{"deletion_protection", "clone"},
},
},
})
}
{{- end }}

func testAccSqlDatabaseInstanceImportStateIdFunc(resourceName string) resource.ImportStateIdFunc {
Comment thread
zli82016 marked this conversation as resolved.
return func(s *terraform.State) (string, error) {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
return "", fmt.Errorf("Not found: %s", resourceName)
}
return fmt.Sprintf("%s/%s", rs.Primary.Attributes["project"], rs.Primary.Attributes["name"]), nil
}
}

func TestAccSqlDatabaseInstance_cloneWithSettings(t *testing.T) {
// Sqladmin client
acctest.SkipIfVcr(t)
Expand Down Expand Up @@ -8252,6 +8296,113 @@ data "google_sql_backup_run" "backup" {
`, context)
}

func testAccSqlDatabaseInstance_crossProjectClone(context map[string]interface{}) string {
Comment thread
zli82016 marked this conversation as resolved.
return acctest.Nprintf(`
Comment thread
gsa725 marked this conversation as resolved.
resource "google_project" "project" {
provider = google-beta
name = "tf-test-cpc-%{random_suffix}"
project_id = "tf-test-cpc-%{random_suffix}"
org_id = "%{orgId}"
billing_account = "%{billingAccount}"
deletion_policy = "DELETE"
}

resource "time_sleep" "wait_60_seconds" {
create_duration = "60s"
depends_on = [google_project.project]
}

resource "google_project_service" "compute" {
provider = google-beta
project = google_project.project.project_id
service = "compute.googleapis.com"
depends_on = [time_sleep.wait_60_seconds]
}

resource "google_project_service" "servicenetworking" {
provider = google-beta
project = google_project.project.project_id
service = "servicenetworking.googleapis.com"
depends_on = [google_project_service.compute]
}

resource "time_sleep" "wait_300_seconds" {
create_duration = "300s"
depends_on = [google_project_service.servicenetworking]
}

resource "google_compute_network" "sql_network" {
provider = google-beta
name = "sql-network"
project = google_project.project.project_id
depends_on = [time_sleep.wait_300_seconds]
}

resource "google_compute_global_address" "sql_range" {
provider = google-beta
name = "sql-range"
purpose = "VPC_PEERING"
address_type = "INTERNAL"
prefix_length = 16
network = google_compute_network.sql_network.id
project = google_project.project.project_id
}

resource "google_service_networking_connection" "sql_vpc_connection" {
provider = google-beta
network = google_compute_network.sql_network.id
service = "servicenetworking.googleapis.com"
reserved_peering_ranges = [google_compute_global_address.sql_range.name]
depends_on = [google_project_service.servicenetworking]
deletion_policy = "ABANDON"
}

resource "google_sql_database_instance" "instance" {
provider = google-beta
name = "tf-test-cpc-%{random_suffix}"
database_version = "POSTGRES_11"
region = "us-central1"
project = google_project.project.project_id

settings {
tier = "db-custom-2-3840"
edition = "ENTERPRISE"
ip_configuration {
private_network = google_compute_network.sql_network.self_link
}
backup_configuration {
enabled = true
point_in_time_recovery_enabled = true
}
}

clone {
source_project = "%{cloneSourceProject}"
source_instance_name = google_sql_database_instance.source_instance.name
}

deletion_protection = false

// Ignore changes, since the most recent backup may change during the test
lifecycle{
ignore_changes = [clone[0].point_in_time]
}
depends_on = [google_service_networking_connection.sql_vpc_connection]
}

resource "google_sql_database_instance" "source_instance" {
provider = google-beta
name = "tf-test-source-%{random_suffix}"
database_version = "POSTGRES_11"
region = "us-central1"
deletion_protection = false
settings {
tier = "db-g1-small"
}
}
`, context)
}

func testAccSqlDatabaseInstance_cloneWithSettings(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_sql_database_instance" "instance" {
Expand Down Expand Up @@ -9031,4 +9182,4 @@ func testGoogleSqlDatabaseInstanceCheckNodeCount(t *testing.T, instance string,

return nil
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ The optional `point_in_time_restore_context` block supports:
The optional `clone` block supports:

* `source_instance_name` - (Required) Name of the source instance which will be cloned.
* `source_project` - (Optional) Id of source project where source instances exits, required for cross project clone scenario.

* `point_in_time` - (Optional) The timestamp of the point in time that should be restored.

Expand Down