Merge "Add disk config option support"
This commit is contained in:
commit
12663d44ff
|
@ -76,7 +76,8 @@ class Server(base.APIResourceWrapper):
|
|||
'image_name', 'VirtualInterfaces', 'flavor', 'key_name', 'fault',
|
||||
'tenant_id', 'user_id', 'created', 'OS-EXT-STS:power_state',
|
||||
'OS-EXT-STS:task_state', 'OS-EXT-SRV-ATTR:instance_name',
|
||||
'OS-EXT-SRV-ATTR:host', 'OS-EXT-AZ:availability_zone']
|
||||
'OS-EXT-SRV-ATTR:host', 'OS-EXT-AZ:availability_zone',
|
||||
'OS-DCF:diskConfig']
|
||||
|
||||
def __init__(self, apiresource, request):
|
||||
super(Server, self).__init__(apiresource)
|
||||
|
@ -478,14 +479,16 @@ def keypair_list(request):
|
|||
def server_create(request, name, image, flavor, key_name, user_data,
|
||||
security_groups, block_device_mapping=None,
|
||||
block_device_mapping_v2=None, nics=None,
|
||||
availability_zone=None, instance_count=1, admin_pass=None):
|
||||
availability_zone=None, instance_count=1, admin_pass=None,
|
||||
disk_config=None):
|
||||
return Server(novaclient(request).servers.create(
|
||||
name, image, flavor, userdata=user_data,
|
||||
security_groups=security_groups,
|
||||
key_name=key_name, block_device_mapping=block_device_mapping,
|
||||
block_device_mapping_v2=block_device_mapping_v2,
|
||||
nics=nics, availability_zone=availability_zone,
|
||||
min_count=instance_count, admin_pass=admin_pass), request)
|
||||
min_count=instance_count, admin_pass=admin_pass,
|
||||
disk_config=disk_config), request)
|
||||
|
||||
|
||||
def server_delete(request, instance):
|
||||
|
@ -553,9 +556,10 @@ def server_reboot(request, instance_id, soft_reboot=False):
|
|||
novaclient(request).servers.reboot(instance_id, hardness)
|
||||
|
||||
|
||||
def server_rebuild(request, instance_id, image_id, password=None):
|
||||
def server_rebuild(request, instance_id, image_id, password=None,
|
||||
disk_config=None):
|
||||
return novaclient(request).servers.rebuild(instance_id, image_id,
|
||||
password)
|
||||
password, disk_config)
|
||||
|
||||
|
||||
def server_update(request, instance_id, name):
|
||||
|
@ -573,8 +577,9 @@ def server_live_migrate(request, instance_id, host, block_migration=False,
|
|||
disk_over_commit)
|
||||
|
||||
|
||||
def server_resize(request, instance_id, flavor, **kwargs):
|
||||
novaclient(request).servers.resize(instance_id, flavor, **kwargs)
|
||||
def server_resize(request, instance_id, flavor, disk_config=None, **kwargs):
|
||||
novaclient(request).servers.resize(instance_id, flavor,
|
||||
disk_config, **kwargs)
|
||||
|
||||
|
||||
def server_confirm_resize(request, instance_id):
|
||||
|
|
|
@ -49,6 +49,8 @@ class RebuildInstanceForm(forms.SelfHandlingForm):
|
|||
confirm_password = forms.CharField(label=_("Confirm Rebuild Password"),
|
||||
required=False,
|
||||
widget=forms.PasswordInput(render_value=False))
|
||||
disk_config = forms.ChoiceField(label=_("Disk Partition"),
|
||||
required=False)
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(RebuildInstanceForm, self).__init__(request, *args, **kwargs)
|
||||
|
@ -67,6 +69,10 @@ class RebuildInstanceForm(forms.SelfHandlingForm):
|
|||
del self.fields['password']
|
||||
del self.fields['confirm_password']
|
||||
|
||||
# Set our disk_config choices
|
||||
config_choices = [("AUTO", _("Automatic")), ("MANUAL", _("Manual"))]
|
||||
self.fields['disk_config'].choices = config_choices
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(RebuildInstanceForm, self).clean()
|
||||
if 'password' in cleaned_data:
|
||||
|
@ -84,8 +90,10 @@ class RebuildInstanceForm(forms.SelfHandlingForm):
|
|||
instance = data.get('instance_id')
|
||||
image = data.get('image')
|
||||
password = data.get('password') or None
|
||||
disk_config = data.get('disk_config', None)
|
||||
try:
|
||||
api.nova.server_rebuild(request, instance, image, password)
|
||||
api.nova.server_rebuild(request, instance, image, password,
|
||||
disk_config)
|
||||
messages.success(request, _('Rebuilding instance %s.') % instance)
|
||||
except Exception:
|
||||
redirect = reverse('horizon:project:instances:index')
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
{% load i18n %}
|
||||
<p>{% blocktrans %}Automatic: Entire disk is single partition and automatically resizes.{% endblocktrans %}</p>
|
||||
<p>{% blocktrans %}Manual: Faster build times but requires manual partitioning.{% endblocktrans %}</p>
|
|
@ -1091,7 +1091,8 @@ class InstanceTests(test.TestCase):
|
|||
['<SetInstanceDetails: setinstancedetailsaction>',
|
||||
'<SetAccessControls: setaccesscontrolsaction>',
|
||||
'<SetNetwork: setnetworkaction>',
|
||||
'<PostCreationStep: customizeaction>'])
|
||||
'<PostCreationStep: customizeaction>',
|
||||
'<SetAdvanced: setadvancedaction>'])
|
||||
|
||||
if custom_flavor_sort == 'id':
|
||||
# Reverse sorted by id
|
||||
|
@ -1257,7 +1258,8 @@ class InstanceTests(test.TestCase):
|
|||
nics=nics,
|
||||
availability_zone=avail_zone.zoneName,
|
||||
instance_count=IsA(int),
|
||||
admin_pass=u'')
|
||||
admin_pass=u'',
|
||||
disk_config=u'AUTO')
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
|
@ -1277,7 +1279,8 @@ class InstanceTests(test.TestCase):
|
|||
'availability_zone': avail_zone.zoneName,
|
||||
'volume_type': '',
|
||||
'network': self.networks.first().id,
|
||||
'count': 1}
|
||||
'count': 1,
|
||||
'disk_config': 'AUTO'}
|
||||
url = reverse('horizon:project:instances:launch')
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
|
@ -1366,7 +1369,8 @@ class InstanceTests(test.TestCase):
|
|||
nics=nics,
|
||||
availability_zone=avail_zone.zoneName,
|
||||
instance_count=IsA(int),
|
||||
admin_pass=u'')
|
||||
admin_pass=u'',
|
||||
disk_config=u'AUTO')
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
|
||||
|
@ -1386,7 +1390,8 @@ class InstanceTests(test.TestCase):
|
|||
'volume_id': volume_choice,
|
||||
'device_name': device_name,
|
||||
'network': self.networks.first().id,
|
||||
'count': 1}
|
||||
'count': 1,
|
||||
'disk_config': 'AUTO'}
|
||||
url = reverse('horizon:project:instances:launch')
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
|
@ -1481,7 +1486,8 @@ class InstanceTests(test.TestCase):
|
|||
nics=nics,
|
||||
availability_zone=avail_zone.zoneName,
|
||||
instance_count=IsA(int),
|
||||
admin_pass=u'')
|
||||
admin_pass=u'',
|
||||
disk_config='MANUAL')
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
|
@ -1499,7 +1505,8 @@ class InstanceTests(test.TestCase):
|
|||
'volume_type': 'volume_id',
|
||||
'volume_id': volume_choice,
|
||||
'device_name': device_name,
|
||||
'count': 1}
|
||||
'count': 1,
|
||||
'disk_config': 'MANUAL'}
|
||||
url = reverse('horizon:project:instances:launch')
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
|
@ -1729,7 +1736,8 @@ class InstanceTests(test.TestCase):
|
|||
nics=nics,
|
||||
availability_zone=avail_zone.zoneName,
|
||||
instance_count=IsA(int),
|
||||
admin_pass='password') \
|
||||
admin_pass='password',
|
||||
disk_config='AUTO') \
|
||||
.AndRaise(self.exceptions.keystone)
|
||||
quotas.tenant_quota_usages(IsA(http.HttpRequest)) \
|
||||
.AndReturn(quota_usages)
|
||||
|
@ -1754,7 +1762,8 @@ class InstanceTests(test.TestCase):
|
|||
'network': self.networks.first().id,
|
||||
'count': 1,
|
||||
'admin_pass': 'password',
|
||||
'confirm_admin_pass': 'password'}
|
||||
'confirm_admin_pass': 'password',
|
||||
'disk_config': 'AUTO'}
|
||||
url = reverse('horizon:project:instances:launch')
|
||||
res = self.client.post(url, form_data)
|
||||
|
||||
|
@ -2327,9 +2336,10 @@ class InstanceTests(test.TestCase):
|
|||
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
def _instance_resize_post(self, server_id, flavor_id):
|
||||
def _instance_resize_post(self, server_id, flavor_id, disk_config):
|
||||
formData = {'flavor': flavor_id,
|
||||
'default_role': 'member'}
|
||||
'default_role': 'member',
|
||||
'disk_config': disk_config}
|
||||
url = reverse('horizon:project:instances:resize',
|
||||
args=[server_id])
|
||||
return self.client.post(url, formData)
|
||||
|
@ -2347,12 +2357,12 @@ class InstanceTests(test.TestCase):
|
|||
.AndReturn(server)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.server_resize(IsA(http.HttpRequest), server.id, flavor.id) \
|
||||
.AndReturn([])
|
||||
api.nova.server_resize(IsA(http.HttpRequest), server.id, flavor.id,
|
||||
'AUTO').AndReturn([])
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self._instance_resize_post(server.id, flavor.id)
|
||||
res = self._instance_resize_post(server.id, flavor.id, u'AUTO')
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
|
@ -2365,12 +2375,13 @@ class InstanceTests(test.TestCase):
|
|||
.AndReturn(server)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.nova.server_resize(IsA(http.HttpRequest), server.id, flavor.id) \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
api.nova.server_resize(IsA(http.HttpRequest), server.id, flavor.id,
|
||||
'AUTO') \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self._instance_resize_post(server.id, flavor.id)
|
||||
res = self._instance_resize_post(server.id, flavor.id, 'AUTO')
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs({api.glance: ('image_list_detailed',)})
|
||||
|
@ -2404,9 +2415,11 @@ class InstanceTests(test.TestCase):
|
|||
self.test_rebuild_instance_get(expect_password_fields=False)
|
||||
|
||||
def _instance_rebuild_post(self, server_id, image_id,
|
||||
password=None, confirm_password=None):
|
||||
password=None, confirm_password=None,
|
||||
disk_config=None):
|
||||
form_data = {'instance_id': server_id,
|
||||
'image': image_id}
|
||||
'image': image_id,
|
||||
'disk_config': disk_config}
|
||||
if password is not None:
|
||||
form_data.update(password=password)
|
||||
if confirm_password is not None:
|
||||
|
@ -2436,13 +2449,15 @@ class InstanceTests(test.TestCase):
|
|||
api.nova.server_rebuild(IsA(http.HttpRequest),
|
||||
server.id,
|
||||
image.id,
|
||||
password).AndReturn([])
|
||||
password,
|
||||
'AUTO').AndReturn([])
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self._instance_rebuild_post(server.id, image.id,
|
||||
password=password,
|
||||
confirm_password=password)
|
||||
confirm_password=password,
|
||||
disk_config='AUTO')
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
|
@ -2462,13 +2477,16 @@ class InstanceTests(test.TestCase):
|
|||
api.nova.server_rebuild(IsA(http.HttpRequest),
|
||||
server.id,
|
||||
image.id,
|
||||
None).AndRaise(self.exceptions.nova)
|
||||
None,
|
||||
'AUTO') \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self._instance_rebuild_post(server.id, image.id,
|
||||
password=None,
|
||||
confirm_password=None)
|
||||
confirm_password=None,
|
||||
disk_config='AUTO')
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@test.create_stubs(instance_rebuild_post_stubs)
|
||||
|
@ -2490,7 +2508,8 @@ class InstanceTests(test.TestCase):
|
|||
self.mox.ReplayAll()
|
||||
res = self._instance_rebuild_post(server.id, image.id,
|
||||
password=pass1,
|
||||
confirm_password=pass2)
|
||||
confirm_password=pass2,
|
||||
disk_config='MANUAL')
|
||||
|
||||
self.assertContains(res, "Passwords do not match.")
|
||||
|
||||
|
@ -2510,13 +2529,15 @@ class InstanceTests(test.TestCase):
|
|||
api.nova.server_rebuild(IsA(http.HttpRequest),
|
||||
server.id,
|
||||
image.id,
|
||||
None).AndReturn([])
|
||||
None,
|
||||
'AUTO').AndReturn([])
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self._instance_rebuild_post(server.id, image.id,
|
||||
password=u'',
|
||||
confirm_password=u'')
|
||||
confirm_password=u'',
|
||||
disk_config=u'AUTO')
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
|
@ -2537,13 +2558,16 @@ class InstanceTests(test.TestCase):
|
|||
api.nova.server_rebuild(IsA(http.HttpRequest),
|
||||
server.id,
|
||||
image.id,
|
||||
password).AndRaise(self.exceptions.nova)
|
||||
password,
|
||||
'AUTO') \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self._instance_rebuild_post(server.id, image.id,
|
||||
password=password,
|
||||
confirm_password=password)
|
||||
confirm_password=password,
|
||||
disk_config='AUTO')
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
|
||||
|
|
|
@ -623,6 +623,27 @@ class SetNetwork(workflows.Step):
|
|||
return context
|
||||
|
||||
|
||||
class SetAdvancedAction(workflows.Action):
|
||||
disk_config = forms.ChoiceField(label=_("Disk Partition"),
|
||||
required=False)
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(SetAdvancedAction, self).__init__(request, *args, **kwargs)
|
||||
# Set our disk_config choices
|
||||
config_choices = [("AUTO", _("Automatic")), ("MANUAL", _("Manual"))]
|
||||
self.fields['disk_config'].choices = config_choices
|
||||
|
||||
class Meta:
|
||||
name = _("Advanced Options")
|
||||
help_text_template = ("project/instances/"
|
||||
"_launch_advanced_help.html")
|
||||
|
||||
|
||||
class SetAdvanced(workflows.Step):
|
||||
action_class = SetAdvancedAction
|
||||
contributes = ("disk_config",)
|
||||
|
||||
|
||||
class LaunchInstance(workflows.Workflow):
|
||||
slug = "launch_instance"
|
||||
name = _("Launch Instance")
|
||||
|
@ -634,7 +655,8 @@ class LaunchInstance(workflows.Workflow):
|
|||
SetInstanceDetails,
|
||||
SetAccessControls,
|
||||
SetNetwork,
|
||||
PostCreationStep)
|
||||
PostCreationStep,
|
||||
SetAdvanced)
|
||||
|
||||
def format_status_message(self, message):
|
||||
name = self.context.get('name', 'unknown instance')
|
||||
|
@ -719,7 +741,8 @@ class LaunchInstance(workflows.Workflow):
|
|||
nics=nics,
|
||||
availability_zone=avail_zone,
|
||||
instance_count=int(context['count']),
|
||||
admin_pass=context['admin_pass'])
|
||||
admin_pass=context['admin_pass'],
|
||||
disk_config=context['disk_config'])
|
||||
return True
|
||||
except Exception:
|
||||
exceptions.handle(request)
|
||||
|
|
|
@ -28,6 +28,8 @@ from openstack_dashboard import api
|
|||
|
||||
from openstack_dashboard.dashboards.project.instances \
|
||||
import utils as instance_utils
|
||||
from openstack_dashboard.dashboards.project.instances.workflows \
|
||||
import create_instance
|
||||
|
||||
|
||||
class SetFlavorChoiceAction(workflows.Action):
|
||||
|
@ -93,7 +95,7 @@ class ResizeInstance(workflows.Workflow):
|
|||
success_message = _('Preparing instance "%s" for resize.')
|
||||
failure_message = _('Unable to resize instance "%s".')
|
||||
success_url = "horizon:project:instances:index"
|
||||
default_steps = (SetFlavorChoice,)
|
||||
default_steps = (SetFlavorChoice, create_instance.SetAdvanced)
|
||||
|
||||
def format_status_message(self, message):
|
||||
return message % self.context.get('name', 'unknown instance')
|
||||
|
@ -102,8 +104,9 @@ class ResizeInstance(workflows.Workflow):
|
|||
def handle(self, request, context):
|
||||
instance_id = context.get('instance_id', None)
|
||||
flavor = context.get('flavor', None)
|
||||
disk_config = context.get('disk_config', None)
|
||||
try:
|
||||
api.nova.server_resize(request, instance_id, flavor)
|
||||
api.nova.server_resize(request, instance_id, flavor, disk_config)
|
||||
return True
|
||||
except Exception:
|
||||
exceptions.handle(request)
|
||||
|
|
Loading…
Reference in New Issue