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
4c1443f2
authored
Dec 11, 2017
by
cloud
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dashboard, storage, vm: add snapshot limit and minor fixes
parent
895d9a95
Pipeline
#626
passed with stage
in 0 seconds
Changes
7
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
61 additions
and
25 deletions
+61
-25
circle/dashboard/forms.py
+8
-1
circle/dashboard/migrations/0007_profile_disk_snapshot_limit.py
+20
-0
circle/dashboard/models.py
+5
-1
circle/dashboard/static/dashboard/dashboard.less
+2
-8
circle/dashboard/views/vm.py
+6
-5
circle/storage/models.py
+2
-2
circle/vm/operations.py
+18
-8
No files found.
circle/dashboard/forms.py
View file @
4c1443f2
...
@@ -1386,6 +1386,9 @@ class UserEditForm(forms.ModelForm):
...
@@ -1386,6 +1386,9 @@ class UserEditForm(forms.ModelForm):
label
=
_
(
'Two-factor authentication secret'
),
label
=
_
(
'Two-factor authentication secret'
),
help_text
=
_
(
"Remove the secret key to disable two-factor "
help_text
=
_
(
"Remove the secret key to disable two-factor "
"authentication for this user."
),
required
=
False
)
"authentication for this user."
),
required
=
False
)
disk_snapshot_limit
=
forms
.
IntegerField
(
label
=
_
(
'Snapshot limit per disk'
),
min_value
=
0
,
widget
=
NumberInput
)
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
UserEditForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
super
(
UserEditForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
...
@@ -1393,11 +1396,13 @@ class UserEditForm(forms.ModelForm):
...
@@ -1393,11 +1396,13 @@ class UserEditForm(forms.ModelForm):
self
.
instance
.
profile
.
instance_limit
)
self
.
instance
.
profile
.
instance_limit
)
self
.
fields
[
"two_factor_secret"
]
.
initial
=
(
self
.
fields
[
"two_factor_secret"
]
.
initial
=
(
self
.
instance
.
profile
.
two_factor_secret
)
self
.
instance
.
profile
.
two_factor_secret
)
self
.
fields
[
"disk_snapshot_limit"
]
.
initial
=
(
self
.
instance
.
profile
.
disk_snapshot_limit
)
class
Meta
:
class
Meta
:
model
=
User
model
=
User
fields
=
(
'email'
,
'first_name'
,
'last_name'
,
'instance_limit'
,
fields
=
(
'email'
,
'first_name'
,
'last_name'
,
'instance_limit'
,
'is_active'
,
"two_factor_secret"
,
)
'
disk_snapshot_limit'
,
'
is_active'
,
"two_factor_secret"
,
)
def
save
(
self
,
commit
=
True
):
def
save
(
self
,
commit
=
True
):
user
=
super
(
UserEditForm
,
self
)
.
save
()
user
=
super
(
UserEditForm
,
self
)
.
save
()
...
@@ -1405,6 +1410,8 @@ class UserEditForm(forms.ModelForm):
...
@@ -1405,6 +1410,8 @@ class UserEditForm(forms.ModelForm):
self
.
cleaned_data
[
'instance_limit'
]
or
None
)
self
.
cleaned_data
[
'instance_limit'
]
or
None
)
user
.
profile
.
two_factor_secret
=
(
user
.
profile
.
two_factor_secret
=
(
self
.
cleaned_data
[
'two_factor_secret'
]
or
None
)
self
.
cleaned_data
[
'two_factor_secret'
]
or
None
)
user
.
profile
.
disk_snapshot_limit
=
(
self
.
cleaned_data
[
'disk_snapshot_limit'
]
or
None
)
user
.
profile
.
save
()
user
.
profile
.
save
()
return
user
return
user
...
...
circle/dashboard/migrations/0007_profile_disk_snapshot_limit.py
0 → 100644
View file @
4c1443f2
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-11 21:24
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'dashboard'
,
'0006_auto_20170707_1909'
),
]
operations
=
[
migrations
.
AddField
(
model_name
=
'profile'
,
name
=
'disk_snapshot_limit'
,
field
=
models
.
IntegerField
(
default
=
3
,
help_text
=
'Snapshot limit per disk.'
,
verbose_name
=
'disk snapshot limit'
),
),
]
circle/dashboard/models.py
View file @
4c1443f2
...
@@ -200,6 +200,10 @@ class Profile(Model):
...
@@ -200,6 +200,10 @@ class Profile(Model):
verbose_name
=
_
(
'disk quota'
),
verbose_name
=
_
(
'disk quota'
),
default
=
2048
*
1024
*
1024
,
default
=
2048
*
1024
*
1024
,
help_text
=
_
(
'Disk quota in mebibytes.'
))
help_text
=
_
(
'Disk quota in mebibytes.'
))
disk_snapshot_limit
=
IntegerField
(
verbose_name
=
_
(
'disk snapshot limit'
),
default
=
3
,
help_text
=
_
(
'Snapshot limit per disk.'
))
two_factor_secret
=
CharField
(
two_factor_secret
=
CharField
(
verbose_name
=
_
(
"two factor secret key"
),
verbose_name
=
_
(
"two factor secret key"
),
max_length
=
32
,
null
=
True
,
blank
=
True
,
max_length
=
32
,
null
=
True
,
blank
=
True
,
...
@@ -332,7 +336,7 @@ def create_profile(user):
...
@@ -332,7 +336,7 @@ def create_profile(user):
try
:
try
:
Store
(
user
)
.
create_user
(
profile
.
smb_password
,
None
,
profile
.
disk_quota
)
Store
(
user
)
.
create_user
(
profile
.
smb_password
,
None
,
profile
.
disk_quota
)
except
:
except
Exception
:
logger
.
exception
(
"Can't create user
%
s"
,
unicode
(
user
))
logger
.
exception
(
"Can't create user
%
s"
,
unicode
(
user
))
return
created
return
created
...
...
circle/dashboard/static/dashboard/dashboard.less
View file @
4c1443f2
...
@@ -1536,16 +1536,10 @@ textarea[name="new_members"] {
...
@@ -1536,16 +1536,10 @@ textarea[name="new_members"] {
background: gray;
background: gray;
}
}
.show-snapshot-btn {
margin-top: 10px;
}
.disk-create_snapshot-btn {
margin-right: 5px;
}
.snapshot-table {
.snapshot-table {
background: white;
background: white;
}
#two-factor-qr {
#two-factor-qr {
text-align: center;
text-align: center;
...
...
circle/dashboard/views/vm.py
View file @
4c1443f2
...
@@ -248,7 +248,7 @@ class VmDetailView(GraphMixin, CheckedDetailView):
...
@@ -248,7 +248,7 @@ class VmDetailView(GraphMixin, CheckedDetailView):
try
:
try
:
messages
.
error
(
request
,
message
)
messages
.
error
(
request
,
message
)
except
:
except
Exception
:
pass
pass
return
redirect
(
reverse_lazy
(
"dashboard.views.detail"
,
return
redirect
(
reverse_lazy
(
"dashboard.views.detail"
,
...
@@ -263,7 +263,7 @@ class VmDetailView(GraphMixin, CheckedDetailView):
...
@@ -263,7 +263,7 @@ class VmDetailView(GraphMixin, CheckedDetailView):
self
.
object
.
tags
.
remove
(
to_remove
)
self
.
object
.
tags
.
remove
(
to_remove
)
message
=
u"Success"
message
=
u"Success"
except
:
# note this won't really happen
except
Exception
:
# note this won't really happen
message
=
u"Not success"
message
=
u"Not success"
if
request
.
is_ajax
():
if
request
.
is_ajax
():
...
@@ -808,7 +808,8 @@ vm_ops = OrderedDict([
...
@@ -808,7 +808,8 @@ vm_ops = OrderedDict([
)),
)),
(
'create_snapshot'
,
VmDiskModifyView
.
factory
(
(
'create_snapshot'
,
VmDiskModifyView
.
factory
(
op
=
'create_snapshot'
,
icon
=
'camera'
,
effect
=
'success'
,
op
=
'create_snapshot'
,
icon
=
'camera'
,
effect
=
'success'
,
form_class
=
VmSnapshotDiskForm
)),
form_class
=
VmSnapshotDiskForm
,
)),
(
'remove_snapshot'
,
VmCommonSnapshotDiskView
.
factory
(
(
'remove_snapshot'
,
VmCommonSnapshotDiskView
.
factory
(
op
=
'remove_snapshot'
,
icon
=
'times'
,
effect
=
'danger'
)),
op
=
'remove_snapshot'
,
icon
=
'times'
,
effect
=
'danger'
)),
(
'revert_snapshot'
,
VmCommonSnapshotDiskView
.
factory
(
(
'revert_snapshot'
,
VmCommonSnapshotDiskView
.
factory
(
...
@@ -1182,7 +1183,7 @@ class VmCreate(LoginRequiredMixin, TemplateView):
...
@@ -1182,7 +1183,7 @@ class VmCreate(LoginRequiredMixin, TemplateView):
else
:
else
:
try
:
try
:
amount
=
int
(
request
.
POST
.
get
(
"amount"
,
1
))
amount
=
int
(
request
.
POST
.
get
(
"amount"
,
1
))
except
:
except
Exception
:
amount
=
limit
# TODO this should definitely use a Form
amount
=
limit
# TODO this should definitely use a Form
current
=
Instance
.
active
.
filter
(
owner
=
user
)
.
count
()
current
=
Instance
.
active
.
filter
(
owner
=
user
)
.
count
()
logger
.
debug
(
'current use:
%
d, limit:
%
d'
,
current
,
limit
)
logger
.
debug
(
'current use:
%
d, limit:
%
d'
,
current
,
limit
)
...
@@ -1207,7 +1208,7 @@ def get_vm_screenshot(request, pk):
...
@@ -1207,7 +1208,7 @@ def get_vm_screenshot(request, pk):
instance
=
get_object_or_404
(
Instance
,
pk
=
pk
)
instance
=
get_object_or_404
(
Instance
,
pk
=
pk
)
try
:
try
:
image
=
instance
.
screenshot
(
user
=
request
.
user
)
.
getvalue
()
image
=
instance
.
screenshot
(
user
=
request
.
user
)
.
getvalue
()
except
:
except
Exception
:
# TODO handle this better
# TODO handle this better
raise
Http404
()
raise
Http404
()
...
...
circle/storage/models.py
View file @
4c1443f2
...
@@ -564,7 +564,7 @@ class Disk(TimeStampedModel):
...
@@ -564,7 +564,7 @@ class Disk(TimeStampedModel):
disk
.
destroy
()
disk
.
destroy
()
raise
humanize_exception
(
ugettext_noop
(
raise
humanize_exception
(
ugettext_noop
(
"Operation aborted by user."
),
e
)
"Operation aborted by user."
),
e
)
except
:
except
Exception
:
disk
.
destroy
()
disk
.
destroy
()
raise
raise
disk
.
is_ready
=
True
disk
.
is_ready
=
True
...
@@ -581,4 +581,4 @@ class Disk(TimeStampedModel):
...
@@ -581,4 +581,4 @@ class Disk(TimeStampedModel):
@property
@property
def
is_read_only
(
self
):
def
is_read_only
(
self
):
return
not
self
.
type
in
(
'qcow2-norm'
,
'raw-rw'
,
)
return
self
.
type
not
in
(
'qcow2-norm'
,
'raw-rw'
,
)
circle/vm/operations.py
View file @
4c1443f2
...
@@ -321,6 +321,16 @@ class CreateSnapshotDiskOperation(RemoteSnapshotDiskOperation):
...
@@ -321,6 +321,16 @@ class CreateSnapshotDiskOperation(RemoteSnapshotDiskOperation):
self
.
disk
.
did_have_snapshot
=
True
self
.
disk
.
did_have_snapshot
=
True
self
.
disk
.
save
()
self
.
disk
.
save
()
def
_operation
(
self
,
disk
,
**
kwargs
):
user
=
kwargs
.
get
(
'user'
)
snap_num
=
len
(
disk
.
list_snapshots
())
limit
=
user
.
profile
.
disk_snapshot_limit
if
snap_num
==
limit
:
raise
humanize_exception
(
ugettext_noop
(
"Snapshot limit (
%(limit)
d) exceeded."
),
PermissionDenied
(),
limit
=
limit
)
super
(
CreateSnapshotDiskOperation
,
self
)
.
_operation
(
disk
,
**
kwargs
)
def
get_activity_name
(
self
,
kwargs
):
def
get_activity_name
(
self
,
kwargs
):
return
create_readable
(
return
create_readable
(
ugettext_noop
(
'Created snapshot
%(snap_name)
s'
ugettext_noop
(
'Created snapshot
%(snap_name)
s'
...
@@ -478,7 +488,7 @@ class DeployOperation(InstanceOperation):
...
@@ -478,7 +488,7 @@ class DeployOperation(InstanceOperation):
# Deploy virtual images
# Deploy virtual images
try
:
try
:
self
.
instance
.
_deploy_disks
(
parent_activity
=
activity
)
self
.
instance
.
_deploy_disks
(
parent_activity
=
activity
)
except
:
except
Exception
:
self
.
instance
.
yield_node
()
self
.
instance
.
yield_node
()
self
.
instance
.
yield_vnc_port
()
self
.
instance
.
yield_vnc_port
()
raise
raise
...
@@ -495,7 +505,7 @@ class DeployOperation(InstanceOperation):
...
@@ -495,7 +505,7 @@ class DeployOperation(InstanceOperation):
try
:
try
:
self
.
instance
.
renew
(
parent_activity
=
activity
)
self
.
instance
.
renew
(
parent_activity
=
activity
)
except
:
except
Exception
:
pass
pass
self
.
instance
.
_resume_vm
(
parent_activity
=
activity
)
self
.
instance
.
_resume_vm
(
parent_activity
=
activity
)
...
@@ -580,7 +590,7 @@ class DestroyOperation(InstanceOperation):
...
@@ -580,7 +590,7 @@ class DestroyOperation(InstanceOperation):
# Delete mem. dump if exists
# Delete mem. dump if exists
try
:
try
:
self
.
instance
.
_delete_mem_dump
(
parent_activity
=
activity
)
self
.
instance
.
_delete_mem_dump
(
parent_activity
=
activity
)
except
:
except
Exception
:
pass
pass
# Clear node and VNC port association
# Clear node and VNC port association
...
@@ -827,7 +837,7 @@ class SaveAsTemplateOperation(InstanceOperation):
...
@@ -827,7 +837,7 @@ class SaveAsTemplateOperation(InstanceOperation):
with_shutdown
=
True
,
clone
=
False
,
task
=
None
,
**
kwargs
):
with_shutdown
=
True
,
clone
=
False
,
task
=
None
,
**
kwargs
):
try
:
try
:
self
.
instance
.
_cleanup
(
parent_activity
=
activity
,
user
=
user
)
self
.
instance
.
_cleanup
(
parent_activity
=
activity
,
user
=
user
)
except
:
except
Exception
:
pass
pass
if
with_shutdown
:
if
with_shutdown
:
...
@@ -891,7 +901,7 @@ class SaveAsTemplateOperation(InstanceOperation):
...
@@ -891,7 +901,7 @@ class SaveAsTemplateOperation(InstanceOperation):
# create interface templates
# create interface templates
for
i
in
self
.
instance
.
interface_set
.
all
():
for
i
in
self
.
instance
.
interface_set
.
all
():
i
.
save_as_template
(
tmpl
)
i
.
save_as_template
(
tmpl
)
except
:
except
Exception
:
tmpl
.
delete
()
tmpl
.
delete
()
raise
raise
else
:
else
:
...
@@ -1046,7 +1056,7 @@ class WakeUpOperation(InstanceOperation):
...
@@ -1046,7 +1056,7 @@ class WakeUpOperation(InstanceOperation):
try
:
try
:
self
.
instance
.
renew
(
parent_activity
=
activity
)
self
.
instance
.
renew
(
parent_activity
=
activity
)
except
:
except
Exception
:
pass
pass
@register_operation
@register_operation
...
@@ -1446,7 +1456,7 @@ class RecoverOperation(InstanceOperation):
...
@@ -1446,7 +1456,7 @@ class RecoverOperation(InstanceOperation):
try
:
try
:
self
.
instance
.
renew
(
parent_activity
=
activity
)
self
.
instance
.
renew
(
parent_activity
=
activity
)
except
:
except
Exception
:
pass
pass
if
self
.
instance
.
template
:
if
self
.
instance
.
template
:
...
@@ -1636,7 +1646,7 @@ class AgentStartedOperation(InstanceOperation):
...
@@ -1636,7 +1646,7 @@ class AgentStartedOperation(InstanceOperation):
if
not
self
.
initialized
:
if
not
self
.
initialized
:
try
:
try
:
self
.
measure_boot_time
()
self
.
measure_boot_time
()
except
:
except
Exception
:
logger
.
exception
(
'Unhandled error in measure_boot_time()'
)
logger
.
exception
(
'Unhandled error in measure_boot_time()'
)
self
.
instance
.
_cleanup
(
parent_activity
=
activity
)
self
.
instance
.
_cleanup
(
parent_activity
=
activity
)
self
.
instance
.
password_reset
(
self
.
instance
.
password_reset
(
...
...
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