Skip to content

Commit

Permalink
ability to change instance_state
Browse files Browse the repository at this point in the history
  • Loading branch information
Artur Gadelshin committed Jan 29, 2019
1 parent 60264e3 commit e17c192
Show file tree
Hide file tree
Showing 2 changed files with 191 additions and 0 deletions.
76 changes: 76 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/helper/customdiff"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
"github.com/mitchellh/hashstructure"
Expand Down Expand Up @@ -127,6 +128,13 @@ func resourceComputeInstance() *schema.Resource {
Required: true,
},

"instance_state": {
Type: schema.TypeString,
Optional: true,
Default: "running",
ValidateFunc: validation.StringInSlice([]string{"stopped", "running"}, false),
},

"name": {
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -762,6 +770,15 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
d.Set("can_ip_forward", instance.CanIpForward)
d.Set("machine_type", GetResourceNameFromSelfLink(instance.MachineType))

// PROVISIONING, STAGING, RUNNING, STOPPING, STOPPED,
// // SUSPENDING, SUSPENDED, and TERMINATED
switch instance.Status {
case "PROVISIONING", "STAGING", "RUNNING":
d.Set("instance_state", "running")
default:
d.Set("instance_state", "stopped")
}

// Set the networks
// Use the first external IP found for the default connection info.
networkInterfaces, _, internalIP, externalIP, err := flattenNetworkInterfaces(d, config, instance.NetworkInterfaces)
Expand Down Expand Up @@ -964,6 +981,55 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err
d.SetPartial("tags")
}

if d.HasChange("instance_state") {
if d.Get("instance_state") == "running" {
_, err := config.clientCompute.Instances.Start(project,
zone, d.Id()).Do()
if err != nil {
return fmt.Errorf(
"Error starting an instance (%s): %s", d.Id(), err)
}

stateConf := &resource.StateChangeConf{
Pending: []string{"PROVISIONING", "STAGING", "TERMINATED"},
Target: []string{"RUNNING"},
Refresh: instanceStateRefreshFunc(config.clientCompute, project, zone, d.Id()),
Timeout: 10 * time.Minute,
Delay: 10 * time.Second,
MinTimeout: 3 * time.Second,
}

_, err = stateConf.WaitForState()
if err != nil {
return fmt.Errorf(
"Error waiting for instance (%s) to start: %s", d.Id(), err)
}
} else {
_, err := config.clientCompute.Instances.Stop(project,
zone, d.Id()).Do()
if err != nil {
return fmt.Errorf(
"Error stopping an instance (%s): %s", d.Id(), err)
}

stateConf := &resource.StateChangeConf{
Pending: []string{"PROVISIONING", "STAGING", "RUNNING", "STOPPING"},
Target: []string{"TERMINATED"},
Refresh: instanceStateRefreshFunc(config.clientCompute, project, zone, d.Id()),
Timeout: 10 * time.Minute,
Delay: 10 * time.Second,
MinTimeout: 3 * time.Second,
}

_, err = stateConf.WaitForState()
if err != nil {
return fmt.Errorf(
"Error waiting for instance (%s) to stop: %s", d.Id(), err)
}
}

}

if d.HasChange("labels") {
labels := expandLabels(d)
labelFingerprint := d.Get("label_fingerprint").(string)
Expand Down Expand Up @@ -1335,6 +1401,16 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err
return resourceComputeInstanceRead(d, meta)
}

func instanceStateRefreshFunc(computeClient *compute.Service, project, zone, instance string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
i, err := computeClient.Instances.Get(project, zone, instance).Do()
if err != nil {
return nil, "", err
}
return i, i.Status, nil
}
}

func expandAttachedDisk(diskConfig map[string]interface{}, d *schema.ResourceData, meta interface{}) (*computeBeta.AttachedDisk, error) {
config := meta.(*Config)

Expand Down
115 changes: 115 additions & 0 deletions google/resource_compute_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,37 @@ func TestAccComputeInstance_secondaryAliasIpRange(t *testing.T) {
})
}

func TestAccComputeInstanceState(t *testing.T) {
t.Parallel()

var instance compute.Instance
var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccComputeInstance_running(instanceName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeInstanceExists(
"google_compute_instance.foobar", &instance),
testAccCheckComputeInstanceRunning(&instance),
),
},
{
Config: testAccComputeInstance_stopped(instanceName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeInstanceExists(
"google_compute_instance.foobar", &instance),
testAccCheckComputeInstanceTerminated(&instance),
),
},
},
})
}

func testAccCheckComputeInstanceUpdateMachineType(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
Expand Down Expand Up @@ -1133,6 +1164,24 @@ func testAccCheckComputeInstanceExistsInProject(n, p string, instance *compute.I
}
}

func testAccCheckComputeInstanceRunning(instance *compute.Instance) resource.TestCheckFunc {
return func(s *terraform.State) error {
if instance.Status != "RUNNING" {
return fmt.Errorf("Instance is not RUNNING, state: %s", instance.Status)
}
return nil
}
}

func testAccCheckComputeInstanceTerminated(instance *compute.Instance) resource.TestCheckFunc {
return func(s *terraform.State) error {
if instance.Status != "TERMINATED" {
return fmt.Errorf("Instance is not TERMINATED, state: %s", instance.Status)
}
return nil
}
}

func testAccCheckComputeInstanceMetadata(
instance *compute.Instance,
k string, v string) resource.TestCheckFunc {
Expand Down Expand Up @@ -1584,6 +1633,72 @@ resource "google_compute_instance" "foobar" {
`, instance)
}

func testAccComputeInstance_running(instance string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
family = "debian-9"
project = "debian-cloud"
}
resource "google_compute_instance" "foobar" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"
can_ip_forward = false
tags = ["foo", "bar"]
boot_disk {
initialize_params{
image = "${data.google_compute_image.my_image.self_link}"
}
}
network_interface {
network = "default"
}
instance_state = "running"
metadata = {
foo = "bar"
}
}
`, instance)
}

func testAccComputeInstance_stopped(instance string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
family = "debian-9"
project = "debian-cloud"
}
resource "google_compute_instance" "foobar" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"
can_ip_forward = false
tags = ["foo", "bar"]
boot_disk {
initialize_params{
image = "${data.google_compute_image.my_image.self_link}"
}
}
network_interface {
network = "default"
}
instance_state = "stopped"
metadata = {
foo = "bar"
}
}
`, instance)
}

func testAccComputeInstance_basic3(instance string) string {
return fmt.Sprintf(`
data "google_compute_image" "my_image" {
Expand Down

0 comments on commit e17c192

Please sign in to comment.