Skip to content

Commit 0965b88

Browse files
karolgorcakshat-jindal-nit
authored andcommitted
Allow for setting desired_status to different values than "RUNNING" on creation of google_compute_instance (GoogleCloudPlatform#11902)
1 parent 046393e commit 0965b88

File tree

2 files changed

+130
-37
lines changed

2 files changed

+130
-37
lines changed

mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl

+40-27
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,6 @@ be from 0 to 999,999,999 inclusive.`,
12861286
},
12871287
suppressEmptyGuestAcceleratorDiff,
12881288
),
1289-
desiredStatusDiff,
12901289
validateSubnetworkProject,
12911290
forceNewIfNetworkIPNotUpdatable,
12921291
tpgresource.SetLabelsDiff,
@@ -1477,10 +1476,34 @@ func getAllStatusBut(status string) []string {
14771476
return computeInstanceStatus
14781477
}
14791478

1480-
func waitUntilInstanceHasDesiredStatus(config *transport_tpg.Config, d *schema.ResourceData) error {
1481-
desiredStatus := d.Get("desired_status").(string)
1479+
func changeInstanceStatusOnCreation(config *transport_tpg.Config, d *schema.ResourceData, project, zone, status, userAgent string) error {
1480+
var op *compute.Operation
1481+
var err error
1482+
if status == "TERMINATED" {
1483+
op, err = config.NewComputeClient(userAgent).Instances.Stop(project, zone, d.Get("name").(string)).Do()
1484+
} else if status == "SUSPENDED" {
1485+
op, err = config.NewComputeClient(userAgent).Instances.Suspend(project, zone, d.Get("name").(string)).Do()
1486+
}
1487+
if err != nil {
1488+
return fmt.Errorf("Error changing instance status after creation: %s", err)
1489+
}
1490+
1491+
waitErr := ComputeOperationWaitTime(config, op, project, "changing instance status", userAgent, d.Timeout(schema.TimeoutCreate))
1492+
if waitErr != nil {
1493+
d.SetId("")
1494+
return waitErr
1495+
}
1496+
1497+
err = waitUntilInstanceHasDesiredStatus(config, d, status)
1498+
if err != nil {
1499+
return fmt.Errorf("Error waiting for status: %s", err)
1500+
}
1501+
1502+
return nil
1503+
}
14821504

1483-
if desiredStatus != "" {
1505+
func waitUntilInstanceHasDesiredStatus(config *transport_tpg.Config, d *schema.ResourceData, status string) error {
1506+
if status != "" {
14841507
stateRefreshFunc := func() (interface{}, string, error) {
14851508
instance, err := getInstance(config, d)
14861509
if err != nil || instance == nil {
@@ -1491,17 +1514,17 @@ func waitUntilInstanceHasDesiredStatus(config *transport_tpg.Config, d *schema.R
14911514
}
14921515
stateChangeConf := retry.StateChangeConf{
14931516
Delay: 5 * time.Second,
1494-
Pending: getAllStatusBut(desiredStatus),
1517+
Pending: getAllStatusBut(status),
14951518
Refresh: stateRefreshFunc,
1496-
Target: []string{desiredStatus},
1519+
Target: []string{status},
14971520
Timeout: d.Timeout(schema.TimeoutUpdate),
14981521
MinTimeout: 2 * time.Second,
14991522
}
15001523
_, err := stateChangeConf.WaitForState()
15011524

15021525
if err != nil {
15031526
return fmt.Errorf(
1504-
"Error waiting for instance to reach desired status %s: %s", desiredStatus, err)
1527+
"Error waiting for instance to reach desired status %s: %s", status, err)
15051528
}
15061529
}
15071530

@@ -1568,11 +1591,20 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
15681591
}
15691592
{{- end }}
15701593

1571-
err = waitUntilInstanceHasDesiredStatus(config, d)
1594+
err = waitUntilInstanceHasDesiredStatus(config, d, "RUNNING")
15721595
if err != nil {
15731596
return fmt.Errorf("Error waiting for status: %s", err)
15741597
}
15751598

1599+
if val, ok := d.GetOk("desired_status"); ok {
1600+
if val.(string) != "RUNNING" {
1601+
err = changeInstanceStatusOnCreation(config, d, project, zone.Name, val.(string), userAgent)
1602+
if err != nil {
1603+
return fmt.Errorf("Error changing instance status after creation: %s", err)
1604+
}
1605+
}
1606+
}
1607+
15761608
return resourceComputeInstanceRead(d, meta)
15771609
}
15781610

@@ -2916,25 +2948,6 @@ func suppressEmptyGuestAcceleratorDiff(_ context.Context, d *schema.ResourceDiff
29162948
return nil
29172949
}
29182950

2919-
// return an error if the desired_status field is set to a value other than RUNNING on Create.
2920-
func desiredStatusDiff(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error {
2921-
// when creating an instance, name is not set
2922-
oldName, _ := diff.GetChange("name")
2923-
2924-
if oldName == nil || oldName == "" {
2925-
_, newDesiredStatus := diff.GetChange("desired_status")
2926-
2927-
if newDesiredStatus == nil || newDesiredStatus == "" {
2928-
return nil
2929-
} else if newDesiredStatus != "RUNNING" {
2930-
return fmt.Errorf("When creating an instance, desired_status can only accept RUNNING value")
2931-
}
2932-
return nil
2933-
}
2934-
2935-
return nil
2936-
}
2937-
29382951
func resourceComputeInstanceDelete(d *schema.ResourceData, meta interface{}) error {
29392952
config := meta.(*transport_tpg.Config)
29402953
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)

mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.tmpl

+90-10
Original file line numberDiff line numberDiff line change
@@ -2288,27 +2288,80 @@ func TestAccComputeInstance_enableDisplay(t *testing.T) {
22882288
})
22892289
}
22902290

2291-
func TestAccComputeInstance_desiredStatusOnCreation(t *testing.T) {
2291+
func TestAccComputeInstance_desiredStatusTerminatedOnCreation(t *testing.T) {
22922292
t.Parallel()
22932293

22942294
var instance compute.Instance
2295-
var instanceName = fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))
2295+
2296+
context_1 := map[string]interface{}{
2297+
"instance_name": fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)),
2298+
"zone": "us-central1-a",
2299+
"desired_status": "TERMINATED",
2300+
}
2301+
2302+
context_2 := map[string]interface{}{
2303+
"instance_name": context_1["instance_name"],
2304+
"zone": context_1["zone"],
2305+
"desired_status": "RUNNING",
2306+
}
22962307

22972308
acctest.VcrTest(t, resource.TestCase{
2298-
PreCheck: func() { acctest.AccTestPreCheck(t) },
2309+
PreCheck: func() { acctest.AccTestPreCheck(t) },
22992310
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
2300-
CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t),
2311+
CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t),
23012312
Steps: []resource.TestStep{
23022313
{
2303-
Config: testAccComputeInstance_machineType_desiredStatus_allowStoppingForUpdate(instanceName, "e2-medium", "TERMINATED", false),
2304-
ExpectError: regexp.MustCompile("When creating an instance, desired_status can only accept RUNNING value"),
2314+
Config: testAccComputeInstance_desiredStatusOnCreation(context_1),
2315+
Check: resource.ComposeTestCheckFunc(
2316+
testAccCheckComputeInstanceExists(t, "google_compute_instance.foobar", &instance),
2317+
testAccCheckComputeInstanceHasStatus(&instance, context_1["desired_status"].(string)),
2318+
),
23052319
},
23062320
{
2307-
Config: testAccComputeInstance_machineType_desiredStatus_allowStoppingForUpdate(instanceName, "e2-medium", "RUNNING", false),
2321+
Config: testAccComputeInstance_desiredStatusOnCreation(context_2),
23082322
Check: resource.ComposeTestCheckFunc(
2309-
testAccCheckComputeInstanceExists(
2310-
t, "google_compute_instance.foobar", &instance),
2311-
testAccCheckComputeInstanceHasStatus(&instance, "RUNNING"),
2323+
testAccCheckComputeInstanceExists(t, "google_compute_instance.foobar", &instance),
2324+
testAccCheckComputeInstanceHasStatus(&instance, context_2["desired_status"].(string)),
2325+
),
2326+
},
2327+
},
2328+
})
2329+
}
2330+
2331+
func TestAccComputeInstance_desiredStatusSuspendedOnCreation(t *testing.T) {
2332+
t.Parallel()
2333+
2334+
var instance compute.Instance
2335+
2336+
context_1 := map[string]interface{}{
2337+
"instance_name": fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)),
2338+
"zone": "us-central1-a",
2339+
"desired_status": "SUSPENDED",
2340+
}
2341+
2342+
context_2 := map[string]interface{}{
2343+
"instance_name": context_1["instance_name"],
2344+
"zone": context_1["zone"],
2345+
"desired_status": "RUNNING",
2346+
}
2347+
2348+
acctest.VcrTest(t, resource.TestCase{
2349+
PreCheck: func() { acctest.AccTestPreCheck(t) },
2350+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
2351+
CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t),
2352+
Steps: []resource.TestStep{
2353+
{
2354+
Config: testAccComputeInstance_desiredStatusOnCreation(context_1),
2355+
Check: resource.ComposeTestCheckFunc(
2356+
testAccCheckComputeInstanceExists(t, "google_compute_instance.foobar", &instance),
2357+
testAccCheckComputeInstanceHasStatus(&instance, context_1["desired_status"].(string)),
2358+
),
2359+
},
2360+
{
2361+
Config: testAccComputeInstance_desiredStatusOnCreation(context_2),
2362+
Check: resource.ComposeTestCheckFunc(
2363+
testAccCheckComputeInstanceExists(t, "google_compute_instance.foobar", &instance),
2364+
testAccCheckComputeInstanceHasStatus(&instance, context_2["desired_status"].(string)),
23122365
),
23132366
},
23142367
},
@@ -8974,6 +9027,33 @@ resource "google_compute_instance" "foobar" {
89749027
`, instance)
89759028
}
89769029

9030+
func testAccComputeInstance_desiredStatusOnCreation(context map[string]interface{}) string {
9031+
return acctest.Nprintf(`
9032+
data "google_compute_image" "my_image" {
9033+
family = "debian-11"
9034+
project = "debian-cloud"
9035+
}
9036+
9037+
resource "google_compute_instance" "foobar" {
9038+
name = "%{instance_name}"
9039+
machine_type = "e2-medium"
9040+
zone = "%{zone}"
9041+
9042+
boot_disk {
9043+
initialize_params{
9044+
image = "${data.google_compute_image.my_image.self_link}"
9045+
}
9046+
}
9047+
9048+
network_interface {
9049+
network = "default"
9050+
}
9051+
9052+
desired_status = "%{desired_status}"
9053+
}
9054+
`, context)
9055+
}
9056+
89779057
func testAccComputeInstance_resourcePolicyCollocate(instance, suffix string) string {
89789058
return fmt.Sprintf(`
89799059
data "google_compute_image" "my_image" {

0 commit comments

Comments
 (0)