Added scheduler_hints to the OpenStack instance resource.

This allows various hints to be passed to the OpenStack scheduler
that will determine where the instance will be hosted in the cloud.
pull/1921/head
Joe Topjian 11 years ago
parent b74e74fc16
commit 7ca7eeabe7

@ -15,6 +15,7 @@ import (
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip"
"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/secgroups"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/tenantnetworks"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach"
@ -225,6 +226,48 @@ func resourceComputeInstanceV2() *schema.Resource {
},
Set: resourceComputeVolumeAttachmentHash,
},
"scheduler_hints": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"group": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"different_host": &schema.Schema{
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"same_host": &schema.Schema{
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"query": &schema.Schema{
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"target_cell": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"build_near_host_ip": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
},
},
Set: resourceComputeSchedulerHintsHash,
},
},
}
}
@ -290,6 +333,16 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e
}
}
schedulerHintsRaw := d.Get("scheduler_hints").(*schema.Set).List()
if len(schedulerHintsRaw) > 0 {
log.Printf("[DEBUG] schedulerhints: %+v", schedulerHintsRaw)
schedulerHints := resourceInstanceSchedulerHintsV2(d, schedulerHintsRaw[0].(map[string]interface{}))
createOpts = &schedulerhints.CreateOptsExt{
createOpts,
schedulerHints,
}
}
log.Printf("[DEBUG] Create Options: %#v", createOpts)
server, err := servers.Create(computeClient, createOpts).Extract()
if err != nil {
@ -873,6 +926,40 @@ func resourceInstanceBlockDeviceV2(d *schema.ResourceData, bd map[string]interfa
return bfvOpts
}
func resourceInstanceSchedulerHintsV2(d *schema.ResourceData, schedulerHintsRaw map[string]interface{}) schedulerhints.SchedulerHints {
differentHost := []string{}
if len(schedulerHintsRaw["different_host"].([]interface{})) > 0 {
for _, dh := range schedulerHintsRaw["different_host"].([]interface{}) {
differentHost = append(differentHost, dh.(string))
}
}
sameHost := []string{}
if len(schedulerHintsRaw["same_host"].([]interface{})) > 0 {
for _, sh := range schedulerHintsRaw["same_host"].([]interface{}) {
sameHost = append(sameHost, sh.(string))
}
}
query := make([]interface{}, len(schedulerHintsRaw["query"].([]interface{})))
if len(schedulerHintsRaw["query"].([]interface{})) > 0 {
for _, q := range schedulerHintsRaw["query"].([]interface{}) {
query = append(query, q.(string))
}
}
schedulerHints := schedulerhints.SchedulerHints{
Group: schedulerHintsRaw["group"].(string),
DifferentHost: differentHost,
SameHost: sameHost,
Query: query,
TargetCell: schedulerHintsRaw["target_cell"].(string),
BuildNearHostIP: schedulerHintsRaw["build_near_host_ip"].(string),
}
return schedulerHints
}
func getImageID(client *gophercloud.ServiceClient, d *schema.ResourceData) (string, error) {
imageId := d.Get("image_id").(string)
@ -959,6 +1046,29 @@ func resourceComputeVolumeAttachmentHash(v interface{}) int {
return hashcode.String(buf.String())
}
func resourceComputeSchedulerHintsHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
if m["group"] != nil {
buf.WriteString(fmt.Sprintf("%s-", m["group"].(string)))
}
if m["target_cell"] != nil {
buf.WriteString(fmt.Sprintf("%s-", m["target_cell"].(string)))
}
if m["build_host_near_ip"] != nil {
buf.WriteString(fmt.Sprintf("%s-", m["build_host_near_ip"].(string)))
}
buf.WriteString(fmt.Sprintf("%s-", m["different_host"].([]interface{})))
buf.WriteString(fmt.Sprintf("%s-", m["same_host"].([]interface{})))
buf.WriteString(fmt.Sprintf("%s-", m["query"].([]interface{})))
return hashcode.String(buf.String())
}
func attachVolumesToInstance(computeClient *gophercloud.ServiceClient, blockClient *gophercloud.ServiceClient, serverId string, vols []interface{}) error {
if len(vols) > 0 {
for _, v := range vols {

@ -8,6 +8,7 @@ import (
"github.com/hashicorp/terraform/terraform"
"github.com/rackspace/gophercloud/openstack/compute/v2/extensions/servergroups"
"github.com/rackspace/gophercloud/openstack/compute/v2/servers"
)
func TestAccComputeV2ServerGroup_basic(t *testing.T) {
@ -28,6 +29,27 @@ func TestAccComputeV2ServerGroup_basic(t *testing.T) {
})
}
func TestAccComputeV2ServerGroup_affinity(t *testing.T) {
var instance servers.Server
var sg servergroups.ServerGroup
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeV2ServerGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeV2ServerGroup_affinity,
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeV2ServerGroupExists(t, "openstack_compute_servergroup_v2.mysg", &sg),
testAccCheckComputeV2InstanceExists(t, "openstack_compute_instance_v2.myinstance", &instance),
testAccCheckComputeV2InstanceInServerGroup(&instance, &sg),
),
},
},
})
}
func testAccCheckComputeV2ServerGroupDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
computeClient, err := config.computeV2Client(OS_REGION_NAME)
@ -81,8 +103,36 @@ func testAccCheckComputeV2ServerGroupExists(t *testing.T, n string, kp *servergr
}
}
func testAccCheckComputeV2InstanceInServerGroup(instance *servers.Server, sg *servergroups.ServerGroup) resource.TestCheckFunc {
return func(s *terraform.State) error {
if len(sg.Members) > 0 {
for _, m := range sg.Members {
if m == instance.ID {
return nil
}
}
}
return fmt.Errorf("Instance %s is not part of Server Group %s", instance.ID, sg.ID)
}
}
var testAccComputeV2ServerGroup_basic = `
resource "openstack_compute_servergroup_v2" "mysg" {
name = "my server group"
name = "mysg"
policies = ["affinity"]
}`
var testAccComputeV2ServerGroup_affinity = `
resource "openstack_compute_servergroup_v2" "mysg" {
name = "mysg"
policies = ["affinity"]
}
resource "openstack_compute_instance_v2" "myinstance" {
name = "myinstance"
security_groups = ["default"]
scheduler_hints {
group = "${openstack_compute_servergroup_v2.mysg.id}"
}
}`

@ -83,6 +83,9 @@ The following arguments are supported:
* `volume` - (Optional) Attach an existing volume to the instance. The volume
structure is described below.
* `scheduler_hints` - (Optional) Provider the Nova scheduler with hints on how
the instance should be launched. The available hints are described below.
The `network` block supports:
* `uuid` - (Required unless `port` or `name` is provided) The network UUID to
@ -119,6 +122,25 @@ The `volume` block supports:
example: `/dev/vdc`. Omit this option to allow the volume to be
auto-assigned a device.
The `scheduler_hints` block supports:
* `group` - (Optional) A UUID of a Server Group. The instance will be placed
into that group.
* `different_host` - (Optional) A list of instance UUIDs. The instance will
be scheduled on a different host than all other instances.
* `same_host` - (Optional) A list of instance UUIDs. The instance will be
scheduled on the same host of those specified.
* `query` - (Optional) A conditional query that a compute node must pass in
order to host an instance.
* `target_cell` - (Optional) The name of a cell to host the instance.
* `build_near_host_ip` - (Optional) An IP Address in CIDR form. The instance
will be placed on a compute node that is in the same subnet.
## Attributes Reference
The following attributes are exported:

Loading…
Cancel
Save