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
8f6b93ba
authored
Sep 24, 2014
by
Bach Dániel
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature-resize_disk' into 'master'
Feature Resize Disk Resize disk image on a running virtual machine.
parents
ed1b46ed
dec67193
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
117 additions
and
8 deletions
+117
-8
circle/dashboard/forms.py
+42
-0
circle/dashboard/templates/dashboard/_disk-list-element.html
+12
-6
circle/dashboard/views/vm.py
+26
-1
circle/storage/models.py
+3
-1
circle/vm/models/instance.py
+8
-0
circle/vm/operations.py
+21
-0
circle/vm/tasks/vm_tasks.py
+5
-0
No files found.
circle/dashboard/forms.py
View file @
8f6b93ba
...
...
@@ -790,6 +790,48 @@ class VmCreateDiskForm(forms.Form):
return
helper
class
VmDiskResizeForm
(
forms
.
Form
):
size
=
forms
.
CharField
(
widget
=
FileSizeWidget
,
initial
=
(
10
<<
30
),
label
=
_
(
'Size'
),
help_text
=
_
(
'Size to resize the disk in bytes or with units '
'like MB or GB.'
))
def
__init__
(
self
,
*
args
,
**
kwargs
):
choices
=
kwargs
.
pop
(
'choices'
)
self
.
disk
=
kwargs
.
pop
(
'default'
)
super
(
VmDiskResizeForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
self
.
fields
.
insert
(
0
,
'disk'
,
forms
.
ModelChoiceField
(
queryset
=
choices
,
initial
=
self
.
disk
,
required
=
True
,
empty_label
=
None
,
label
=
_
(
'Disk'
)))
if
self
.
disk
:
self
.
fields
[
'disk'
]
.
widget
=
HiddenInput
()
self
.
fields
[
'size'
]
.
initial
+=
self
.
disk
.
size
def
clean
(
self
):
cleaned_data
=
super
(
VmDiskResizeForm
,
self
)
.
clean
()
size_in_bytes
=
self
.
cleaned_data
.
get
(
"size"
)
disk
=
self
.
cleaned_data
.
get
(
'disk'
)
if
not
size_in_bytes
.
isdigit
()
and
len
(
size_in_bytes
)
>
0
:
raise
forms
.
ValidationError
(
_
(
"Invalid format, you can use "
" GB or MB!"
))
if
int
(
size_in_bytes
)
<
int
(
disk
.
size
):
raise
forms
.
ValidationError
(
_
(
"Disk size must be greater than the "
"actual size."
))
return
cleaned_data
@property
def
helper
(
self
):
helper
=
FormHelper
(
self
)
helper
.
form_tag
=
False
if
self
.
disk
:
helper
.
layout
=
Layout
(
HTML
(
_
(
"<label>Disk:</label>
%
s"
)
%
self
.
disk
),
Field
(
'disk'
),
Field
(
'size'
))
return
helper
class
VmDownloadDiskForm
(
forms
.
Form
):
name
=
forms
.
CharField
(
max_length
=
100
,
label
=
_
(
"Name"
))
url
=
forms
.
CharField
(
label
=
_
(
'URL'
),
validators
=
[
URLValidator
(),
])
...
...
circle/dashboard/templates/dashboard/_disk-list-element.html
View file @
8f6b93ba
...
...
@@ -11,11 +11,17 @@
{% endif %}
{% else %}
<span
class=
"disk-list-disk-percentage"
data-disk-pk=
"{{ d.pk }}"
>
{{ d.get_download_percentage }}
</span>
%{% endif %}
{% if is_owner != False %}
<a
href=
"{% url "
dashboard
.
views
.
disk-remove
"
pk=
d.pk
%}?
next=
{{
request
.
path
}}"
data-disk-pk=
"{{ d.pk }}"
class=
"btn btn-xs btn-danger pull-right disk-remove"
{%
if
not
long_remove
%}
title=
"{% trans "
Remove
"
%}"{%
endif
%}
>
<i
class=
"fa fa-times"
></i>
{% if long_remove %} {% trans "Remove" %}{% endif %}
</a>
<a
href=
"{% url "
dashboard
.
views
.
disk-remove
"
pk=
d.pk
%}?
next=
{{
request
.
path
}}"
data-disk-pk=
"{{ d.pk }}"
class=
"btn btn-xs btn-danger pull-right disk-remove"
{%
if
not
long_remove
%}
title=
"{% trans "
Remove
"
%}"{%
endif
%}
>
<i
class=
"fa fa-times"
></i>
{% if long_remove %} {% trans "Remove" %}{% endif %}
</a>
{% if op.resize_disk %}
<span
class=
"operation-wrapper"
>
<a
href=
"{{ op.resize_disk.get_url }}?disk={{d.pk}}"
class=
"btn btn-xs btn-warning pull-right operation"
>
<i
class=
"fa fa-arrows-alt"
></i>
{% trans "Resize" %}
</a>
</span>
{% endif %}
{% endif %}
<div
style=
"clear: both;"
></div>
circle/dashboard/views/vm.py
View file @
8f6b93ba
...
...
@@ -58,7 +58,7 @@ from ..forms import (
AclUserOrGroupAddForm
,
VmResourcesForm
,
TraitsForm
,
RawDataForm
,
VmAddInterfaceForm
,
VmCreateDiskForm
,
VmDownloadDiskForm
,
VmSaveForm
,
VmRenewForm
,
VmStateChangeForm
,
VmListSearchForm
,
VmCustomizeForm
,
TransferOwnershipForm
,
TransferOwnershipForm
,
VmDiskResizeForm
,
)
from
..models
import
Favourite
,
Profile
...
...
@@ -365,6 +365,30 @@ class VmAddInterfaceView(FormOperationMixin, VmOperationView):
return
val
class
VmDiskResizeView
(
FormOperationMixin
,
VmOperationView
):
op
=
'resize_disk'
form_class
=
VmDiskResizeForm
show_in_toolbar
=
False
icon
=
'arrows-alt'
effect
=
"success"
def
get_form_kwargs
(
self
):
choices
=
self
.
get_op
()
.
instance
.
disks
disk_pk
=
self
.
request
.
GET
.
get
(
'disk'
)
if
disk_pk
:
try
:
default
=
choices
.
get
(
pk
=
disk_pk
)
except
(
ValueError
,
Disk
.
DoesNotExist
):
raise
Http404
()
else
:
default
=
None
val
=
super
(
VmDiskResizeView
,
self
)
.
get_form_kwargs
()
val
.
update
({
'choices'
:
choices
,
'default'
:
default
})
return
val
class
VmCreateDiskView
(
FormOperationMixin
,
VmOperationView
):
op
=
'create_disk'
...
...
@@ -601,6 +625,7 @@ vm_ops = OrderedDict([
op
=
'destroy'
,
icon
=
'times'
,
effect
=
'danger'
)),
(
'create_disk'
,
VmCreateDiskView
),
(
'download_disk'
,
VmDownloadDiskView
),
(
'resize_disk'
,
VmDiskResizeView
),
(
'add_interface'
,
VmAddInterfaceView
),
(
'renew'
,
VmRenewView
),
(
'resources_change'
,
VmResourcesChangeView
),
...
...
circle/storage/models.py
View file @
8f6b93ba
...
...
@@ -104,7 +104,9 @@ class Disk(TimeStampedModel):
verbose_name_plural
=
_
(
'disks'
)
permissions
=
(
(
'create_empty_disk'
,
_
(
'Can create an empty disk.'
)),
(
'download_disk'
,
_
(
'Can download a disk.'
)))
(
'download_disk'
,
_
(
'Can download a disk.'
)),
(
'resize_disk'
,
_
(
'Can resize a disk.'
))
)
class
DiskError
(
HumanReadableException
):
admin_message
=
None
...
...
circle/vm/models/instance.py
View file @
8f6b93ba
...
...
@@ -790,6 +790,14 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
else
:
raise
def
resize_disk_live
(
self
,
disk
,
size
,
timeout
=
15
):
queue_name
=
self
.
get_remote_queue_name
(
'vm'
,
'slow'
)
return
vm_tasks
.
resize_disk
.
apply_async
(
args
=
[
self
.
vm_name
,
disk
.
path
,
size
],
queue
=
queue_name
)
.
get
(
timeout
=
timeout
)
disk
.
size
=
size
disk
.
save
()
def
deploy_disks
(
self
):
"""Deploy all associated disks.
"""
...
...
circle/vm/operations.py
View file @
8f6b93ba
...
...
@@ -205,6 +205,27 @@ class CreateDiskOperation(InstanceOperation):
@register_operation
class
ResizeDiskOperation
(
InstanceOperation
):
activity_code_suffix
=
'resize_disk'
id
=
'resize_disk'
name
=
_
(
"resize disk"
)
description
=
_
(
"Resize the virtual disk image. "
"Size must be greater value than the actual size."
)
required_perms
=
(
'storage.resize_disk'
,
)
accept_states
=
(
'RUNNING'
,
)
async_queue
=
"localhost.man.slow"
def
_operation
(
self
,
user
,
disk
,
size
,
activity
):
self
.
instance
.
resize_disk_live
(
disk
,
size
)
def
get_activity_name
(
self
,
kwargs
):
return
create_readable
(
ugettext_noop
(
"resize disk
%(name)
s to
%(size)
s"
),
size
=
filesizeformat
(
kwargs
[
'size'
]),
name
=
kwargs
[
'disk'
]
.
name
)
@register_operation
class
DownloadDiskOperation
(
InstanceOperation
):
activity_code_suffix
=
'download_disk'
id
=
'download_disk'
...
...
circle/vm/tasks/vm_tasks.py
View file @
8f6b93ba
...
...
@@ -132,6 +132,11 @@ def migrate(params):
pass
@celery.task
(
name
=
'vmdriver.resize_disk'
)
def
resize_disk
(
params
):
pass
@celery.task
(
name
=
'vmdriver.domain_info'
)
def
domain_info
(
params
):
pass
...
...
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