Merge pull request #7184 from alkersan/openstack_stop_before_detele

provider/openstack stop before destroy
This commit is contained in:
Joe Topjian 2016-06-23 08:15:08 -06:00 committed by GitHub
commit 5ce693df99
7 changed files with 124 additions and 1 deletions

View File

@ -18,6 +18,7 @@ import (
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/schedulerhints" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/schedulerhints"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/startstop"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach"
"github.com/rackspace/gophercloud/openstack/compute/v2/flavors" "github.com/rackspace/gophercloud/openstack/compute/v2/flavors"
@ -318,6 +319,11 @@ func resourceComputeInstanceV2() *schema.Resource {
}, },
Set: resourceComputeInstancePersonalityHash, Set: resourceComputeInstancePersonalityHash,
}, },
"stop_before_destroy": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
},
}, },
} }
} }
@ -808,6 +814,27 @@ func resourceComputeInstanceV2Delete(d *schema.ResourceData, meta interface{}) e
return fmt.Errorf("Error creating OpenStack compute client: %s", err) return fmt.Errorf("Error creating OpenStack compute client: %s", err)
} }
if d.Get("stop_before_destroy").(bool) {
err = startstop.Stop(computeClient, d.Id()).ExtractErr()
if err != nil {
log.Printf("[WARN] Error stopping OpenStack instance: %s", err)
} else {
stopStateConf := &resource.StateChangeConf{
Pending: []string{"ACTIVE"},
Target: []string{"SHUTOFF"},
Refresh: ServerV2StateRefreshFunc(computeClient, d.Id()),
Timeout: 3 * time.Minute,
Delay: 10 * time.Second,
MinTimeout: 3 * time.Second,
}
log.Printf("[DEBUG] Waiting for instance (%s) to stop", d.Id())
_, err = stopStateConf.WaitForState()
if err != nil {
log.Printf("[WARN] Error waiting for instance (%s) to stop: %s, proceeding to delete", d.Id(), err)
}
}
}
err = servers.Delete(computeClient, d.Id()).ExtractErr() err = servers.Delete(computeClient, d.Id()).ExtractErr()
if err != nil { if err != nil {
return fmt.Errorf("Error deleting OpenStack server: %s", err) return fmt.Errorf("Error deleting OpenStack server: %s", err)
@ -817,7 +844,7 @@ func resourceComputeInstanceV2Delete(d *schema.ResourceData, meta interface{}) e
log.Printf("[DEBUG] Waiting for instance (%s) to delete", d.Id()) log.Printf("[DEBUG] Waiting for instance (%s) to delete", d.Id())
stateConf := &resource.StateChangeConf{ stateConf := &resource.StateChangeConf{
Pending: []string{"ACTIVE"}, Pending: []string{"ACTIVE", "SHUTOFF"},
Target: []string{"DELETED"}, Target: []string{"DELETED"},
Refresh: ServerV2StateRefreshFunc(computeClient, d.Id()), Refresh: ServerV2StateRefreshFunc(computeClient, d.Id()),
Timeout: 30 * time.Minute, Timeout: 30 * time.Minute,

View File

@ -840,3 +840,31 @@ func testAccCheckComputeV2InstanceInstanceIDsDoNotMatch(
return nil return nil
} }
} }
func TestAccComputeV2Instance_stop_before_destroy(t *testing.T) {
var instance servers.Server
var testAccComputeV2Instance_stop_before_destroy = fmt.Sprintf(`
resource "openstack_compute_instance_v2" "foo" {
name = "terraform-test"
security_groups = ["default"]
network {
uuid = "%s"
}
stop_before_destroy = true
}`,
os.Getenv("OS_NETWORK_ID"))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeV2InstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeV2Instance_stop_before_destroy,
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeV2InstanceExists(t, "openstack_compute_instance_v2.foo", &instance),
),
},
},
})
}

View File

@ -0,0 +1,5 @@
/*
Package startstop provides functionality to start and stop servers that have
been provisioned by the OpenStack Compute service.
*/
package startstop

View File

@ -0,0 +1,29 @@
// +build fixtures
package startstop
import (
"net/http"
"testing"
th "github.com/rackspace/gophercloud/testhelper"
"github.com/rackspace/gophercloud/testhelper/client"
)
func mockStartServerResponse(t *testing.T, id string) {
th.Mux.HandleFunc("/servers/"+id+"/action", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "POST")
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
th.TestJSONRequest(t, r, `{"os-start": null}`)
w.WriteHeader(http.StatusAccepted)
})
}
func mockStopServerResponse(t *testing.T, id string) {
th.Mux.HandleFunc("/servers/"+id+"/action", func(w http.ResponseWriter, r *http.Request) {
th.TestMethod(t, r, "POST")
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
th.TestJSONRequest(t, r, `{"os-stop": null}`)
w.WriteHeader(http.StatusAccepted)
})
}

View File

@ -0,0 +1,23 @@
package startstop
import "github.com/rackspace/gophercloud"
func actionURL(client *gophercloud.ServiceClient, id string) string {
return client.ServiceURL("servers", id, "action")
}
// Start is the operation responsible for starting a Compute server.
func Start(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
var res gophercloud.ErrResult
reqBody := map[string]interface{}{"os-start": nil}
_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
return res
}
// Stop is the operation responsible for stopping a Compute server.
func Stop(client *gophercloud.ServiceClient, id string) gophercloud.ErrResult {
var res gophercloud.ErrResult
reqBody := map[string]interface{}{"os-stop": nil}
_, res.Err = client.Post(actionURL(client, id), reqBody, nil, nil)
return res
}

6
vendor/vendor.json vendored
View File

@ -1184,6 +1184,12 @@
"revision": "d47105ce4ef90cea9a14b85c8dd172b760085828", "revision": "d47105ce4ef90cea9a14b85c8dd172b760085828",
"revisionTime": "2016-06-03T22:34:01Z" "revisionTime": "2016-06-03T22:34:01Z"
}, },
{
"checksumSHA1": "jqSmOJoNKVtGwDhuoilAF7iftqA=",
"path": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/startstop",
"revision": "d47105ce4ef90cea9a14b85c8dd172b760085828",
"revisionTime": "2016-06-03T22:34:01Z"
},
{ {
"checksumSHA1": "rHEOEAm10HDsfBLU8FqKSUdwqFY=", "checksumSHA1": "rHEOEAm10HDsfBLU8FqKSUdwqFY=",
"path": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks", "path": "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks",

View File

@ -264,6 +264,11 @@ The following arguments are supported:
defining one or more files and their contents. The personality structure defining one or more files and their contents. The personality structure
is described below. is described below.
* `stop_before_destroy` - (Optional) Whether to try stop instance gracefully
before destroying it, thus giving chance for guest OS daemons to stop correctly.
If instance doesn't stop within timeout, it will be destroyed anyway.
The `network` block supports: The `network` block supports:
* `uuid` - (Required unless `port` or `name` is provided) The network UUID to * `uuid` - (Required unless `port` or `name` is provided) The network UUID to