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.
This commit is contained in:
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…
Reference in New Issue