Choose a server group when booting a VM
Allow users to choose a server group when booting a VM. Adds a dropdown list to select a server group to the Launch Instance workflow. Change-Id: I0b0d5ec79841da3da569bd22c533fdbf76002c96 Partially-Implements: blueprint nova-server-groups
This commit is contained in:
parent
aba6d1f0da
commit
bc2826efd9
@ -950,6 +950,10 @@ def availability_zone_list(request, detailed=False):
|
|||||||
return novaclient(request).availability_zones.list(detailed=detailed)
|
return novaclient(request).availability_zones.list(detailed=detailed)
|
||||||
|
|
||||||
|
|
||||||
|
def server_group_list(request):
|
||||||
|
return novaclient(request).server_groups.list()
|
||||||
|
|
||||||
|
|
||||||
def service_list(request, binary=None):
|
def service_list(request, binary=None):
|
||||||
return novaclient(request).services.list(binary=binary)
|
return novaclient(request).services.list(binary=binary)
|
||||||
|
|
||||||
|
@ -1497,6 +1497,7 @@ class InstanceTests(helpers.TestCase):
|
|||||||
@helpers.create_stubs({api.nova: ('extension_supported',
|
@helpers.create_stubs({api.nova: ('extension_supported',
|
||||||
'flavor_list',
|
'flavor_list',
|
||||||
'keypair_list',
|
'keypair_list',
|
||||||
|
'server_group_list',
|
||||||
'tenant_absolute_limits',
|
'tenant_absolute_limits',
|
||||||
'availability_zone_list',),
|
'availability_zone_list',),
|
||||||
api.network: ('security_group_list',),
|
api.network: ('security_group_list',),
|
||||||
@ -1568,6 +1569,10 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(disk_config)
|
.AndReturn(disk_config)
|
||||||
api.nova.extension_supported(
|
api.nova.extension_supported(
|
||||||
'ConfigDrive', IsA(http.HttpRequest)).AndReturn(config_drive)
|
'ConfigDrive', IsA(http.HttpRequest)).AndReturn(config_drive)
|
||||||
|
api.nova.extension_supported(
|
||||||
|
'ServerGroups', IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.server_group_list(IsA(http.HttpRequest)) \
|
||||||
|
.AndReturn(self.server_groups.list())
|
||||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest))\
|
api.nova.tenant_absolute_limits(IsA(http.HttpRequest))\
|
||||||
.AndReturn(self.limits['absolute'])
|
.AndReturn(self.limits['absolute'])
|
||||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||||
@ -1747,6 +1752,7 @@ class InstanceTests(helpers.TestCase):
|
|||||||
@helpers.create_stubs({api.nova: ('extension_supported',
|
@helpers.create_stubs({api.nova: ('extension_supported',
|
||||||
'flavor_list',
|
'flavor_list',
|
||||||
'keypair_list',
|
'keypair_list',
|
||||||
|
'server_group_list',
|
||||||
'tenant_absolute_limits',
|
'tenant_absolute_limits',
|
||||||
'availability_zone_list',),
|
'availability_zone_list',),
|
||||||
api.network: ('security_group_list',),
|
api.network: ('security_group_list',),
|
||||||
@ -1813,6 +1819,10 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(disk_config)
|
.AndReturn(disk_config)
|
||||||
api.nova.extension_supported(
|
api.nova.extension_supported(
|
||||||
'ConfigDrive', IsA(http.HttpRequest)).AndReturn(config_drive)
|
'ConfigDrive', IsA(http.HttpRequest)).AndReturn(config_drive)
|
||||||
|
api.nova.extension_supported(
|
||||||
|
'ServerGroups', IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.server_group_list(IsA(http.HttpRequest)) \
|
||||||
|
.AndReturn(self.server_groups.list())
|
||||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest))\
|
api.nova.tenant_absolute_limits(IsA(http.HttpRequest))\
|
||||||
.AndReturn(self.limits['absolute'])
|
.AndReturn(self.limits['absolute'])
|
||||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||||
@ -1862,6 +1872,7 @@ class InstanceTests(helpers.TestCase):
|
|||||||
'flavor_list',
|
'flavor_list',
|
||||||
'keypair_list',
|
'keypair_list',
|
||||||
'availability_zone_list',
|
'availability_zone_list',
|
||||||
|
'server_group_list',
|
||||||
'server_create',),
|
'server_create',),
|
||||||
api.network: ('security_group_list',),
|
api.network: ('security_group_list',),
|
||||||
cinder: ('volume_list',
|
cinder: ('volume_list',
|
||||||
@ -1881,6 +1892,7 @@ class InstanceTests(helpers.TestCase):
|
|||||||
customization_script = 'user data'
|
customization_script = 'user data'
|
||||||
nics = [{"net-id": self.networks.first().id, "v4-fixed-ip": ''}]
|
nics = [{"net-id": self.networks.first().id, "v4-fixed-ip": ''}]
|
||||||
quota_usages = self.quota_usages.first()
|
quota_usages = self.quota_usages.first()
|
||||||
|
scheduler_hints = {"group": self.server_groups.first().id}
|
||||||
|
|
||||||
api.nova.extension_supported('BlockDeviceMappingV2Boot',
|
api.nova.extension_supported('BlockDeviceMappingV2Boot',
|
||||||
IsA(http.HttpRequest)) \
|
IsA(http.HttpRequest)) \
|
||||||
@ -1946,6 +1958,10 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(disk_config)
|
.AndReturn(disk_config)
|
||||||
api.nova.extension_supported(
|
api.nova.extension_supported(
|
||||||
'ConfigDrive', IsA(http.HttpRequest)).AndReturn(config_drive)
|
'ConfigDrive', IsA(http.HttpRequest)).AndReturn(config_drive)
|
||||||
|
api.nova.extension_supported(
|
||||||
|
'ServerGroups', IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.server_group_list(IsA(http.HttpRequest)) \
|
||||||
|
.AndReturn(self.server_groups.list())
|
||||||
cinder.volume_list(IsA(http.HttpRequest),
|
cinder.volume_list(IsA(http.HttpRequest),
|
||||||
search_opts=VOLUME_SEARCH_OPTS) \
|
search_opts=VOLUME_SEARCH_OPTS) \
|
||||||
.AndReturn([])
|
.AndReturn([])
|
||||||
@ -1974,7 +1990,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
instance_count=IsA(int),
|
instance_count=IsA(int),
|
||||||
admin_pass=u'',
|
admin_pass=u'',
|
||||||
disk_config=disk_config_value,
|
disk_config=disk_config_value,
|
||||||
config_drive=config_drive_value)
|
config_drive=config_drive_value,
|
||||||
|
scheduler_hints=scheduler_hints)
|
||||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||||
.AndReturn(quota_usages)
|
.AndReturn(quota_usages)
|
||||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||||
@ -1995,7 +2012,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
'availability_zone': avail_zone.zoneName,
|
'availability_zone': avail_zone.zoneName,
|
||||||
'volume_type': '',
|
'volume_type': '',
|
||||||
'network': self.networks.first().id,
|
'network': self.networks.first().id,
|
||||||
'count': 1}
|
'count': 1,
|
||||||
|
'server_group': self.server_groups.first().id}
|
||||||
if disk_config:
|
if disk_config:
|
||||||
form_data['disk_config'] = 'AUTO'
|
form_data['disk_config'] = 'AUTO'
|
||||||
if config_drive:
|
if config_drive:
|
||||||
@ -2108,6 +2126,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(False)
|
||||||
cinder.volume_list(IsA(http.HttpRequest),
|
cinder.volume_list(IsA(http.HttpRequest),
|
||||||
search_opts=VOLUME_SEARCH_OPTS) \
|
search_opts=VOLUME_SEARCH_OPTS) \
|
||||||
.AndReturn([])
|
.AndReturn([])
|
||||||
@ -2291,6 +2311,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(False)
|
||||||
volumes = [v for v in self.volumes.list()
|
volumes = [v for v in self.volumes.list()
|
||||||
if (v.status == AVAILABLE and v.bootable == 'true')]
|
if (v.status == AVAILABLE and v.bootable == 'true')]
|
||||||
cinder.volume_list(IsA(http.HttpRequest),
|
cinder.volume_list(IsA(http.HttpRequest),
|
||||||
@ -2317,7 +2339,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
instance_count=IsA(int),
|
instance_count=IsA(int),
|
||||||
admin_pass=u'',
|
admin_pass=u'',
|
||||||
disk_config=u'AUTO',
|
disk_config=u'AUTO',
|
||||||
config_drive=True)
|
config_drive=True,
|
||||||
|
scheduler_hints={})
|
||||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||||
.AndReturn(quota_usages)
|
.AndReturn(quota_usages)
|
||||||
|
|
||||||
@ -2367,6 +2390,7 @@ class InstanceTests(helpers.TestCase):
|
|||||||
'flavor_list',
|
'flavor_list',
|
||||||
'keypair_list',
|
'keypair_list',
|
||||||
'availability_zone_list',
|
'availability_zone_list',
|
||||||
|
'server_group_list',
|
||||||
'tenant_absolute_limits',),
|
'tenant_absolute_limits',),
|
||||||
api.network: ('security_group_list',),
|
api.network: ('security_group_list',),
|
||||||
cinder: ('volume_list',
|
cinder: ('volume_list',
|
||||||
@ -2446,6 +2470,9 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.server_group_list(IsA(http.HttpRequest)).AndReturn([])
|
||||||
volumes = [v for v in self.volumes.list()
|
volumes = [v for v in self.volumes.list()
|
||||||
if (v.status == AVAILABLE and v.bootable == 'true')]
|
if (v.status == AVAILABLE and v.bootable == 'true')]
|
||||||
cinder.volume_list(IsA(http.HttpRequest),
|
cinder.volume_list(IsA(http.HttpRequest),
|
||||||
@ -2474,7 +2501,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
instance_count=IsA(int),
|
instance_count=IsA(int),
|
||||||
admin_pass=u'',
|
admin_pass=u'',
|
||||||
disk_config='MANUAL',
|
disk_config='MANUAL',
|
||||||
config_drive=True)
|
config_drive=True,
|
||||||
|
scheduler_hints={})
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -2578,6 +2606,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(False)
|
||||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||||
.AndReturn(self.flavors.list())
|
.AndReturn(self.flavors.list())
|
||||||
api.nova.keypair_list(IsA(http.HttpRequest)) \
|
api.nova.keypair_list(IsA(http.HttpRequest)) \
|
||||||
@ -2632,6 +2662,7 @@ class InstanceTests(helpers.TestCase):
|
|||||||
'flavor_list',
|
'flavor_list',
|
||||||
'keypair_list',
|
'keypair_list',
|
||||||
'availability_zone_list',
|
'availability_zone_list',
|
||||||
|
'server_group_list',
|
||||||
'server_create',),
|
'server_create',),
|
||||||
api.network: ('security_group_list',),
|
api.network: ('security_group_list',),
|
||||||
cinder: ('volume_list',
|
cinder: ('volume_list',
|
||||||
@ -2729,6 +2760,9 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.server_group_list(IsA(http.HttpRequest)).AndReturn([])
|
||||||
snapshots = [v for v in self.cinder_volume_snapshots.list()
|
snapshots = [v for v in self.cinder_volume_snapshots.list()
|
||||||
if (v.status == AVAILABLE)]
|
if (v.status == AVAILABLE)]
|
||||||
cinder.volume_list(IsA(http.HttpRequest),
|
cinder.volume_list(IsA(http.HttpRequest),
|
||||||
@ -2755,7 +2789,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
instance_count=IsA(int),
|
instance_count=IsA(int),
|
||||||
admin_pass=u'',
|
admin_pass=u'',
|
||||||
disk_config=u'AUTO',
|
disk_config=u'AUTO',
|
||||||
config_drive=True)
|
config_drive=True,
|
||||||
|
scheduler_hints={})
|
||||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||||
.AndReturn(quota_usages)
|
.AndReturn(quota_usages)
|
||||||
|
|
||||||
@ -2948,6 +2983,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(False)
|
||||||
api.nova.tenant_absolute_limits(IsA(http.HttpRequest)) \
|
api.nova.tenant_absolute_limits(IsA(http.HttpRequest)) \
|
||||||
.AndReturn(self.limits['absolute'])
|
.AndReturn(self.limits['absolute'])
|
||||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||||
@ -2983,6 +3020,7 @@ class InstanceTests(helpers.TestCase):
|
|||||||
'flavor_list',
|
'flavor_list',
|
||||||
'keypair_list',
|
'keypair_list',
|
||||||
'availability_zone_list',
|
'availability_zone_list',
|
||||||
|
'server_group_list',
|
||||||
'server_create',),
|
'server_create',),
|
||||||
api.network: ('security_group_list',),
|
api.network: ('security_group_list',),
|
||||||
cinder: ('volume_list',
|
cinder: ('volume_list',
|
||||||
@ -3063,6 +3101,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(False)
|
||||||
api.nova.server_create(IsA(http.HttpRequest),
|
api.nova.server_create(IsA(http.HttpRequest),
|
||||||
server.name,
|
server.name,
|
||||||
image.id,
|
image.id,
|
||||||
@ -3077,7 +3117,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
instance_count=IsA(int),
|
instance_count=IsA(int),
|
||||||
admin_pass='password',
|
admin_pass='password',
|
||||||
disk_config='AUTO',
|
disk_config='AUTO',
|
||||||
config_drive=False) \
|
config_drive=False,
|
||||||
|
scheduler_hints={}) \
|
||||||
.AndRaise(self.exceptions.keystone)
|
.AndRaise(self.exceptions.keystone)
|
||||||
if test_with_profile:
|
if test_with_profile:
|
||||||
api.neutron.port_delete(IsA(http.HttpRequest), port.id)
|
api.neutron.port_delete(IsA(http.HttpRequest), port.id)
|
||||||
@ -3195,6 +3236,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(False)
|
||||||
volumes = [v for v in self.volumes.list()
|
volumes = [v for v in self.volumes.list()
|
||||||
if (v.status == AVAILABLE and v.bootable == 'true')]
|
if (v.status == AVAILABLE and v.bootable == 'true')]
|
||||||
cinder.volume_list(IsA(http.HttpRequest),
|
cinder.volume_list(IsA(http.HttpRequest),
|
||||||
@ -3242,6 +3285,7 @@ class InstanceTests(helpers.TestCase):
|
|||||||
api.nova: ('extension_supported',
|
api.nova: ('extension_supported',
|
||||||
'flavor_list',
|
'flavor_list',
|
||||||
'keypair_list',
|
'keypair_list',
|
||||||
|
'server_group_list',
|
||||||
'tenant_absolute_limits',
|
'tenant_absolute_limits',
|
||||||
'availability_zone_list',),
|
'availability_zone_list',),
|
||||||
api.network: ('security_group_list',),
|
api.network: ('security_group_list',),
|
||||||
@ -3314,6 +3358,10 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.server_group_list(IsA(http.HttpRequest)) \
|
||||||
|
.AndReturn(self.server_groups.list())
|
||||||
volumes = [v for v in self.volumes.list()
|
volumes = [v for v in self.volumes.list()
|
||||||
if (v.status == AVAILABLE and v.bootable == 'true')]
|
if (v.status == AVAILABLE and v.bootable == 'true')]
|
||||||
cinder.volume_list(IsA(http.HttpRequest),
|
cinder.volume_list(IsA(http.HttpRequest),
|
||||||
@ -3451,6 +3499,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(False)
|
||||||
volumes = [v for v in self.volumes.list()
|
volumes = [v for v in self.volumes.list()
|
||||||
if (v.status == AVAILABLE and v.bootable == 'true')]
|
if (v.status == AVAILABLE and v.bootable == 'true')]
|
||||||
cinder.volume_list(IsA(http.HttpRequest),
|
cinder.volume_list(IsA(http.HttpRequest),
|
||||||
@ -3599,6 +3649,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
'DiskConfig', IsA(http.HttpRequest)).AndReturn(True)
|
'DiskConfig', IsA(http.HttpRequest)).AndReturn(True)
|
||||||
api.nova.extension_supported(
|
api.nova.extension_supported(
|
||||||
'ConfigDrive', IsA(http.HttpRequest)).AndReturn(True)
|
'ConfigDrive', IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported(
|
||||||
|
'ServerGroups', IsA(http.HttpRequest)).AndReturn(False)
|
||||||
volumes = [v for v in self.volumes.list()
|
volumes = [v for v in self.volumes.list()
|
||||||
if (v.status == AVAILABLE and v.bootable == 'true')]
|
if (v.status == AVAILABLE and v.bootable == 'true')]
|
||||||
cinder.volume_list(IsA(http.HttpRequest),
|
cinder.volume_list(IsA(http.HttpRequest),
|
||||||
@ -3669,6 +3721,7 @@ class InstanceTests(helpers.TestCase):
|
|||||||
api.nova: ('extension_supported',
|
api.nova: ('extension_supported',
|
||||||
'flavor_list',
|
'flavor_list',
|
||||||
'keypair_list',
|
'keypair_list',
|
||||||
|
'server_group_list',
|
||||||
'tenant_absolute_limits',
|
'tenant_absolute_limits',
|
||||||
'availability_zone_list',),
|
'availability_zone_list',),
|
||||||
api.network: ('security_group_list',),
|
api.network: ('security_group_list',),
|
||||||
@ -3738,6 +3791,10 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.server_group_list(IsA(http.HttpRequest)) \
|
||||||
|
.AndReturn(self.server_groups.list())
|
||||||
volumes = [v for v in self.volumes.list()
|
volumes = [v for v in self.volumes.list()
|
||||||
if (v.status == AVAILABLE and v.bootable == 'true')]
|
if (v.status == AVAILABLE and v.bootable == 'true')]
|
||||||
cinder.volume_list(IsA(http.HttpRequest),
|
cinder.volume_list(IsA(http.HttpRequest),
|
||||||
@ -3913,6 +3970,7 @@ class InstanceTests(helpers.TestCase):
|
|||||||
'flavor_list',
|
'flavor_list',
|
||||||
'keypair_list',
|
'keypair_list',
|
||||||
'availability_zone_list',
|
'availability_zone_list',
|
||||||
|
'server_group_list',
|
||||||
'tenant_absolute_limits',
|
'tenant_absolute_limits',
|
||||||
'server_create',),
|
'server_create',),
|
||||||
api.network: ('security_group_list',),
|
api.network: ('security_group_list',),
|
||||||
@ -3982,6 +4040,9 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.server_group_list(IsA(http.HttpRequest)).AndReturn([])
|
||||||
volumes = [v for v in self.volumes.list()
|
volumes = [v for v in self.volumes.list()
|
||||||
if (v.status == AVAILABLE and v.bootable == 'true')]
|
if (v.status == AVAILABLE and v.bootable == 'true')]
|
||||||
cinder.volume_list(IsA(http.HttpRequest),
|
cinder.volume_list(IsA(http.HttpRequest),
|
||||||
@ -4010,7 +4071,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
instance_count=IsA(int),
|
instance_count=IsA(int),
|
||||||
admin_pass=u'',
|
admin_pass=u'',
|
||||||
config_drive=False,
|
config_drive=False,
|
||||||
disk_config=u'')
|
disk_config=u'',
|
||||||
|
scheduler_hints={})
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -4137,6 +4199,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(False)
|
||||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||||
.AndReturn(self.flavors.list())
|
.AndReturn(self.flavors.list())
|
||||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||||
@ -4249,6 +4313,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
api.nova.extension_supported('DiskConfig',
|
api.nova.extension_supported('DiskConfig',
|
||||||
IsA(http.HttpRequest)) \
|
IsA(http.HttpRequest)) \
|
||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(False)
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -4321,6 +4387,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
api.nova.extension_supported('DiskConfig',
|
api.nova.extension_supported('DiskConfig',
|
||||||
IsA(http.HttpRequest)) \
|
IsA(http.HttpRequest)) \
|
||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(False)
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -4356,6 +4424,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
api.nova.extension_supported('DiskConfig',
|
api.nova.extension_supported('DiskConfig',
|
||||||
IsA(http.HttpRequest)) \
|
IsA(http.HttpRequest)) \
|
||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(False)
|
||||||
api.nova.server_resize(IsA(http.HttpRequest), server.id, flavor.id,
|
api.nova.server_resize(IsA(http.HttpRequest), server.id, flavor.id,
|
||||||
'AUTO').AndReturn([])
|
'AUTO').AndReturn([])
|
||||||
|
|
||||||
@ -4379,6 +4449,8 @@ class InstanceTests(helpers.TestCase):
|
|||||||
api.nova.extension_supported('DiskConfig',
|
api.nova.extension_supported('DiskConfig',
|
||||||
IsA(http.HttpRequest)) \
|
IsA(http.HttpRequest)) \
|
||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(False)
|
||||||
api.nova.server_resize(IsA(http.HttpRequest), server.id, flavor.id,
|
api.nova.server_resize(IsA(http.HttpRequest), server.id, flavor.id,
|
||||||
'AUTO') \
|
'AUTO') \
|
||||||
.AndRaise(self.exceptions.nova)
|
.AndRaise(self.exceptions.nova)
|
||||||
@ -5106,6 +5178,7 @@ class ConsoleManagerTests(helpers.TestCase):
|
|||||||
'flavor_list',
|
'flavor_list',
|
||||||
'keypair_list',
|
'keypair_list',
|
||||||
'availability_zone_list',
|
'availability_zone_list',
|
||||||
|
'server_group_list',
|
||||||
'server_create',),
|
'server_create',),
|
||||||
api.network: ('security_group_list',),
|
api.network: ('security_group_list',),
|
||||||
cinder: ('volume_list',
|
cinder: ('volume_list',
|
||||||
@ -5182,6 +5255,9 @@ class ConsoleManagerTests(helpers.TestCase):
|
|||||||
.AndReturn(True)
|
.AndReturn(True)
|
||||||
api.nova.extension_supported('ConfigDrive',
|
api.nova.extension_supported('ConfigDrive',
|
||||||
IsA(http.HttpRequest)).AndReturn(True)
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.extension_supported('ServerGroups',
|
||||||
|
IsA(http.HttpRequest)).AndReturn(True)
|
||||||
|
api.nova.server_group_list(IsA(http.HttpRequest)).AndReturn([])
|
||||||
api.nova.server_create(IsA(http.HttpRequest),
|
api.nova.server_create(IsA(http.HttpRequest),
|
||||||
server.name,
|
server.name,
|
||||||
image.id,
|
image.id,
|
||||||
@ -5196,7 +5272,8 @@ class ConsoleManagerTests(helpers.TestCase):
|
|||||||
instance_count=IsA(int),
|
instance_count=IsA(int),
|
||||||
admin_pass='password',
|
admin_pass='password',
|
||||||
disk_config='AUTO',
|
disk_config='AUTO',
|
||||||
config_drive=False) \
|
config_drive=False,
|
||||||
|
scheduler_hints={}) \
|
||||||
.AndRaise(self.exceptions.neutron)
|
.AndRaise(self.exceptions.neutron)
|
||||||
api.neutron.port_delete(IsA(http.HttpRequest), port.id)
|
api.neutron.port_delete(IsA(http.HttpRequest), port.id)
|
||||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||||
|
@ -74,6 +74,16 @@ def availability_zone_list(request):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def server_group_list(request):
|
||||||
|
"""Utility method to retrieve a list of server groups."""
|
||||||
|
try:
|
||||||
|
return api.nova.server_group_list(request)
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request,
|
||||||
|
_('Unable to retrieve Nova server groups.'))
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
def network_field_data(request, include_empty_option=False):
|
def network_field_data(request, include_empty_option=False):
|
||||||
"""Returns a list of tuples of all networks.
|
"""Returns a list of tuples of all networks.
|
||||||
|
|
||||||
@ -185,3 +195,21 @@ def port_field_data(request):
|
|||||||
if port.device_owner == ''])
|
if port.device_owner == ''])
|
||||||
ports.sort(key=lambda obj: obj[1])
|
ports.sort(key=lambda obj: obj[1])
|
||||||
return ports
|
return ports
|
||||||
|
|
||||||
|
|
||||||
|
def server_group_field_data(request):
|
||||||
|
"""Returns a list of tuples of all server groups.
|
||||||
|
|
||||||
|
Generates a list of server groups available. And returns a list of
|
||||||
|
(id, name) tuples.
|
||||||
|
|
||||||
|
:param request: django http request object
|
||||||
|
:return: list of (id, name) tuples
|
||||||
|
"""
|
||||||
|
server_groups = server_group_list(request)
|
||||||
|
if server_groups:
|
||||||
|
server_groups_list = [(sg.id, sg.name) for sg in server_groups]
|
||||||
|
server_groups_list.sort(key=lambda obj: obj[1])
|
||||||
|
return [("", _("Select Server Group")), ] + server_groups_list
|
||||||
|
|
||||||
|
return [("", _("No server groups available")), ]
|
||||||
|
@ -823,6 +823,9 @@ class SetAdvancedAction(workflows.Action):
|
|||||||
required=False, help_text=_("Configure OpenStack to write metadata to "
|
required=False, help_text=_("Configure OpenStack to write metadata to "
|
||||||
"a special configuration drive that "
|
"a special configuration drive that "
|
||||||
"attaches to the instance when it boots."))
|
"attaches to the instance when it boots."))
|
||||||
|
server_group = forms.ChoiceField(
|
||||||
|
label=_("Server Group"), required=False,
|
||||||
|
help_text=_("Server group to associate with this instance."))
|
||||||
|
|
||||||
def __init__(self, request, context, *args, **kwargs):
|
def __init__(self, request, context, *args, **kwargs):
|
||||||
super(SetAdvancedAction, self).__init__(request, context,
|
super(SetAdvancedAction, self).__init__(request, context,
|
||||||
@ -841,6 +844,13 @@ class SetAdvancedAction(workflows.Action):
|
|||||||
if context.get('workflow_slug') != 'launch_instance' or (
|
if context.get('workflow_slug') != 'launch_instance' or (
|
||||||
not api.nova.extension_supported("ConfigDrive", request)):
|
not api.nova.extension_supported("ConfigDrive", request)):
|
||||||
del self.fields['config_drive']
|
del self.fields['config_drive']
|
||||||
|
|
||||||
|
if not api.nova.extension_supported("ServerGroups", request):
|
||||||
|
del self.fields['server_group']
|
||||||
|
else:
|
||||||
|
server_group_choices = instance_utils.server_group_field_data(
|
||||||
|
request)
|
||||||
|
self.fields['server_group'].choices = server_group_choices
|
||||||
except Exception:
|
except Exception:
|
||||||
exceptions.handle(request, _('Unable to retrieve extensions '
|
exceptions.handle(request, _('Unable to retrieve extensions '
|
||||||
'information.'))
|
'information.'))
|
||||||
@ -853,7 +863,7 @@ class SetAdvancedAction(workflows.Action):
|
|||||||
|
|
||||||
class SetAdvanced(workflows.Step):
|
class SetAdvanced(workflows.Step):
|
||||||
action_class = SetAdvancedAction
|
action_class = SetAdvancedAction
|
||||||
contributes = ("disk_config", "config_drive",)
|
contributes = ("disk_config", "config_drive", "server_group",)
|
||||||
|
|
||||||
def prepare_action_context(self, request, context):
|
def prepare_action_context(self, request, context):
|
||||||
context = super(SetAdvanced, self).prepare_action_context(request,
|
context = super(SetAdvanced, self).prepare_action_context(request,
|
||||||
@ -960,6 +970,11 @@ class LaunchInstance(workflows.Workflow):
|
|||||||
|
|
||||||
avail_zone = context.get('availability_zone', None)
|
avail_zone = context.get('availability_zone', None)
|
||||||
|
|
||||||
|
scheduler_hints = {}
|
||||||
|
server_group = context.get('server_group', None)
|
||||||
|
if server_group:
|
||||||
|
scheduler_hints['group'] = server_group
|
||||||
|
|
||||||
port_profiles_supported = api.neutron.is_port_profiles_supported()
|
port_profiles_supported = api.neutron.is_port_profiles_supported()
|
||||||
|
|
||||||
if port_profiles_supported:
|
if port_profiles_supported:
|
||||||
@ -988,7 +1003,8 @@ class LaunchInstance(workflows.Workflow):
|
|||||||
instance_count=int(context['count']),
|
instance_count=int(context['count']),
|
||||||
admin_pass=context['admin_pass'],
|
admin_pass=context['admin_pass'],
|
||||||
disk_config=context.get('disk_config'),
|
disk_config=context.get('disk_config'),
|
||||||
config_drive=context.get('config_drive'))
|
config_drive=context.get('config_drive'),
|
||||||
|
scheduler_hints=scheduler_hints)
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
if port_profiles_supported:
|
if port_profiles_supported:
|
||||||
|
@ -588,3 +588,15 @@ class ComputeApiTests(test.APITestCase):
|
|||||||
tenant)
|
tenant)
|
||||||
self.assertEqual(len(api_val), len([]))
|
self.assertEqual(len(api_val), len([]))
|
||||||
self.assertIsInstance(api_val, list)
|
self.assertIsInstance(api_val, list)
|
||||||
|
|
||||||
|
def test_server_group_list(self):
|
||||||
|
server_groups = self.server_groups.list()
|
||||||
|
|
||||||
|
novaclient = self.stub_novaclient()
|
||||||
|
novaclient.server_groups = self.mox.CreateMockAnything()
|
||||||
|
novaclient.server_groups.list().AndReturn(server_groups)
|
||||||
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
|
ret_val = api.nova.server_group_list(self.request)
|
||||||
|
self.assertIsInstance(ret_val, list)
|
||||||
|
self.assertEqual(len(ret_val), len(server_groups))
|
||||||
|
@ -27,6 +27,7 @@ from novaclient.v2 import keypairs
|
|||||||
from novaclient.v2 import quotas
|
from novaclient.v2 import quotas
|
||||||
from novaclient.v2 import security_group_rules as rules
|
from novaclient.v2 import security_group_rules as rules
|
||||||
from novaclient.v2 import security_groups as sec_groups
|
from novaclient.v2 import security_groups as sec_groups
|
||||||
|
from novaclient.v2 import server_groups
|
||||||
from novaclient.v2 import servers
|
from novaclient.v2 import servers
|
||||||
from novaclient.v2 import services
|
from novaclient.v2 import services
|
||||||
from novaclient.v2 import usage
|
from novaclient.v2 import usage
|
||||||
@ -179,6 +180,7 @@ def data(TEST):
|
|||||||
TEST.services = utils.TestDataContainer()
|
TEST.services = utils.TestDataContainer()
|
||||||
TEST.aggregates = utils.TestDataContainer()
|
TEST.aggregates = utils.TestDataContainer()
|
||||||
TEST.hosts = utils.TestDataContainer()
|
TEST.hosts = utils.TestDataContainer()
|
||||||
|
TEST.server_groups = utils.TestDataContainer()
|
||||||
|
|
||||||
# Data return by novaclient.
|
# Data return by novaclient.
|
||||||
# It is used if API layer does data conversion.
|
# It is used if API layer does data conversion.
|
||||||
@ -781,3 +783,34 @@ def data(TEST):
|
|||||||
TEST.hosts.add(host2)
|
TEST.hosts.add(host2)
|
||||||
TEST.hosts.add(host3)
|
TEST.hosts.add(host3)
|
||||||
TEST.hosts.add(host4)
|
TEST.hosts.add(host4)
|
||||||
|
|
||||||
|
server_group_1 = server_groups.ServerGroup(
|
||||||
|
server_groups.ServerGroupsManager(None),
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"name": "server_group_1",
|
||||||
|
"policies": [],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
server_group_2 = server_groups.ServerGroup(
|
||||||
|
server_groups.ServerGroupsManager(None),
|
||||||
|
{
|
||||||
|
"id": "2",
|
||||||
|
"name": "server_group_2",
|
||||||
|
"policies": ["affinity", "some_other_policy"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
server_group_3 = server_groups.ServerGroup(
|
||||||
|
server_groups.ServerGroupsManager(None),
|
||||||
|
{
|
||||||
|
"id": "3",
|
||||||
|
"name": "server_group_3",
|
||||||
|
"policies": ["anti-affinity", "some_other_policy"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
TEST.server_groups.add(server_group_1)
|
||||||
|
TEST.server_groups.add(server_group_2)
|
||||||
|
TEST.server_groups.add(server_group_3)
|
||||||
|
Loading…
Reference in New Issue
Block a user