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,
for
klass
in
app_models
:
# Force looking up the content types in the current database
# before creating foreign keys to them.
ctype
=
ContentType
.
objects
.
db_manager
(
db
)
.
get_for_model
(
klass
)
ctypes
.
add
(
ctype
)
ctype
1
=
ContentType
.
objects
.
db_manager
(
db
)
.
get_for_model
(
klass
)
ctypes
.
add
(
ctype
1
)
weight
=
0
try
:
for
codename
,
name
in
klass
.
ACL_LEVELS
:
searched_levels
.
append
((
ctype
,
(
codename
,
name
)))
level_weights
.
append
((
ctype
,
codename
,
weight
))
searched_levels
.
append
((
ctype
1
,
(
codename
,
name
)))
level_weights
.
append
((
ctype
1
,
codename
,
weight
))
weight
+=
1
except
AttributeError
:
raise
ImproperlyConfigured
(
...
...
circle/circle/settings/base.py
View file @
51a45b5a
...
...
@@ -18,8 +18,10 @@
"""Common settings and globals."""
# flake8: noqa
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
subprocess
import
check_output
from
django.core.exceptions
import
ImproperlyConfigured
from
django.utils.translation
import
ugettext_lazy
as
_
...
...
@@ -418,6 +420,16 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
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'
),
)
COMPANY_NAME
=
"BME IK 2014"
SOUTH_MIGRATION_MODULES
=
{
...
...
circle/circle/settings/local.py
View file @
51a45b5a
...
...
@@ -16,6 +16,7 @@
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
"""Development settings and globals."""
# flake8: noqa
from
base
import
*
# noqa
...
...
circle/circle/settings/production.py
View file @
51a45b5a
...
...
@@ -16,6 +16,7 @@
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
"""Production settings and globals."""
# flake8: noqa
from
os
import
environ
...
...
circle/circle/settings/test.py
View file @
51a45b5a
...
...
@@ -17,6 +17,8 @@
from
.base
import
*
# noqa
# flake8: noqa
########## IN-MEMORY TEST DATABASE
DATABASES
=
{
"default"
:
{
...
...
circle/circle/urls.py
View file @
51a45b5a
...
...
@@ -30,7 +30,7 @@ admin.autodiscover()
urlpatterns
=
patterns
(
''
,
#url(r'^$', TemplateView.as_view(template_name='base.html')),
#
url(r'^$', TemplateView.as_view(template_name='base.html')),
# Examples:
# url(r'^$', 'circle.views.home', name='home'),
...
...
circle/common/operations.py
View file @
51a45b5a
...
...
@@ -33,6 +33,7 @@ class Operation(object):
required_perms
=
()
do_not_call_in_templates
=
True
abortable
=
False
has_percentage
=
False
def
__call__
(
self
,
**
kwargs
):
return
self
.
call
(
**
kwargs
)
...
...
circle/dashboard/fixtures/test-vm-fixture.json
View file @
51a45b5a
...
...
@@ -38,25 +38,9 @@
"datastore"
:
1
,
"dev_num"
:
"a"
,
"type"
:
"qcow2-norm"
,
"size"
:
8589934592
}
},
{
"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
}
"size"
:
8589934592
,
"is_ready"
:
true
}
},
{
"pk"
:
1
,
...
...
circle/dashboard/forms.py
View file @
51a45b5a
...
...
@@ -24,6 +24,7 @@ from django.contrib.auth.forms import (
PasswordChangeForm
,
)
from
django.contrib.auth.models
import
User
,
Group
from
django.core.validators
import
URLValidator
from
crispy_forms.helper
import
FormHelper
from
crispy_forms.layout
import
(
...
...
@@ -40,9 +41,9 @@ from django.utils.translation import ugettext as _
from
sizefield.widgets
import
FileSizeWidget
from
firewall.models
import
Vlan
,
Host
from
storage.models
import
Disk
,
DataStore
from
storage.models
import
Disk
from
vm.models
import
(
InstanceTemplate
,
Lease
,
InterfaceTemplate
,
Node
,
Trait
,
Instance
InstanceTemplate
,
Lease
,
InterfaceTemplate
,
Node
,
Trait
)
from
.models
import
Profile
,
GroupProfile
from
circle.settings.base
import
LANGUAGES
...
...
@@ -852,20 +853,12 @@ class LeaseForm(forms.ModelForm):
model
=
Lease
class
DiskAddForm
(
forms
.
Form
):
name
=
forms
.
CharField
()
size
=
forms
.
CharField
(
widget
=
FileSizeWidget
,
required
=
False
)
url
=
forms
.
CharField
(
required
=
False
)
is_template
=
forms
.
CharField
()
object_pk
=
forms
.
CharField
()
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
class
VmCreateDiskForm
(
forms
.
Form
):
name
=
forms
.
CharField
(
max_length
=
100
,
label
=
_
(
"Name"
))
size
=
forms
.
CharField
(
widget
=
FileSizeWidget
,
initial
=
(
10
<<
30
),
label
=
_
(
'Size'
),
help_text
=
_
(
'Size of disk to create in bytes or with units '
'like MB or GB.'
))
def
clean_size
(
self
):
size_in_bytes
=
self
.
cleaned_data
.
get
(
"size"
)
...
...
@@ -874,66 +867,23 @@ class DiskAddForm(forms.Form):
" GB or MB!"
))
return
size_in_bytes
def
clean
(
self
):
cleaned_data
=
self
.
cleaned_data
size
=
cleaned_data
.
get
(
"size"
)
url
=
cleaned_data
.
get
(
"url"
)
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
@property
def
helper
(
self
):
helper
=
FormHelper
(
self
)
helper
.
form_tag
=
False
return
helper
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
def
helper
(
self
):
helper
=
FormHelper
()
helper
.
form_show_labels
=
False
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"
),
helper
=
FormHelper
(
self
)
helper
.
add_input
(
Submit
(
"submit"
,
_
(
"Create"
),
css_class
=
"btn btn-success"
))
helper
.
form_tag
=
False
return
helper
...
...
circle/dashboard/static/dashboard/dashboard.css
View file @
51a45b5a
...
...
@@ -705,6 +705,7 @@ textarea[name="list-new-namelist"] {
#group-detail-user-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
,
.no-style-link
,
.no-style-link
:hover
{
color
:
#555
!important
;
...
...
circle/dashboard/static/dashboard/vm-common.js
View file @
51a45b5a
...
...
@@ -3,7 +3,7 @@
$
(
function
()
{
/* 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'
);
$
.
ajax
({
...
...
circle/dashboard/templates/dashboard/index-templates.html
View file @
51a45b5a
...
...
@@ -11,7 +11,7 @@
<div
id=
"dashboard-template-list"
>
{% for t in templates %}
<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"
>
<i
class=
"icon-{{ t.os_type }}"
></i>
{{ t.name }}
</span>
...
...
circle/dashboard/templates/dashboard/template-edit.html
View file @
51a45b5a
...
...
@@ -37,48 +37,62 @@
<th>
{% trans "Who" %}
</th>
<th>
{% trans "What" %}
</th>
<th><i
class=
"icon-remove"
></i></th>
</tr></thead>
</tr>
</thead>
<tbody>
{% for i in acl.users %}
<tr>
<td><i
class=
"icon-user"
></i></td><td>
{{i.user}}
</td>
<td>
<select
class=
"form-control"
name=
"perm-u-{{i.user.id}}"
>
{% for id, name in acl.levels %}
<option
{%
if
id =
i.level%}
selected=
"selected"
{%
endif
%}
value=
"{{id}}"
>
{{name}}
</option>
{% endfor %}
</select>
</td>
<td>
<input
type=
"checkbox"
name=
"remove-u-{{i.user.id}}"
title=
"{% trans "
Remove
"
%}"
/>
</td>
</tr>
{% endfor %}
{% for i in acl.groups %}
<tr>
<td><i
class=
"icon-group"
></i></td><td>
{{i.group}}
</td>
<td>
<select
class=
"form-control"
name=
"perm-g-{{i.group.id}}"
>
{% for id, name in acl.levels %}
<option
{%
if
id =
i.level%}
selected=
"selected"
{%
endif
%}
value=
"{{id}}"
>
{{name}}
</option>
{% endfor %}
</select>
</td>
<td>
<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>
{% for i in acl.users %}
<tr>
<td>
<i
class=
"icon-user"
></i>
</td>
<td>
<a
href=
"{% url "
dashboard
.
views
.
profile
"
username=
i.user.username
%}"
title=
"{{ i.user.username }}"
>
{% include "dashboard/_display-name.html" with user=i.user show_org=True %}
</a>
</td>
<td>
<select
class=
"form-control"
name=
"perm-u-{{i.user.id}}"
>
{% for id, name in acl.levels %}
<option
{%
if
id =
i.level%}
selected=
"selected"
{%
endif
%}
value=
"{{id}}"
>
{{name}}
</option>
{% endfor %}
</select>
</td>
<td>
<input
type=
"checkbox"
name=
"remove-u-{{i.user.id}}"
title=
"{% trans "
Remove
"
%}"
/>
</td>
</tr>
{% endfor %}
{% for i in acl.groups %}
<tr>
<td><i
class=
"icon-group"
></i></td>
<td>
<a
href=
"{% url "
dashboard
.
views
.
group-detail
"
pk=
i.group.pk
%}"
>
{{i.group}}
</a>
</td>
<td>
<select
class=
"form-control"
name=
"perm-g-{{i.group.id}}"
>
{% for id, name in acl.levels %}
<option
{%
if
id =
i.level%}
selected=
"selected"
{%
endif
%}
value=
"{{id}}"
>
{{name}}
</option>
{% endfor %}
</select>
</td>
<td>
<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>
<div
class=
"form-actions"
>
<button
type=
"submit"
class=
"btn btn-success"
>
{% trans "Save" %}
</button>
...
...
@@ -105,17 +119,6 @@
</ul>
</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>
<!-- .row -->
...
...
circle/dashboard/templates/dashboard/vm-detail/_activity-timeline.html
View file @
51a45b5a
...
...
@@ -13,6 +13,9 @@
{% include "dashboard/_display-name.html" with user=a.user show_org=True %}
</a>
{% endif %}
{% if a.has_percent %}
{{ a.percentage }}%
{% endif %}
{% if a.is_abortable_for_user %}
<form
action=
"{{ a.instance.get_absolute_url }}"
method=
"POST"
class=
"pull-right"
>
{% csrf_token %}
...
...
circle/dashboard/templates/dashboard/vm-detail/_operations.html
View file @
51a45b5a
{% load i18n %}
{% for op in ops %}
{% if op.show_in_toolbar %}
<a
href=
"{{op.get_url}}"
class=
"operation operation-{{op.op}} btn btn-default btn-xs"
title=
"{{op.name}}: {{op.description}}"
>
<i
class=
"icon-{{op.icon}}"
></i>
<span
class=
"sr-only"
>
{{op.name}}
</span>
</a>
{% endif %}
{% endfor %}
circle/dashboard/templates/dashboard/vm-detail/resources.html
View file @
51a45b5a
...
...
@@ -47,9 +47,18 @@
<h3>
{% trans "Disks" %}
<div
class=
"pull-right"
>
<a
href=
"#"
id=
"vm-details-disk-add"
class=
"btn btn-success btn-xs"
>
<i
class=
"icon-plus"
></i>
{% trans "Add new disk" %}
</a>
{% if op.download_disk %}
<a
href=
"{{op.download_disk.get_url}}"
class=
"btn btn-success btn-xs
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>
</h3>
...
...
@@ -68,17 +77,6 @@
</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 %}
<style>
...
...
circle/dashboard/tests/test_views.py
View file @
51a45b5a
...
...
@@ -17,7 +17,7 @@
import
json
from
unittest
import
skip
#
from unittest import skip
from
django.test
import
TestCase
from
django.test.client
import
Client
from
django.contrib.auth.models
import
User
,
Group
...
...
@@ -333,38 +333,6 @@ class VmDetailTest(LoginMixin, TestCase):
self
.
assertEqual
(
response
.
status_code
,
302
)
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
):
c
=
Client
()
self
.
login
(
c
,
"user1"
)
...
...
circle/dashboard/urls.py
View file @
51a45b5a
...
...
@@ -20,7 +20,7 @@ from django.conf.urls import patterns, url, include
from
vm.models
import
Instance
from
.views
import
(
AclUpdateView
,
DiskAddView
,
FavouriteView
,
GroupAclUpdateView
,
GroupDelete
,
AclUpdateView
,
FavouriteView
,
GroupAclUpdateView
,
GroupDelete
,
GroupDetailView
,
GroupList
,
IndexView
,
InstanceActivityDetail
,
LeaseCreate
,
LeaseDelete
,
LeaseDetail
,
MyPreferencesView
,
NodeAddTraitView
,
NodeCreate
,
NodeDelete
,
...
...
@@ -128,8 +128,6 @@ urlpatterns = patterns(
url
(
r'^notifications/$'
,
NotificationView
.
as_view
(),
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
(),
name
=
"dashboard.views.disk-remove"
),
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,
from
django.contrib
import
messages
from
django.utils.translation
import
ugettext
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
import
RequestContext
...
...
@@ -55,10 +54,11 @@ from braces.views import (LoginRequiredMixin, SuperuserRequiredMixin,
from
braces.views._access
import
AccessMixin
from
.forms
import
(
CircleAuthenticationForm
,
DiskAddForm
,
HostForm
,
LeaseForm
,
MyProfileForm
,
CircleAuthenticationForm
,
HostForm
,
LeaseForm
,
MyProfileForm
,
NodeForm
,
TemplateForm
,
TraitForm
,
VmCustomizeForm
,
GroupCreateForm
,
UserCreationForm
,
GroupProfileUpdateForm
,
UnsubscribeForm
,
CirclePasswordChangeForm
,
VmSaveForm
,
VmSaveForm
,
CirclePasswordChangeForm
,
VmCreateDiskForm
,
VmDownloadDiskForm
,
)
from
.tables
import
(
...
...
@@ -126,7 +126,11 @@ class FilterMixin(object):
filters
=
{}
for
item
in
self
.
allowed_filters
:
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
def
get_queryset
(
self
):
...
...
@@ -275,12 +279,6 @@ class VmDetailView(CheckedDetailView):
instance
=
self
.
get_object
())
.
values_list
(
"vlan"
,
flat
=
True
)
)
.
all
()
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"
,
"question"
)
# ipv6 infos
...
...
@@ -600,6 +598,22 @@ class FormOperationMixin(object):
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
):
op
=
'migrate'
...
...
@@ -639,6 +653,8 @@ vm_ops = {
'destroy'
:
VmOperationView
.
factory
(
op
=
'destroy'
,
icon
=
'remove'
),
'sleep'
:
VmOperationView
.
factory
(
op
=
'sleep'
,
icon
=
'moon'
),
'wake_up'
:
VmOperationView
.
factory
(
op
=
'wake_up'
,
icon
=
'sun'
),
'create_disk'
:
VmCreateDiskView
,
'download_disk'
:
VmDownloadDiskView
,
}
...
...
@@ -897,7 +913,9 @@ class TemplateAclUpdateView(AclUpdateView):
post_for_disk
[
'perm-new'
]
=
'user'
request
.
POST
=
post_for_disk
for
d
in
template
.
disks
.
all
():
self
.
set_levels
(
request
,
d
)
self
.
add_levels
(
request
,
d
)
self
.
remove_levels
(
request
,
d
)
return
redirect
(
template
)
...
...
@@ -1064,12 +1082,6 @@ class TemplateDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
context
=
super
(
TemplateDetail
,
self
)
.
get_context_data
(
**
kwargs
)
context
[
'acl'
]
=
get_vm_acl_data
(
obj
)
context
[
'disks'
]
=
obj
.
disks
.
all
()
context
[
'disk_add_form'
]
=
DiskAddForm
(
user
=
self
.
request
.
user
,
is_template
=
True
,
object_pk
=
obj
.
pk
,
prefix
=
"disk"
,
)
return
context
def
get_success_url
(
self
):
...
...
@@ -1150,7 +1162,8 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
'name'
:
"name__icontains"
,
'node'
:
"node__name__icontains"
,
'status'
:
"status__iexact"
,
'tags'
:
"tags__name__in"
,
# note: use it as ?tags[]=a,b
'tags[]'
:
"tags__name__in"
,
'tags'
:
"tags__name__in"
,
# for search string
'owner'
:
"owner__username"
,
}
...
...
@@ -1189,8 +1202,10 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
(
sort
[
1
:]
if
sort
[
0
]
==
"-"
else
sort
)
in
[
i
.
name
for
i
in
Instance
.
_meta
.
fields
]
+
[
"pk"
]):
queryset
=
queryset
.
order_by
(
sort
)
return
queryset
.
filter
(
**
self
.
get_queryset_filters
()
)
.
select_related
(
'owner'
,
'node'
)
return
queryset
.
filter
(
**
self
.
get_queryset_filters
())
.
select_related
(
'owner'
,
'node'
)
.
distinct
()
def
create_fake_get
(
self
):
"""
...
...
@@ -1222,8 +1237,7 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
# generate a new GET request, that is kinda fake
fake
=
self
.
request
.
GET
.
copy
()
for
k
,
v
in
got
.
iteritems
():
fake
[
"
%
s
%
s"
%
(
k
,
"[]"
if
len
(
v
.
split
(
","
))
>
1
else
""
)]
=
v
fake
[
k
]
=
v
self
.
request
.
GET
=
fake
...
...
@@ -2523,47 +2537,6 @@ def circle_login(request):
return
response
class
DiskAddView
(
TemplateView
):
def
post
(
self
,
*
args
,
**
kwargs
):
is_template
=
self
.
request
.
POST
.
get
(
"disk-is_template"
)
object_pk
=
self
.
request
.
POST
.
get
(
"disk-object_pk"
)
is_template
=
int
(
is_template
)
==
1
if
is_template
:
obj
=
InstanceTemplate
.
objects
.
get
(
pk
=
object_pk
)
else
:
obj
=
Instance
.
objects
.
get
(
pk
=
object_pk
)
if
not
obj
.
has_level
(
self
.
request
.
user
,
'owner'
):
raise
PermissionDenied
()
form
=
DiskAddForm
(
self
.
request
.
POST
,
user
=
self
.
request
.
user
,
is_template
=
is_template
,
object_pk
=
object_pk
,
prefix
=
"disk"
)
if
form
.
is_valid
():
if
form
.
cleaned_data
.
get
(
"size"
):
messages
.
success
(
self
.
request
,
_
(
"Disk successfully added."
))
else
:
messages
.
success
(
self
.
request
,
_
(
"Disk download started."
))
form
.
save
()
else
:
error
=
"<br /> "
.
join
([
"<strong>
%
s</strong>:
%
s"
%
(
title_filter
(
i
[
0
]),
i
[
1
][
0
])
for
i
in
form
.
errors
.
items
()])
messages
.
error
(
self
.
request
,
error
)
if
is_template
:
r
=
obj
.
get_absolute_url
()
else
:
r
=
obj
.
get_absolute_url
()
r
=
"
%
s#resources"
%
r
return
redirect
(
r
)
class
MyPreferencesView
(
UpdateView
):
model
=
Profile
...
...
circle/firewall/fields.py
View file @
51a45b5a
...
...
@@ -201,7 +201,7 @@ class IPNetworkField(models.Field):
return
super
(
IPNetworkField
,
self
)
.
formfield
(
**
defaults
)
add_introspection_rules
([],
[
"firewall
\
.fields
\
.
MACAddressField
"
])
add_introspection_rules
([],
[
"firewall
\
.fields
\
."
])
def
val_alfanum
(
value
):
...
...
circle/firewall/models.py
View file @
51a45b5a
...
...
@@ -52,7 +52,7 @@ class Rule(models.Model):
Others set address translation or other free-form iptables parameters.
"""
CHOICES_type
=
((
'host'
,
'host'
),
(
'firewall'
,
'firewall'
),
(
'vlan'
,
'vlan'
))
(
'vlan'
,
'vlan'
))
CHOICES_proto
=
((
'tcp'
,
'tcp'
),
(
'udp'
,
'udp'
),
(
'icmp'
,
'icmp'
))
CHOICES_dir
=
((
'out'
,
_
(
'out'
)),
(
'in'
,
_
(
'in'
)))
CHOICES_action
=
((
'accept'
,
_
(
'accept'
)),
(
'drop'
,
_
(
'drop'
)),
...
...
@@ -820,7 +820,7 @@ class Domain(models.Model):
class
Record
(
models
.
Model
):
CHOICES_type
=
((
'A'
,
'A'
),
(
'CNAME'
,
'CNAME'
),
(
'AAAA'
,
'AAAA'
),
(
'MX'
,
'MX'
),
(
'NS'
,
'NS'
),
(
'PTR'
,
'PTR'
),
(
'TXT'
,
'TXT'
))
(
'MX'
,
'MX'
),
(
'NS'
,
'NS'
),
(
'PTR'
,
'PTR'
),
(
'TXT'
,
'TXT'
))