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
385ad3e3
authored
Apr 30, 2014
by
Kálmán Viktor
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/master' into feature-template-wizard
parents
5912d4e8
d9fb045f
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
168 additions
and
13 deletions
+168
-13
circle/circle/settings/base.py
+3
-0
circle/common/operations.py
+1
-1
circle/dashboard/templates/dashboard/_vm-save.html
+21
-0
circle/dashboard/tests/test_mockedviews.py
+67
-0
circle/dashboard/views.py
+23
-4
circle/firewall/tests/test_firewall.py
+3
-0
circle/vm/migrations/0022_auto__del_unique_instancetemplate_n.py
+0
-0
circle/vm/models/instance.py
+4
-2
circle/vm/operations.py
+42
-2
circle/vm/tasks/local_periodic_tasks.py
+2
-2
circle/vm/tests/test_models.py
+2
-2
No files found.
circle/circle/settings/base.py
View file @
385ad3e3
...
...
@@ -400,3 +400,6 @@ LOGIN_REDIRECT_URL = "/"
LOCALE_PATHS
=
(
join
(
SITE_ROOT
,
'locale'
),
)
COMPANY_NAME
=
"BME IK 2014"
SOUTH_MIGRATION_MODULES
=
{
'taggit'
:
'taggit.south_migrations'
,
}
circle/common/operations.py
View file @
385ad3e3
...
...
@@ -134,8 +134,8 @@ class OperatedMixin(object):
"""Yield Operations that match permissions of user and preconditions.
"""
for
name
in
getattr
(
self
,
operation_registry_name
,
{}):
op
=
getattr
(
self
,
name
)
try
:
op
=
getattr
(
self
,
name
)
op
.
check_auth
(
user
)
op
.
check_precond
()
except
:
...
...
circle/dashboard/templates/dashboard/_vm-save.html
0 → 100644
View file @
385ad3e3
{% extends "dashboard/operate.html" %}
{% load i18n %}
{% load sizefieldtags %}
{% block question %}
<p>
{% blocktrans %}
Choose a name for the new template.
{% endblocktrans %}
</p>
<p
class=
"text-info"
>
{{op.name}}: {{op.description}}
</p>
{% endblock %}
{% block formfields %}
<div
class=
"form-group"
>
<label
for=
"input-name"
class=
"col-sm-4"
>
{% trans "Name of template" %}
</label>
<div
class=
"col-sm-8"
>
<input
type=
"text"
value=
"{{name}}"
name=
"name"
class=
"form-control"
/>
</div>
</div>
{% endblock %}
circle/dashboard/tests/test_mockedviews.py
View file @
385ad3e3
...
...
@@ -112,6 +112,73 @@ class VmOperationViewTestCase(unittest.TestCase):
self
.
assertEquals
(
view
.
as_view
()(
request
,
pk
=
1234
)
.
render
()
.
status_code
,
200
)
def
test_save_as_wo_name
(
self
):
request
=
FakeRequestFactory
(
POST
=
{})
view
=
vm_ops
[
'save_as_template'
]
with
patch
.
object
(
view
,
'get_object'
)
as
go
,
\
patch
(
'dashboard.views.messages'
)
as
msg
,
\
patch
(
'dashboard.views.get_object_or_404'
)
as
go4
:
inst
=
MagicMock
(
spec
=
Instance
)
inst
.
_meta
.
object_name
=
"Instance"
inst
.
save_as_template
=
Instance
.
_ops
[
'save_as_template'
](
inst
)
inst
.
save_as_template
.
async
=
MagicMock
()
inst
.
has_level
.
return_value
=
True
go
.
return_value
=
inst
go4
.
return_value
=
MagicMock
()
assert
view
.
as_view
()(
request
,
pk
=
1234
)[
'location'
]
assert
not
msg
.
error
.
called
def
test_save_as_w_name
(
self
):
request
=
FakeRequestFactory
(
POST
=
{
'name'
:
'foobar'
})
view
=
vm_ops
[
'save_as_template'
]
with
patch
.
object
(
view
,
'get_object'
)
as
go
,
\
patch
(
'dashboard.views.messages'
)
as
msg
,
\
patch
(
'dashboard.views.get_object_or_404'
)
as
go4
:
inst
=
MagicMock
(
spec
=
Instance
)
inst
.
_meta
.
object_name
=
"Instance"
inst
.
save_as_template
=
Instance
.
_ops
[
'save_as_template'
](
inst
)
inst
.
save_as_template
.
async
=
MagicMock
()
inst
.
has_level
.
return_value
=
True
go
.
return_value
=
inst
go4
.
return_value
=
MagicMock
()
assert
view
.
as_view
()(
request
,
pk
=
1234
)[
'location'
]
assert
not
msg
.
error
.
called
def
test_save_as_failed
(
self
):
request
=
FakeRequestFactory
(
POST
=
{})
view
=
vm_ops
[
'save_as_template'
]
with
patch
.
object
(
view
,
'get_object'
)
as
go
,
\
patch
(
'dashboard.views.messages'
)
as
msg
,
\
patch
(
'dashboard.views.get_object_or_404'
)
as
go4
:
inst
=
MagicMock
(
spec
=
Instance
)
inst
.
_meta
.
object_name
=
"Instance"
inst
.
save_as_template
=
Instance
.
_ops
[
'save_as_template'
](
inst
)
inst
.
save_as_template
.
async
=
MagicMock
()
inst
.
save_as_template
.
async
.
side_effect
=
Exception
inst
.
has_level
.
return_value
=
True
go
.
return_value
=
inst
go4
.
return_value
=
MagicMock
()
assert
view
.
as_view
()(
request
,
pk
=
1234
)[
'location'
]
assert
msg
.
error
.
called
def
test_save_as_template
(
self
):
request
=
FakeRequestFactory
()
view
=
vm_ops
[
'save_as_template'
]
with
patch
.
object
(
view
,
'get_object'
)
as
go
:
inst
=
MagicMock
(
spec
=
Instance
)
inst
.
_meta
.
object_name
=
"Instance"
inst
.
name
=
'foo'
inst
.
save_as_template
=
Instance
.
_ops
[
'save_as_template'
](
inst
)
inst
.
has_level
.
return_value
=
True
go
.
return_value
=
inst
rend
=
view
.
as_view
()(
request
,
pk
=
1234
)
.
render
()
self
.
assertEquals
(
rend
.
status_code
,
200
)
assert
'foo v1'
in
rend
.
content
def
FakeRequestFactory
(
*
args
,
**
kwargs
):
''' FakeRequestFactory, FakeMessages and FakeRequestContext are good for
...
...
circle/dashboard/views.py
View file @
385ad3e3
...
...
@@ -513,7 +513,7 @@ class VmMigrateView(VmOperationView):
template_name
=
'dashboard/_vm-migrate.html'
def
get_context_data
(
self
,
**
kwargs
):
ctx
=
super
(
Vm
Operation
View
,
self
)
.
get_context_data
(
**
kwargs
)
ctx
=
super
(
Vm
Migrate
View
,
self
)
.
get_context_data
(
**
kwargs
)
ctx
[
'nodes'
]
=
[
n
for
n
in
Node
.
objects
.
filter
(
enabled
=
True
)
if
n
.
state
==
"ONLINE"
]
return
ctx
...
...
@@ -528,6 +528,26 @@ class VmMigrateView(VmOperationView):
return
super
(
VmMigrateView
,
self
)
.
post
(
request
,
extra
,
*
args
,
**
kwargs
)
class
VmSaveView
(
VmOperationView
):
op
=
'save_as_template'
icon
=
'save'
template_name
=
'dashboard/_vm-save.html'
def
get_context_data
(
self
,
**
kwargs
):
ctx
=
super
(
VmSaveView
,
self
)
.
get_context_data
(
**
kwargs
)
ctx
[
'name'
]
=
self
.
get_op
()
.
_rename
(
self
.
object
.
name
)
return
ctx
def
post
(
self
,
request
,
extra
=
None
,
*
args
,
**
kwargs
):
if
extra
is
None
:
extra
=
{}
name
=
self
.
request
.
POST
.
get
(
"name"
)
if
name
:
extra
[
"name"
]
=
name
return
super
(
VmSaveView
,
self
)
.
post
(
request
,
extra
,
*
args
,
**
kwargs
)
vm_ops
=
{
'reset'
:
VmOperationView
.
factory
(
op
=
'reset'
,
icon
=
'bolt'
),
'deploy'
:
VmOperationView
.
factory
(
op
=
'deploy'
,
icon
=
'play'
),
...
...
@@ -535,8 +555,7 @@ vm_ops = {
'reboot'
:
VmOperationView
.
factory
(
op
=
'reboot'
,
icon
=
'refresh'
),
'shut_off'
:
VmOperationView
.
factory
(
op
=
'shut_off'
,
icon
=
'ban-circle'
),
'shutdown'
:
VmOperationView
.
factory
(
op
=
'shutdown'
,
icon
=
'off'
),
'save_as_template'
:
VmOperationView
.
factory
(
op
=
'save_as_template'
,
icon
=
'save'
),
'save_as_template'
:
VmSaveView
,
'destroy'
:
VmOperationView
.
factory
(
op
=
'destroy'
,
icon
=
'remove'
),
'sleep'
:
VmOperationView
.
factory
(
op
=
'sleep'
,
icon
=
'moon'
),
'wake_up'
:
VmOperationView
.
factory
(
op
=
'wake_up'
,
icon
=
'sun'
),
...
...
@@ -2342,7 +2361,7 @@ class DiskRemoveView(DeleteView):
disk
=
self
.
get_object
()
app
=
disk
.
get_appliance
()
app
.
disks
.
remove
(
disk
)
app
.
remove_disk
(
disk
=
disk
,
user
=
request
.
user
)
disk
.
destroy
()
next_url
=
request
.
POST
.
get
(
"next"
)
...
...
circle/firewall/tests/test_firewall.py
View file @
385ad3e3
...
...
@@ -231,6 +231,9 @@ class ReloadTestCase(TestCase):
self
.
rm
.
save
()
self
.
rt
.
save
()
def
tearDown
(
self
):
settings
[
"default_host_groups"
]
=
[]
def
test_bad_aaaa_record
(
self
):
self
.
assertRaises
(
AddrFormatError
,
ipv6_to_octal
,
self
.
rb
.
address
)
...
...
circle/vm/migrations/0022_auto__del_unique_instancetemplate_n.py
0 → 100644
View file @
385ad3e3
This diff is collapsed.
Click to expand it.
circle/vm/models/instance.py
View file @
385ad3e3
...
...
@@ -111,8 +111,7 @@ class InstanceTemplate(AclBase, VirtualMachineDescModel, TimeStampedModel):
(
'operator'
,
_
(
'operator'
)),
(
'owner'
,
_
(
'owner'
)),
# superuser, can delete, delegate perms
)
name
=
CharField
(
max_length
=
100
,
unique
=
True
,
verbose_name
=
_
(
'name'
),
name
=
CharField
(
max_length
=
100
,
verbose_name
=
_
(
'name'
),
help_text
=
_
(
'Human readable name of template.'
))
description
=
TextField
(
verbose_name
=
_
(
'description'
),
blank
=
True
)
parent
=
ForeignKey
(
'self'
,
null
=
True
,
blank
=
True
,
...
...
@@ -166,6 +165,9 @@ class InstanceTemplate(AclBase, VirtualMachineDescModel, TimeStampedModel):
def
get_absolute_url
(
self
):
return
(
'dashboard.views.template-detail'
,
None
,
{
'pk'
:
self
.
pk
})
def
remove_disk
(
self
,
disk
,
**
kwargs
):
self
.
disks
.
remove
(
disk
)
class
Instance
(
AclBase
,
VirtualMachineDescModel
,
StatusModel
,
OperatedMixin
,
TimeStampedModel
):
...
...
circle/vm/operations.py
View file @
385ad3e3
...
...
@@ -80,6 +80,26 @@ class AddInterfaceOperation(InstanceOperation):
register_operation
(
AddInterfaceOperation
)
class
AddDiskOperation
(
InstanceOperation
):
activity_code_suffix
=
'add_disk'
id
=
'add_disk'
name
=
_
(
"add disk"
)
description
=
_
(
"Add the specified disk to the VM."
)
def
check_precond
(
self
):
super
(
AddDiskOperation
,
self
)
.
check_precond
()
# TODO remove check when hot-attach is implemented
if
self
.
instance
.
status
not
in
[
'STOPPED'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
activity
,
user
,
system
,
disk
):
# TODO implement with hot-attach when it'll be available
return
self
.
instance
.
disks
.
add
(
disk
)
register_operation
(
AddDiskOperation
)
class
DeployOperation
(
InstanceOperation
):
activity_code_suffix
=
'deploy'
id
=
'deploy'
...
...
@@ -217,6 +237,26 @@ class RemoveInterfaceOperation(InstanceOperation):
register_operation
(
RemoveInterfaceOperation
)
class
RemoveDiskOperation
(
InstanceOperation
):
activity_code_suffix
=
'remove_disk'
id
=
'remove_disk'
name
=
_
(
"remove disk"
)
description
=
_
(
"Remove the specified disk from the VM."
)
def
check_precond
(
self
):
super
(
RemoveDiskOperation
,
self
)
.
check_precond
()
# TODO remove check when hot-detach is implemented
if
self
.
instance
.
status
not
in
[
'STOPPED'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
activity
,
user
,
system
,
disk
):
# TODO implement with hot-detach when it'll be available
return
self
.
instance
.
disks
.
remove
(
disk
)
register_operation
(
RemoveDiskOperation
)
class
ResetOperation
(
InstanceOperation
):
activity_code_suffix
=
'reset'
id
=
'reset'
...
...
@@ -249,7 +289,7 @@ class SaveAsTemplateOperation(InstanceOperation):
v
=
1
return
"
%
s v
%
d"
%
(
name
,
v
)
def
_operation
(
self
,
activity
,
user
,
system
,
timeout
=
300
,
def
_operation
(
self
,
activity
,
user
,
system
,
timeout
=
300
,
name
=
None
,
with_shutdown
=
True
,
**
kwargs
):
if
with_shutdown
:
try
:
...
...
@@ -266,7 +306,7 @@ class SaveAsTemplateOperation(InstanceOperation):
'description'
:
self
.
instance
.
description
,
'lease'
:
self
.
instance
.
lease
,
# Can be problem in new VM
'max_ram_size'
:
self
.
instance
.
max_ram_size
,
'name'
:
self
.
_rename
(
self
.
instance
.
name
),
'name'
:
name
or
self
.
_rename
(
self
.
instance
.
name
),
'num_cores'
:
self
.
instance
.
num_cores
,
'owner'
:
user
,
'parent'
:
self
.
instance
.
template
,
# Can be problem
...
...
circle/vm/tasks/local_periodic_tasks.py
View file @
385ad3e3
...
...
@@ -27,7 +27,7 @@ def garbage_collector(timeout=15):
now
=
timezone
.
now
()
for
i
in
Instance
.
objects
.
filter
(
destroyed_at
=
None
)
.
all
():
if
i
.
time_of_delete
and
now
>
i
.
time_of_delete
:
i
.
destroy
.
async
()
i
.
destroy
.
async
(
system
=
True
)
logger
.
info
(
"Expired instance
%
d destroyed."
,
i
.
pk
)
try
:
i
.
owner
.
profile
.
notify
(
...
...
@@ -39,7 +39,7 @@ def garbage_collector(timeout=15):
i
.
pk
,
unicode
(
e
))
elif
(
i
.
time_of_suspend
and
now
>
i
.
time_of_suspend
and
i
.
state
==
'RUNNING'
):
i
.
sleep
.
async
()
i
.
sleep
.
async
(
system
=
True
)
logger
.
info
(
"Expired instance
%
d suspended."
%
i
.
pk
)
try
:
i
.
owner
.
profile
.
notify
(
...
...
circle/vm/tests/test_models.py
View file @
385ad3e3
...
...
@@ -39,8 +39,8 @@ class TemplateTestCase(TestCase):
class
InstanceTestCase
(
TestCase
):
def
test_is_running
(
self
):
inst
=
M
ock
(
state
=
'RUNNING'
)
assert
Instance
.
is_running
.
getter
(
inst
)
inst
=
M
agicMock
(
status
=
'RUNNING'
)
self
.
assertTrue
(
Instance
.
is_running
.
fget
(
inst
)
)
def
test_mon_stopped_while_activity_running
(
self
):
node
=
Mock
()
...
...
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