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

Add status argument (RUNNING/TERMINATED) to google_compute_instance #4797

Merged
115 changes: 115 additions & 0 deletions google/resource_compute_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform-plugin-sdk/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/mitchellh/hashstructure"
Expand Down Expand Up @@ -537,6 +538,12 @@ func resourceComputeInstance() *schema.Resource {
},
},

"desired_status": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{"RUNNING", "TERMINATED"}, false),
},

"tags": {
Type: schema.TypeSet,
Optional: true,
Expand Down Expand Up @@ -594,6 +601,7 @@ func resourceComputeInstance() *schema.Resource {
},
suppressEmptyGuestAcceleratorDiff,
),
desiredStatusDiff,
),
}
}
Expand Down Expand Up @@ -715,6 +723,58 @@ func expandComputeInstance(project string, d *schema.ResourceData, config *Confi
}, nil
}

// return all possible Compute instances status except the one passed as parameter
func getAllStatusBut(status string) []string {
norbjd marked this conversation as resolved.
Show resolved Hide resolved
allStatus := []string{
"PROVISIONING",
"REPAIRING",
"RUNNING",
"STAGING",
"STOPPED",
"STOPPING",
"SUSPENDED",
"SUSPENDING",
"TERMINATED",
}
for i, s := range allStatus {
if status == s {
return append(allStatus[:i], allStatus[i+1:]...)
}
}
return nil
}

func waitUntilInstanceHasDesiredStatus(config *Config, d *schema.ResourceData) error {
desiredStatus := d.Get("desired_status").(string)
rileykarson marked this conversation as resolved.
Show resolved Hide resolved

if desiredStatus != "" {
stateRefreshFunc := func() (interface{}, string, error) {
instance, err := getInstance(config, d)
if err != nil || instance == nil {
log.Printf("Error on InstanceStateRefresh: %s", err)
return nil, "", err
}
return instance.Id, instance.Status, nil
}
stateChangeConf := resource.StateChangeConf{
Delay: 5 * time.Second,
Pending: getAllStatusBut(desiredStatus),
Refresh: stateRefreshFunc,
Target: []string{desiredStatus},
Timeout: d.Timeout(schema.TimeoutUpdate),
MinTimeout: 2 * time.Second,
}
_, err := stateChangeConf.WaitForState()

if err != nil {
return fmt.Errorf(
"Error waiting for instance to reach desired status %s: %s", desiredStatus, err)
}
}

return nil
}

func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

Expand Down Expand Up @@ -760,6 +820,11 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
return waitErr
}

err = waitUntilInstanceHasDesiredStatus(config, d)
if err != nil {
return fmt.Errorf("Error waiting for status: %s", err)
}

return resourceComputeInstanceRead(d, meta)
}

Expand Down Expand Up @@ -945,6 +1010,11 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
d.Set("name", instance.Name)
d.Set("description", instance.Description)
d.Set("hostname", instance.Hostname)

if d.Get("desired_status") != "" {
d.Set("desired_status", instance.Status)
}

d.SetId(fmt.Sprintf("projects/%s/zones/%s/instances/%s", project, zone, instance.Name))

return nil
Expand Down Expand Up @@ -1077,6 +1147,33 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err
d.SetPartial("scheduling")
}

if d.HasChange("desired_status") {
desiredStatus := d.Get("desired_status").(string)
rileykarson marked this conversation as resolved.
Show resolved Hide resolved

if desiredStatus != "" {
var op *compute.Operation

if desiredStatus == "RUNNING" {
op, err = config.clientCompute.Instances.Start(project, zone, instance.Name).Do()
if err != nil {
return err
}
} else if desiredStatus == "TERMINATED" {
op, err = config.clientCompute.Instances.Stop(project, zone, instance.Name).Do()
if err != nil {
return err
}
}
opErr := computeOperationWaitTime(
config, op, project, "updating status",
int(d.Timeout(schema.TimeoutUpdate).Minutes()))
if opErr != nil {
return opErr
}
}
d.SetPartial("desired_status")
}

networkInterfacesCount := d.Get("network_interface.#").(int)
// Sanity check
if networkInterfacesCount != len(instance.NetworkInterfaces) {
Expand Down Expand Up @@ -1581,6 +1678,24 @@ func suppressEmptyGuestAcceleratorDiff(d *schema.ResourceDiff, meta interface{})
return nil
}

func desiredStatusDiff(diff *schema.ResourceDiff, meta interface{}) error {
norbjd marked this conversation as resolved.
Show resolved Hide resolved
// when creating an instance, name is not set
oldName, _ := diff.GetChange("name")
rileykarson marked this conversation as resolved.
Show resolved Hide resolved

if oldName == nil || oldName == "" {
_, newDesiredStatus := diff.GetChange("desired_status")

if newDesiredStatus == nil || newDesiredStatus == "" {
return nil
} else if newDesiredStatus != "RUNNING" {
return fmt.Errorf("When creating an instance, desired_status can only accept RUNNING value")
}
return nil
}

return nil
}

func resourceComputeInstanceDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

Expand Down
Loading