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
2c621f0f
authored
Jul 30, 2014
by
Őry Máté
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature-operations-hre' into 'master'
Handle and use HumanReadableExceptions
parents
8f0c13b8
0385e921
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
126 additions
and
135 deletions
+126
-135
circle/common/models.py
+44
-11
circle/dashboard/tests/test_views.py
+8
-6
circle/dashboard/views.py
+10
-2
circle/vm/models/instance.py
+17
-19
circle/vm/operations.py
+47
-97
No files found.
circle/common/models.py
View file @
2c621f0f
...
@@ -23,6 +23,7 @@ from logging import getLogger
...
@@ -23,6 +23,7 @@ from logging import getLogger
from
time
import
time
from
time
import
time
from
warnings
import
warn
from
warnings
import
warn
from
django.contrib
import
messages
from
django.contrib.auth.models
import
User
from
django.contrib.auth.models
import
User
from
django.core.cache
import
cache
from
django.core.cache
import
cache
from
django.core.serializers.json
import
DjangoJSONEncoder
from
django.core.serializers.json
import
DjangoJSONEncoder
...
@@ -46,17 +47,24 @@ class WorkerNotFound(Exception):
...
@@ -46,17 +47,24 @@ class WorkerNotFound(Exception):
def
activitycontextimpl
(
act
,
on_abort
=
None
,
on_commit
=
None
):
def
activitycontextimpl
(
act
,
on_abort
=
None
,
on_commit
=
None
):
try
:
try
:
try
:
yield
act
yield
act
except
HumanReadableException
as
e
:
result
=
e
raise
except
BaseException
as
e
:
except
BaseException
as
e
:
# BaseException is the common parent of Exception and
# BaseException is the common parent of Exception and
# system-exiting exceptions, e.g. KeyboardInterrupt
# system-exiting exceptions, e.g. KeyboardInterrupt
handler
=
None
if
on_abort
is
None
else
lambda
a
:
on_abort
(
a
,
e
)
result
=
create_readable
(
result
=
create_readable
(
ugettext_noop
(
"Failure."
),
ugettext_noop
(
"Failure."
),
ugettext_noop
(
"Unhandled exception: "
ugettext_noop
(
"Unhandled exception:
%(error)
s"
),
"
%(error)
s"
),
error
=
unicode
(
e
))
error
=
unicode
(
e
))
raise
except
:
logger
.
exception
(
"Failed activity
%
s"
%
unicode
(
act
))
handler
=
None
if
on_abort
is
None
else
lambda
a
:
on_abort
(
a
,
e
)
act
.
finish
(
succeeded
=
False
,
result
=
result
,
event_handler
=
handler
)
act
.
finish
(
succeeded
=
False
,
result
=
result
,
event_handler
=
handler
)
raise
e
raise
else
:
else
:
act
.
finish
(
succeeded
=
True
,
event_handler
=
on_commit
)
act
.
finish
(
succeeded
=
True
,
event_handler
=
on_commit
)
...
@@ -196,6 +204,10 @@ class ActivityModel(TimeStampedModel):
...
@@ -196,6 +204,10 @@ class ActivityModel(TimeStampedModel):
DeprecationWarning
,
stacklevel
=
2
)
DeprecationWarning
,
stacklevel
=
2
)
value
=
create_readable
(
user_text_template
=
""
,
value
=
create_readable
(
user_text_template
=
""
,
admin_text_template
=
value
)
admin_text_template
=
value
)
elif
not
hasattr
(
value
,
"to_dict"
):
warn
(
"Use HumanReadableObject."
,
DeprecationWarning
,
stacklevel
=
2
)
value
=
create_readable
(
user_text_template
=
""
,
admin_text_template
=
unicode
(
value
))
self
.
result_data
=
None
if
value
is
None
else
value
.
to_dict
()
self
.
result_data
=
None
if
value
is
None
else
value
.
to_dict
()
...
@@ -361,8 +373,9 @@ class HumanReadableObject(object):
...
@@ -361,8 +373,9 @@ class HumanReadableObject(object):
@classmethod
@classmethod
def
create
(
cls
,
user_text_template
,
admin_text_template
=
None
,
**
params
):
def
create
(
cls
,
user_text_template
,
admin_text_template
=
None
,
**
params
):
return
cls
(
user_text_template
,
return
cls
(
user_text_template
=
user_text_template
,
admin_text_template
or
user_text_template
,
params
)
admin_text_template
=
(
admin_text_template
or
user_text_template
),
params
=
params
)
def
set
(
self
,
user_text_template
,
admin_text_template
=
None
,
**
params
):
def
set
(
self
,
user_text_template
,
admin_text_template
=
None
,
**
params
):
self
.
_set_values
(
user_text_template
,
self
.
_set_values
(
user_text_template
,
...
@@ -407,10 +420,28 @@ create_readable = HumanReadableObject.create
...
@@ -407,10 +420,28 @@ create_readable = HumanReadableObject.create
class
HumanReadableException
(
HumanReadableObject
,
Exception
):
class
HumanReadableException
(
HumanReadableObject
,
Exception
):
"""HumanReadableObject that is an Exception so can used in except clause.
"""HumanReadableObject that is an Exception so can used in except clause.
"""
"""
pass
def
__init__
(
self
,
level
=
None
,
*
args
,
**
kwargs
):
super
(
HumanReadableException
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
if
level
is
not
None
:
if
hasattr
(
messages
,
level
):
self
.
level
=
level
else
:
raise
ValueError
(
"Level should be the name of an attribute of django."
"contrib.messages (and it should be callable with "
"(request, message)). Like 'error', 'warning'."
)
else
:
self
.
level
=
"error"
def
send_message
(
self
,
request
,
level
=
None
):
if
request
.
user
and
request
.
user
.
is_superuser
:
msg
=
self
.
get_admin_text
()
else
:
msg
=
self
.
get_user_text
()
getattr
(
messages
,
level
or
self
.
level
)(
request
,
msg
)
def
humanize_exception
(
message
,
exception
=
None
,
**
params
):
def
humanize_exception
(
message
,
exception
=
None
,
level
=
None
,
**
params
):
"""Return new dynamic-class exception which is based on
"""Return new dynamic-class exception which is based on
HumanReadableException and the original class with the dict of exception.
HumanReadableException and the original class with the dict of exception.
...
@@ -419,8 +450,10 @@ def humanize_exception(message, exception=None, **params):
...
@@ -419,8 +450,10 @@ def humanize_exception(message, exception=None, **params):
...
...
Welcome!
Welcome!
"""
"""
Ex
=
type
(
"HumanReadable"
+
type
(
exception
)
.
__name__
,
Ex
=
type
(
"HumanReadable"
+
type
(
exception
)
.
__name__
,
(
HumanReadableException
,
type
(
exception
)),
(
HumanReadableException
,
type
(
exception
)),
exception
.
__dict__
)
exception
.
__dict__
)
return
Ex
.
create
(
message
,
**
params
)
ex
=
Ex
.
create
(
message
,
**
params
)
if
level
:
ex
.
level
=
level
return
ex
circle/dashboard/tests/test_views.py
View file @
2c621f0f
...
@@ -529,24 +529,25 @@ class VmDetailTest(LoginMixin, TestCase):
...
@@ -529,24 +529,25 @@ class VmDetailTest(LoginMixin, TestCase):
def
test_permitted_wake_up_wrong_state
(
self
):
def
test_permitted_wake_up_wrong_state
(
self
):
c
=
Client
()
c
=
Client
()
self
.
login
(
c
,
"user2"
)
self
.
login
(
c
,
"user2"
)
with
patch
.
object
(
WakeUpOperation
,
'async'
)
as
mock_method
:
with
patch
.
object
(
WakeUpOperation
,
'async'
)
as
mock_method
,
\
patch
.
object
(
Instance
.
WrongStateError
,
'send_message'
)
as
wro
:
inst
=
Instance
.
objects
.
get
(
pk
=
1
)
inst
=
Instance
.
objects
.
get
(
pk
=
1
)
mock_method
.
side_effect
=
inst
.
wake_up
mock_method
.
side_effect
=
inst
.
wake_up
inst
.
status
=
'RUNNING'
inst
.
status
=
'RUNNING'
inst
.
set_level
(
self
.
u2
,
'owner'
)
inst
.
set_level
(
self
.
u2
,
'owner'
)
with
patch
(
'dashboard.views.messages'
)
as
msg
:
c
.
post
(
"/dashboard/vm/1/op/wake_up/"
)
c
.
post
(
"/dashboard/vm/1/op/wake_up/"
)
assert
msg
.
error
.
called
inst
=
Instance
.
objects
.
get
(
pk
=
1
)
inst
=
Instance
.
objects
.
get
(
pk
=
1
)
self
.
assertEqual
(
inst
.
status
,
'RUNNING'
)
# mocked anyway
self
.
assertEqual
(
inst
.
status
,
'RUNNING'
)
# mocked anyway
assert
mock_method
.
called
assert
mock_method
.
called
assert
wro
.
called
def
test_permitted_wake_up
(
self
):
def
test_permitted_wake_up
(
self
):
c
=
Client
()
c
=
Client
()
self
.
login
(
c
,
"user2"
)
self
.
login
(
c
,
"user2"
)
with
patch
.
object
(
Instance
,
'select_node'
,
return_value
=
None
):
with
patch
.
object
(
Instance
,
'select_node'
,
return_value
=
None
),
\
with
patch
.
object
(
WakeUpOperation
,
'async'
)
as
new_wake_up
:
patch
.
object
(
WakeUpOperation
,
'async'
)
as
new_wake_up
,
\
with
patch
(
'vm.tasks.vm_tasks.wake_up.apply_async'
)
as
wuaa
:
patch
(
'vm.tasks.vm_tasks.wake_up.apply_async'
)
as
wuaa
,
\
patch
.
object
(
Instance
.
WrongStateError
,
'send_message'
)
as
wro
:
inst
=
Instance
.
objects
.
get
(
pk
=
1
)
inst
=
Instance
.
objects
.
get
(
pk
=
1
)
new_wake_up
.
side_effect
=
inst
.
wake_up
new_wake_up
.
side_effect
=
inst
.
wake_up
inst
.
get_remote_queue_name
=
Mock
(
return_value
=
'test'
)
inst
.
get_remote_queue_name
=
Mock
(
return_value
=
'test'
)
...
@@ -559,6 +560,7 @@ class VmDetailTest(LoginMixin, TestCase):
...
@@ -559,6 +560,7 @@ class VmDetailTest(LoginMixin, TestCase):
self
.
assertEqual
(
inst
.
status
,
'RUNNING'
)
self
.
assertEqual
(
inst
.
status
,
'RUNNING'
)
assert
new_wake_up
.
called
assert
new_wake_up
.
called
assert
wuaa
.
called
assert
wuaa
.
called
assert
not
wro
.
called
def
test_unpermitted_wake_up
(
self
):
def
test_unpermitted_wake_up
(
self
):
c
=
Client
()
c
=
Client
()
...
...
circle/dashboard/views.py
View file @
2c621f0f
...
@@ -71,7 +71,7 @@ from .tables import (
...
@@ -71,7 +71,7 @@ from .tables import (
NodeListTable
,
NodeVmListTable
,
TemplateListTable
,
LeaseListTable
,
NodeListTable
,
NodeVmListTable
,
TemplateListTable
,
LeaseListTable
,
GroupListTable
,
UserKeyListTable
GroupListTable
,
UserKeyListTable
)
)
from
common.models
import
HumanReadableObject
from
common.models
import
HumanReadableObject
,
HumanReadableException
from
vm.models
import
(
from
vm.models
import
(
Instance
,
instance_activity
,
InstanceActivity
,
InstanceTemplate
,
Interface
,
Instance
,
instance_activity
,
InstanceActivity
,
InstanceTemplate
,
Interface
,
InterfaceTemplate
,
Lease
,
Node
,
NodeActivity
,
Trait
,
InterfaceTemplate
,
Lease
,
Node
,
NodeActivity
,
Trait
,
...
@@ -562,9 +562,13 @@ class OperationView(RedirectToLoginMixin, DetailView):
...
@@ -562,9 +562,13 @@ class OperationView(RedirectToLoginMixin, DetailView):
done
=
False
done
=
False
try
:
try
:
task
=
self
.
get_op
()
.
async
(
user
=
request
.
user
,
**
extra
)
task
=
self
.
get_op
()
.
async
(
user
=
request
.
user
,
**
extra
)
except
HumanReadableException
as
e
:
e
.
send_message
(
request
)
logger
.
exception
(
"Could not start operation"
)
result
=
e
except
Exception
as
e
:
except
Exception
as
e
:
messages
.
error
(
request
,
_
(
'Could not start operation.'
))
messages
.
error
(
request
,
_
(
'Could not start operation.'
))
logger
.
exception
(
e
)
logger
.
exception
(
"Could not start operation"
)
result
=
e
result
=
e
else
:
else
:
wait
=
self
.
wait_for_result
wait
=
self
.
wait_for_result
...
@@ -575,6 +579,10 @@ class OperationView(RedirectToLoginMixin, DetailView):
...
@@ -575,6 +579,10 @@ class OperationView(RedirectToLoginMixin, DetailView):
except
TimeoutError
:
except
TimeoutError
:
logger
.
debug
(
"Result didn't arrive in
%
ss"
,
logger
.
debug
(
"Result didn't arrive in
%
ss"
,
self
.
wait_for_result
,
exc_info
=
True
)
self
.
wait_for_result
,
exc_info
=
True
)
except
HumanReadableException
as
e
:
e
.
send_message
(
request
)
logger
.
exception
(
e
)
result
=
e
except
Exception
as
e
:
except
Exception
as
e
:
messages
.
error
(
request
,
_
(
'Operation failed.'
))
messages
.
error
(
request
,
_
(
'Operation failed.'
))
logger
.
debug
(
"Operation failed."
,
exc_info
=
True
)
logger
.
debug
(
"Operation failed."
,
exc_info
=
True
)
...
...
circle/vm/models/instance.py
View file @
2c621f0f
...
@@ -41,7 +41,7 @@ from model_utils.models import TimeStampedModel, StatusModel
...
@@ -41,7 +41,7 @@ from model_utils.models import TimeStampedModel, StatusModel
from
taggit.managers
import
TaggableManager
from
taggit.managers
import
TaggableManager
from
acl.models
import
AclBase
from
acl.models
import
AclBase
from
common.models
import
create_readable
from
common.models
import
create_readable
,
HumanReadableException
from
common.operations
import
OperatedMixin
from
common.operations
import
OperatedMixin
from
..tasks
import
vm_tasks
,
agent_tasks
from
..tasks
import
vm_tasks
,
agent_tasks
from
.activity
import
(
ActivityInProgressError
,
instance_activity
,
from
.activity
import
(
ActivityInProgressError
,
instance_activity
,
...
@@ -276,28 +276,26 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
...
@@ -276,28 +276,26 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
verbose_name
=
_
(
'instance'
)
verbose_name
=
_
(
'instance'
)
verbose_name_plural
=
_
(
'instances'
)
verbose_name_plural
=
_
(
'instances'
)
class
Instance
DestroyedError
(
Exception
):
class
Instance
Error
(
HumanReadable
Exception
):
def
__init__
(
self
,
instance
,
message
=
None
):
def
__init__
(
self
,
instance
,
params
=
None
,
level
=
None
,
**
kwargs
):
if
message
is
None
:
kwargs
.
update
(
params
or
{})
message
=
(
"The instance (
%
s) has already been destroyed."
self
.
instance
=
kwargs
[
"instance"
]
=
instance
%
instance
)
super
(
Instance
.
InstanceError
,
self
)
.
__init__
(
level
,
self
.
message
,
self
.
message
,
kwargs
)
Exception
.
__init__
(
self
,
message
)
class
InstanceDestroyedError
(
InstanceError
):
message
=
ugettext_noop
(
"Instance
%(instance)
s has already been destroyed."
)
self
.
instance
=
instance
class
WrongStateError
(
InstanceError
):
message
=
ugettext_noop
(
"Current state (
%(state)
s) of instance
%(instance)
s is "
"inappropriate for the invoked operation."
)
class
WrongStateError
(
Exception
):
def
__init__
(
self
,
instance
,
params
=
None
,
**
kwargs
):
super
(
Instance
.
WrongStateError
,
self
)
.
__init__
(
def
__init__
(
self
,
instance
,
message
=
None
):
instance
,
params
,
state
=
instance
.
status
)
if
message
is
None
:
message
=
(
"The instance's current state (
%
s) is "
"inappropriate for the invoked operation."
%
instance
.
status
)
Exception
.
__init__
(
self
,
message
)
self
.
instance
=
instance
def
__unicode__
(
self
):
def
__unicode__
(
self
):
parts
=
(
self
.
name
,
"("
+
str
(
self
.
id
)
+
")"
)
parts
=
(
self
.
name
,
"("
+
str
(
self
.
id
)
+
")"
)
...
...
circle/vm/operations.py
View file @
2c621f0f
...
@@ -26,7 +26,7 @@ from django.utils.translation import ugettext_lazy as _, ugettext_noop
...
@@ -26,7 +26,7 @@ from django.utils.translation import ugettext_lazy as _, ugettext_noop
from
celery.exceptions
import
TimeLimitExceeded
from
celery.exceptions
import
TimeLimitExceeded
from
common.models
import
create_readable
from
common.models
import
create_readable
,
humanize_exception
from
common.operations
import
Operation
,
register_operation
from
common.operations
import
Operation
,
register_operation
from
.tasks.local_tasks
import
(
from
.tasks.local_tasks
import
(
abortable_async_instance_operation
,
abortable_async_node_operation
,
abortable_async_instance_operation
,
abortable_async_node_operation
,
...
@@ -45,6 +45,8 @@ class InstanceOperation(Operation):
...
@@ -45,6 +45,8 @@ class InstanceOperation(Operation):
async_operation
=
abortable_async_instance_operation
async_operation
=
abortable_async_instance_operation
host_cls
=
Instance
host_cls
=
Instance
concurrency_check
=
True
concurrency_check
=
True
accept_states
=
None
deny_states
=
None
def
__init__
(
self
,
instance
):
def
__init__
(
self
,
instance
):
super
(
InstanceOperation
,
self
)
.
__init__
(
subject
=
instance
)
super
(
InstanceOperation
,
self
)
.
__init__
(
subject
=
instance
)
...
@@ -53,11 +55,26 @@ class InstanceOperation(Operation):
...
@@ -53,11 +55,26 @@ class InstanceOperation(Operation):
def
check_precond
(
self
):
def
check_precond
(
self
):
if
self
.
instance
.
destroyed_at
:
if
self
.
instance
.
destroyed_at
:
raise
self
.
instance
.
InstanceDestroyedError
(
self
.
instance
)
raise
self
.
instance
.
InstanceDestroyedError
(
self
.
instance
)
if
self
.
accept_states
:
if
self
.
instance
.
status
not
in
self
.
accept_states
:
logger
.
debug
(
"precond failed for
%
s:
%
s not in
%
s"
,
unicode
(
self
.
__class__
),
unicode
(
self
.
instance
.
status
),
unicode
(
self
.
accept_states
))
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
if
self
.
deny_states
:
if
self
.
instance
.
status
in
self
.
deny_states
:
logger
.
debug
(
"precond failed for
%
s:
%
s in
%
s"
,
unicode
(
self
.
__class__
),
unicode
(
self
.
instance
.
status
),
unicode
(
self
.
accept_states
))
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
check_auth
(
self
,
user
):
def
check_auth
(
self
,
user
):
if
not
self
.
instance
.
has_level
(
user
,
self
.
acl_level
):
if
not
self
.
instance
.
has_level
(
user
,
self
.
acl_level
):
raise
PermissionDenied
(
"
%
s doesn't have the required ACL level."
%
raise
humanize_exception
(
ugettext_noop
(
user
)
"
%(acl_level)
s level is required for this operation."
),
PermissionDenied
(),
acl_level
=
self
.
acl_level
)
super
(
InstanceOperation
,
self
)
.
check_auth
(
user
=
user
)
super
(
InstanceOperation
,
self
)
.
check_auth
(
user
=
user
)
...
@@ -94,6 +111,7 @@ class AddInterfaceOperation(InstanceOperation):
...
@@ -94,6 +111,7 @@ class AddInterfaceOperation(InstanceOperation):
description
=
_
(
"Add a new network interface for the specified VLAN to "
description
=
_
(
"Add a new network interface for the specified VLAN to "
"the VM."
)
"the VM."
)
required_perms
=
()
required_perms
=
()
accept_states
=
(
'STOPPED'
,
'PENDING'
,
'RUNNING'
)
def
rollback
(
self
,
net
,
activity
):
def
rollback
(
self
,
net
,
activity
):
with
activity
.
sub_activity
(
with
activity
.
sub_activity
(
...
@@ -102,14 +120,11 @@ class AddInterfaceOperation(InstanceOperation):
...
@@ -102,14 +120,11 @@ class AddInterfaceOperation(InstanceOperation):
net
.
destroy
()
net
.
destroy
()
net
.
delete
()
net
.
delete
()
def
check_precond
(
self
):
super
(
AddInterfaceOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'STOPPED'
,
'PENDING'
,
'RUNNING'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
activity
,
user
,
system
,
vlan
,
managed
=
None
):
def
_operation
(
self
,
activity
,
user
,
system
,
vlan
,
managed
=
None
):
if
not
vlan
.
has_level
(
user
,
'user'
):
if
not
vlan
.
has_level
(
user
,
'user'
):
raise
PermissionDenied
()
raise
humanize_exception
(
ugettext_noop
(
"User acces to vlan
%(vlan)
s is required."
),
PermissionDenied
(),
vlan
=
vlan
)
if
managed
is
None
:
if
managed
is
None
:
managed
=
vlan
.
managed
managed
=
vlan
.
managed
...
@@ -141,11 +156,7 @@ class CreateDiskOperation(InstanceOperation):
...
@@ -141,11 +156,7 @@ class CreateDiskOperation(InstanceOperation):
name
=
_
(
"create disk"
)
name
=
_
(
"create disk"
)
description
=
_
(
"Create empty disk for the VM."
)
description
=
_
(
"Create empty disk for the VM."
)
required_perms
=
(
'storage.create_empty_disk'
,
)
required_perms
=
(
'storage.create_empty_disk'
,
)
accept_states
=
(
'STOPPED'
,
'PENDING'
,
'RUNNING'
)
def
check_precond
(
self
):
super
(
CreateDiskOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'STOPPED'
,
'PENDING'
,
'RUNNING'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
user
,
size
,
activity
,
name
=
None
):
def
_operation
(
self
,
user
,
size
,
activity
,
name
=
None
):
from
storage.models
import
Disk
from
storage.models
import
Disk
...
@@ -183,11 +194,7 @@ class DownloadDiskOperation(InstanceOperation):
...
@@ -183,11 +194,7 @@ class DownloadDiskOperation(InstanceOperation):
abortable
=
True
abortable
=
True
has_percentage
=
True
has_percentage
=
True
required_perms
=
(
'storage.download_disk'
,
)
required_perms
=
(
'storage.download_disk'
,
)
accept_states
=
(
'STOPPED'
,
'PENDING'
,
'RUNNING'
)
def
check_precond
(
self
):
super
(
DownloadDiskOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'STOPPED'
,
'PENDING'
,
'RUNNING'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
user
,
url
,
task
,
activity
,
name
=
None
):
def
_operation
(
self
,
user
,
url
,
task
,
activity
,
name
=
None
):
activity
.
result
=
url
activity
.
result
=
url
...
@@ -218,11 +225,7 @@ class DeployOperation(InstanceOperation):
...
@@ -218,11 +225,7 @@ class DeployOperation(InstanceOperation):
name
=
_
(
"deploy"
)
name
=
_
(
"deploy"
)
description
=
_
(
"Deploy new virtual machine with network."
)
description
=
_
(
"Deploy new virtual machine with network."
)
required_perms
=
()
required_perms
=
()
deny_states
=
(
'SUSPENDED'
,
'RUNNING'
)
def
check_precond
(
self
):
super
(
DeployOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
in
[
'RUNNING'
,
'SUSPENDED'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
is_preferred
(
self
):
def
is_preferred
(
self
):
return
self
.
instance
.
status
in
(
self
.
instance
.
STATUS
.
STOPPED
,
return
self
.
instance
.
status
in
(
self
.
instance
.
STATUS
.
STOPPED
,
...
@@ -323,6 +326,7 @@ class MigrateOperation(InstanceOperation):
...
@@ -323,6 +326,7 @@ class MigrateOperation(InstanceOperation):
name
=
_
(
"migrate"
)
name
=
_
(
"migrate"
)
description
=
_
(
"Live migrate running VM to another node."
)
description
=
_
(
"Live migrate running VM to another node."
)
required_perms
=
()
required_perms
=
()
accept_states
=
(
'RUNNING'
,
)
def
rollback
(
self
,
activity
):
def
rollback
(
self
,
activity
):
with
activity
.
sub_activity
(
with
activity
.
sub_activity
(
...
@@ -330,11 +334,6 @@ class MigrateOperation(InstanceOperation):
...
@@ -330,11 +334,6 @@ class MigrateOperation(InstanceOperation):
"redeploy network (rollback)"
)):
"redeploy network (rollback)"
)):
self
.
instance
.
deploy_net
()
self
.
instance
.
deploy_net
()
def
check_precond
(
self
):
super
(
MigrateOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'RUNNING'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
check_auth
(
self
,
user
):
def
check_auth
(
self
,
user
):
if
not
user
.
is_superuser
:
if
not
user
.
is_superuser
:
raise
PermissionDenied
()
raise
PermissionDenied
()
...
@@ -384,11 +383,7 @@ class RebootOperation(InstanceOperation):
...
@@ -384,11 +383,7 @@ class RebootOperation(InstanceOperation):
name
=
_
(
"reboot"
)
name
=
_
(
"reboot"
)
description
=
_
(
"Reboot virtual machine with Ctrl+Alt+Del signal."
)
description
=
_
(
"Reboot virtual machine with Ctrl+Alt+Del signal."
)
required_perms
=
()
required_perms
=
()
accept_states
=
(
'RUNNING'
,
)
def
check_precond
(
self
):
super
(
RebootOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'RUNNING'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
timeout
=
5
):
def
_operation
(
self
,
timeout
=
5
):
self
.
instance
.
reboot_vm
(
timeout
=
timeout
)
self
.
instance
.
reboot_vm
(
timeout
=
timeout
)
...
@@ -403,11 +398,7 @@ class RemoveInterfaceOperation(InstanceOperation):
...
@@ -403,11 +398,7 @@ class RemoveInterfaceOperation(InstanceOperation):
name
=
_
(
"remove interface"
)
name
=
_
(
"remove interface"
)
description
=
_
(
"Remove the specified network interface from the VM."
)
description
=
_
(
"Remove the specified network interface from the VM."
)
required_perms
=
()
required_perms
=
()
accept_states
=
(
'STOPPED'
,
'PENDING'
,
'RUNNING'
)
def
check_precond
(
self
):
super
(
RemoveInterfaceOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'STOPPED'
,
'PENDING'
,
'RUNNING'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
activity
,
user
,
system
,
interface
):
def
_operation
(
self
,
activity
,
user
,
system
,
interface
):
if
self
.
instance
.
is_running
:
if
self
.
instance
.
is_running
:
...
@@ -428,11 +419,7 @@ class RemoveDiskOperation(InstanceOperation):
...
@@ -428,11 +419,7 @@ class RemoveDiskOperation(InstanceOperation):
name
=
_
(
"remove disk"
)
name
=
_
(
"remove disk"
)
description
=
_
(
"Remove the specified disk from the VM."
)
description
=
_
(
"Remove the specified disk from the VM."
)
required_perms
=
()
required_perms
=
()
accept_states
=
(
'STOPPED'
,
'PENDING'
,
'RUNNING'
)
def
check_precond
(
self
):
super
(
RemoveDiskOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'STOPPED'
,
'PENDING'
,
'RUNNING'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
activity
,
user
,
system
,
disk
):
def
_operation
(
self
,
activity
,
user
,
system
,
disk
):
if
self
.
instance
.
is_running
and
disk
.
type
not
in
[
"iso"
]:
if
self
.
instance
.
is_running
and
disk
.
type
not
in
[
"iso"
]:
...
@@ -450,11 +437,7 @@ class ResetOperation(InstanceOperation):
...
@@ -450,11 +437,7 @@ class ResetOperation(InstanceOperation):
name
=
_
(
"reset"
)
name
=
_
(
"reset"
)
description
=
_
(
"Reset virtual machine (reset button)."
)
description
=
_
(
"Reset virtual machine (reset button)."
)
required_perms
=
()
required_perms
=
()
accept_states
=
(
'RUNNING'
,
)
def
check_precond
(
self
):
super
(
ResetOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'RUNNING'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
timeout
=
5
):
def
_operation
(
self
,
timeout
=
5
):
self
.
instance
.
reset_vm
(
timeout
=
timeout
)
self
.
instance
.
reset_vm
(
timeout
=
timeout
)
...
@@ -473,6 +456,7 @@ class SaveAsTemplateOperation(InstanceOperation):
...
@@ -473,6 +456,7 @@ class SaveAsTemplateOperation(InstanceOperation):
"""
)
"""
)
abortable
=
True
abortable
=
True
required_perms
=
(
'vm.create_template'
,
)
required_perms
=
(
'vm.create_template'
,
)
accept_states
=
(
'RUNNING'
,
'PENDING'
,
'STOPPED'
)
def
is_preferred
(
self
):
def
is_preferred
(
self
):
return
(
self
.
instance
.
is_base
and
return
(
self
.
instance
.
is_base
and
...
@@ -493,11 +477,6 @@ class SaveAsTemplateOperation(InstanceOperation):
...
@@ -493,11 +477,6 @@ class SaveAsTemplateOperation(InstanceOperation):
for
disk
in
self
.
disks
:
for
disk
in
self
.
disks
:
disk
.
destroy
()
disk
.
destroy
()
def
check_precond
(
self
):
super
(
SaveAsTemplateOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'RUNNING'
,
'PENDING'
,
'STOPPED'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
activity
,
user
,
system
,
timeout
=
300
,
name
=
None
,
def
_operation
(
self
,
activity
,
user
,
system
,
timeout
=
300
,
name
=
None
,
with_shutdown
=
True
,
task
=
None
,
**
kwargs
):
with_shutdown
=
True
,
task
=
None
,
**
kwargs
):
if
with_shutdown
:
if
with_shutdown
:
...
@@ -567,11 +546,7 @@ class ShutdownOperation(InstanceOperation):
...
@@ -567,11 +546,7 @@ class ShutdownOperation(InstanceOperation):
description
=
_
(
"Shutdown virtual machine with ACPI signal."
)
description
=
_
(
"Shutdown virtual machine with ACPI signal."
)
abortable
=
True
abortable
=
True
required_perms
=
()
required_perms
=
()
accept_states
=
(
'RUNNING'
,
)
def
check_precond
(
self
):
super
(
ShutdownOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'RUNNING'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
on_commit
(
self
,
activity
):
def
on_commit
(
self
,
activity
):
activity
.
resultant_state
=
'STOPPED'
activity
.
resultant_state
=
'STOPPED'
...
@@ -591,11 +566,7 @@ class ShutOffOperation(InstanceOperation):
...
@@ -591,11 +566,7 @@ class ShutOffOperation(InstanceOperation):
name
=
_
(
"shut off"
)
name
=
_
(
"shut off"
)
description
=
_
(
"Shut off VM (plug-out)."
)
description
=
_
(
"Shut off VM (plug-out)."
)
required_perms
=
()
required_perms
=
()
accept_states
=
(
'RUNNING'
,
)
def
check_precond
(
self
):
super
(
ShutOffOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'RUNNING'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
on_commit
(
self
,
activity
):
def
on_commit
(
self
,
activity
):
activity
.
resultant_state
=
'STOPPED'
activity
.
resultant_state
=
'STOPPED'
...
@@ -623,16 +594,12 @@ class SleepOperation(InstanceOperation):
...
@@ -623,16 +594,12 @@ class SleepOperation(InstanceOperation):
name
=
_
(
"sleep"
)
name
=
_
(
"sleep"
)
description
=
_
(
"Suspend virtual machine with memory dump."
)
description
=
_
(
"Suspend virtual machine with memory dump."
)
required_perms
=
()
required_perms
=
()
accept_states
=
(
'RUNNING'
,
)
def
is_preferred
(
self
):
def
is_preferred
(
self
):
return
(
not
self
.
instance
.
is_base
and
return
(
not
self
.
instance
.
is_base
and
self
.
instance
.
status
==
self
.
instance
.
STATUS
.
RUNNING
)
self
.
instance
.
status
==
self
.
instance
.
STATUS
.
RUNNING
)
def
check_precond
(
self
):
super
(
SleepOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'RUNNING'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
on_abort
(
self
,
activity
,
error
):
def
on_abort
(
self
,
activity
,
error
):
if
isinstance
(
error
,
TimeLimitExceeded
):
if
isinstance
(
error
,
TimeLimitExceeded
):
activity
.
resultant_state
=
None
activity
.
resultant_state
=
None
...
@@ -670,15 +637,11 @@ class WakeUpOperation(InstanceOperation):
...
@@ -670,15 +637,11 @@ class WakeUpOperation(InstanceOperation):
Power on Virtual Machine and load its memory from dump.
Power on Virtual Machine and load its memory from dump.
"""
)
"""
)
required_perms
=
()
required_perms
=
()
accept_states
=
(
'SUSPENDED'
,
)
def
is_preferred
(
self
):
def
is_preferred
(
self
):
return
self
.
instance
.
status
==
self
.
instance
.
STATUS
.
SUSPENDED
return
self
.
instance
.
status
==
self
.
instance
.
STATUS
.
SUSPENDED
def
check_precond
(
self
):
super
(
WakeUpOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'SUSPENDED'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
on_abort
(
self
,
activity
,
error
):
def
on_abort
(
self
,
activity
,
error
):
activity
.
resultant_state
=
'ERROR'
activity
.
resultant_state
=
'ERROR'
...
@@ -718,11 +681,6 @@ class RenewOperation(InstanceOperation):
...
@@ -718,11 +681,6 @@ class RenewOperation(InstanceOperation):
required_perms
=
()
required_perms
=
()
concurrency_check
=
False
concurrency_check
=
False
def
check_precond
(
self
):
super
(
RenewOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
==
'DESTROYED'
:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
lease
=
None
):
def
_operation
(
self
,
lease
=
None
):
(
self
.
instance
.
time_of_suspend
,
(
self
.
instance
.
time_of_suspend
,
self
.
instance
.
time_of_delete
)
=
self
.
instance
.
get_renew_times
(
lease
)
self
.
instance
.
time_of_delete
)
=
self
.
instance
.
get_renew_times
(
lease
)
...
@@ -790,7 +748,8 @@ class FlushOperation(NodeOperation):
...
@@ -790,7 +748,8 @@ class FlushOperation(NodeOperation):
def
check_auth
(
self
,
user
):
def
check_auth
(
self
,
user
):
if
not
user
.
is_superuser
:
if
not
user
.
is_superuser
:
raise
PermissionDenied
()
raise
humanize_exception
(
ugettext_noop
(
"Superuser privileges are required."
),
PermissionDenied
())
super
(
FlushOperation
,
self
)
.
check_auth
(
user
=
user
)
super
(
FlushOperation
,
self
)
.
check_auth
(
user
=
user
)
...
@@ -815,11 +774,7 @@ class ScreenshotOperation(InstanceOperation):
...
@@ -815,11 +774,7 @@ class ScreenshotOperation(InstanceOperation):
description
=
_
(
"Get screenshot"
)
description
=
_
(
"Get screenshot"
)
acl_level
=
"owner"
acl_level
=
"owner"
required_perms
=
()
required_perms
=
()
accept_states
=
(
'RUNNING'
,
)
def
check_precond
(
self
):
super
(
ScreenshotOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
'RUNNING'
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
):
def
_operation
(
self
):
return
self
.
instance
.
get_screenshot
(
timeout
=
20
)
return
self
.
instance
.
get_screenshot
(
timeout
=
20
)
...
@@ -835,10 +790,13 @@ class RecoverOperation(InstanceOperation):
...
@@ -835,10 +790,13 @@ class RecoverOperation(InstanceOperation):
description
=
_
(
"Recover virtual machine from destroyed state."
)
description
=
_
(
"Recover virtual machine from destroyed state."
)
acl_level
=
"owner"
acl_level
=
"owner"
required_perms
=
(
'vm.recover'
,
)
required_perms
=
(
'vm.recover'
,
)
accept_states
=
(
'DESTROYED'
,
)
def
check_precond
(
self
):
def
check_precond
(
self
):
if
not
self
.
instance
.
destroyed_at
:
try
:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
super
(
RecoverOperation
,
self
)
.
check_precond
()
except
Instance
.
InstanceDestroyedError
:
pass
def
on_commit
(
self
,
activity
):
def
on_commit
(
self
,
activity
):
activity
.
resultant_state
=
'PENDING'
activity
.
resultant_state
=
'PENDING'
...
@@ -862,11 +820,7 @@ class ResourcesOperation(InstanceOperation):
...
@@ -862,11 +820,7 @@ class ResourcesOperation(InstanceOperation):
description
=
_
(
"Change resources"
)
description
=
_
(
"Change resources"
)
acl_level
=
"owner"
acl_level
=
"owner"
required_perms
=
(
'vm.change_resources'
,
)
required_perms
=
(
'vm.change_resources'
,
)
accept_states
=
(
'STOPPED'
,
'PENDING'
,
)
def
check_precond
(
self
):
super
(
ResourcesOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
"STOPPED"
,
"PENDING"
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
,
user
,
num_cores
,
ram_size
,
max_ram_size
,
priority
):
def
_operation
(
self
,
user
,
num_cores
,
ram_size
,
max_ram_size
,
priority
):
...
@@ -889,11 +843,7 @@ class PasswordResetOperation(InstanceOperation):
...
@@ -889,11 +843,7 @@ class PasswordResetOperation(InstanceOperation):
description
=
_
(
"Password reset"
)
description
=
_
(
"Password reset"
)
acl_level
=
"owner"
acl_level
=
"owner"
required_perms
=
()
required_perms
=
()
accept_states
=
(
'RUNNING'
,
)
def
check_precond
(
self
):
super
(
PasswordResetOperation
,
self
)
.
check_precond
()
if
self
.
instance
.
status
not
in
[
"RUNNING"
]:
raise
self
.
instance
.
WrongStateError
(
self
.
instance
)
def
_operation
(
self
):
def
_operation
(
self
):
self
.
instance
.
pw
=
pwgen
()
self
.
instance
.
pw
=
pwgen
()
...
...
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