Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Gelencsér Szabolcs
/
circlestack
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
cab22b32
authored
Mar 19, 2014
by
Őry Máté
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature-flush-node'
Add Node.flush *
✅
model *
✅
tasks *
☑
view
parents
0964aa9c
c086ab65
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
255 additions
and
34 deletions
+255
-34
circle/dashboard/static/dashboard/dashboard.js
+15
-0
circle/dashboard/templates/dashboard/confirm/ajax-node-flush.html
+27
-0
circle/dashboard/templates/dashboard/confirm/node-flush.html
+33
-0
circle/dashboard/templates/dashboard/node-detail.html
+4
-9
circle/dashboard/templates/dashboard/node-list/column-actions.html
+6
-11
circle/dashboard/templates/dashboard/node-list/column-admin.html
+1
-1
circle/dashboard/urls.py
+8
-6
circle/dashboard/views.py
+36
-1
circle/vm/models/instance.py
+6
-1
circle/vm/models/node.py
+23
-3
circle/vm/tasks/local_tasks.py
+5
-0
circle/vm/tests/test_models.py
+91
-2
No files found.
circle/dashboard/static/dashboard/dashboard.js
View file @
cab22b32
...
@@ -137,6 +137,21 @@ $(function () {
...
@@ -137,6 +137,21 @@ $(function () {
return
false
;
return
false
;
});
});
/* for Node flush buttons */
$
(
'.node-flush'
).
click
(
function
()
{
var
node_pk
=
$
(
this
).
data
(
'node-pk'
);
var
postto
=
$
(
this
).
attr
(
'href'
);
var
dir
=
window
.
location
.
pathname
.
indexOf
(
'list'
)
==
-
1
;
addModalConfirmation
(
function
(){},
{
'url'
:
postto
,
'data'
:
[],
'pk'
:
node_pk
,
'type'
:
"node"
,
'redirect'
:
dir
});
return
false
;
});
/* for Group removes buttons */
/* for Group removes buttons */
$
(
'.group-delete'
).
click
(
function
()
{
$
(
'.group-delete'
).
click
(
function
()
{
var
group_pk
=
$
(
this
).
data
(
'group-pk'
);
var
group_pk
=
$
(
this
).
data
(
'group-pk'
);
...
...
circle/dashboard/templates/dashboard/confirm/ajax-node-flush.html
0 → 100644
View file @
cab22b32
{% load i18n %}
<div
class=
"modal fade"
id=
"confirmation-modal"
tabindex=
"-1"
role=
"dialog"
>
<div
class=
"modal-dialog"
>
<div
class=
"modal-content"
>
<div
class=
"modal-body"
>
{% if text %}
{{ text }}
{% else %}
{%blocktrans with object=object%}
Are you sure you want to flush
<strong>
{{ object }}
</strong>
?
{%endblocktrans%}
{% endif %}
<div
class=
"pull-right"
>
<form
action=
"{% url "
dashboard
.
views
.
flush-node
"
pk=
node.pk
%}?
next=
{{next}}"
method=
"POST"
>
{% csrf_token %}
<button
type=
"button"
class=
"btn btn-default"
data-dismiss=
"modal"
>
{% trans "Cancel" %}
</button>
<input
type=
"hidden"
name=
"flush"
value=
""
/>
<button
class=
"btn btn-warning"
>
{% trans "Yes" %}
</button>
</form>
</div>
<div
class=
"clearfix"
></div>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal-dialog -->
</div>
circle/dashboard/templates/dashboard/confirm/node-flush.html
0 → 100644
View file @
cab22b32
{% extends "dashboard/base.html" %}
{% load i18n %}
{% block content %}
<div
class=
"body-content"
>
<div
class=
"panel panel-default"
>
<div
class=
"panel-heading"
>
<h3
class=
"no-margin"
>
{% if title %}
{{ title }}
{% else %}
Flush confirmation
{% endif %}
</h3>
</div>
<div
class=
"panel-body"
>
{% if text %}
{{ text }}
{% else %}
{%blocktrans with object=object%}
Are you sure you want to flush
<strong>
{{ object }}
</strong>
?
{%endblocktrans%}
{% endif %}
<div
class=
"pull-right"
>
<form
action=
""
method=
"POST"
>
{% csrf_token %}
<a
class=
"btn btn-default"
>
{% trans "Back" %}
</a>
<input
type=
"hidden"
name=
"flush"
value=
""
/>
<button
class=
"btn btn-warning"
>
{% trans "Yes" %}
</button>
</form>
</div>
</div>
</div>
{% endblock %}
circle/dashboard/templates/dashboard/node-detail.html
View file @
cab22b32
...
@@ -29,15 +29,10 @@
...
@@ -29,15 +29,10 @@
<button
type=
"button"
class=
"btn {{ btn_size }} btn-warning nojs-dropdown-toogle dropdown-toggle"
data-toggle=
"dropdown"
>
Action
<i
class=
"icon-caret-down"
></i></button>
<button
type=
"button"
class=
"btn {{ btn_size }} btn-warning nojs-dropdown-toogle dropdown-toggle"
data-toggle=
"dropdown"
>
Action
<i
class=
"icon-caret-down"
></i></button>
<ul
class=
"dropdown-menu nojs-dropdown-toogle"
role=
"menu"
>
<ul
class=
"dropdown-menu nojs-dropdown-toogle"
role=
"menu"
>
<li><a
href=
"#"
class=
"node-details-rename-button"
><i
class=
"icon-pencil"
></i>
{% trans "Rename" %}
</a></li>
<li><a
href=
"#"
class=
"node-details-rename-button"
><i
class=
"icon-pencil"
></i>
{% trans "Rename" %}
</a></li>
<li><a
href=
"#"
><i
class=
"icon-cloud-upload"
></i>
Flush
</a></li>
<li><a
data-node-pk=
"{{ node.pk }}"
class=
"real-link node-flush"
href=
"{% url "
dashboard
.
views
.
flush-node
"
pk=
node.pk
%}"
><i
class=
"icon-cloud-upload"
></i>
{% trans "Flush" %}
</a>
{% if node.enabled %}
<li>
<li><a
style=
"display:none"
data-node-pk=
"{{ node.pk }}"
class=
"real-link node-enable"
href=
"{% url "
dashboard
.
views
.
status-node
"
pk=
node.pk
%}?
next=
{{
request
.
path
}}"
><i
class=
"icon-check"
></i>
Enable
</a>
<a
style=
"display:{% if node.enabled %}none{% else %}block{% endif %}"
data-node-pk=
"{{ node.pk }}"
class=
"real-link node-enable"
href=
"{% url "
dashboard
.
views
.
status-node
"
pk=
node.pk
%}?
next=
{{
request
.
path
}}"
><i
class=
"icon-check"
></i>
{% trans "Enable" %}
</a>
<a
style=
"display:block"
data-node-pk=
"{{ node.pk }}"
class=
"real-link node-enable"
href=
"{% url "
dashboard
.
views
.
status-node
"
pk=
node.pk
%}?
next=
{{
request
.
path
}}"
><i
class=
"icon-remove"
></i>
Disable
</a></li>
<a
style=
"display:{% if not node.enabled %}none{% else %}block{% endif %}"
data-node-pk=
"{{ node.pk }}"
class=
"real-link node-enable"
href=
"{% url "
dashboard
.
views
.
status-node
"
pk=
node.pk
%}?
next=
{{
request
.
path
}}"
><i
class=
"icon-remove"
></i>
{% trans "Disable" %}
</a></li>
{% else %}
<li><a
style=
"display:block"
data-node-pk=
"{{ node.pk }}"
class=
"real-link node-enable"
href=
"{% url "
dashboard
.
views
.
status-node
"
pk=
node.pk
%}?
next=
{{
request
.
path
}}"
>
<i
class=
"icon-check"
></i>
Enable
</a>
<a
style=
"display:none"
data-node-pk=
"{{ node.pk }}"
class=
"real-link node-enable"
href=
"{% url "
dashboard
.
views
.
status-node
"
pk=
node.pk
%}?
next=
{{
request
.
path
}}"
><i
class=
"icon-remove"
></i>
Disable
</a></li>
{% endif %}
<li><a
data-node-pk=
"{{ node.pk }}"
class=
"real-link node-delete"
href=
"{% url "
dashboard
.
views
.
delete-node
"
pk=
node.pk
%}?
next=
{{
request
.
path
}}"
><i
class=
"icon-trash"
></i>
Delete
</a></li>
<li><a
data-node-pk=
"{{ node.pk }}"
class=
"real-link node-delete"
href=
"{% url "
dashboard
.
views
.
delete-node
"
pk=
node.pk
%}?
next=
{{
request
.
path
}}"
><i
class=
"icon-trash"
></i>
Delete
</a></li>
</ul>
</ul>
</div>
</div>
...
...
circle/dashboard/templates/dashboard/node-list/column-actions.html
View file @
cab22b32
{% load i18n %}
<div
class=
"btn-group"
>
<div
class=
"btn-group"
>
<button
type=
"button"
class=
"btn {{ btn_size }} btn-warning nojs-dropdown-toogle dropdown-toggle"
data-toggle=
"dropdown"
>
Action
<i
class=
"icon-caret-down"
></i></button>
<button
type=
"button"
class=
"btn {{ btn_size }} btn-warning nojs-dropdown-toogle dropdown-toggle"
data-toggle=
"dropdown"
>
Action
<i
class=
"icon-caret-down"
></i></button>
<ul
class=
"dropdown-menu nojs-dropdown-toogle"
role=
"menu"
>
<ul
class=
"dropdown-menu nojs-dropdown-toogle"
role=
"menu"
>
<li><a
href=
"#"
><i
class=
"icon-cloud-upload"
></i>
Flush
</a></li>
<li><a
href=
"#"
class=
"node-details-rename-button"
><i
class=
"icon-pencil"
></i>
{% trans "Rename" %}
</a></li>
{% if record.enabled %}
<li><a
data-node-pk=
"{{ record.pk }}"
class=
"real-link node-flush"
href=
"{% url "
dashboard
.
views
.
flush-node
"
pk=
record.pk
%}"
><i
class=
"icon-cloud-upload"
></i>
{% trans "Flush" %}
</a>
<li><a
style=
"display:none"
data-status=
"enable"
data-node-pk=
"{{ record.pk }}"
class=
"real-link node-enable"
href=
"{% url "
dashboard
.
views
.
status-node
"
pk=
record.pk
%}?
next=
{{
request
.
path
}}&
status=
enable"
><i
class=
"icon-check"
></i>
Enable
</a>
<li><a
style=
{%
if
record
.
enabled
%}"
display:none
"{%
else
%}"
display:block
"{%
endif
%}
data-status=
"enable"
data-node-pk=
"{{ record.pk }}"
class=
"real-link node-enable"
href=
"{% url "
dashboard
.
views
.
status-node
"
pk=
record.pk
%}?
next=
{{
request
.
path
}}&
status=
enable"
><i
class=
"icon-check"
></i>
{% trans "Enable" %}
</a>
<a
style=
"display:block"
data-status=
"disable"
data-node-pk=
"{{ record.pk }}"
class=
"real-link node-enable"
href=
"{% url "
dashboard
.
views
.
status-node
"
pk=
record.pk
%}?
next=
{{
request
.
path
}}&
status=
disable"
><i
class=
"icon-remove"
></i>
Disable
</a></li>
<a
style=
{%
if
record
.
enabled
%}"
display:block
"{%
else
%}"
display:none
"{%
endif
%}
data-status=
"disable"
data-node-pk=
"{{ record.pk }}"
class=
"real-link node-enable"
href=
"{% url "
dashboard
.
views
.
status-node
"
pk=
record.pk
%}?
next=
{{
request
.
path
}}&
status=
disable"
><i
class=
"icon-remove"
></i>
{% trans "Disable" %}
</a></li>
{% else %}
<li><a
data-node-pk=
"{{ record.pk }}"
class=
"real-link node-delete"
href=
"{% url "
dashboard
.
views
.
delete-node
"
pk=
record.pk
%}?
next=
{{
request
.
path
}}"
><i
class=
"icon-trash"
></i>
{% trans "Delete" %}
</a></li>
<li><a
style=
"display:block"
data-status=
"enable"
data-node-pk=
"{{ record.pk }}"
class=
"real-link node-enable"
href=
"{% url "
dashboard
.
views
.
status-node
"
pk=
record.pk
%}?
next=
{{
request
.
path
}}&
status=
enable"
>
<i
class=
"icon-check"
></i>
Enable
</a>
<a
style=
"display:none"
data-status=
"disable"
data-node-pk=
"{{ record.pk }}"
class=
"real-link node-enable"
href=
"{% url "
dashboard
.
views
.
status-node
"
pk=
record.pk
%}?
next=
{{
request
.
path
}}&
status=
disable"
><i
class=
"icon-remove"
></i>
Disable
</a></li>
{% endif %}
<li><a
data-node-pk=
"{{ record.pk }}"
class=
"real-link node-delete"
href=
"{% url "
dashboard
.
views
.
delete-node
"
pk=
record.pk
%}?
next=
{{
request
.
path
}}"
><i
class=
"icon-trash"
></i>
Delete
</a></li>
</ul>
</ul>
</div>
</div>
circle/dashboard/templates/dashboard/node-list/column-admin.html
View file @
cab22b32
...
@@ -4,4 +4,4 @@
...
@@ -4,4 +4,4 @@
<a
id=
"node-list-rename-button"
class=
"btn btn-default btn-xs"
title
data-original-title=
"Rename"
>
<a
id=
"node-list-rename-button"
class=
"btn btn-default btn-xs"
title
data-original-title=
"Rename"
>
<i
class=
"icon-pencil"
></i>
<i
class=
"icon-pencil"
></i>
</a>
</a>
circle/dashboard/urls.py
View file @
cab22b32
...
@@ -5,12 +5,12 @@ from .views import (
...
@@ -5,12 +5,12 @@ from .views import (
AclUpdateView
,
DiskAddView
,
FavouriteView
,
GroupAclUpdateView
,
GroupDelete
,
AclUpdateView
,
DiskAddView
,
FavouriteView
,
GroupAclUpdateView
,
GroupDelete
,
GroupDetailView
,
GroupList
,
GroupUserDelete
,
IndexView
,
LeaseCreate
,
GroupDetailView
,
GroupList
,
GroupUserDelete
,
IndexView
,
LeaseCreate
,
LeaseDelete
,
LeaseDetail
,
MyPreferencesView
,
NodeAddTraitView
,
NodeCreate
,
LeaseDelete
,
LeaseDetail
,
MyPreferencesView
,
NodeAddTraitView
,
NodeCreate
,
NodeDelete
,
NodeDetailView
,
Node
GraphView
,
NodeList
,
NodeStatus
,
NodeDelete
,
NodeDetailView
,
Node
FlushView
,
NodeGraphView
,
NodeList
,
No
tificationView
,
PortDelete
,
TemplateAclUpdateView
,
TemplateCreate
,
No
deStatus
,
NotificationView
,
PortDelete
,
TemplateAclUpdateView
,
Template
Delete
,
TemplateDetail
,
TemplateList
,
TransferOwnershipConfirmView
,
Template
Create
,
TemplateDelete
,
TemplateDetail
,
TemplateList
,
TransferOwnership
View
,
vm_activity
,
VmCreate
,
VmDelete
,
VmDetailView
,
TransferOwnership
ConfirmView
,
TransferOwnershipView
,
vm_activity
,
VmCreate
,
VmDe
tailVncTokenView
,
VmGraphView
,
VmList
,
VmMassDelete
,
VmMigrateView
,
VmDe
lete
,
VmDetailView
,
VmDetailVncTokenView
,
VmGraphView
,
VmList
,
VmRenewView
,
Vm
MassDelete
,
VmMigrateView
,
Vm
RenewView
,
)
)
urlpatterns
=
patterns
(
urlpatterns
=
patterns
(
...
@@ -68,6 +68,8 @@ urlpatterns = patterns(
...
@@ -68,6 +68,8 @@ urlpatterns = patterns(
name
=
"dashboard.views.delete-node"
),
name
=
"dashboard.views.delete-node"
),
url
(
r'^node/status/(?P<pk>\d+)/$'
,
NodeStatus
.
as_view
(),
url
(
r'^node/status/(?P<pk>\d+)/$'
,
NodeStatus
.
as_view
(),
name
=
"dashboard.views.status-node"
),
name
=
"dashboard.views.status-node"
),
url
(
r'^node/flush/(?P<pk>\d+)/$'
,
NodeFlushView
.
as_view
(),
name
=
"dashboard.views.flush-node"
),
url
(
r'^node/create/$'
,
NodeCreate
.
as_view
(),
url
(
r'^node/create/$'
,
NodeCreate
.
as_view
(),
name
=
'dashboard.views.node-create'
),
name
=
'dashboard.views.node-create'
),
...
...
circle/dashboard/views.py
View file @
cab22b32
...
@@ -505,7 +505,6 @@ class NodeDetailView(LoginRequiredMixin, SuperuserRequiredMixin, DetailView):
...
@@ -505,7 +505,6 @@ class NodeDetailView(LoginRequiredMixin, SuperuserRequiredMixin, DetailView):
return
context
return
context
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
print
request
.
POST
if
request
.
POST
.
get
(
'new_name'
):
if
request
.
POST
.
get
(
'new_name'
):
return
self
.
__set_name
(
request
)
return
self
.
__set_name
(
request
)
if
request
.
POST
.
get
(
'change_status'
)
is
not
None
:
if
request
.
POST
.
get
(
'change_status'
)
is
not
None
:
...
@@ -1401,6 +1400,42 @@ class NodeStatus(LoginRequiredMixin, SuperuserRequiredMixin, DetailView):
...
@@ -1401,6 +1400,42 @@ class NodeStatus(LoginRequiredMixin, SuperuserRequiredMixin, DetailView):
return
redirect
(
self
.
get_success_url
())
return
redirect
(
self
.
get_success_url
())
class
NodeFlushView
(
LoginRequiredMixin
,
SuperuserRequiredMixin
,
DetailView
):
template_name
=
"dashboard/confirm/node-flush.html"
model
=
Node
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
return
[
'dashboard/confirm/ajax-node-flush.html'
]
else
:
return
[
'dashboard/confirm/node-flush.html'
]
def
get_success_url
(
self
):
next
=
self
.
request
.
GET
.
get
(
'next'
)
if
next
:
return
next
else
:
return
reverse_lazy
(
"dashboard.views.node-detail"
,
kwargs
=
{
'pk'
:
self
.
object
.
pk
})
def
get_context_data
(
self
,
**
kwargs
):
context
=
super
(
NodeFlushView
,
self
)
.
get_context_data
(
**
kwargs
)
return
context
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
if
request
.
POST
.
get
(
'flush'
)
is
not
None
:
return
self
.
__flush
(
request
)
return
redirect
(
reverse_lazy
(
"dashboard.views.node-detail"
,
kwargs
=
{
'pk'
:
self
.
get_object
()
.
pk
}))
def
__flush
(
self
,
request
):
self
.
object
=
self
.
get_object
()
self
.
object
.
flush_async
(
user
=
request
.
user
)
success_message
=
_
(
"Node successfully flushed!"
)
messages
.
success
(
request
,
success_message
)
return
redirect
(
self
.
get_success_url
())
class
PortDelete
(
LoginRequiredMixin
,
DeleteView
):
class
PortDelete
(
LoginRequiredMixin
,
DeleteView
):
model
=
Rule
model
=
Rule
pk_url_kwarg
=
'rule'
pk_url_kwarg
=
'rule'
...
...
circle/vm/models/instance.py
View file @
cab22b32
...
@@ -1096,10 +1096,15 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel,
...
@@ -1096,10 +1096,15 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel,
return
local_tasks
.
migrate
.
apply_async
(
args
=
[
self
,
to_node
,
user
],
return
local_tasks
.
migrate
.
apply_async
(
args
=
[
self
,
to_node
,
user
],
queue
=
"localhost.man"
)
queue
=
"localhost.man"
)
def
migrate
(
self
,
to_node
,
user
=
None
,
task_uuid
=
None
,
timeout
=
120
):
def
migrate
(
self
,
to_node
=
None
,
user
=
None
,
task_uuid
=
None
,
timeout
=
120
):
"""Live migrate running vm to another node. """
"""Live migrate running vm to another node. """
with
instance_activity
(
code_suffix
=
'migrate'
,
instance
=
self
,
with
instance_activity
(
code_suffix
=
'migrate'
,
instance
=
self
,
task_uuid
=
task_uuid
,
user
=
user
)
as
act
:
task_uuid
=
task_uuid
,
user
=
user
)
as
act
:
if
not
to_node
:
with
act
.
sub_activity
(
'scheduling'
)
as
sa
:
to_node
=
self
.
select_node
()
sa
.
result
=
to_node
# Destroy networks
# Destroy networks
with
act
.
sub_activity
(
'destroying_net'
):
with
act
.
sub_activity
(
'destroying_net'
):
for
net
in
self
.
interface_set
.
all
():
for
net
in
self
.
interface_set
.
all
():
...
...
circle/vm/models/node.py
View file @
cab22b32
...
@@ -13,7 +13,7 @@ from taggit.managers import TaggableManager
...
@@ -13,7 +13,7 @@ from taggit.managers import TaggableManager
from
common.models
import
method_cache
,
WorkerNotFound
from
common.models
import
method_cache
,
WorkerNotFound
from
firewall.models
import
Host
from
firewall.models
import
Host
from
..tasks
import
vm_tasks
from
..tasks
import
vm_tasks
,
local_tasks
from
.common
import
Trait
from
.common
import
Trait
from
.activity
import
node_activity
,
NodeActivity
from
.activity
import
node_activity
,
NodeActivity
...
@@ -106,13 +106,33 @@ class Node(TimeStampedModel):
...
@@ -106,13 +106,33 @@ class Node(TimeStampedModel):
def
get_status_display
(
self
):
def
get_status_display
(
self
):
return
self
.
STATES
[
self
.
enabled
][
self
.
online
][
1
]
return
self
.
STATES
[
self
.
enabled
][
self
.
online
][
1
]
def
disable
(
self
,
user
=
None
):
def
disable
(
self
,
user
=
None
,
base_activity
=
None
):
''' Disable the node.'''
''' Disable the node.'''
if
self
.
enabled
:
if
self
.
enabled
:
with
node_activity
(
code_suffix
=
'disable'
,
node
=
self
,
user
=
user
):
if
base_activity
:
act_ctx
=
base_activity
.
sub_activity
(
'disable'
)
else
:
act_ctx
=
node_activity
(
'disable'
,
node
=
self
,
user
=
user
)
with
act_ctx
:
self
.
enabled
=
False
self
.
enabled
=
False
self
.
save
()
self
.
save
()
def
flush
(
self
,
user
=
None
,
task_uuid
=
None
):
"""Disable node and move all instances to other ones.
"""
with
node_activity
(
'flush'
,
node
=
self
,
user
=
user
,
task_uuid
=
task_uuid
)
as
act
:
self
.
disable
(
user
,
act
)
for
i
in
self
.
instance_set
.
all
():
with
act
.
sub_activity
(
'migrate_instance_
%
d'
%
i
.
pk
):
i
.
migrate
()
def
flush_async
(
self
,
user
=
None
):
"""Execute flush asynchronously.
"""
return
local_tasks
.
flush
.
apply_async
(
args
=
[
self
,
user
],
queue
=
"localhost.man"
)
def
enable
(
self
,
user
=
None
):
def
enable
(
self
,
user
=
None
):
''' Enable the node. '''
''' Enable the node. '''
if
self
.
enabled
is
not
True
:
if
self
.
enabled
is
not
True
:
...
...
circle/vm/tasks/local_tasks.py
View file @
cab22b32
...
@@ -57,3 +57,8 @@ def reboot(instance, user):
...
@@ -57,3 +57,8 @@ def reboot(instance, user):
@celery.task
@celery.task
def
migrate
(
instance
,
to_node
,
user
):
def
migrate
(
instance
,
to_node
,
user
):
instance
.
migrate
(
to_node
,
task_uuid
=
migrate
.
request
.
id
,
user
=
user
)
instance
.
migrate
(
to_node
,
task_uuid
=
migrate
.
request
.
id
,
user
=
user
)
@celery.task
def
flush
(
node
,
user
):
node
.
flush
(
task_uuid
=
flush
.
request
.
id
,
user
=
user
)
circle/vm/tests/test_models.py
View file @
cab22b32
from
datetime
import
datetime
from
datetime
import
datetime
from
django.contrib.auth.models
import
User
from
django.test
import
TestCase
from
django.test
import
TestCase
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
mock
import
Mock
,
MagicMock
,
patch
from
mock
import
Mock
,
MagicMock
,
patch
,
call
from
..models
import
(
from
..models
import
(
Lease
,
Node
,
Interface
,
Instance
,
InstanceTemplate
,
InstanceActivity
,
Lease
,
Node
,
Interface
,
Instance
,
InstanceTemplate
,
InstanceActivity
,
...
@@ -68,12 +70,38 @@ class InstanceTestCase(TestCase):
...
@@ -68,12 +70,38 @@ class InstanceTestCase(TestCase):
self
.
assertTrue
(
inst
.
destroyed_at
)
self
.
assertTrue
(
inst
.
destroyed_at
)
inst
.
save
.
assert_called
()
inst
.
save
.
assert_called
()
def
test_migrate_with_scheduling
(
self
):
inst
=
MagicMock
(
spec
=
Instance
)
inst
.
interface_set
.
all
.
return_value
=
[]
inst
.
node
=
MagicMock
(
spec
=
Node
)
with
patch
(
'vm.models.instance.instance_activity'
)
as
ia
,
\
patch
(
'vm.models.instance.vm_tasks.migrate'
)
as
migr
:
Instance
.
migrate
(
inst
)
migr
.
apply_async
.
assert_called
()
self
.
assertIn
(
call
()
.
__enter__
()
.
sub_activity
(
u'scheduling'
),
ia
.
mock_calls
)
inst
.
select_node
.
assert_called
()
def
test_migrate_wo_scheduling
(
self
):
inst
=
MagicMock
(
spec
=
Instance
)
inst
.
interface_set
.
all
.
return_value
=
[]
inst
.
node
=
MagicMock
(
spec
=
Node
)
with
patch
(
'vm.models.instance.instance_activity'
)
as
ia
,
\
patch
(
'vm.models.instance.vm_tasks.migrate'
)
as
migr
:
inst
.
select_node
.
side_effect
=
AssertionError
Instance
.
migrate
(
inst
,
inst
.
node
)
migr
.
apply_async
.
assert_called
()
self
.
assertNotIn
(
call
()
.
__enter__
()
.
sub_activity
(
u'scheduling'
),
ia
.
mock_calls
)
class
InterfaceTestCase
(
TestCase
):
class
InterfaceTestCase
(
TestCase
):
def
test_interface_create
(
self
):
def
test_interface_create
(
self
):
from
firewall.models
import
Vlan
,
Domain
from
firewall.models
import
Vlan
,
Domain
from
django.contrib.auth.models
import
User
owner
=
User
()
owner
=
User
()
owner
.
save
()
owner
.
save
()
i
=
Instance
(
id
=
10
,
owner
=
owner
,
access_method
=
'rdp'
)
i
=
Instance
(
id
=
10
,
owner
=
owner
,
access_method
=
'rdp'
)
...
@@ -165,3 +193,64 @@ class InstanceActivityTestCase(TestCase):
...
@@ -165,3 +193,64 @@ class InstanceActivityTestCase(TestCase):
patch
(
'vm.models.activity.timezone.now'
):
patch
(
'vm.models.activity.timezone.now'
):
original_method
(
iaobj
,
"test"
,
concurrency_check
=
False
)
original_method
(
iaobj
,
"test"
,
concurrency_check
=
False
)
ia
.
save
.
assert_called
()
ia
.
save
.
assert_called
()
def
test_disable_enabled
(
self
):
node
=
MagicMock
(
spec
=
Node
,
enabled
=
True
)
with
patch
(
'vm.models.node.node_activity'
)
as
nac
:
na
=
MagicMock
()
nac
.
return_value
=
na
na
.
__enter__
.
return_value
=
MagicMock
()
Node
.
disable
(
node
)
self
.
assertFalse
(
node
.
enabled
)
node
.
save
.
assert_called_once
()
na
.
assert_called
()
def
test_disable_disabled
(
self
):
node
=
MagicMock
(
spec
=
Node
,
enabled
=
False
)
with
patch
(
'vm.models.node.node_activity'
)
as
nac
:
na
=
MagicMock
()
na
.
__enter__
.
side_effect
=
AssertionError
nac
.
return_value
=
na
Node
.
disable
(
node
)
self
.
assertFalse
(
node
.
enabled
)
def
test_disable_enabled_sub
(
self
):
node
=
MagicMock
(
spec
=
Node
,
enabled
=
True
)
act
=
MagicMock
()
subact
=
MagicMock
()
act
.
sub_activity
.
return_value
=
subact
Node
.
disable
(
node
,
base_activity
=
act
)
self
.
assertFalse
(
node
.
enabled
)
subact
.
__enter__
.
assert_called
()
def
test_flush
(
self
):
node
=
MagicMock
(
spec
=
Node
,
enabled
=
True
)
user
=
MagicMock
(
spec
=
User
)
insts
=
[
MagicMock
(
spec
=
Instance
),
MagicMock
(
spec
=
Instance
)]
with
patch
(
'vm.models.node.node_activity'
)
as
na
:
act
=
na
.
return_value
.
__enter__
.
return_value
=
MagicMock
()
node
.
instance_set
.
all
.
return_value
=
insts
Node
.
flush
(
node
,
user
)
na
.
__enter__
.
assert_called
()
node
.
disable
.
assert_called_with
(
user
,
act
)
for
i
in
insts
:
i
.
migrate
.
assert_called
()
def
test_flush_disabled_wo_user
(
self
):
node
=
MagicMock
(
spec
=
Node
,
enabled
=
False
)
insts
=
[
MagicMock
(
spec
=
Instance
),
MagicMock
(
spec
=
Instance
)]
with
patch
(
'vm.models.node.node_activity'
)
as
na
:
act
=
na
.
return_value
.
__enter__
.
return_value
=
MagicMock
()
node
.
instance_set
.
all
.
return_value
=
insts
Node
.
flush
(
node
)
node
.
disable
.
assert_called_with
(
None
,
act
)
# ^ should be called, but real method no-ops if disabled
na
.
__enter__
.
assert_called
()
for
i
in
insts
:
i
.
migrate
.
assert_called
()
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