Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
CIRCLE
/
cloud
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
94
Merge Requests
10
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
bfd76bee
authored
Oct 07, 2014
by
Bach Dániel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dashboard: add non-live migration support
Closes
#324
parent
709eec33
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
41 additions
and
26 deletions
+41
-26
circle/dashboard/forms.py
+20
-0
circle/dashboard/templates/dashboard/_vm-migrate.html
+5
-3
circle/dashboard/views/vm.py
+11
-18
circle/vm/operations.py
+5
-5
No files found.
circle/dashboard/forms.py
View file @
bfd76bee
...
@@ -752,6 +752,26 @@ class VmRenewForm(forms.Form):
...
@@ -752,6 +752,26 @@ class VmRenewForm(forms.Form):
return
helper
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
):
class
VmStateChangeForm
(
forms
.
Form
):
interrupt
=
forms
.
BooleanField
(
required
=
False
,
label
=
_
(
interrupt
=
forms
.
BooleanField
(
required
=
False
,
label
=
_
(
...
...
circle/dashboard/templates/dashboard/_vm-migrate.html
View file @
bfd76bee
{% extends "dashboard/operate.html" %}
{% extends "dashboard/operate.html" %}
{% load i18n %}
{% load i18n %}
{% load sizefieldtags %}
{% load sizefieldtags %}
{% load crispy_forms_tags %}
{% block question %}
{% block question %}
<p>
<p>
...
@@ -13,8 +14,8 @@ Choose a compute node to migrate {{obj}} to.
...
@@ -13,8 +14,8 @@ Choose a compute node to migrate {{obj}} to.
{% block formfields %}
{% block formfields %}
<ul
id=
"vm-migrate-node-list"
class=
"list-unstyled"
>
<ul
id=
"vm-migrate-node-list"
class=
"list-unstyled"
>
{% with current=object.node.pk %}
{% with current=object.node.pk
recommended=form.fields.to_node.initial
%}
{% for n in
nodes
%}
{% for n in
form.fields.to_node.queryset.all
%}
<li
class=
"panel panel-default"
><div
class=
"panel-body"
>
<li
class=
"panel panel-default"
><div
class=
"panel-body"
>
<label
for=
"migrate-to-{{n.pk}}"
>
<label
for=
"migrate-to-{{n.pk}}"
>
<strong>
{{ n }}
</strong>
<strong>
{{ n }}
</strong>
...
@@ -23,7 +24,7 @@ Choose a compute node to migrate {{obj}} to.
...
@@ -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 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 %}
{% if recommended == n.pk %}
<div
class=
"label label-success"
>
{% trans "recommended" %}
</div>
{% endif %}
</label>
</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
current =
=
n
.
pk
%}
disabled=
"disabled"
{%
endif
%}
{%
if
recommended =
=
n
.
pk
%}
checked=
"checked"
{%
endif
%}
/>
{%
if
recommended =
=
n
.
pk
%}
checked=
"checked"
{%
endif
%}
/>
<span
class=
"vm-migrate-node-property"
>
{% trans "CPU load" %}: {{ n.cpu_usage }}
</span>
<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.
...
@@ -33,4 +34,5 @@ Choose a compute node to migrate {{obj}} to.
{% endfor %}
{% endfor %}
{% endwith %}
{% endwith %}
</ul>
</ul>
{{ form.live_migration|as_crispy_field }}
{% endblock %}
{% endblock %}
circle/dashboard/views/vm.py
View file @
bfd76bee
...
@@ -60,6 +60,7 @@ from ..forms import (
...
@@ -60,6 +60,7 @@ from ..forms import (
VmAddInterfaceForm
,
VmCreateDiskForm
,
VmDownloadDiskForm
,
VmSaveForm
,
VmAddInterfaceForm
,
VmCreateDiskForm
,
VmDownloadDiskForm
,
VmSaveForm
,
VmRenewForm
,
VmStateChangeForm
,
VmListSearchForm
,
VmCustomizeForm
,
VmRenewForm
,
VmStateChangeForm
,
VmListSearchForm
,
VmCustomizeForm
,
TransferOwnershipForm
,
VmDiskResizeForm
,
RedeployForm
,
VmDiskRemoveForm
,
TransferOwnershipForm
,
VmDiskResizeForm
,
RedeployForm
,
VmDiskRemoveForm
,
VmMigrateForm
,
)
)
from
..models
import
Favourite
,
Profile
from
..models
import
Favourite
,
Profile
...
@@ -421,36 +422,28 @@ class VmDownloadDiskView(FormOperationMixin, VmOperationView):
...
@@ -421,36 +422,28 @@ class VmDownloadDiskView(FormOperationMixin, VmOperationView):
with_reload
=
True
with_reload
=
True
class
VmMigrateView
(
VmOperationView
):
class
VmMigrateView
(
FormOperationMixin
,
VmOperationView
):
op
=
'migrate'
op
=
'migrate'
icon
=
'truck'
icon
=
'truck'
effect
=
'info'
effect
=
'info'
template_name
=
'dashboard/_vm-migrate.html'
template_name
=
'dashboard/_vm-migrate.html'
form_class
=
VmMigrateForm
def
get_context_data
(
self
,
**
kwargs
):
def
get_form_kwargs
(
self
):
ctx
=
super
(
VmMigrateView
,
self
)
.
get_context_data
(
**
kwargs
)
online
=
(
n
.
pk
for
n
in
Node
.
objects
.
filter
(
enabled
=
True
)
if
n
.
online
)
ctx
[
'nodes'
]
=
[
n
for
n
in
Node
.
objects
.
filter
(
enabled
=
True
)
choices
=
Node
.
objects
.
filter
(
pk__in
=
online
)
if
n
.
online
]
default
=
None
inst
=
self
.
get_object
()
inst
=
self
.
get_object
()
ctx
[
"recommended"
]
=
None
try
:
try
:
if
isinstance
(
inst
,
Instance
):
if
isinstance
(
inst
,
Instance
):
ctx
[
"recommended"
]
=
inst
.
select_node
()
.
pk
default
=
inst
.
select_node
()
.
pk
except
SchedulerError
:
except
SchedulerError
:
logger
.
exception
(
"scheduler error:"
)
logger
.
exception
(
"scheduler error:"
)
return
ctx
val
=
super
(
VmMigrateView
,
self
)
.
get_form_kwargs
()
val
.
update
({
'choices'
:
choices
,
'default'
:
default
})
def
post
(
self
,
request
,
extra
=
None
,
*
args
,
**
kwargs
):
return
val
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
)
class
VmSaveView
(
FormOperationMixin
,
VmOperationView
):
class
VmSaveView
(
FormOperationMixin
,
VmOperationView
):
...
...
circle/vm/operations.py
View file @
bfd76bee
...
@@ -472,10 +472,9 @@ class MigrateOperation(RemoteInstanceOperation):
...
@@ -472,10 +472,9 @@ class MigrateOperation(RemoteInstanceOperation):
remote_queue
=
(
"vm"
,
"slow"
)
remote_queue
=
(
"vm"
,
"slow"
)
timeout
=
600
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
)
return
(
super
(
MigrateOperation
,
self
)
.
_get_remote_args
(
**
kwargs
)
+
[
to_node
.
host
.
hostname
,
True
])
+
[
to_node
.
host
.
hostname
,
live_migration
])
# TODO handle non-live migration
def
rollback
(
self
,
activity
):
def
rollback
(
self
,
activity
):
with
activity
.
sub_activity
(
with
activity
.
sub_activity
(
...
@@ -483,7 +482,7 @@ class MigrateOperation(RemoteInstanceOperation):
...
@@ -483,7 +482,7 @@ class MigrateOperation(RemoteInstanceOperation):
"redeploy network (rollback)"
)):
"redeploy network (rollback)"
)):
self
.
instance
.
deploy_net
()
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
:
if
not
to_node
:
with
activity
.
sub_activity
(
'scheduling'
,
with
activity
.
sub_activity
(
'scheduling'
,
readable_name
=
ugettext_noop
(
readable_name
=
ugettext_noop
(
...
@@ -495,7 +494,8 @@ class MigrateOperation(RemoteInstanceOperation):
...
@@ -495,7 +494,8 @@ class MigrateOperation(RemoteInstanceOperation):
with
activity
.
sub_activity
(
with
activity
.
sub_activity
(
'migrate_vm'
,
readable_name
=
create_readable
(
'migrate_vm'
,
readable_name
=
create_readable
(
ugettext_noop
(
"migrate to
%(node)
s"
),
node
=
to_node
)):
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
:
except
Exception
as
e
:
if
hasattr
(
e
,
'libvirtError'
):
if
hasattr
(
e
,
'libvirtError'
):
self
.
rollback
(
activity
)
self
.
rollback
(
activity
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment