Commit bfd76bee by Bach Dániel

dashboard: add non-live migration support

Closes #324
parent 709eec33
......@@ -752,6 +752,26 @@ class VmRenewForm(forms.Form):
return helper
class VmMigrateForm(forms.Form):
live_migration = forms.BooleanField(
required=False, initial=True, label=_("live migration"))
def __init__(self, *args, **kwargs):
choices = kwargs.pop('choices')
default = kwargs.pop('default')
super(VmMigrateForm, self).__init__(*args, **kwargs)
self.fields.insert(0, 'to_node', forms.ModelChoiceField(
queryset=choices, initial=default, required=False,
widget=forms.RadioSelect(), label=_("Node")))
@property
def helper(self):
helper = FormHelper(self)
helper.form_tag = False
return helper
class VmStateChangeForm(forms.Form):
interrupt = forms.BooleanField(required=False, label=_(
......
{% extends "dashboard/operate.html" %}
{% load i18n %}
{% load sizefieldtags %}
{% load crispy_forms_tags %}
{% block question %}
<p>
......@@ -13,8 +14,8 @@ Choose a compute node to migrate {{obj}} to.
{% block formfields %}
<ul id="vm-migrate-node-list" class="list-unstyled">
{% with current=object.node.pk %}
{% for n in nodes %}
{% with current=object.node.pk recommended=form.fields.to_node.initial %}
{% for n in form.fields.to_node.queryset.all %}
<li class="panel panel-default"><div class="panel-body">
<label for="migrate-to-{{n.pk}}">
<strong>{{ n }}</strong>
......@@ -23,7 +24,7 @@ Choose a compute node to migrate {{obj}} to.
{% if current == n.pk %}<div class="label label-info">{% trans "current" %}</div>{% endif %}
{% if recommended == n.pk %}<div class="label label-success">{% trans "recommended" %}</div>{% endif %}
</label>
<input id="migrate-to-{{n.pk}}" type="radio" name="node" value="{{ n.pk }}" style="float: right;"
<input id="migrate-to-{{n.pk}}" type="radio" name="to_node" value="{{ n.pk }}" style="float: right;"
{% if current == n.pk %}disabled="disabled"{% endif %}
{% if recommended == n.pk %}checked="checked"{% endif %} />
<span class="vm-migrate-node-property">{% trans "CPU load" %}: {{ n.cpu_usage }}</span>
......@@ -33,4 +34,5 @@ Choose a compute node to migrate {{obj}} to.
{% endfor %}
{% endwith %}
</ul>
{{ form.live_migration|as_crispy_field }}
{% endblock %}
......@@ -60,6 +60,7 @@ from ..forms import (
VmAddInterfaceForm, VmCreateDiskForm, VmDownloadDiskForm, VmSaveForm,
VmRenewForm, VmStateChangeForm, VmListSearchForm, VmCustomizeForm,
TransferOwnershipForm, VmDiskResizeForm, RedeployForm, VmDiskRemoveForm,
VmMigrateForm,
)
from ..models import Favourite, Profile
......@@ -421,36 +422,28 @@ class VmDownloadDiskView(FormOperationMixin, VmOperationView):
with_reload = True
class VmMigrateView(VmOperationView):
class VmMigrateView(FormOperationMixin, VmOperationView):
op = 'migrate'
icon = 'truck'
effect = 'info'
template_name = 'dashboard/_vm-migrate.html'
form_class = VmMigrateForm
def get_context_data(self, **kwargs):
ctx = super(VmMigrateView, self).get_context_data(**kwargs)
ctx['nodes'] = [n for n in Node.objects.filter(enabled=True)
if n.online]
def get_form_kwargs(self):
online = (n.pk for n in Node.objects.filter(enabled=True) if n.online)
choices = Node.objects.filter(pk__in=online)
default = None
inst = self.get_object()
ctx["recommended"] = None
try:
if isinstance(inst, Instance):
ctx["recommended"] = inst.select_node().pk
default = inst.select_node().pk
except SchedulerError:
logger.exception("scheduler error:")
return ctx
def post(self, request, extra=None, *args, **kwargs):
if extra is None:
extra = {}
node = self.request.POST.get("node")
if node:
node = get_object_or_404(Node, pk=node)
extra["to_node"] = node
return super(VmMigrateView, self).post(request, extra, *args, **kwargs)
val = super(VmMigrateView, self).get_form_kwargs()
val.update({'choices': choices, 'default': default})
return val
class VmSaveView(FormOperationMixin, VmOperationView):
......
......@@ -472,10 +472,9 @@ class MigrateOperation(RemoteInstanceOperation):
remote_queue = ("vm", "slow")
timeout = 600
def _get_remote_args(self, to_node, **kwargs):
def _get_remote_args(self, to_node, live_migration, **kwargs):
return (super(MigrateOperation, self)._get_remote_args(**kwargs)
+ [to_node.host.hostname, True])
# TODO handle non-live migration
+ [to_node.host.hostname, live_migration])
def rollback(self, activity):
with activity.sub_activity(
......@@ -483,7 +482,7 @@ class MigrateOperation(RemoteInstanceOperation):
"redeploy network (rollback)")):
self.instance.deploy_net()
def _operation(self, activity, to_node=None):
def _operation(self, activity, to_node=None, live_migration=True):
if not to_node:
with activity.sub_activity('scheduling',
readable_name=ugettext_noop(
......@@ -495,7 +494,8 @@ class MigrateOperation(RemoteInstanceOperation):
with activity.sub_activity(
'migrate_vm', readable_name=create_readable(
ugettext_noop("migrate to %(node)s"), node=to_node)):
super(MigrateOperation, self)._operation(to_node=to_node)
super(MigrateOperation, self)._operation(
to_node=to_node, live_migration=live_migration)
except Exception as e:
if hasattr(e, 'libvirtError'):
self.rollback(activity)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment