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
Show 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):
label
=
_
(
'Two-factor authentication secret'
),
help_text
=
_
(
"Remove the secret key to disable two-factor "
"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
):
super
(
UserEditForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
...
...
@@ -1393,11 +1396,13 @@ class UserEditForm(forms.ModelForm):
self
.
instance
.
profile
.
instance_limit
)
self
.
fields
[
"two_factor_secret"
]
.
initial
=
(
self
.
instance
.
profile
.
two_factor_secret
)
self
.
fields
[
"disk_snapshot_limit"
]
.
initial
=
(
self
.
instance
.
profile
.
disk_snapshot_limit
)
class
Meta
:
model
=
User
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
):
user
=
super
(
UserEditForm
,
self
)
.
save
()
...
...
@@ -1405,6 +1410,8 @@ class UserEditForm(forms.ModelForm):
self
.
cleaned_data
[
'instance_limit'
]
or
None
)
user
.
profile
.
two_factor_secret
=
(
self
.
cleaned_data
[
'two_factor_secret'
]
or
None
)
user
.
profile
.
disk_snapshot_limit
=
(
self
.
cleaned_data
[
'disk_snapshot_limit'
]
or
None
)
user
.
profile
.
save
()
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):
verbose_name
=
_
(
'disk quota'
),
default
=
2048
*
1024
*
1024
,
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
(
verbose_name
=
_
(
"two factor secret key"
),
max_length
=
32
,
null
=
True
,
blank
=
True
,
...
...
@@ -332,7 +336,7 @@ def create_profile(user):
try
:
Store
(
user
)
.
create_user
(
profile
.
smb_password
,
None
,
profile
.
disk_quota
)
except
:
except
Exception
:
logger
.
exception
(
"Can't create user
%
s"
,
unicode
(
user
))
return
created
...
...
circle/dashboard/static/dashboard/dashboard.less
View file @
4c1443f2
...
...
@@ -1536,16 +1536,10 @@ textarea[name="new_members"] {
background: gray;
}
.show-snapshot-btn {
margin-top: 10px;
}
.disk-create_snapshot-btn {
margin-right: 5px;
}
.snapshot-table {
background: white;
}
#two-factor-qr {
text-align: center;
...
...
circle/dashboard/views/vm.py
View file @
4c1443f2
...
...
@@ -248,7 +248,7 @@ class VmDetailView(GraphMixin, CheckedDetailView):
try
:
messages
.
error
(
request
,
message
)
except
:
except
Exception
:
pass
return
redirect
(
reverse_lazy
(
"dashboard.views.detail"
,
...
...
@@ -263,7 +263,7 @@ class VmDetailView(GraphMixin, CheckedDetailView):
self
.
object
.
tags
.
remove
(
to_remove
)
message
=
u"Success"
except
:
# note this won't really happen
except
Exception
:
# note this won't really happen
message
=
u"Not success"
if
request
.
is_ajax
():
...
...
@@ -808,7 +808,8 @@ vm_ops = OrderedDict([
)),
(
'create_snapshot'
,
VmDiskModifyView
.
factory
(
op
=
'create_snapshot'
,
icon
=
'camera'
,
effect
=
'success'
,
form_class
=
VmSnapshotDiskForm
)),
form_class
=
VmSnapshotDiskForm
,
)),
(
'remove_snapshot'
,
VmCommonSnapshotDiskView
.
factory
(
op
=
'remove_snapshot'
,
icon
=
'times'
,
effect
=
'danger'
)),
(
'revert_snapshot'
,
VmCommonSnapshotDiskView
.
factory
(
...
...
@@ -1182,7 +1183,7 @@ class VmCreate(LoginRequiredMixin, TemplateView):
else
:
try
:
amount
=
int
(
request
.
POST
.
get
(
"amount"
,
1
))
except
:
except
Exception
:
amount
=
limit
# TODO this should definitely use a Form
current
=
Instance
.
active
.
filter
(
owner
=
user
)
.
count
()
logger
.
debug
(
'current use:
%
d, limit:
%
d'
,
current
,
limit
)
...
...
@@ -1207,7 +1208,7 @@ def get_vm_screenshot(request, pk):
instance
=
get_object_or_404
(
Instance
,
pk
=
pk
)
try
:
image
=
instance
.
screenshot
(
user
=
request
.
user
)
.
getvalue
()
except
:
except
Exception
:
# TODO handle this better
raise
Http404
()
...
...
circle/storage/models.py
View file @
4c1443f2
...
...
@@ -564,7 +564,7 @@ class Disk(TimeStampedModel):
disk
.
destroy
()
raise
humanize_exception
(
ugettext_noop
(
"Operation aborted by user."
),
e
)
except
:
except
Exception
:
disk
.
destroy
()
raise
disk
.
is_ready
=
True
...
...
@@ -581,4 +581,4 @@ class Disk(TimeStampedModel):
@property
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):
self
.
disk
.
did_have_snapshot
=
True
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
):
return
create_readable
(
ugettext_noop
(
'Created snapshot
%(snap_name)
s'
...
...
@@ -478,7 +488,7 @@ class DeployOperation(InstanceOperation):
# Deploy virtual images
try
:
self
.
instance
.
_deploy_disks
(
parent_activity
=
activity
)
except
:
except
Exception
:
self
.
instance
.
yield_node
()
self
.
instance
.
yield_vnc_port
()
raise
...
...
@@ -495,7 +505,7 @@ class DeployOperation(InstanceOperation):
try
:
self
.
instance
.
renew
(
parent_activity
=
activity
)
except
:
except
Exception
:
pass
self
.
instance
.
_resume_vm
(
parent_activity
=
activity
)
...
...
@@ -580,7 +590,7 @@ class DestroyOperation(InstanceOperation):
# Delete mem. dump if exists
try
:
self
.
instance
.
_delete_mem_dump
(
parent_activity
=
activity
)
except
:
except
Exception
:
pass
# Clear node and VNC port association
...
...
@@ -827,7 +837,7 @@ class SaveAsTemplateOperation(InstanceOperation):
with_shutdown
=
True
,
clone
=
False
,
task
=
None
,
**
kwargs
):
try
:
self
.
instance
.
_cleanup
(
parent_activity
=
activity
,
user
=
user
)
except
:
except
Exception
:
pass
if
with_shutdown
:
...
...
@@ -891,7 +901,7 @@ class SaveAsTemplateOperation(InstanceOperation):
# create interface templates
for
i
in
self
.
instance
.
interface_set
.
all
():
i
.
save_as_template
(
tmpl
)
except
:
except
Exception
:
tmpl
.
delete
()
raise
else
:
...
...
@@ -1046,7 +1056,7 @@ class WakeUpOperation(InstanceOperation):
try
:
self
.
instance
.
renew
(
parent_activity
=
activity
)
except
:
except
Exception
:
pass
@register_operation
...
...
@@ -1446,7 +1456,7 @@ class RecoverOperation(InstanceOperation):
try
:
self
.
instance
.
renew
(
parent_activity
=
activity
)
except
:
except
Exception
:
pass
if
self
.
instance
.
template
:
...
...
@@ -1636,7 +1646,7 @@ class AgentStartedOperation(InstanceOperation):
if
not
self
.
initialized
:
try
:
self
.
measure_boot_time
()
except
:
except
Exception
:
logger
.
exception
(
'Unhandled error in measure_boot_time()'
)
self
.
instance
.
_cleanup
(
parent_activity
=
activity
)
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