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
51a45b5a
authored
Jun 14, 2014
by
Kálmán Viktor
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into feature-profile-rework
parents
287cedde
e561b9eb
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
44 changed files
with
556 additions
and
339 deletions
+556
-339
circle/acl/management/__init__.py
+4
-4
circle/circle/settings/base.py
+13
-1
circle/circle/settings/local.py
+1
-0
circle/circle/settings/production.py
+1
-0
circle/circle/settings/test.py
+2
-0
circle/circle/urls.py
+1
-1
circle/common/operations.py
+1
-0
circle/dashboard/fixtures/test-vm-fixture.json
+3
-19
circle/dashboard/forms.py
+20
-70
circle/dashboard/static/dashboard/dashboard.css
+1
-0
circle/dashboard/static/dashboard/vm-common.js
+1
-1
circle/dashboard/templates/dashboard/index-templates.html
+1
-1
circle/dashboard/templates/dashboard/template-edit.html
+55
-52
circle/dashboard/templates/dashboard/vm-detail/_activity-timeline.html
+3
-0
circle/dashboard/templates/dashboard/vm-detail/_operations.html
+2
-0
circle/dashboard/templates/dashboard/vm-detail/resources.html
+12
-14
circle/dashboard/tests/test_views.py
+1
-33
circle/dashboard/urls.py
+1
-3
circle/dashboard/views.py
+35
-62
circle/firewall/fields.py
+1
-1
circle/firewall/models.py
+2
-2
circle/firewall/tests/test_firewall.py
+1
-1
circle/network/static/js/network.js
+4
-0
circle/network/static/network/network.css
+8
-0
circle/network/tables.py
+2
-2
circle/network/templates/network/base.html
+1
-1
circle/network/templates/network/vlan-edit.html
+65
-4
circle/network/tests.py
+0
-33
circle/network/tests/__init__.py
+0
-0
circle/network/tests/test_views.py
+107
-0
circle/network/urls.py
+4
-1
circle/network/views.py
+17
-0
circle/storage/admin.py
+1
-2
circle/storage/migrations/0014_auto__del_diskactivity__add_field_disk_is_ready__chg_field_disk_size.py
+74
-0
circle/storage/models.py
+0
-0
circle/storage/tasks/periodic_tasks.py
+8
-8
circle/storage/tasks/storage_tasks.py
+0
-0
circle/storage/tests/test_models.py
+1
-6
circle/vm/models/activity.py
+14
-0
circle/vm/models/common.py
+2
-2
circle/vm/models/instance.py
+5
-0
circle/vm/operations.py
+34
-9
circle/vm/tasks/agent_tasks.py
+5
-0
circle/vm/tasks/local_agent_tasks.py
+42
-6
No files found.
circle/acl/management/__init__.py
View file @
51a45b5a
...
@@ -31,13 +31,13 @@ def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
...
@@ -31,13 +31,13 @@ def create_levels(app, created_models, verbosity, db=DEFAULT_DB_ALIAS,
for
klass
in
app_models
:
for
klass
in
app_models
:
# Force looking up the content types in the current database
# Force looking up the content types in the current database
# before creating foreign keys to them.
# before creating foreign keys to them.
ctype
=
ContentType
.
objects
.
db_manager
(
db
)
.
get_for_model
(
klass
)
ctype
1
=
ContentType
.
objects
.
db_manager
(
db
)
.
get_for_model
(
klass
)
ctypes
.
add
(
ctype
)
ctypes
.
add
(
ctype
1
)
weight
=
0
weight
=
0
try
:
try
:
for
codename
,
name
in
klass
.
ACL_LEVELS
:
for
codename
,
name
in
klass
.
ACL_LEVELS
:
searched_levels
.
append
((
ctype
,
(
codename
,
name
)))
searched_levels
.
append
((
ctype
1
,
(
codename
,
name
)))
level_weights
.
append
((
ctype
,
codename
,
weight
))
level_weights
.
append
((
ctype
1
,
codename
,
weight
))
weight
+=
1
weight
+=
1
except
AttributeError
:
except
AttributeError
:
raise
ImproperlyConfigured
(
raise
ImproperlyConfigured
(
...
...
circle/circle/settings/base.py
View file @
51a45b5a
...
@@ -18,8 +18,10 @@
...
@@ -18,8 +18,10 @@
"""Common settings and globals."""
"""Common settings and globals."""
# flake8: noqa
# flake8: noqa
from
os
import
environ
from
os
import
environ
from
os.path
import
abspath
,
basename
,
dirname
,
join
,
normpath
,
isfile
from
os.path
import
(
abspath
,
basename
,
dirname
,
join
,
normpath
,
isfile
,
expanduser
)
from
sys
import
path
from
sys
import
path
from
subprocess
import
check_output
from
django.core.exceptions
import
ImproperlyConfigured
from
django.core.exceptions
import
ImproperlyConfigured
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
...
@@ -418,6 +420,16 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
...
@@ -418,6 +420,16 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
LOGIN_REDIRECT_URL
=
"/"
LOGIN_REDIRECT_URL
=
"/"
AGENT_DIR
=
get_env_variable
(
'DJANGO_AGENT_DIR'
,
join
(
unicode
(
expanduser
(
"~"
)),
'agent'
))
try
:
git_env
=
{
'GIT_DIR'
:
join
(
AGENT_DIR
,
'.git'
)}
AGENT_VERSION
=
check_output
(
(
'git'
,
'log'
,
'-1'
,
r'--pretty=format:
%
h'
,
'HEAD'
),
env
=
git_env
)
except
:
AGENT_VERSION
=
None
LOCALE_PATHS
=
(
join
(
SITE_ROOT
,
'locale'
),
)
LOCALE_PATHS
=
(
join
(
SITE_ROOT
,
'locale'
),
)
COMPANY_NAME
=
"BME IK 2014"
COMPANY_NAME
=
"BME IK 2014"
SOUTH_MIGRATION_MODULES
=
{
SOUTH_MIGRATION_MODULES
=
{
...
...
circle/circle/settings/local.py
View file @
51a45b5a
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
"""Development settings and globals."""
"""Development settings and globals."""
# flake8: noqa
from
base
import
*
# noqa
from
base
import
*
# noqa
...
...
circle/circle/settings/production.py
View file @
51a45b5a
...
@@ -16,6 +16,7 @@
...
@@ -16,6 +16,7 @@
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
"""Production settings and globals."""
"""Production settings and globals."""
# flake8: noqa
from
os
import
environ
from
os
import
environ
...
...
circle/circle/settings/test.py
View file @
51a45b5a
...
@@ -17,6 +17,8 @@
...
@@ -17,6 +17,8 @@
from
.base
import
*
# noqa
from
.base
import
*
# noqa
# flake8: noqa
########## IN-MEMORY TEST DATABASE
########## IN-MEMORY TEST DATABASE
DATABASES
=
{
DATABASES
=
{
"default"
:
{
"default"
:
{
...
...
circle/circle/urls.py
View file @
51a45b5a
...
@@ -30,7 +30,7 @@ admin.autodiscover()
...
@@ -30,7 +30,7 @@ admin.autodiscover()
urlpatterns
=
patterns
(
urlpatterns
=
patterns
(
''
,
''
,
#url(r'^$', TemplateView.as_view(template_name='base.html')),
#
url(r'^$', TemplateView.as_view(template_name='base.html')),
# Examples:
# Examples:
# url(r'^$', 'circle.views.home', name='home'),
# url(r'^$', 'circle.views.home', name='home'),
...
...
circle/common/operations.py
View file @
51a45b5a
...
@@ -33,6 +33,7 @@ class Operation(object):
...
@@ -33,6 +33,7 @@ class Operation(object):
required_perms
=
()
required_perms
=
()
do_not_call_in_templates
=
True
do_not_call_in_templates
=
True
abortable
=
False
abortable
=
False
has_percentage
=
False
def
__call__
(
self
,
**
kwargs
):
def
__call__
(
self
,
**
kwargs
):
return
self
.
call
(
**
kwargs
)
return
self
.
call
(
**
kwargs
)
...
...
circle/dashboard/fixtures/test-vm-fixture.json
View file @
51a45b5a
...
@@ -38,25 +38,9 @@
...
@@ -38,25 +38,9 @@
"datastore"
:
1
,
"datastore"
:
1
,
"dev_num"
:
"a"
,
"dev_num"
:
"a"
,
"type"
:
"qcow2-norm"
,
"type"
:
"qcow2-norm"
,
"size"
:
8589934592
"size"
:
8589934592
,
}
"is_ready"
:
true
},
}
{
"pk"
:
1
,
"model"
:
"storage.diskactivity"
,
"fields"
:{
"activity_code"
:
"storage.Disk.create"
,
"succeeded"
:
true
,
"parent"
:
null
,
"created"
:
"2014-03-18T15:44:37.671Z"
,
"started"
:
"2014-03-18T15:44:37.671Z"
,
"finished"
:
"2014-03-18T15:44:37.677Z"
,
"modified"
:
"2014-03-18T15:44:37.679Z"
,
"task_uuid"
:
null
,
"user"
:
1
,
"disk"
:
1
,
"result"
:
null
}
},
},
{
{
"pk"
:
1
,
"pk"
:
1
,
...
...
circle/dashboard/forms.py
View file @
51a45b5a
...
@@ -24,6 +24,7 @@ from django.contrib.auth.forms import (
...
@@ -24,6 +24,7 @@ from django.contrib.auth.forms import (
PasswordChangeForm
,
PasswordChangeForm
,
)
)
from
django.contrib.auth.models
import
User
,
Group
from
django.contrib.auth.models
import
User
,
Group
from
django.core.validators
import
URLValidator
from
crispy_forms.helper
import
FormHelper
from
crispy_forms.helper
import
FormHelper
from
crispy_forms.layout
import
(
from
crispy_forms.layout
import
(
...
@@ -40,9 +41,9 @@ from django.utils.translation import ugettext as _
...
@@ -40,9 +41,9 @@ from django.utils.translation import ugettext as _
from
sizefield.widgets
import
FileSizeWidget
from
sizefield.widgets
import
FileSizeWidget
from
firewall.models
import
Vlan
,
Host
from
firewall.models
import
Vlan
,
Host
from
storage.models
import
Disk
,
DataStore
from
storage.models
import
Disk
from
vm.models
import
(
from
vm.models
import
(
InstanceTemplate
,
Lease
,
InterfaceTemplate
,
Node
,
Trait
,
Instance
InstanceTemplate
,
Lease
,
InterfaceTemplate
,
Node
,
Trait
)
)
from
.models
import
Profile
,
GroupProfile
from
.models
import
Profile
,
GroupProfile
from
circle.settings.base
import
LANGUAGES
from
circle.settings.base
import
LANGUAGES
...
@@ -852,20 +853,12 @@ class LeaseForm(forms.ModelForm):
...
@@ -852,20 +853,12 @@ class LeaseForm(forms.ModelForm):
model
=
Lease
model
=
Lease
class
DiskAddForm
(
forms
.
Form
):
class
VmCreateDiskForm
(
forms
.
Form
):
name
=
forms
.
CharField
()
name
=
forms
.
CharField
(
max_length
=
100
,
label
=
_
(
"Name"
))
size
=
forms
.
CharField
(
widget
=
FileSizeWidget
,
required
=
False
)
size
=
forms
.
CharField
(
url
=
forms
.
CharField
(
required
=
False
)
widget
=
FileSizeWidget
,
initial
=
(
10
<<
30
),
label
=
_
(
'Size'
),
is_template
=
forms
.
CharField
()
help_text
=
_
(
'Size of disk to create in bytes or with units '
object_pk
=
forms
.
CharField
()
'like MB or GB.'
))
def
__init__
(
self
,
*
args
,
**
kwargs
):
self
.
is_template
=
kwargs
.
pop
(
"is_template"
)
self
.
object_pk
=
kwargs
.
pop
(
"object_pk"
)
self
.
user
=
kwargs
.
pop
(
"user"
)
super
(
DiskAddForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
self
.
initial
[
'is_template'
]
=
1
if
self
.
is_template
else
0
self
.
initial
[
'object_pk'
]
=
self
.
object_pk
def
clean_size
(
self
):
def
clean_size
(
self
):
size_in_bytes
=
self
.
cleaned_data
.
get
(
"size"
)
size_in_bytes
=
self
.
cleaned_data
.
get
(
"size"
)
...
@@ -874,66 +867,23 @@ class DiskAddForm(forms.Form):
...
@@ -874,66 +867,23 @@ class DiskAddForm(forms.Form):
" GB or MB!"
))
" GB or MB!"
))
return
size_in_bytes
return
size_in_bytes
def
clean
(
self
):
@property
cleaned_data
=
self
.
cleaned_data
def
helper
(
self
):
size
=
cleaned_data
.
get
(
"size"
)
helper
=
FormHelper
(
self
)
url
=
cleaned_data
.
get
(
"url"
)
helper
.
form_tag
=
False
return
helper
if
not
size
and
not
url
:
msg
=
_
(
"You have to either specify size or URL"
)
self
.
_errors
[
_
(
"Global"
)]
=
self
.
error_class
([
msg
])
return
cleaned_data
def
save
(
self
,
commit
=
True
):
data
=
self
.
cleaned_data
if
self
.
is_template
:
inst
=
InstanceTemplate
.
objects
.
get
(
pk
=
self
.
object_pk
)
else
:
inst
=
Instance
.
objects
.
get
(
pk
=
self
.
object_pk
)
if
data
[
'size'
]:
kwargs
=
{
'name'
:
data
[
'name'
],
'type'
:
"qcow2-norm"
,
'datastore'
:
DataStore
.
objects
.
all
()[
0
],
'size'
:
data
[
'size'
],
}
d
=
Disk
.
create_empty
(
instance
=
inst
,
user
=
self
.
user
,
**
kwargs
)
else
:
kwargs
=
{
'name'
:
data
[
'name'
],
'url'
:
data
[
'url'
],
}
Disk
.
create_from_url_async
(
instance
=
inst
,
user
=
self
.
user
,
**
kwargs
)
d
=
None
return
d
class
VmDownloadDiskForm
(
forms
.
Form
):
name
=
forms
.
CharField
(
max_length
=
100
,
label
=
_
(
"Name"
))
url
=
forms
.
CharField
(
label
=
_
(
'URL'
),
validators
=
[
URLValidator
(),
])
@property
@property
def
helper
(
self
):
def
helper
(
self
):
helper
=
FormHelper
()
helper
=
FormHelper
(
self
)
helper
.
form_show_labels
=
False
helper
.
add_input
(
Submit
(
"submit"
,
_
(
"Create"
),
helper
.
layout
=
Layout
(
Field
(
"is_template"
,
type
=
"hidden"
),
Field
(
"object_pk"
,
type
=
"hidden"
),
Field
(
"name"
,
placeholder
=
_
(
"Name"
)),
Field
(
"size"
,
placeholder
=
_
(
"Disk size (for example: 20GB, "
"1500MB)"
)),
Field
(
"url"
,
placeholder
=
_
(
"URL to an ISO image"
)),
AnyTag
(
"div"
,
HTML
(
_
(
"Either specify the size for an empty disk or a URL "
"to an ISO image!"
)
),
css_class
=
"alert alert-info"
,
style
=
"padding: 5px; text-align: justify;"
,
),
)
helper
.
add_input
(
Submit
(
"submit"
,
_
(
"Add"
),
css_class
=
"btn btn-success"
))
css_class
=
"btn btn-success"
))
helper
.
form_tag
=
False
return
helper
return
helper
...
...
circle/dashboard/static/dashboard/dashboard.css
View file @
51a45b5a
...
@@ -705,6 +705,7 @@ textarea[name="list-new-namelist"] {
...
@@ -705,6 +705,7 @@ textarea[name="list-new-namelist"] {
#group-detail-user-table
td
:nth-child
(
2
)
a
,
#group-detail-user-table
td
:nth-child
(
2
)
a
,
#group-detail-perm-table
td
:nth-child
(
2
)
a
,
#group-detail-perm-table
td
:nth-child
(
2
)
a
,
#template-access-table
td
:nth-child
(
2
)
a
,
#vm-access-table
td
:nth-child
(
2
)
a
,
#vm-access-table
td
:nth-child
(
2
)
a
,
.no-style-link
,
.no-style-link
:hover
{
.no-style-link
,
.no-style-link
:hover
{
color
:
#555
!important
;
color
:
#555
!important
;
...
...
circle/dashboard/static/dashboard/vm-common.js
View file @
51a45b5a
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
$
(
function
()
{
$
(
function
()
{
/* vm operations */
/* vm operations */
$
(
'#ops'
).
on
(
'click'
,
'.operation.btn'
,
function
(
e
)
{
$
(
'#ops
, #vm-details-resources-disk
'
).
on
(
'click'
,
'.operation.btn'
,
function
(
e
)
{
var
icon
=
$
(
this
).
children
(
"i"
).
addClass
(
'icon-spinner icon-spin'
);
var
icon
=
$
(
this
).
children
(
"i"
).
addClass
(
'icon-spinner icon-spin'
);
$
.
ajax
({
$
.
ajax
({
...
...
circle/dashboard/templates/dashboard/index-templates.html
View file @
51a45b5a
...
@@ -11,7 +11,7 @@
...
@@ -11,7 +11,7 @@
<div
id=
"dashboard-template-list"
>
<div
id=
"dashboard-template-list"
>
{% for t in templates %}
{% for t in templates %}
<a
href=
"{% url "
dashboard
.
views
.
template-detail
"
pk=
t.pk
%}"
class=
"list-group-item
<a
href=
"{% url "
dashboard
.
views
.
template-detail
"
pk=
t.pk
%}"
class=
"list-group-item
{% if forloop.last and
nod
es|length < 5 %} list-group-item-last{% endif %}"
>
{% if forloop.last and
templat
es|length < 5 %} list-group-item-last{% endif %}"
>
<span
class=
"index-template-list-name"
>
<span
class=
"index-template-list-name"
>
<i
class=
"icon-{{ t.os_type }}"
></i>
{{ t.name }}
<i
class=
"icon-{{ t.os_type }}"
></i>
{{ t.name }}
</span>
</span>
...
...
circle/dashboard/templates/dashboard/template-edit.html
View file @
51a45b5a
...
@@ -37,48 +37,62 @@
...
@@ -37,48 +37,62 @@
<th>
{% trans "Who" %}
</th>
<th>
{% trans "Who" %}
</th>
<th>
{% trans "What" %}
</th>
<th>
{% trans "What" %}
</th>
<th><i
class=
"icon-remove"
></i></th>
<th><i
class=
"icon-remove"
></i></th>
</tr></thead>
</tr>
</thead>
<tbody>
<tbody>
{% for i in acl.users %}
{% for i in acl.users %}
<tr>
<tr>
<td><i
class=
"icon-user"
></i></td><td>
{{i.user}}
</td>
<td>
<td>
<i
class=
"icon-user"
></i>
<select
class=
"form-control"
name=
"perm-u-{{i.user.id}}"
>
</td>
{% for id, name in acl.levels %}
<td>
<option
{%
if
id =
i.level%}
selected=
"selected"
{%
endif
%}
value=
"{{id}}"
>
{{name}}
</option>
<a
href=
"{% url "
dashboard
.
views
.
profile
"
username=
i.user.username
%}"
{% endfor %}
title=
"{{ i.user.username }}"
>
</select>
{% include "dashboard/_display-name.html" with user=i.user show_org=True %}
</td>
</a>
<td>
</td>
<input
type=
"checkbox"
name=
"remove-u-{{i.user.id}}"
title=
"{% trans "
Remove
"
%}"
/>
<td>
</td>
<select
class=
"form-control"
name=
"perm-u-{{i.user.id}}"
>
</tr>
{% for id, name in acl.levels %}
{% endfor %}
<option
{%
if
id =
i.level%}
selected=
"selected"
{%
endif
%}
value=
"{{id}}"
>
{{name}}
</option>
{% for i in acl.groups %}
{% endfor %}
<tr>
</select>
<td><i
class=
"icon-group"
></i></td><td>
{{i.group}}
</td>
</td>
<td>
<td>
<select
class=
"form-control"
name=
"perm-g-{{i.group.id}}"
>
<input
type=
"checkbox"
name=
"remove-u-{{i.user.id}}"
title=
"{% trans "
Remove
"
%}"
/>
{% for id, name in acl.levels %}
</td>
<option
{%
if
id =
i.level%}
selected=
"selected"
{%
endif
%}
value=
"{{id}}"
>
{{name}}
</option>
</tr>
{% endfor %}
{% endfor %}
</select>
{% for i in acl.groups %}
</td>
<tr>
<td>
<td><i
class=
"icon-group"
></i></td>
<input
type=
"checkbox"
name=
"remove-g-{{i.group.id}}"
title=
"{% trans "
Remove
"
%}"
/>
<td>
</td>
<a
href=
"{% url "
dashboard
.
views
.
group-detail
"
pk=
i.group.pk
%}"
>
</tr>
{{i.group}}
{% endfor %}
</a>
<tr><td><i
class=
"icon-plus"
></i></td>
</td>
<td><input
type=
"text"
class=
"form-control"
name=
"perm-new-name"
<td>
placeholder=
"{% trans "
Name
of
group
or
user
"
%}"
></td>
<select
class=
"form-control"
name=
"perm-g-{{i.group.id}}"
>
<td><select
class=
"form-control"
name=
"perm-new"
>
{% for id, name in acl.levels %}
{% for id, name in acl.levels %}
<option
{%
if
id =
i.level%}
selected=
"selected"
{%
endif
%}
value=
"{{id}}"
>
{{name}}
</option>
<option
value=
"{{id}}"
>
{{name}}
</option>
{% endfor %}
{% endfor %}
</select>
</select></td><td></td>
</td>
</tr>
<td>
</tbody>
<input
type=
"checkbox"
name=
"remove-g-{{i.group.id}}"
title=
"{% trans "
Remove
"
%}"
/>
</td>
</tr>
{% endfor %}
<tr><td><i
class=
"icon-plus"
></i></td>
<td><input
type=
"text"
class=
"form-control"
name=
"perm-new-name"
placeholder=
"{% trans "
Name
of
group
or
user
"
%}"
></td>
<td><select
class=
"form-control"
name=
"perm-new"
>
{% for id, name in acl.levels %}
<option
value=
"{{id}}"
>
{{name}}
</option>
{% endfor %}
</select></td><td></td>
</tr>
</tbody>
</table>
</table>
<div
class=
"form-actions"
>
<div
class=
"form-actions"
>
<button
type=
"submit"
class=
"btn btn-success"
>
{% trans "Save" %}
</button>
<button
type=
"submit"
class=
"btn btn-success"
>
{% trans "Save" %}
</button>
...
@@ -105,17 +119,6 @@
...
@@ -105,17 +119,6 @@
</ul>
</ul>
</div>
</div>
</div>
</div>
<div
class=
"panel panel-default"
>
<div
class=
"panel-heading"
>
<h4
class=
"no-margin"
><i
class=
"icon-folder-open"
></i>
{% trans "Create new disk" %}
</h4>
</div>
<div
class=
"panel-body"
>
<form
action=
"{% url "
dashboard
.
views
.
disk-add
"
%}"
method=
"POST"
>
{% crispy disk_add_form %}
</form>
</div>
</div>
</div>
<!-- .col-md-4 -->
</div>
<!-- .col-md-4 -->
</div>
<!-- .row -->
</div>
<!-- .row -->
...
...
circle/dashboard/templates/dashboard/vm-detail/_activity-timeline.html
View file @
51a45b5a
...
@@ -13,6 +13,9 @@
...
@@ -13,6 +13,9 @@
{% include "dashboard/_display-name.html" with user=a.user show_org=True %}
{% include "dashboard/_display-name.html" with user=a.user show_org=True %}
</a>
</a>
{% endif %}
{% endif %}
{% if a.has_percent %}
{{ a.percentage }}%
{% endif %}
{% if a.is_abortable_for_user %}
{% if a.is_abortable_for_user %}
<form
action=
"{{ a.instance.get_absolute_url }}"
method=
"POST"
class=
"pull-right"
>
<form
action=
"{{ a.instance.get_absolute_url }}"
method=
"POST"
class=
"pull-right"
>
{% csrf_token %}
{% csrf_token %}
...
...
circle/dashboard/templates/dashboard/vm-detail/_operations.html
View file @
51a45b5a
{% load i18n %}
{% load i18n %}
{% for op in ops %}
{% for op in ops %}
{% if op.show_in_toolbar %}
<a
href=
"{{op.get_url}}"
class=
"operation operation-{{op.op}} btn btn-default btn-xs"
<a
href=
"{{op.get_url}}"
class=
"operation operation-{{op.op}} btn btn-default btn-xs"
title=
"{{op.name}}: {{op.description}}"
>
title=
"{{op.name}}: {{op.description}}"
>
<i
class=
"icon-{{op.icon}}"
></i>
<i
class=
"icon-{{op.icon}}"
></i>
<span
class=
"sr-only"
>
{{op.name}}
</span>
<span
class=
"sr-only"
>
{{op.name}}
</span>
</a>
</a>
{% endif %}
{% endfor %}
{% endfor %}
circle/dashboard/templates/dashboard/vm-detail/resources.html
View file @
51a45b5a
...
@@ -47,9 +47,18 @@
...
@@ -47,9 +47,18 @@
<h3>
<h3>
{% trans "Disks" %}
{% trans "Disks" %}
<div
class=
"pull-right"
>
<div
class=
"pull-right"
>
<a
href=
"#"
id=
"vm-details-disk-add"
class=
"btn btn-success btn-xs"
>
{% if op.download_disk %}
<i
class=
"icon-plus"
></i>
{% trans "Add new disk" %}
<a
href=
"{{op.download_disk.get_url}}"
class=
"btn btn-success btn-xs
</a>
operation operation-{{op.download_disk.op}} btn btn-default"
>
<i
class=
"icon-{{op.download_disk.icon}}"
></i>
{{op.download_disk.name}}
</a>
{% endif %}
{% if op.create_disk %}
<a
href=
"{{op.create_disk.get_url}}"
class=
"btn btn-success btn-xs
operation operation-{{op.create_disk.op}} btn btn-default"
>
<i
class=
"icon-{{op.create_disk.icon}}"
></i>
{{op.create_disk.name}}
</a>
{% endif %}
</div>
</div>
</h3>
</h3>
...
@@ -68,17 +77,6 @@
...
@@ -68,17 +77,6 @@
</div>
</div>
</div>
</div>
<div
class=
"js-hidden row"
id=
"vm-details-disk-add-form"
>
<div
class=
"col-md-12"
>
<div>
<hr
/>
<form
method=
"POST"
action=
"{% url "
dashboard
.
views
.
disk-add
"
%}"
style=
"max-width: 350px;"
>
{% crispy forms.disk_add_form %}
</form>
<hr
/>
</div>
</div>
</div>
{% block extra_js %}
{% block extra_js %}
<style>
<style>
...
...
circle/dashboard/tests/test_views.py
View file @
51a45b5a
...
@@ -17,7 +17,7 @@
...
@@ -17,7 +17,7 @@
import
json
import
json
from
unittest
import
skip
#
from unittest import skip
from
django.test
import
TestCase
from
django.test
import
TestCase
from
django.test.client
import
Client
from
django.test.client
import
Client
from
django.contrib.auth.models
import
User
,
Group
from
django.contrib.auth.models
import
User
,
Group
...
@@ -333,38 +333,6 @@ class VmDetailTest(LoginMixin, TestCase):
...
@@ -333,38 +333,6 @@ class VmDetailTest(LoginMixin, TestCase):
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
assertEqual
(
leases
,
Lease
.
objects
.
count
())
self
.
assertEqual
(
leases
,
Lease
.
objects
.
count
())
def
test_unpermitted_vm_disk_add
(
self
):
c
=
Client
()
self
.
login
(
c
,
"user2"
)
inst
=
Instance
.
objects
.
get
(
pk
=
1
)
inst
.
set_level
(
self
.
u1
,
'owner'
)
disks
=
inst
.
disks
.
count
()
response
=
c
.
post
(
"/dashboard/disk/add/"
,
{
'disk-name'
:
"a"
,
'disk-size'
:
1
,
'disk-is_template'
:
0
,
'disk-object_pk'
:
1
,
})
self
.
assertEqual
(
response
.
status_code
,
403
)
self
.
assertEqual
(
disks
,
inst
.
disks
.
count
())
@skip
(
"until fix merged"
)
def
test_permitted_vm_disk_add
(
self
):
c
=
Client
()
self
.
login
(
c
,
"user1"
)
inst
=
Instance
.
objects
.
get
(
pk
=
1
)
inst
.
set_level
(
self
.
u1
,
'owner'
)
# disks = inst.disks.count()
response
=
c
.
post
(
"/dashboard/disk/add/"
,
{
'disk-name'
:
"a"
,
'disk-size'
:
1
,
'disk-is_template'
:
0
,
'disk-object_pk'
:
1
,
})
self
.
assertEqual
(
response
.
status_code
,
302
)
# mancelery is needed TODO
# self.assertEqual(disks + 1, inst.disks.count())
def
test_notification_read
(
self
):
def
test_notification_read
(
self
):
c
=
Client
()
c
=
Client
()
self
.
login
(
c
,
"user1"
)
self
.
login
(
c
,
"user1"
)
...
...
circle/dashboard/urls.py
View file @
51a45b5a
...
@@ -20,7 +20,7 @@ from django.conf.urls import patterns, url, include
...
@@ -20,7 +20,7 @@ from django.conf.urls import patterns, url, include
from
vm.models
import
Instance
from
vm.models
import
Instance
from
.views
import
(
from
.views
import
(
AclUpdateView
,
DiskAddView
,
FavouriteView
,
GroupAclUpdateView
,
GroupDelete
,
AclUpdateView
,
FavouriteView
,
GroupAclUpdateView
,
GroupDelete
,
GroupDetailView
,
GroupList
,
IndexView
,
GroupDetailView
,
GroupList
,
IndexView
,
InstanceActivityDetail
,
LeaseCreate
,
LeaseDelete
,
LeaseDetail
,
InstanceActivityDetail
,
LeaseCreate
,
LeaseDelete
,
LeaseDetail
,
MyPreferencesView
,
NodeAddTraitView
,
NodeCreate
,
NodeDelete
,
MyPreferencesView
,
NodeAddTraitView
,
NodeCreate
,
NodeDelete
,
...
@@ -128,8 +128,6 @@ urlpatterns = patterns(
...
@@ -128,8 +128,6 @@ urlpatterns = patterns(
url
(
r'^notifications/$'
,
NotificationView
.
as_view
(),
url
(
r'^notifications/$'
,
NotificationView
.
as_view
(),
name
=
"dashboard.views.notifications"
),
name
=
"dashboard.views.notifications"
),
url
(
r'^disk/add/$'
,
DiskAddView
.
as_view
(),
name
=
"dashboard.views.disk-add"
),
url
(
r'^disk/(?P<pk>\d+)/remove/$'
,
DiskRemoveView
.
as_view
(),
url
(
r'^disk/(?P<pk>\d+)/remove/$'
,
DiskRemoveView
.
as_view
(),
name
=
"dashboard.views.disk-remove"
),
name
=
"dashboard.views.disk-remove"
),
url
(
r'^disk/(?P<pk>\d+)/status/$'
,
get_disk_download_status
,
url
(
r'^disk/(?P<pk>\d+)/status/$'
,
get_disk_download_status
,
...
...
circle/dashboard/views.py
View file @
51a45b5a
...
@@ -44,7 +44,6 @@ from django.views.generic import (TemplateView, DetailView, View, DeleteView,
...
@@ -44,7 +44,6 @@ from django.views.generic import (TemplateView, DetailView, View, DeleteView,
from
django.contrib
import
messages
from
django.contrib
import
messages
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ugettext
as
_
from
django.utils.translation
import
ungettext
as
__
from
django.utils.translation
import
ungettext
as
__
from
django.template.defaultfilters
import
title
as
title_filter
from
django.template.loader
import
render_to_string
from
django.template.loader
import
render_to_string
from
django.template
import
RequestContext
from
django.template
import
RequestContext
...
@@ -55,10 +54,11 @@ from braces.views import (LoginRequiredMixin, SuperuserRequiredMixin,
...
@@ -55,10 +54,11 @@ from braces.views import (LoginRequiredMixin, SuperuserRequiredMixin,
from
braces.views._access
import
AccessMixin
from
braces.views._access
import
AccessMixin
from
.forms
import
(
from
.forms
import
(
CircleAuthenticationForm
,
DiskAddForm
,
HostForm
,
LeaseForm
,
MyProfileForm
,
CircleAuthenticationForm
,
HostForm
,
LeaseForm
,
MyProfileForm
,
NodeForm
,
TemplateForm
,
TraitForm
,
VmCustomizeForm
,
GroupCreateForm
,
NodeForm
,
TemplateForm
,
TraitForm
,
VmCustomizeForm
,
GroupCreateForm
,
UserCreationForm
,
GroupProfileUpdateForm
,
UnsubscribeForm
,
UserCreationForm
,
GroupProfileUpdateForm
,
UnsubscribeForm
,
CirclePasswordChangeForm
,
VmSaveForm
,
VmSaveForm
,
CirclePasswordChangeForm
,
VmCreateDiskForm
,
VmDownloadDiskForm
,
)
)
from
.tables
import
(
from
.tables
import
(
...
@@ -126,7 +126,11 @@ class FilterMixin(object):
...
@@ -126,7 +126,11 @@ class FilterMixin(object):
filters
=
{}
filters
=
{}
for
item
in
self
.
allowed_filters
:
for
item
in
self
.
allowed_filters
:
if
item
in
self
.
request
.
GET
:
if
item
in
self
.
request
.
GET
:
filters
[
self
.
allowed_filters
[
item
]]
=
self
.
request
.
GET
[
item
]
filters
[
self
.
allowed_filters
[
item
]]
=
(
self
.
request
.
GET
[
item
]
.
split
(
","
)
if
self
.
allowed_filters
[
item
]
.
endswith
(
"__in"
)
else
self
.
request
.
GET
[
item
])
return
filters
return
filters
def
get_queryset
(
self
):
def
get_queryset
(
self
):
...
@@ -275,12 +279,6 @@ class VmDetailView(CheckedDetailView):
...
@@ -275,12 +279,6 @@ class VmDetailView(CheckedDetailView):
instance
=
self
.
get_object
())
.
values_list
(
"vlan"
,
flat
=
True
)
instance
=
self
.
get_object
())
.
values_list
(
"vlan"
,
flat
=
True
)
)
.
all
()
)
.
all
()
context
[
'acl'
]
=
get_vm_acl_data
(
instance
)
context
[
'acl'
]
=
get_vm_acl_data
(
instance
)
context
[
'forms'
]
=
{
'disk_add_form'
:
DiskAddForm
(
user
=
self
.
request
.
user
,
is_template
=
False
,
object_pk
=
self
.
get_object
()
.
pk
,
prefix
=
"disk"
),
}
context
[
'os_type_icon'
]
=
instance
.
os_type
.
replace
(
"unknown"
,
context
[
'os_type_icon'
]
=
instance
.
os_type
.
replace
(
"unknown"
,
"question"
)
"question"
)
# ipv6 infos
# ipv6 infos
...
@@ -600,6 +598,22 @@ class FormOperationMixin(object):
...
@@ -600,6 +598,22 @@ class FormOperationMixin(object):
return
self
.
get
(
request
)
return
self
.
get
(
request
)
class
VmCreateDiskView
(
FormOperationMixin
,
VmOperationView
):
op
=
'create_disk'
form_class
=
VmCreateDiskForm
show_in_toolbar
=
False
icon
=
'hdd'
class
VmDownloadDiskView
(
FormOperationMixin
,
VmOperationView
):
op
=
'download_disk'
form_class
=
VmDownloadDiskForm
show_in_toolbar
=
False
icon
=
'download'
class
VmMigrateView
(
VmOperationView
):
class
VmMigrateView
(
VmOperationView
):
op
=
'migrate'
op
=
'migrate'
...
@@ -639,6 +653,8 @@ vm_ops = {
...
@@ -639,6 +653,8 @@ vm_ops = {
'destroy'
:
VmOperationView
.
factory
(
op
=
'destroy'
,
icon
=
'remove'
),
'destroy'
:
VmOperationView
.
factory
(
op
=
'destroy'
,
icon
=
'remove'
),
'sleep'
:
VmOperationView
.
factory
(
op
=
'sleep'
,
icon
=
'moon'
),
'sleep'
:
VmOperationView
.
factory
(
op
=
'sleep'
,
icon