Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Gutyán Gábor
/
circlestack
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
90122b75
authored
Sep 03, 2014
by
Őry Máté
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature-template-list' into 'master'
Template list upgrade and show deleted vms Closes #234 Closes #258
parents
0963fa06
986782b5
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
252 additions
and
92 deletions
+252
-92
circle/dashboard/forms.py
+25
-1
circle/dashboard/static/dashboard/dashboard.css
+12
-2
circle/dashboard/static/dashboard/dashboard.js
+8
-0
circle/dashboard/static/dashboard/template-list.js
+1
-0
circle/dashboard/static/dashboard/vm-list.js
+5
-2
circle/dashboard/tables.py
+10
-9
circle/dashboard/templates/dashboard/_display-name.html
+1
-5
circle/dashboard/templates/dashboard/profile_form.html
+2
-2
circle/dashboard/templates/dashboard/template-list.html
+17
-0
circle/dashboard/templates/dashboard/template-list/column-template-actions.html
+4
-0
circle/dashboard/templates/dashboard/template-list/column-template-created.html
+3
-0
circle/dashboard/templates/dashboard/template-list/column-template-owner.html
+1
-1
circle/dashboard/templates/dashboard/template-list/column-template-resources.html
+9
-0
circle/dashboard/templates/dashboard/template-list/column-template-running.html
+1
-1
circle/dashboard/templates/dashboard/vm-list.html
+34
-7
circle/dashboard/views.py
+114
-55
circle/vm/models/instance.py
+5
-1
miscellaneous/manager.conf
+0
-1
miscellaneous/mancelery.conf
+0
-1
miscellaneous/moncelery.conf
+0
-1
miscellaneous/portal-uwsgi.conf
+0
-1
miscellaneous/portal.conf
+0
-1
miscellaneous/slowcelery.conf
+0
-1
No files found.
circle/dashboard/forms.py
View file @
90122b75
...
@@ -1199,7 +1199,12 @@ class VmListSearchForm(forms.Form):
...
@@ -1199,7 +1199,12 @@ class VmListSearchForm(forms.Form):
}))
}))
stype
=
forms
.
ChoiceField
(
vm_search_choices
,
widget
=
forms
.
Select
(
attrs
=
{
stype
=
forms
.
ChoiceField
(
vm_search_choices
,
widget
=
forms
.
Select
(
attrs
=
{
'class'
:
"btn btn-default input-tags"
,
'class'
:
"btn btn-default form-control input-tags"
,
'style'
:
"min-width: 80px;"
,
}))
include_deleted
=
forms
.
BooleanField
(
widget
=
forms
.
CheckboxInput
(
attrs
=
{
'id'
:
"vm-list-search-checkbox"
,
}))
}))
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
...
@@ -1209,3 +1214,22 @@ class VmListSearchForm(forms.Form):
...
@@ -1209,3 +1214,22 @@ class VmListSearchForm(forms.Form):
data
=
self
.
data
.
copy
()
data
=
self
.
data
.
copy
()
data
[
'stype'
]
=
"all"
data
[
'stype'
]
=
"all"
self
.
data
=
data
self
.
data
=
data
class
TemplateListSearchForm
(
forms
.
Form
):
s
=
forms
.
CharField
(
widget
=
forms
.
TextInput
(
attrs
=
{
'class'
:
"form-control input-tags"
,
'placeholder'
:
_
(
"Search..."
)
}))
stype
=
forms
.
ChoiceField
(
vm_search_choices
,
widget
=
forms
.
Select
(
attrs
=
{
'class'
:
"btn btn-default input-tags"
,
}))
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
TemplateListSearchForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
# set initial value, otherwise it would be overwritten by request.GET
if
not
self
.
data
.
get
(
"stype"
):
data
=
self
.
data
.
copy
()
data
[
'stype'
]
=
"owned"
self
.
data
=
data
circle/dashboard/static/dashboard/dashboard.css
View file @
90122b75
...
@@ -868,10 +868,10 @@ textarea[name="list-new-namelist"] {
...
@@ -868,10 +868,10 @@ textarea[name="list-new-namelist"] {
padding
:
5px
0px
;
padding
:
5px
0px
;
}
}
#profile-key-list-table
td
:last-child
,
#profile-key-list-table
th
:last-child
,
#profile-key-list-table
td
:last-child
,
#profile-key-list-table
th
:last-child
,
#profile-command-list-table
td
:last-child
,
#profile-command-list-table
th
:last-child
,
#profile-command-list-table
td
:last-child
,
#profile-command-list-table
th
:last-child
,
#profile-command-list-table
td
:nth-child
(
2
),
#profile-command-list-table
th
:nth-child
(
2
)
{
#profile-command-list-table
td
:nth-child
(
2
),
#profile-command-list-table
th
:nth-child
(
2
)
{
text-align
:
center
;
text-align
:
center
;
vertical-align
:
middle
;
vertical-align
:
middle
;
}
}
...
@@ -946,3 +946,13 @@ textarea[name="list-new-namelist"] {
...
@@ -946,3 +946,13 @@ textarea[name="list-new-namelist"] {
#vm-list-search
,
#vm-mass-ops
{
#vm-list-search
,
#vm-mass-ops
{
margin-top
:
8px
;
margin-top
:
8px
;
}
}
#vm-list-search-checkbox
{
margin-top
:
-1px
;
display
:
inline-block
;
vertical-align
:
middle
;
}
#vm-list-search-checkbox-span
{
cursor
:
pointer
}
circle/dashboard/static/dashboard/dashboard.js
View file @
90122b75
...
@@ -617,3 +617,11 @@ function noJS() {
...
@@ -617,3 +617,11 @@ function noJS() {
$
(
'.no-js-hidden'
).
show
();
$
(
'.no-js-hidden'
).
show
();
$
(
'.js-hidden'
).
hide
();
$
(
'.js-hidden'
).
hide
();
}
}
function
getParameterByName
(
name
)
{
name
=
name
.
replace
(
/
[\[]
/
,
"\\["
).
replace
(
/
[\]]
/
,
"\\]"
);
var
regex
=
new
RegExp
(
"[\\?&]"
+
name
+
"=([^&#]*)"
),
results
=
regex
.
exec
(
location
.
search
);
return
results
==
null
?
""
:
decodeURIComponent
(
results
[
1
].
replace
(
/
\+
/g
,
" "
));
}
circle/dashboard/static/dashboard/template-list.js
View file @
90122b75
...
@@ -39,6 +39,7 @@ $(function() {
...
@@ -39,6 +39,7 @@ $(function() {
$
(
".template-list-table thead th"
).
css
(
"cursor"
,
"pointer"
);
$
(
".template-list-table thead th"
).
css
(
"cursor"
,
"pointer"
);
$
(
".template-list-table th a"
).
on
(
"click"
,
function
(
event
)
{
$
(
".template-list-table th a"
).
on
(
"click"
,
function
(
event
)
{
if
(
!
$
(
this
).
closest
(
"th"
).
data
(
"sort"
))
return
true
;
event
.
preventDefault
();
event
.
preventDefault
();
});
});
});
});
...
...
circle/dashboard/static/dashboard/vm-list.js
View file @
90122b75
...
@@ -163,9 +163,10 @@ $(function() {
...
@@ -163,9 +163,10 @@ $(function() {
$
(
this
).
find
(
'input[type="radio"]'
).
prop
(
"checked"
,
true
);
$
(
this
).
find
(
'input[type="radio"]'
).
prop
(
"checked"
,
true
);
});
});
if
(
checkStatusUpdate
())
{
if
(
checkStatusUpdate
()
||
$
(
"#vm-list-table tbody tr"
).
length
>=
100
)
{
updateStatuses
(
1
);
updateStatuses
(
1
);
}
}
});
});
...
@@ -178,6 +179,7 @@ function checkStatusUpdate() {
...
@@ -178,6 +179,7 @@ function checkStatusUpdate() {
function
updateStatuses
(
runs
)
{
function
updateStatuses
(
runs
)
{
var
include_deleted
=
getParameterByName
(
"include_deleted"
);
$
.
get
(
"/dashboard/vm/list/?compact"
,
function
(
result
)
{
$
.
get
(
"/dashboard/vm/list/?compact"
,
function
(
result
)
{
$
(
"#vm-list-table tbody tr"
).
each
(
function
()
{
$
(
"#vm-list-table tbody tr"
).
each
(
function
()
{
vm
=
$
(
this
).
data
(
"vm-pk"
);
vm
=
$
(
this
).
data
(
"vm-pk"
);
...
@@ -203,7 +205,8 @@ function updateStatuses(runs) {
...
@@ -203,7 +205,8 @@ function updateStatuses(runs) {
$
(
this
).
find
(
".node"
).
text
(
result
[
vm
].
node
);
$
(
this
).
find
(
".node"
).
text
(
result
[
vm
].
node
);
}
}
}
else
{
}
else
{
$
(
this
).
remove
();
if
(
!
include_deleted
)
$
(
this
).
remove
();
}
}
});
});
...
...
circle/dashboard/tables.py
View file @
90122b75
...
@@ -147,13 +147,11 @@ class TemplateListTable(Table):
...
@@ -147,13 +147,11 @@ class TemplateListTable(Table):
template_name
=
"dashboard/template-list/column-template-name.html"
,
template_name
=
"dashboard/template-list/column-template-name.html"
,
attrs
=
{
'th'
:
{
'data-sort'
:
"string"
}}
attrs
=
{
'th'
:
{
'data-sort'
:
"string"
}}
)
)
num_cores
=
Column
(
resources
=
TemplateColumn
(
verbose_name
=
_
(
"Cores"
),
template_name
=
"dashboard/template-list/column-template-resources.html"
,
attrs
=
{
'th'
:
{
'data-sort'
:
"int"
}}
verbose_name
=
_
(
"Resources"
),
)
ram_size
=
TemplateColumn
(
"{{ record.ram_size }} MiB"
,
attrs
=
{
'th'
:
{
'data-sort'
:
"int"
}},
attrs
=
{
'th'
:
{
'data-sort'
:
"int"
}},
order_by
=
(
"ram_size"
),
)
)
lease
=
TemplateColumn
(
lease
=
TemplateColumn
(
"{{ record.lease.name }}"
,
"{{ record.lease.name }}"
,
...
@@ -171,11 +169,14 @@ class TemplateListTable(Table):
...
@@ -171,11 +169,14 @@ class TemplateListTable(Table):
verbose_name
=
_
(
"Owner"
),
verbose_name
=
_
(
"Owner"
),
attrs
=
{
'th'
:
{
'data-sort'
:
"string"
}}
attrs
=
{
'th'
:
{
'data-sort'
:
"string"
}}
)
)
created
=
TemplateColumn
(
template_name
=
"dashboard/template-list/column-template-created.html"
,
verbose_name
=
_
(
"Created at"
),
)
running
=
TemplateColumn
(
running
=
TemplateColumn
(
template_name
=
"dashboard/template-list/column-template-running.html"
,
template_name
=
"dashboard/template-list/column-template-running.html"
,
verbose_name
=
_
(
"Running"
),
verbose_name
=
_
(
"Running"
),
attrs
=
{
'th'
:
{
'data-sort'
:
"int"
}},
attrs
=
{
'th'
:
{
'data-sort'
:
"int"
}},
orderable
=
False
,
)
)
actions
=
TemplateColumn
(
actions
=
TemplateColumn
(
verbose_name
=
_
(
"Actions"
),
verbose_name
=
_
(
"Actions"
),
...
@@ -188,8 +189,8 @@ class TemplateListTable(Table):
...
@@ -188,8 +189,8 @@ class TemplateListTable(Table):
model
=
InstanceTemplate
model
=
InstanceTemplate
attrs
=
{
'class'
:
(
'table table-bordered table-striped table-hover'
attrs
=
{
'class'
:
(
'table table-bordered table-striped table-hover'
' template-list-table'
)}
' template-list-table'
)}
fields
=
(
'name'
,
'
num_cores'
,
'ram_size'
,
'system
'
,
fields
=
(
'name'
,
'
resources'
,
'system'
,
'access_method'
,
'lease
'
,
'
access_method'
,
'lease'
,
'owner
'
,
'running'
,
'actions'
,
)
'
owner'
,
'created
'
,
'running'
,
'actions'
,
)
prefix
=
"template-"
prefix
=
"template-"
...
...
circle/dashboard/templates/dashboard/_display-name.html
View file @
90122b75
{% load i18n %}
{% load i18n %}
{% if user and user.pk %}
{% if user and user.pk %}
{% if user.get_full_name %}
{% if user.get_full_name %}{{ user.get_full_name }}{% else %}{{ user.username }}{% endif %}{% if new_line %}
<br
/>
{% endif %}
{{ user.get_full_name }}
{% else %}
{{ user.username }}
{% endif %}
{% if show_org %}
{% if show_org %}
{% if user.profile and user.profile.org_id %}
{% if user.profile and user.profile.org_id %}
...
...
circle/dashboard/templates/dashboard/profile_form.html
View file @
90122b75
...
@@ -70,7 +70,7 @@
...
@@ -70,7 +70,7 @@
<div
class=
"col-md-12"
>
<div
class=
"col-md-12"
>
<div
class=
"panel panel-default"
>
<div
class=
"panel panel-default"
>
<div
class=
"panel-heading"
>
<div
class=
"panel-heading"
>
<a
href=
"{% url "
dashboard
.
views
.
connect-command-create
"
%}"
<a
href=
"{% url "
dashboard
.
views
.
connect-command-create
"
%}"
class=
"pull-right btn btn-success btn-xs"
style=
"margin-right: 10px;"
>
class=
"pull-right btn btn-success btn-xs"
style=
"margin-right: 10px;"
>
<i
class=
"fa fa-plus"
></i>
{% trans "add command template" %}
<i
class=
"fa fa-plus"
></i>
{% trans "add command template" %}
</a>
</a>
...
@@ -82,4 +82,4 @@
...
@@ -82,4 +82,4 @@
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% endblock %}
circle/dashboard/templates/dashboard/template-list.html
View file @
90122b75
...
@@ -16,6 +16,23 @@
...
@@ -16,6 +16,23 @@
<h3
class=
"no-margin"
><i
class=
"fa fa-puzzle-piece"
></i>
{% trans "Templates" %}
</h3>
<h3
class=
"no-margin"
><i
class=
"fa fa-puzzle-piece"
></i>
{% trans "Templates" %}
</h3>
</div>
</div>
<div
class=
"panel-body"
>
<div
class=
"panel-body"
>
<div
class=
"row"
>
<div
class=
"col-md-offset-8 col-md-4"
id=
"template-list-search"
>
<form
action=
""
method=
"GET"
>
<div
class=
"input-group"
>
{{ search_form.s }}
<div
class=
"input-group-btn"
>
{{ search_form.stype }}
<button
type=
"submit"
class=
"btn btn-primary input-tags"
>
<i
class=
"fa fa-search"
></i>
</button>
</div>
</div>
<!-- .input-group -->
</form>
</div>
<!-- .col-md-4 #template-list-search -->
</div>
</div>
<div
class=
"panel-body"
>
{% render_table table %}
{% render_table table %}
</div>
</div>
</div>
</div>
...
...
circle/dashboard/templates/dashboard/template-list/column-template-actions.html
View file @
90122b75
{% load i18n %}
{% load i18n %}
<a
href=
"{% url "
dashboard
.
views
.
vm-create
"
%}?
template=
{{
record
.
pk
}}"
class=
"btn btn-success btn-xs customize-vm"
title=
"{% trans "
Start
"
%}"
>
<i
class=
"fa fa-play"
></i>
</a>
<a
href=
"{% url "
dashboard
.
views
.
template-detail
"
pk=
record.pk%}"
id=
"template-list-edit-button"
class=
"btn btn-default btn-xs"
title=
"{% trans "
Edit
"
%}"
>
<a
href=
"{% url "
dashboard
.
views
.
template-detail
"
pk=
record.pk%}"
id=
"template-list-edit-button"
class=
"btn btn-default btn-xs"
title=
"{% trans "
Edit
"
%}"
>
<i
class=
"fa fa-edit"
></i>
<i
class=
"fa fa-edit"
></i>
</a>
</a>
...
...
circle/dashboard/templates/dashboard/template-list/column-template-created.html
0 → 100644
View file @
90122b75
{{ record.created|date }}
<br
/>
{{ record.created|time }}
circle/dashboard/templates/dashboard/template-list/column-template-owner.html
View file @
90122b75
{% include "dashboard/_display-name.html" with user=record.owner show_org=True %}
{% include "dashboard/_display-name.html" with user=record.owner show_org=True
new_line=True
%}
circle/dashboard/templates/dashboard/template-list/column-template-resources.html
0 → 100644
View file @
90122b75
{% load i18n %}
{{ record.ram_size }}MiB RAM
<br
/>
{% blocktrans with num_cores=record.num_cores count count=record.num_cores %}
{{ num_cores }} CPU core
{% plural %}
{{ num_cores }} CPU cores
{% endblocktrans %}
circle/dashboard/templates/dashboard/template-list/column-template-running.html
View file @
90122b75
<a
href=
"{% url "
dashboard
.
views
.
vm-list
"
%}?
s=
template:{{
record
.
pk
}}%
20status:running
"
>
<a
href=
"{% url "
dashboard
.
views
.
vm-list
"
%}?
s=
template:{{
record
.
pk
}}%
20status:running
"
>
{{ record.
get_running_instances.count
}}
{{ record.
running
}}
</a>
</a>
circle/dashboard/templates/dashboard/vm-list.html
View file @
90122b75
...
@@ -33,6 +33,12 @@
...
@@ -33,6 +33,12 @@
{{ search_form.s }}
{{ search_form.s }}
<div
class=
"input-group-btn"
>
<div
class=
"input-group-btn"
>
{{ search_form.stype }}
{{ search_form.stype }}
</div>
<label
class=
"input-group-addon input-tags"
title=
"{% trans "
Include
deleted
VMs
"
%}"
id=
"vm-list-search-checkbox-span"
data-container=
"body"
>
{{ search_form.include_deleted }}
</label>
<div
class=
"input-group-btn"
>
<button
type=
"submit"
class=
"btn btn-primary input-tags"
>
<button
type=
"submit"
class=
"btn btn-primary input-tags"
>
<i
class=
"fa fa-search"
></i>
<i
class=
"fa fa-search"
></i>
</button>
</button>
...
@@ -62,10 +68,20 @@
...
@@ -62,10 +68,20 @@
{% trans "Owner" as t %}
{% trans "Owner" as t %}
{% include "dashboard/vm-list/header-link.html" with name=t sort="owner" %}
{% include "dashboard/vm-list/header-link.html" with name=t sort="owner" %}
</th>
</th>
{% if user.is_superuser %}
<th
data-sort=
"string"
class=
"orderable sortable"
>
<th
data-sort=
"string"
class=
"orderable sortable"
>
{% trans "Node" as t %}
{% trans "Lease" as t %}
{% include "dashboard/vm-list/header-link.html" with name=t sort="node" %}
{% include "dashboard/vm-list/header-link.html" with name=t sort="lease" %}
</th>
{% endif %}
</th>
{% if user.is_superuser %}
<th
data-sort=
"string"
class=
"orderable sortable"
>
{% trans "IP address" as t %}
{% include "dashboard/vm-list/header-link.html" with name=t sort="ip_addr" %}
</th>
<th
data-sort=
"string"
class=
"orderable sortable"
>
{% trans "Node" as t %}
{% include "dashboard/vm-list/header-link.html" with name=t sort="node" %}
</th>
{% endif %}
</tr></thead><tbody>
</tr></thead><tbody>
{% for i in object_list %}
{% for i in object_list %}
<tr
class=
"{% cycle 'odd' 'even' %}"
data-vm-pk=
"{{ i.pk }}"
>
<tr
class=
"{% cycle 'odd' 'even' %}"
data-vm-pk=
"{{ i.pk }}"
>
...
@@ -73,16 +89,27 @@
...
@@ -73,16 +89,27 @@
<td
class=
"name"
><a
class=
"real-link"
href=
"{% url "
dashboard
.
views
.
detail
"
i
.
pk
%}"
>
{{ i.name }}
</a>
</td>
<td
class=
"name"
><a
class=
"real-link"
href=
"{% url "
dashboard
.
views
.
detail
"
i
.
pk
%}"
>
{{ i.name }}
</a>
</td>
<td
class=
"state"
>
<td
class=
"state"
>
<i
class=
"fa fa-fw
<i
class=
"fa fa-fw
{% if i.is_in_status_change %}
{% if
show_acts_in_progress and
i.is_in_status_change %}
fa-spin fa-spinner
fa-spin fa-spinner
{% else %}
{% else %}
{{ i.get_status_icon }}{% endif %}"
></i>
{{ i.get_status_icon }}{% endif %}"
></i>
<span>
{{ i.get_status_display }}
</span>
<span>
{{ i.get_status_display }}
</span>
</td>
</td>
<td>
<td>
{% include "dashboard/_display-name.html" with user=i.owner show_org=True %}
{% if i.owner.profile %}
{{ i.owner.profile.get_display_name }}
{% else %}
{{ i.owner.username }}
{% endif %}
{# include "dashboard/_display-name.html" with user=i.owner show_org=True #}
</td>
<td
class=
"lease "
data-sort-value=
"{{ i.lease.name }}"
>
{{ i.lease.name }}
</td>
</td>
{% if user.is_superuser %}
{% if user.is_superuser %}
<td
class=
"ip_addr "
data-sort-value=
"{{ i.ipv4 }}"
>
{{ i.ipv4|default:"-" }}
</td>
<td
class=
"node "
data-sort-value=
"{{ i.node.normalized_name }}"
>
<td
class=
"node "
data-sort-value=
"{{ i.node.normalized_name }}"
>
{{ i.node.name|default:"-" }}
{{ i.node.name|default:"-" }}
</td>
</td>
...
@@ -90,7 +117,7 @@
...
@@ -90,7 +117,7 @@
</tr>
</tr>
{% empty %}
{% empty %}
<tr>
<tr>
<td
colspan=
"
5
"
>
<td
colspan=
"
7
"
>
{% if request.GET.s %}
{% if request.GET.s %}
<strong>
{% trans "No result." %}
</strong>
<strong>
{% trans "No result." %}
</strong>
{% else %}
{% else %}
...
...
circle/dashboard/views.py
View file @
90122b75
...
@@ -70,7 +70,8 @@ from .forms import (
...
@@ -70,7 +70,8 @@ from .forms import (
VmSaveForm
,
UserKeyForm
,
VmRenewForm
,
VmStateChangeForm
,
VmSaveForm
,
UserKeyForm
,
VmRenewForm
,
VmStateChangeForm
,
CirclePasswordChangeForm
,
VmCreateDiskForm
,
VmDownloadDiskForm
,
CirclePasswordChangeForm
,
VmCreateDiskForm
,
VmDownloadDiskForm
,
TraitsForm
,
RawDataForm
,
GroupPermissionForm
,
AclUserAddForm
,
TraitsForm
,
RawDataForm
,
GroupPermissionForm
,
AclUserAddForm
,
VmResourcesForm
,
VmAddInterfaceForm
,
VmListSearchForm
,
ConnectCommandForm
VmResourcesForm
,
VmAddInterfaceForm
,
VmListSearchForm
,
TemplateListSearchForm
,
ConnectCommandForm
)
)
from
.tables
import
(
from
.tables
import
(
...
@@ -173,6 +174,65 @@ class FilterMixin(object):
...
@@ -173,6 +174,65 @@ class FilterMixin(object):
return
super
(
FilterMixin
,
return
super
(
FilterMixin
,
self
)
.
get_queryset
()
.
filter
(
**
self
.
get_queryset_filters
())
self
)
.
get_queryset
()
.
filter
(
**
self
.
get_queryset_filters
())
def
create_fake_get
(
self
):
self
.
request
.
GET
=
self
.
_parse_get
(
self
.
request
.
GET
)
def
_parse_get
(
self
,
GET_dict
):
"""
Returns a new dict from request's GET dict to filter the vm list
For example: "name:xy node:1" updates the GET dict
to resemble this URL ?name=xy&node=1
"name:xy node:1".split(":") becomes ["name", "xy node", "1"]
we pop the the first element and use it as the first dict key
then we iterate over the rest of the list and split by the last
whitespace, the first part of this list will be the previous key's
value, then last part of the list will be the next key.
The final dict looks like this: {'name': xy, 'node':1}
>>> f = FilterMixin()
>>> o = f._parse_get({'s': "hello"}).items()
>>> sorted(o) # doctest: +ELLIPSIS
[(u'name', u'hello'), (...)]
>>> o = f._parse_get({'s': "name:hello owner:test"}).items()
>>> sorted(o) # doctest: +ELLIPSIS
[(u'name', u'hello'), (u'owner', u'test'), (...)]
>>> o = f._parse_get({'s': "name:hello ws node:node 3 oh"}).items()
>>> sorted(o) # doctest: +ELLIPSIS
[(u'name', u'hello ws'), (u'node', u'node 3 oh'), (...)]
"""
s
=
GET_dict
.
get
(
"s"
)
fake
=
GET_dict
.
copy
()
if
s
:
s
=
s
.
split
(
":"
)
if
len
(
s
)
<
2
:
# if there is no ':' in the string, filter by name
got
=
{
'name'
:
s
[
0
]}
else
:
latest
=
s
.
pop
(
0
)
got
=
{
'
%
s'
%
latest
:
None
}
for
i
in
s
[:
-
1
]:
new
=
i
.
rsplit
(
" "
,
1
)
got
[
latest
]
=
new
[
0
]
latest
=
new
[
1
]
if
len
(
new
)
>
1
else
None
got
[
latest
]
=
s
[
-
1
]
# generate a new GET request, that is kinda fake
for
k
,
v
in
got
.
iteritems
():
fake
[
k
]
=
v
return
fake
def
create_acl_queryset
(
self
,
model
):
cleaned_data
=
self
.
search_form
.
cleaned_data
stype
=
cleaned_data
.
get
(
'stype'
,
"all"
)
superuser
=
stype
==
"all"
shared
=
stype
==
"shared"
level
=
"owner"
if
stype
==
"owned"
else
"user"
queryset
=
model
.
get_objects_with_level
(
level
,
self
.
request
.
user
,
group_also
=
shared
,
disregard_superuser
=
not
superuser
,
)
return
queryset
class
IndexView
(
LoginRequiredMixin
,
TemplateView
):
class
IndexView
(
LoginRequiredMixin
,
TemplateView
):
template_name
=
"dashboard/index.html"
template_name
=
"dashboard/index.html"
...
@@ -1641,23 +1701,60 @@ class TemplateDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
...
@@ -1641,23 +1701,60 @@ class TemplateDetail(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
return
kwargs
return
kwargs
class
TemplateList
(
LoginRequiredMixin
,
SingleTableView
):
class
TemplateList
(
LoginRequiredMixin
,
FilterMixin
,
SingleTableView
):
template_name
=
"dashboard/template-list.html"
template_name
=
"dashboard/template-list.html"
model
=
InstanceTemplate
model
=
InstanceTemplate
table_class
=
TemplateListTable
table_class
=
TemplateListTable
table_pagination
=
False
table_pagination
=
False
allowed_filters
=
{
'name'
:
"name__icontains"
,
'tags[]'
:
"tags__name__in"
,
'tags'
:
"tags__name__in"
,
# for search string
'owner'
:
"owner__username"
,
'ram'
:
"ram_size"
,
'ram_size'
:
"ram_size"
,
'cores'
:
"num_cores"
,
'num_cores'
:
"num_cores"
,
'access_method'
:
"access_method__iexact"
,
}
def
get_context_data
(
self
,
*
args
,
**
kwargs
):
def
get_context_data
(
self
,
*
args
,
**
kwargs
):
context
=
super
(
TemplateList
,
self
)
.
get_context_data
(
*
args
,
**
kwargs
)
context
=
super
(
TemplateList
,
self
)
.
get_context_data
(
*
args
,
**
kwargs
)
context
[
'lease_table'
]
=
LeaseListTable
(
Lease
.
objects
.
all
(),
context
[
'lease_table'
]
=
LeaseListTable
(
request
=
self
.
request
)
Lease
.
get_objects_with_level
(
"user"
,
self
.
request
.
user
),
request
=
self
.
request
)
context
[
'search_form'
]
=
self
.
search_form
return
context
return
context
def
get
(
self
,
*
args
,
**
kwargs
):
self
.
search_form
=
TemplateListSearchForm
(
self
.
request
.
GET
)
self
.
search_form
.
full_clean
()
return
super
(
TemplateList
,
self
)
.
get
(
*
args
,
**
kwargs
)
def
create_acl_queryset
(
self
,
model
):
queryset
=
super
(
TemplateList
,
self
)
.
create_acl_queryset
(
model
)
sql
=
(
"SELECT count(*) FROM vm_instance WHERE "
"vm_instance.template_id = vm_instancetemplate.id and "
"vm_instance.destroyed_at is null and "
"vm_instance.status = 'RUNNING'"
)
queryset
=
queryset
.
extra
(
select
=
{
'running'
:
sql
})
return
queryset
def
get_queryset
(
self
):
def
get_queryset
(
self
):
logger
.
debug
(
'TemplateList.get_queryset() called. User:
%
s'
,
logger
.
debug
(
'TemplateList.get_queryset() called. User:
%
s'
,
unicode
(
self
.
request
.
user
))
unicode
(
self
.
request
.
user
))
return
InstanceTemplate
.
get_objects_with_level
(
qs
=
self
.
create_acl_queryset
(
InstanceTemplate
)
'user'
,
self
.
request
.
user
)
.
all
()
self
.
create_fake_get
()
try
:
qs
=
qs
.
filter
(
**
self
.
get_queryset_filters
())
.
distinct
()
except
ValueError
:
messages
.
error
(
self
.
request
,
_
(
"Error during filtering."
))
return
qs
.
select_related
(
"lease"
,
"owner"
,
"owner__profile"
)
class
TemplateDelete
(
LoginRequiredMixin
,
DeleteView
):
class
TemplateDelete
(
LoginRequiredMixin
,
DeleteView
):
...
@@ -1715,6 +1812,7 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
...
@@ -1715,6 +1812,7 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
else
:
else
:
context
[
'ops'
]
.
append
(
v
)
context
[
'ops'
]
.
append
(
v
)
context
[
'search_form'
]
=
self
.
search_form
context
[
'search_form'
]
=
self
.
search_form
context
[
'show_acts_in_progress'
]
=
self
.
object_list
.
count
()
<
100
return
context
return
context
def
get
(
self
,
*
args
,
**
kwargs
):
def
get
(
self
,
*
args
,
**
kwargs
):
...
@@ -1759,10 +1857,16 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
...
@@ -1759,10 +1857,16 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
content_type
=
"application/json"
,
content_type
=
"application/json"
,
)
)
def
create_acl_queryset
(
self
,
model
):
queryset
=
super
(
VmList
,
self
)
.
create_acl_queryset
(
model
)
if
not
self
.
search_form
.
cleaned_data
.
get
(
"include_deleted"
):
queryset
=
queryset
.
filter
(
destroyed_at
=
None
)
return
queryset
def
get_queryset
(
self
):
def
get_queryset
(
self
):
logger
.
debug
(
'VmList.get_queryset() called. User:
%
s'
,
logger
.
debug
(
'VmList.get_queryset() called. User:
%
s'
,
unicode
(
self
.
request
.
user
))
unicode
(
self
.
request
.
user
))
queryset
=
self
.
create_
default_queryset
(
)
queryset
=
self
.
create_
acl_queryset
(
Instance
)
self
.
create_fake_get
()
self
.
create_fake_get
()
sort
=
self
.
request
.
GET
.
get
(
"sort"
)
sort
=
self
.
request
.
GET
.
get
(
"sort"
)
...
@@ -1774,54 +1878,9 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
...
@@ -1774,54 +1878,9 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
queryset
=
queryset
.
order_by
(
sort
)
queryset
=
queryset
.
order_by
(
sort
)
return
queryset
.
filter
(
return
queryset
.
filter
(
**
self
.
get_queryset_filters
())
.
select_related
(
'owner'
,
'node'
**
self
.
get_queryset_filters
())
.
prefetch_related
(
)
.
distinct
()
"owner"
,
"node"
,
"owner__profile"
,
"interface_set"
,
"lease"
,
"interface_set__host"
)
.
distinct
()
def
create_default_queryset
(
self
):
cleaned_data
=
self
.
search_form
.
cleaned_data
stype
=
cleaned_data
.
get
(
'stype'
,
"all"
)
superuser
=
stype
==
"all"
shared
=
stype
==
"shared"
level
=
"owner"
if
stype
==
"owned"
else
"user"
queryset
=
Instance
.
get_objects_with_level
(
level
,
self
.
request
.
user
,
group_also
=
shared
,
disregard_superuser
=
not
superuser
,
)
.
filter
(
destroyed_at
=
None
)
return
queryset
def
create_fake_get
(
self
):
"""
Updates the request's GET dict to filter the vm list
For example: "name:xy node:1" updates the GET dict
to resemble this URL ?name=xy&node=1
"name:xy node:1".split(":") becomes ["name", "xy node", "1"]
we pop the the first element and use it as the first dict key
then we iterate over the rest of the list and split by the last
whitespace, the first part of this list will be the previous key's
value, then last part of the list will be the next key.
The final dict looks like this: {'name': xy, 'node':1}
"""
s
=
self
.
request
.
GET
.
get
(
"s"
)
if
s
:
s
=
s
.
split
(
":"
)
if
len
(
s
)
<
2
:
# if there is no ':' in the string, filter by name
got
=
{
'name'
:
s
[
0
]}
else
:
latest
=
s
.
pop
(
0
)
got
=
{
'
%
s'
%
latest
:
None
}
for
i
in
s
[:
-
1
]:
new
=
i
.
rsplit
(
" "
,
1
)
got
[
latest
]
=
new
[
0
]
latest
=
new
[
1
]
if
len
(
new
)
>
1
else
None
got
[
latest
]
=
s
[
-
1
]
# generate a new GET request, that is kinda fake
fake
=
self
.
request
.
GET
.
copy
()
for
k
,
v
in
got
.
iteritems
():
fake
[
k
]
=
v
self
.
request
.
GET
=
fake
class
NodeList
(
LoginRequiredMixin
,
SuperuserRequiredMixin
,
SingleTableView
):
class
NodeList
(
LoginRequiredMixin
,
SuperuserRequiredMixin
,
SingleTableView
):
...
...
circle/vm/models/instance.py
View file @
90122b75
...
@@ -513,7 +513,11 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
...
@@ -513,7 +513,11 @@ class Instance(AclBase, VirtualMachineDescModel, StatusModel, OperatedMixin,
def
ipv4
(
self
):
def
ipv4
(
self
):
"""Primary IPv4 address of the instance.
"""Primary IPv4 address of the instance.
"""
"""
return
self
.
primary_host
.
ipv4
if
self
.
primary_host
else
None
# return self.primary_host.ipv4 if self.primary_host else None
for
i
in
self
.
interface_set
.
all
():
if
i
.
host
:
return
i
.
host
.
ipv4
return
None
@property
@property
def
ipv6
(
self
):
def
ipv6
(
self
):
...
...
miscellaneous/manager.conf
View file @
90122b75
...
@@ -14,4 +14,3 @@ post-stop script
...
@@ -14,4 +14,3 @@ post-stop script
stop
mancelery
stop
mancelery
stop
slowcelery
stop
slowcelery
end
script
end
script
miscellaneous/mancelery.conf
View file @
90122b75
...
@@ -12,4 +12,3 @@ script
...
@@ -12,4 +12,3 @@ script
. /
home
/
cloud
/.
virtualenvs
/
circle
/
bin
/
postactivate
. /
home
/
cloud
/.
virtualenvs
/
circle
/
bin
/
postactivate
exec
./
manage
.
py
celery
--
app
=
manager
.
mancelery
worker
--
autoreload
--
loglevel
=
info
--
hostname
=
mancelery
-
B
-
c
10
exec
./
manage
.
py
celery
--
app
=
manager
.
mancelery
worker
--
autoreload
--
loglevel
=
info
--
hostname
=
mancelery
-
B
-
c
10
end
script
end
script
miscellaneous/moncelery.conf
View file @
90122b75
...
@@ -12,4 +12,3 @@ script
...
@@ -12,4 +12,3 @@ script
. /
home
/
cloud
/.
virtualenvs
/
circle
/
bin
/
postactivate
. /
home
/
cloud
/.
virtualenvs
/
circle
/
bin
/
postactivate
exec
./
manage
.
py
celery
--
app
=
manager
.
moncelery
worker
--
autoreload
--
loglevel
=
info
--
hostname
=
moncelery
-
B
-
c
3
exec
./
manage
.
py
celery
--
app
=
manager
.
moncelery
worker
--
autoreload
--
loglevel
=
info
--
hostname
=
moncelery
-
B
-
c
3
end
script
end
script
miscellaneous/portal-uwsgi.conf
View file @
90122b75
...
@@ -12,4 +12,3 @@ script
...
@@ -12,4 +12,3 @@ script
. /
home
/
cloud
/.
virtualenvs
/
circle
/
bin
/
postactivate
. /
home
/
cloud
/.
virtualenvs
/
circle
/
bin
/
postactivate
exec
/
home
/
cloud
/.
virtualenvs
/
circle
/
bin
/
uwsgi
--
chdir
=/
home
/
cloud
/
circle
/
circle
-
H
/
home
/
cloud
/.
virtualenvs
/
circle
--
socket
/
tmp
/
uwsgi
.
sock
--
wsgi
-
file
circle
/
wsgi
.
py
--
chmod
-
socket
=
666
exec
/
home
/
cloud
/.
virtualenvs
/
circle
/
bin
/
uwsgi
--
chdir
=/
home
/
cloud
/
circle
/
circle
-
H
/
home
/
cloud
/.
virtualenvs
/
circle
--
socket
/
tmp
/
uwsgi
.
sock
--
wsgi
-
file
circle
/
wsgi
.
py
--
chmod
-
socket
=
666
end
script
end
script
miscellaneous/portal.conf
View file @
90122b75
...
@@ -14,4 +14,3 @@ script
...
@@ -14,4 +14,3 @@ script
. /
home
/
cloud
/.
virtualenvs
/
circle
/
bin
/
postactivate
. /
home
/
cloud
/.
virtualenvs
/
circle
/
bin
/
postactivate
exec
./
manage
.
py
runserver
'[::]:8080'
exec
./
manage
.
py
runserver
'[::]:8080'
end
script
end
script
miscellaneous/slowcelery.conf
View file @
90122b75
...
@@ -12,4 +12,3 @@ script
...
@@ -12,4 +12,3 @@ script
. /
home
/
cloud
/.
virtualenvs
/
circle
/
bin
/
postactivate
. /
home
/
cloud
/.
virtualenvs
/
circle
/
bin
/
postactivate
exec
./
manage
.
py
celery
--
app
=
manager
.
slowcelery
worker
--
autoreload
--
loglevel
=
info
--
hostname
=
slowcelery
-
B
-
c
5
exec
./
manage
.
py
celery
--
app
=
manager
.
slowcelery
worker
--
autoreload
--
loglevel
=
info
--
hostname
=
slowcelery
-
B
-
c
5
end
script
end
script
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