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
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
115 additions
and
6 deletions
+115
-6
circle/dashboard/forms.py
+42
-0
circle/dashboard/templates/dashboard/_disk-list-element.html
+10
-4
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):
...
@@ -790,6 +790,48 @@ class VmCreateDiskForm(forms.Form):
return
helper
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
):
class
VmDownloadDiskForm
(
forms
.
Form
):
name
=
forms
.
CharField
(
max_length
=
100
,
label
=
_
(
"Name"
))
name
=
forms
.
CharField
(
max_length
=
100
,
label
=
_
(
"Name"
))
url
=
forms
.
CharField
(
label
=
_
(
'URL'
),
validators
=
[
URLValidator
(),
])
url
=
forms
.
CharField
(
label
=
_
(
'URL'
),
validators
=
[
URLValidator
(),
])
...
...
circle/dashboard/templates/dashboard/_disk-list-element.html
View file @
8f6b93ba
...
@@ -11,11 +11,17 @@
...
@@ -11,11 +11,17 @@
{% endif %}
{% endif %}
{% else %}
<span
class=
"disk-list-disk-percentage"
data-disk-pk=
"{{ d.pk }}"
>
{{ d.get_download_percentage }}
</span>
%{% endif %}
{% else %}
<span
class=
"disk-list-disk-percentage"
data-disk-pk=
"{{ d.pk }}"
>
{{ d.get_download_percentage }}
</span>
%{% endif %}
{% if is_owner != False %}
{% if is_owner != False %}
<a
href=
"{% url "
dashboard
.
views
.
disk-remove
"
pk=
d.pk
%}?
next=
{{
request
.
path
}}"
<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"
data-disk-pk=
"{{ d.pk }}"
class=
"btn btn-xs btn-danger pull-right disk-remove"
{%
if
not
long_remove
%}
title=
"{% trans "
Remove
"
%}"{%
endif
%}
{%
if
not
long_remove
%}
title=
"{% trans "
Remove
"
%}"{%
endif
%}
>
>
<i
class=
"fa fa-times"
></i>
{% if long_remove %} {% trans "Remove" %}{% endif %}
<i
class=
"fa fa-times"
></i>
{% if long_remove %} {% trans "Remove" %}{% endif %}
</a>
</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 %}
{% endif %}
<div
style=
"clear: both;"
></div>
<div
style=
"clear: both;"
></div>
circle/dashboard/views/vm.py
View file @
8f6b93ba
...
@@ -58,7 +58,7 @@ from ..forms import (
...
@@ -58,7 +58,7 @@ from ..forms import (
AclUserOrGroupAddForm
,
VmResourcesForm
,
TraitsForm
,
RawDataForm
,
AclUserOrGroupAddForm
,
VmResourcesForm
,
TraitsForm
,
RawDataForm
,
VmAddInterfaceForm
,
VmCreateDiskForm
,
VmDownloadDiskForm
,
VmSaveForm
,
VmAddInterfaceForm
,
VmCreateDiskForm
,
VmDownloadDiskForm
,
VmSaveForm
,
VmRenewForm
,
VmStateChangeForm
,
VmListSearchForm
,
VmCustomizeForm
,
VmRenewForm
,
VmStateChangeForm
,
VmListSearchForm
,
VmCustomizeForm
,
TransferOwnershipForm
,
TransferOwnershipForm
,
VmDiskResizeForm
,
)
)
from
..models
import
Favourite
,
Profile
from
..models
import
Favourite
,
Profile
...
@@ -365,6 +365,30 @@ class VmAddInterfaceView(FormOperationMixin, VmOperationView):
...
@@ -365,6 +365,30 @@ class VmAddInterfaceView(FormOperationMixin, VmOperationView):
return
val
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
):
class
VmCreateDiskView
(
FormOperationMixin
,
VmOperationView
):
op
=
'create_disk'
op
=
'create_disk'
...
@@ -601,6 +625,7 @@ vm_ops = OrderedDict([
...
@@ -601,6 +625,7 @@ vm_ops = OrderedDict([
op
=
'destroy'
,
icon
=
'times'
,
effect
=
'danger'
)),
op
=
'destroy'
,
icon
=
'times'
,
effect
=
'danger'
)),
(
'create_disk'
,
VmCreateDiskView
),
(
'create_disk'
,
VmCreateDiskView
),
(
'download_disk'
,
VmDownloadDiskView
),
(
'download_disk'
,
VmDownloadDiskView
),
(
'resize_disk'
,
VmDiskResizeView
),
(
'add_interface'
,
VmAddInterfaceView
),
(
'add_interface'
,
VmAddInterfaceView
),
(
'renew'
,
VmRenewView
),
(
'renew'
,
VmRenewView
),
(
'resources_change'
,
VmResourcesChangeView
),
(
'resources_change'
,
VmResourcesChangeView
),
...
...
circle/storage/models.py
View file @
8f6b93ba
...
@@ -104,7 +104,9 @@ class Disk(TimeStampedModel):
...
@@ -104,7 +104,9 @@ class Disk(TimeStampedModel):
verbose_name_plural
=
_
(
'disks'
)
verbose_name_plural
=
_
(
'disks'
)
permissions
=
(
permissions
=
(
(
'create_empty_disk'
,
_
(
'Can create an empty disk.'
)),
(
'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
):
class
DiskError
(
HumanReadableException
):
admin_message
=
None
admin_message
=
None
...
...
circle/vm/models/instance.py
View file @
8f6b93ba
...
@@ -790,6 +790,14 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
...
@@ -790,6 +790,14 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
else
:
else
:
raise
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
):
def
deploy_disks
(
self
):
"""Deploy all associated disks.
"""Deploy all associated disks.
"""
"""
...
...
circle/vm/operations.py
View file @
8f6b93ba
...
@@ -205,6 +205,27 @@ class CreateDiskOperation(InstanceOperation):
...
@@ -205,6 +205,27 @@ class CreateDiskOperation(InstanceOperation):
@register_operation
@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
):
class
DownloadDiskOperation
(
InstanceOperation
):
activity_code_suffix
=
'download_disk'
activity_code_suffix
=
'download_disk'
id
=
'download_disk'
id
=
'download_disk'
...
...
circle/vm/tasks/vm_tasks.py
View file @
8f6b93ba
...
@@ -132,6 +132,11 @@ def migrate(params):
...
@@ -132,6 +132,11 @@ def migrate(params):
pass
pass
@celery.task
(
name
=
'vmdriver.resize_disk'
)
def
resize_disk
(
params
):
pass
@celery.task
(
name
=
'vmdriver.domain_info'
)
@celery.task
(
name
=
'vmdriver.domain_info'
)
def
domain_info
(
params
):
def
domain_info
(
params
):
pass
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