Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Gelencsér Szabolcs
/
cloud
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
8fd80cf1
authored
Jan 09, 2014
by
Oláh István Gergely
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dashboard: add node create form
parent
e029a56b
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
229 additions
and
198 deletions
+229
-198
circle/dashboard/forms.py
+170
-5
circle/dashboard/static/dashboard/dashboard.js
+6
-6
circle/dashboard/static/dashboard/node-create.js
+0
-0
circle/dashboard/static/dashboard/vm-create.js
+4
-4
circle/dashboard/templates/dashboard/modal-wrapper.html
+1
-1
circle/dashboard/templates/dashboard/node-create.html
+4
-133
circle/dashboard/views.py
+36
-48
circle/vm/models/node.py
+8
-1
No files found.
circle/dashboard/forms.py
View file @
8fd80cf1
from
datetime
import
timedelta
from
django
import
forms
from
vm.models
import
InstanceTemplate
,
Lease
,
InterfaceTemplate
from
vm.models
import
InstanceTemplate
,
Lease
,
InterfaceTemplate
,
Node
from
storage.models
import
Disk
from
firewall.models
import
Vlan
# from django.core.urlresolvers import reverse_lazy
from
firewall.models
import
Vlan
,
Host
from
crispy_forms.helper
import
FormHelper
from
crispy_forms.layout
import
(
Layout
,
Div
,
BaseInput
,
Field
,
HTML
,
Submit
,
Fieldset
)
...
...
@@ -13,8 +11,12 @@ from crispy_forms.utils import render_field
from
django.template
import
Context
from
django.template.loader
import
render_to_string
from
django.forms.widgets
import
TextInput
from
django.forms
import
ModelForm
from
crispy_forms.bootstrap
import
FormActions
from
django.forms.models
import
BaseInlineFormSet
from
django.utils.translation
import
ugettext
as
_
# from crispy_forms.bootstrap import FormActions
VLANS
=
Vlan
.
objects
.
all
()
...
...
@@ -292,6 +294,169 @@ class VmCreateForm(forms.Form):
)
class
HostForm
(
forms
.
ModelForm
):
def
setowner
(
self
,
user
):
self
.
instance
.
owner
=
user
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
HostForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
self
.
helper
=
FormHelper
(
self
)
self
.
helper
.
form_show_labels
=
False
self
.
helper
.
form_tag
=
False
self
.
helper
.
layout
=
Layout
(
Div
(
Div
(
# host
Div
(
AnyTag
(
'h3'
,
HTML
(
_
(
"Host"
)),
),
css_class
=
"col-sm-3"
,
),
css_class
=
"row"
,
),
Div
(
# host data
Div
(
# hostname
HTML
(
'<label for="node-hostname-box">'
'Name'
'</label>'
),
css_class
=
"col-sm-3"
,
),
Div
(
# hostname
'hostname'
,
css_class
=
"col-sm-9"
,
),
Div
(
# mac
HTML
(
'<label for="node-mac-box">'
'MAC'
'</label>'
),
css_class
=
"col-sm-3"
,
),
Div
(
'mac'
,
css_class
=
"col-sm-9"
,
),
Div
(
# ip
HTML
(
'<label for="node-ip-box">'
'IP'
'</label>'
),
css_class
=
"col-sm-3"
,
),
Div
(
'ipv4'
,
css_class
=
"col-sm-9"
,
),
Div
(
# vlan
HTML
(
'<label for="node-vlan-box">'
'VLAN'
'</label>'
),
css_class
=
"col-sm-3"
,
),
Div
(
'vlan'
,
css_class
=
"col-sm-9"
,
),
css_class
=
"row"
,
),
),
)
class
Meta
:
model
=
Host
fields
=
[
'hostname'
,
'vlan'
,
'mac'
,
'ipv4'
,
]
class
NodeForm
(
forms
.
ModelForm
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
NodeForm
,
self
)
.
__init__
(
*
args
,
**
kwargs
)
self
.
helper
=
FormHelper
(
self
)
self
.
helper
.
form_show_labels
=
False
self
.
helper
.
layout
=
Layout
(
Div
(
Div
(
Div
(
Div
(
AnyTag
(
'h3'
,
HTML
(
_
(
"Node"
)),
),
css_class
=
"col-sm-3"
,
),
css_class
=
"row"
,
),
Div
(
Div
(
# nodename
HTML
(
'<label for="node-nodename-box">'
'Name'
'</label>'
),
css_class
=
"col-sm-3"
,
),
Div
(
'name'
,
css_class
=
"col-sm-9"
,
),
css_class
=
"row"
,
),
Div
(
Div
(
# priority
HTML
(
'<label for="node-nodename-box">'
'Priority'
'</label>'
),
css_class
=
"col-sm-3"
,
),
Div
(
'priority'
,
css_class
=
"col-sm-9"
,
),
css_class
=
"row"
,
),
Div
(
Div
(
# enabled
HTML
(
'<label for="node-nodename-box">'
'Enabled'
'</label>'
),
css_class
=
"col-sm-3"
,
),
Div
(
'enabled'
,
css_class
=
"col-sm-9"
,
),
css_class
=
"row"
,
),
Div
(
# nested host
HTML
(
"""{
%
load crispy_forms_tags
%
}
{
%
crispy hostform
%
}
"""
)
),
Div
(
Div
(
AnyTag
(
# tip: don't try to use Button class
"button"
,
AnyTag
(
"i"
,
css_class
=
"icon-play"
),
HTML
(
"Start"
),
css_id
=
"node-create-submit"
,
css_class
=
"btn btn-success"
,
),
css_class
=
"col-sm-12 text-right"
,
),
css_class
=
"row"
,
),
css_class
=
"col-sm-11"
,
),
css_class
=
"row"
,
),
)
class
Meta
:
model
=
Node
fields
=
[
'name'
,
'priority'
,
'enabled'
,
]
class
TemplateForm
(
forms
.
ModelForm
):
managed_networks
=
forms
.
ModelMultipleChoiceField
(
queryset
=
VLANS
,
required
=
False
)
...
...
circle/dashboard/static/dashboard/dashboard.js
View file @
8fd80cf1
...
...
@@ -7,9 +7,9 @@ $(function () {
$
(
'body'
).
append
(
data
);
vmCreateLoaded
();
addSliderMiscs
();
$
(
'#
vm-
create-modal'
).
modal
(
'show'
);
$
(
'#
vm-
create-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#
vm-
create-modal'
).
remove
();
$
(
'#create-modal'
).
modal
(
'show'
);
$
(
'#create-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#create-modal'
).
remove
();
});
}
});
...
...
@@ -24,9 +24,9 @@ $(function () {
$
(
'body'
).
append
(
data
);
nodeCreateLoaded
();
addSliderMiscs
();
$
(
'#
node-
create-modal'
).
modal
(
'show'
);
$
(
'#
node-
create-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#
node-
create-modal'
).
remove
();
$
(
'#create-modal'
).
modal
(
'show'
);
$
(
'#create-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#create-modal'
).
remove
();
});
}
});
...
...
circle/dashboard/static/dashboard/node-create.js
View file @
8fd80cf1
This diff is collapsed.
Click to expand it.
circle/dashboard/static/dashboard/vm-create.js
View file @
8fd80cf1
...
...
@@ -181,13 +181,13 @@ function vmCreateLoaded() {
window
.
location
.
replace
(
data
.
redirect
+
'#activity'
);
}
else
{
var
r
=
$
(
'#
vm-
create-modal'
);
r
.
next
(
'div'
).
remove
();
r
.
remove
();
var
r
=
$
(
'#create-modal'
);
r
.
next
(
'div'
).
remove
();
r
.
remove
();
$
(
'body'
).
append
(
data
);
vmCreateLoaded
();
addSliderMiscs
();
$
(
'#
vm-
create-modal'
).
modal
(
'show'
);
$
(
'#
vm-
create-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#
vm-
create-modal'
).
remove
();
$
(
'#create-modal'
).
modal
(
'show'
);
$
(
'#create-modal'
).
on
(
'hidden.bs.modal'
,
function
()
{
$
(
'#create-modal'
).
remove
();
});
}
},
...
...
circle/dashboard/templates/dashboard/modal-wrapper.html
View file @
8fd80cf1
<div
class=
"modal fade"
id=
"
vm-
create-modal"
tabindex=
"-1"
role=
"dialog"
>
<div
class=
"modal fade"
id=
"create-modal"
tabindex=
"-1"
role=
"dialog"
>
<div
class=
"modal-dialog"
>
<div
class=
"modal-content"
>
<div
class=
"modal-header"
>
...
...
circle/dashboard/templates/dashboard/node-create.html
View file @
8fd80cf1
{% load crispy_forms_tags %}
<style>
.row
{
margin-bottom
:
15px
;
}
</style>
<form
method=
"POST"
action=
"/dashboard/vm/create/"
>
{% csrf_token %}
<div
class=
"row"
>
<div
class=
"col-sm-5"
>
<a
class=
"btn btn-info vm-create-advanced-btn"
>
Advanced
<i
class=
"vm-create-advanced-icon icon-caret-down"
></i></a>
</div>
<div
class=
"col-sm-5 text-right"
>
<button
id=
"vm-create-submit"
type=
"submit"
class=
"btn btn-success "
><i
class=
"icon-play"
></i>
Start
</button>
</div>
</div>
<div
class=
"vm-create-advanced"
>
<div
class=
"row"
>
<div
class=
"col-sm-12"
>
<h2>
Resources
</h2>
</div>
<p
class=
"row"
>
<div
class=
"col-sm-3"
>
<label
for=
"vm-cpu-priority-slider"
><i
class=
"icon-trophy"
></i>
CPU priority
</label>
</div>
<div
class=
"col-sm-9"
>
<input
name=
"cpu-priority"
type=
"text"
id=
"vm-cpu-priority-slider"
class=
"vm-slider"
value=
"20"
data-slider-min=
"0"
data-slider-max=
"100"
data-slider-step=
"1"
data-slider-value=
"20"
data-slider-orientation=
"horizontal"
data-slider-handle=
"square"
data-slider-tooltip=
"hide"
/>
</div>
</p>
<p
class=
"row"
>
<div
class=
"col-sm-3"
>
<label
for=
"cpu-count-slider"
><i
class=
"icon-cogs"
></i>
CPU count
</label>
</div>
<div
class=
"col-sm-9"
>
<input
name=
"cpu-count"
type=
"text"
id=
"vm-cpu-count-slider"
class=
"vm-slider"
value=
"2"
data-slider-min=
"0"
data-slider-max=
"8"
data-slider-step=
"1"
data-slider-value=
"2"
data-slider-orientation=
"horizontal"
data-slider-handle=
"square"
data-slider-tooltip=
"hide"
/>
</div>
</p>
<p
class=
"row"
>
<div
class=
"col-sm-3"
>
<label
for=
"ram-slider"
><i
class=
"icon-ticket"
></i>
RAM amount
</label>
</div>
<div
class=
"col-sm-9"
>
<input
name=
"ram-size"
type=
"text"
id=
"vm-ram-size-slider"
class=
"vm-slider"
value=
"512"
data-slider-min=
"128"
data-slider-max=
"4096"
data-slider-step=
"128"
data-slider-value=
"512"
data-slider-orientation=
"horizontal"
data-slider-handle=
"square"
data-slider-tooltip=
"hide"
/>
MiB
</div>
</p>
</div>
<!-- disk -->
<div
class=
"row"
>
<div
class=
"col-sm-4"
>
<h2>
Disks
</h2>
</div>
<div
class=
"col-sm-8"
style=
"padding-top: 3px;"
>
<div
class=
"js-hidden"
style=
"padding-top: 15px; max-width: 450px;"
>
<select
class=
"form-control"
id=
"vm-create-disk-add-form"
multiple
name=
"disks"
>
{% for d in disks %}
<option
value=
"{{ d.pk }}"
>
{{ d.name }}
</option>
{% endfor %}
</select>
</div>
<div
class=
"no-js-hidden"
>
<h3
id=
"vm-create-disk-list"
>
No disks are added!
</h3>
<h3
id=
"vm-create-disk-add"
>
<div
class=
"input-group"
style=
"max-width: 330px;"
>
<select
class=
"form-control"
id=
"vm-create-disk-add-select"
>
<!-- options should be copied via js from above -->
</select>
<div
class=
"input-group-btn"
>
<!--<input type="submit" value="Add to network" class="btn btn-success"/>-->
<a
href=
"#"
id=
"vm-create-disk-add-button"
class=
"btn btn-success"
><i
class=
"icon-plus-sign"
></i></a>
</div>
</div>
</h3>
</div>
</div>
</div>
<!-- network -->
<div
class=
"row"
>
<div
class=
"col-sm-4"
>
<h2>
Network
</h2>
</div>
<style>
/* temporary inline css for dev */
a
.hover-black
{
color
:
white
;
}
.hover-black
:hover
{
color
:
black
/*#d9534f*/
;
text-decoration
:
none
;
}
.no-js-hidden
{
display
:
none
;
}
</style>
<div
class=
"col-sm-8"
style=
"padding-top: 3px;"
>
<div
class=
"js-hidden"
style=
"padding-top: 15px; max-width: 450px;"
>
<h4>
Managed networks
</h4>
<select
class=
"form-control"
id=
"vm-create-network-add-managed"
multiple
name=
"managed-vlans"
>
{% for v in vlans %}
<option
value=
"{{ v.pk }}"
>
{{ v.name }}
</option>
{% endfor %}
</select>
<h4>
Unmanaged networks
</h4>
<select
class=
"form-control"
id=
"vm-create-network-add-unmanaged"
multiple
name=
"unmanaged-vlans"
>
{% for v in vlans %}
<option
value=
"{{ v.pk }}"
>
{{ v.name }}
</option>
{% endfor %}
</select>
</div>
<div
class=
"no-js-hidden"
>
<h3
id=
"vm-create-network-list"
>
Not added to any network!
</h3>
<h3
id=
"vm-create-network-add"
>
<div
class=
"input-group"
style=
"max-width: 330px;"
>
<select
class=
"form-control"
id=
"vm-create-network-add-select"
>
<!-- options should be copied via js from above -->
</select>
<span
class=
"input-group-addon"
>
<input
id=
"vm-create-network-add-checkbox-managed"
type=
"checkbox"
title
data-original-title=
"Managed network?"
style=
"-webkit-transform: scale(1.4, 1.4); margin-top: 4px;"
checked
/>
</span>
<div
class=
"input-group-btn"
>
<!--<input type="submit" value="Add to network" class="btn btn-success"/>-->
<a
href=
"#"
id=
"vm-create-network-add-button"
class=
"btn btn-success"
><i
class=
"icon-plus-sign"
></i></a>
</div>
</div>
</h3>
</div>
</div>
</div>
</div>
<form
method=
"POST"
action=
"/dashboard/node/create/"
>
{% csrf_token %}
{% crispy formset formset.form.helper %}
</form>
circle/dashboard/views.py
View file @
8fd80cf1
...
...
@@ -19,10 +19,11 @@ from django.views.generic import (TemplateView, DetailView, View, DeleteView,
from
django.contrib
import
messages
from
django.utils.translation
import
ugettext
as
_
from
django.forms.models
import
inlineformset_factory
from
django_tables2
import
SingleTableView
from
braces.views
import
LoginRequiredMixin
,
SuperuserRequiredMixin
from
.forms
import
VmCreateForm
,
TemplateForm
,
LeaseForm
from
.forms
import
VmCreateForm
,
TemplateForm
,
LeaseForm
,
NodeForm
,
HostForm
from
.tables
import
(
VmListTable
,
NodeListTable
,
NodeVmListTable
,
TemplateListTable
,
LeaseListTable
)
from
vm.models
import
(
Instance
,
InstanceTemplate
,
InterfaceTemplate
,
...
...
@@ -517,17 +518,30 @@ class VmCreate(LoginRequiredMixin, TemplateView):
class
NodeCreate
(
LoginRequiredMixin
,
SuperuserRequiredMixin
,
TemplateView
):
form_class
=
HostForm
hostform
=
None
formset_class
=
inlineformset_factory
(
Host
,
Node
,
form
=
NodeForm
,
extra
=
1
)
formset
=
None
def
get_template_names
(
self
):
if
self
.
request
.
is_ajax
():
return
[
'dashboard/modal-wrapper.html'
]
else
:
return
[
'dashboard/nojs-wrapper.html'
]
def
get
(
self
,
request
,
*
args
,
**
kwargs
):
def
get
(
self
,
request
,
hostform
=
None
,
formset
=
None
,
*
args
,
**
kwargs
):
if
hostform
is
None
:
hostform
=
self
.
form_class
()
if
formset
is
None
:
formset
=
self
.
formset_class
(
instance
=
Host
())
context
=
self
.
get_context_data
(
**
kwargs
)
context
.
update
({
'template'
:
'dashboard/node-create.html'
,
'box_title'
:
'Create a Node'
'box_title'
:
'Create a Node'
,
'hostform'
:
hostform
,
'formset'
:
formset
,
})
return
self
.
render_to_response
(
context
)
...
...
@@ -535,60 +549,34 @@ class NodeCreate(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
context
=
super
(
NodeCreate
,
self
)
.
get_context_data
(
**
kwargs
)
# TODO acl
context
.
update
({
'templates'
:
InstanceTemplate
.
objects
.
all
(),
'vlans'
:
Vlan
.
objects
.
all
(),
'disks'
:
Disk
.
objects
.
exclude
(
type
=
"qcow2-snap"
)
})
return
context
# TODO handle not ajax posts
def
post
(
self
,
request
,
*
args
,
**
kwargs
):
if
self
.
request
.
user
.
is_authenticated
():
user
=
self
.
request
.
user
else
:
user
=
None
resp
=
{}
try
:
ikwargs
=
{
'num_cores'
:
int
(
request
.
POST
.
get
(
'cpu-count'
)),
'ram_size'
:
int
(
request
.
POST
.
get
(
'ram-size'
)),
'priority'
:
int
(
request
.
POST
.
get
(
'cpu-priority'
)),
}
networks
=
[
InterfaceTemplate
(
vlan
=
Vlan
.
objects
.
get
(
pk
=
l
),
managed
=
True
)
for
l
in
request
.
POST
.
getlist
(
'managed-vlans'
)
]
networks
.
extend
([
InterfaceTemplate
(
vlan
=
Vlan
.
objects
.
get
(
pk
=
l
),
managed
=
False
)
for
l
in
request
.
POST
.
getlist
(
'unmanaged-vlans'
)
])
disks
=
Disk
.
objects
.
filter
(
pk__in
=
request
.
POST
.
getlist
(
'disks'
))
template
=
InstanceTemplate
.
objects
.
get
(
pk
=
request
.
POST
.
get
(
'template-pk'
))
inst
=
Instance
.
create_from_template
(
template
=
template
,
owner
=
user
,
networks
=
networks
,
disks
=
disks
,
**
ikwargs
)
inst
.
deploy_async
(
user
=
request
.
user
)
resp
[
'pk'
]
=
inst
.
pk
messages
.
success
(
request
,
_
(
'Node successfully created!'
))
except
InstanceTemplate
.
DoesNotExist
:
resp
[
'error'
]
=
True
except
Exception
,
e
:
print
e
resp
[
'error'
]
=
True
if
not
self
.
request
.
user
.
is_authenticated
():
raise
PermissionDenied
()
hostform
=
self
.
form_class
(
request
.
POST
)
formset
=
self
.
formset_class
(
request
.
POST
,
Host
())
if
not
hostform
.
is_valid
():
return
self
.
get
(
request
,
hostform
,
formset
,
*
args
,
**
kwargs
)
hostform
.
setowner
(
request
.
user
)
savedform
=
hostform
.
save
(
commit
=
False
)
formset
=
self
.
formset_class
(
request
.
POST
,
instance
=
savedform
)
if
not
formset
.
is_valid
():
return
self
.
get
(
request
,
hostform
,
formset
,
*
args
,
**
kwargs
)
savedform
.
save
()
nodemodel
=
formset
.
save
()
messages
.
success
(
request
,
_
(
'Node successfully created!'
))
path
=
nodemodel
[
0
]
.
get_absolute_url
()
if
request
.
is_ajax
():
return
HttpResponse
(
json
.
dumps
(
resp
),
content_type
=
"application/json"
,
status
=
500
if
resp
.
get
(
'error'
)
else
200
)
return
HttpResponse
(
json
.
dumps
({
'redirect'
:
path
}),
content_type
=
"application/json"
)
else
:
return
redirect
(
reverse_lazy
(
'dashboard.views.detail'
,
resp
)
)
return
redirect
(
path
)
class
VmDelete
(
LoginRequiredMixin
,
DeleteView
):
...
...
circle/vm/models/node.py
View file @
8fd80cf1
...
...
@@ -3,7 +3,7 @@ from logging import getLogger
from
django.db.models
import
(
CharField
,
IntegerField
,
ForeignKey
,
BooleanField
,
ManyToManyField
,
FloatField
,
FloatField
,
permalink
,
)
from
django.utils.translation
import
ugettext_lazy
as
_
...
...
@@ -143,3 +143,10 @@ class Node(TimeStampedModel):
def
get_state_count
(
cls
,
online
,
enabled
):
return
len
([
1
for
i
in
cls
.
objects
.
filter
(
enabled
=
enabled
)
.
all
()
if
i
.
online
==
online
])
@permalink
def
get_absolute_url
(
self
):
return
(
'dashboard.views.node-detail'
,
None
,
{
'pk'
:
self
.
id
})
def
pr
():
print
"irdki"
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