Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Gelencsér Szabolcs
/
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
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
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
228 additions
and
470 deletions
+228
-470
circle/dashboard/forms.py
+170
-5
circle/dashboard/static/dashboard/dashboard.js
+6
-6
circle/dashboard/static/dashboard/node-create.js
+0
-273
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
+35
-47
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
var
vlans
=
[];
var
disks
=
[];
$
(
function
()
{
nodeCreateLoaded
();
});
function
nodeCreateLoaded
()
{
$
(
'.node-create-advanced'
).
hide
();
$
(
'.node-create-advanced-btn'
).
click
(
function
()
{
$
(
'.vm-create-advanced'
).
stop
().
slideToggle
();
if
(
$
(
'.node-create-advanced-icon'
).
hasClass
(
'icon-caret-down'
))
{
$
(
'.node-create-advanced-icon'
).
removeClass
(
'icon-caret-down'
).
addClass
(
'icon-caret-up'
);
}
else
{
$
(
'.node-create-advanced-icon'
).
removeClass
(
'icon-caret-up'
).
addClass
(
'icon-caret-down'
);
}
});
$
(
'#node-create-template-select'
).
change
(
function
()
{
nodeCreateTemplateChange
(
this
);
});
/* network thingies */
/* add network */
$
(
'#node-create-network-add-button'
).
click
(
function
()
{
var
vlan_pk
=
$
(
'#node-create-network-add-select :selected'
).
val
();
var
managed
=
$
(
'#node-create-network-add-checkbox-managed'
).
prop
(
'checked'
);
var
name
=
$
(
'#node-create-network-add-select :selected'
).
text
();
if
(
$
(
'#node-create-network-list'
).
children
(
'span'
).
length
<
1
)
{
$
(
'#node-create-network-list'
).
html
(
''
);
}
$
(
'#node-create-network-list'
).
append
(
nodeCreateNetworkLabel
(
vlan_pk
,
name
,
managed
)
);
/* select the network from the managed/unmanaged multiple select */
if
(
managed
)
{
$
(
'#node-create-network-add-managed option[value="'
+
vlan_pk
+
'"]'
).
prop
(
'selected'
,
true
);
}
else
{
$
(
'#node-create-network-add-unmanaged option[value="'
+
vlan_pk
+
'"]'
).
prop
(
'selected'
,
true
);
}
$
(
'option:selected'
,
$
(
'#node-create-network-add-select'
)).
remove
();
/* add dummy text if no more networks are available */
if
(
$
(
'#node-create-network-add-select option'
).
length
<
1
)
{
$
(
'#node-create-network-add-button'
).
attr
(
'disabled'
,
true
);
$
(
'#node-create-network-add-select'
).
html
(
'<option value="-1">We are out of <options> hehe</option>'
);
}
return
false
;
});
/* remove network */
// event for network remove button (icon, X)
$
(
'body'
).
on
(
'click'
,
'.node-create-remove-network'
,
function
()
{
var
vlan_pk
=
(
$
(
this
).
parent
(
'span'
).
prop
(
'id'
)).
replace
(
'vlan-'
,
''
)
// if it's "blue" then it's managed, kinda not cool
var
managed
=
$
(
this
).
parent
(
'span'
).
hasClass
(
'label-primary'
);
$
(
this
).
parent
(
'span'
).
fadeOut
(
500
,
function
()
{
/* if ther are no more vlans disabled the add button */
if
(
$
(
'#node-create-network-add-select option'
)[
0
].
value
==
-
1
)
{
$
(
'#node-create-network-add-button'
).
attr
(
'disabled'
,
false
);
$
(
'#node-create-network-add-select'
).
html
(
''
);
}
/* remove the network label */
$
(
this
).
remove
();
var
vlan_name
=
$
(
this
).
text
();
$
(
'#node-create-network-add-select'
).
append
(
$
(
'<option>'
,
{
value
:
vlan_pk
,
text
:
vlan_name
}));
/* remove the selection from the multiple select */
$
(
'#node-create-network-add-'
+
(
managed
?
''
:
'un'
)
+
'managed option[value="'
+
vlan_pk
+
'"]'
).
prop
(
'selected'
,
false
);
if
(
$
(
'#node-create-network-list'
).
children
(
'span'
).
length
<
1
)
{
$
(
'#node-create-network-list'
).
append
(
'Not added to any network!'
);
}
});
return
false
;
});
/* copy networks from hidden select */
$
(
'#node-create-network-add-select'
).
html
(
$
(
'#node-create-network-add-managed'
).
html
());
/* build up network list */
$
(
'#node-create-network-add-select option'
).
each
(
function
()
{
vlans
.
push
({
'name'
:
$
(
this
).
text
(),
'pk'
:
parseInt
(
$
(
this
).
val
())
});
});
/* ----- end of networks thingies ----- */
/* add disk */
$
(
'#node-create-disk-add-button'
).
click
(
function
()
{
var
disk_pk
=
$
(
'#node-create-disk-add-select :selected'
).
val
();
var
name
=
$
(
'#node-create-disk-add-select :selected'
).
text
();
if
(
$
(
'#node-create-disk-list'
).
children
(
'span'
).
length
<
1
)
{
$
(
'#node-create-disk-list'
).
html
(
''
);
}
$
(
'#node-create-disk-list'
).
append
(
nodeCreateDiskLabel
(
disk_pk
,
name
)
);
/* select the disk from the multiple select */
$
(
'#node-create-disk-add-form option[value="'
+
disk_pk
+
'"]'
).
prop
(
'selected'
,
true
);
$
(
'option:selected'
,
$
(
'#node-create-disk-add-select'
)).
remove
();
/* add dummy text if no more disks are available */
if
(
$
(
'#node-create-disk-add-select option'
).
length
<
1
)
{
$
(
'#node-create-disk-add-button'
).
attr
(
'disabled'
,
true
);
$
(
'#node-create-disk-add-select'
).
html
(
'<option value="-1">We are out of <options> hehe</option>'
);
}
return
false
;
});
/* remove disk */
// event for disk remove button (icon, X)
$
(
'body'
).
on
(
'click'
,
'.node-create-remove-disk'
,
function
()
{
var
disk_pk
=
(
$
(
this
).
parent
(
'span'
).
prop
(
'id'
)).
replace
(
'vlan-'
,
''
)
$
(
this
).
parent
(
'span'
).
fadeOut
(
500
,
function
()
{
/* if ther are no more disks disabled the add button */
if
(
$
(
'#node-create-disk-add-select option'
)[
0
].
value
==
-
1
)
{
$
(
'#node-create-disk-add-button'
).
attr
(
'disabled'
,
false
);
$
(
'#node-create-disk-add-select'
).
html
(
''
);
}
/* remove the disk label */
$
(
this
).
remove
();
var
disk_name
=
$
(
this
).
text
();
$
(
'#node-create-disk-add-select'
).
append
(
$
(
'<option>'
,
{
value
:
disk_pk
,
text
:
disk_name
}));
/* remove the selection from the multiple select */
$
(
'#node-create-disk-add-form option[value="'
+
disk_pk
+
'"]'
).
prop
(
'selected'
,
false
);
if
(
$
(
'#node-create-disk-list'
).
children
(
'span'
).
length
<
1
)
{
$
(
'#node-create-disk-list'
).
append
(
'No disks are added!'
);
}
});
return
false
;
});
/* copy disks from hidden select */
$
(
'#node-create-disk-add-select'
).
html
(
$
(
'#node-create-disk-add-form'
).
html
());
/* build up disk list */
$
(
'#node-create-disk-add-select option'
).
each
(
function
()
{
disks
.
push
({
'name'
:
$
(
this
).
text
(),
'pk'
:
parseInt
(
$
(
this
).
val
())
});
});
/* add button */
$
(
'#node-create-submit'
).
click
(
function
()
{
$
.
ajax
({
url
:
'/dashboard/node/create/'
,
headers
:
{
"X-CSRFToken"
:
getCookie
(
'csrftoken'
)},
type
:
'POST'
,
data
:
$
(
'form'
).
serialize
(),
success
:
function
(
data
,
textStatus
,
xhr
)
{
if
(
data
.
pk
)
{
window
.
location
.
replace
(
'/dashboard/node/'
+
data
.
pk
+
'/#activity'
);
}
},
error
:
function
(
xhr
,
textStatus
,
error
)
{
if
(
xhr
.
status
==
500
)
{
alert
(
"uhuhuhuhuhuh"
);
}
else
{
alert
(
"unknown error"
);
}
}
});
return
false
;
});
/* no js compatibility */
$
(
'.no-js-hidden'
).
show
();
$
(
'.js-hidden'
).
hide
();
}
function
nodeCreateTemplateChange
(
new_this
)
{
this
.
value
=
new_this
.
value
;
if
(
this
.
value
<
0
)
return
;
$
.
ajax
({
url
:
'/dashboard/template/'
+
this
.
value
,
type
:
'GET'
,
success
:
function
(
data
,
textStatus
,
xhr
)
{
if
(
xhr
.
status
==
200
)
{
// set sliders
$
(
'#node-cpu-priority-slider'
).
slider
(
"setValue"
,
data
[
'priority'
]);
$
(
'#node-cpu-count-slider'
).
slider
(
"setValue"
,
data
[
'num_cores'
]);
$
(
'#node-ram-size-slider'
).
slider
(
"setValue"
,
data
[
'ram_size'
]);
/* slider doesn't have change event ........................ */
refreshSliders
();
/* clear selections */
$
(
'select[id^="node-create-network-add"], select[id$="managed"]'
).
find
(
'option'
).
prop
(
'selected'
,
false
);
$
(
'#node-create-disk-add-form'
).
find
(
'option'
).
prop
(
'selected'
,
false
);
/* append vlans from InterfaceTemplates */
$
(
'#vm-create-network-list'
).
html
(
''
);
var
added_vlans
=
[]
for
(
var
n
=
0
;
n
<
data
[
'network'
].
length
;
n
++
)
{
nn
=
data
[
'network'
][
n
]
$
(
'#node-create-network-list'
).
append
(
nodeCreateNetworkLabel
(
nn
.
vlan_pk
,
nn
.
vlan
,
nn
.
managed
)
);
$
(
'#node-create-network-add-'
+
(
nn
.
managed
?
''
:
'un'
)
+
'managed option[value="'
+
nn
.
vlan_pk
+
'"]'
).
prop
(
'selected'
,
true
);
added_vlans
.
push
(
nn
.
vlan_pk
);
}
/* remove already added vlans from dropdown or add new ones */
$
(
'#node-create-network-add-select'
).
html
(
''
);
for
(
var
i
=
0
;
i
<
vlans
.
length
;
i
++
)
if
(
added_vlans
.
indexOf
(
vlans
[
i
].
pk
)
==
-
1
)
$
(
'#node-create-network-add-select'
).
append
(
$
(
'<option>'
,
{
value
:
vlans
[
i
].
pk
,
text
:
vlans
[
i
].
name
}));
/* enalbe the network add button if there are not added vlans */
if
(
added_vlans
.
length
!=
vlans
.
length
)
{
$
(
'#node-create-network-add-button'
).
attr
(
'disabled'
,
false
);
}
else
{
$
(
'#node-create-network-add-select'
).
html
(
'<option value="-1">We are out of <options> hehe</option>'
);
$
(
'#node-create-network-add-button'
).
attr
(
'disabled'
,
true
);
}
/* append disks */
$
(
'#node-create-disk-list'
).
html
(
''
);
var
added_disks
=
[]
for
(
var
d
=
0
;
d
<
data
[
'disks'
].
length
;
d
++
)
{
dd
=
data
[
'disks'
][
d
]
$
(
'#node-create-disk-list'
).
append
(
nodeCreateDiskLabel
(
dd
.
pk
,
dd
.
name
)
);
$
(
'#node-create-disk-add-form option[value="'
+
dd
.
pk
+
'"]'
).
prop
(
'selected'
,
true
);
added_disks
.
push
(
dd
.
pk
);
}
/* remove already added disks from dropdown or add new ones */
$
(
'#node-create-disk-add-select'
).
html
(
''
);
for
(
var
i
=
0
;
i
<
disks
.
length
;
i
++
)
if
(
added_disks
.
indexOf
(
disks
[
i
].
pk
)
==
-
1
)
$
(
'#node-create-disk-add-select'
).
append
(
$
(
'<option>'
,
{
value
:
disks
[
i
].
pk
,
text
:
disks
[
i
].
name
}));
/* enalbe the disk add button if there are not added disks */
if
(
added_disks
.
length
!=
disks
.
length
)
{
$
(
'#node-create-disk-add-button'
).
attr
(
'disabled'
,
false
);
}
else
{
$
(
'#node-create-disk-add-select'
).
html
(
'<option value="-1">We are out of <options> hehe</option>'
);
$
(
'#node-create-disk-add-button'
).
attr
(
'disabled'
,
true
);
}
}
}
});
}
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
)
if
not
self
.
request
.
user
.
is_authenticated
():
raise
PermissionDenied
()
resp
[
'pk'
]
=
inst
.
pk
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!'
))
except
InstanceTemplate
.
DoesNotExist
:
resp
[
'error'
]
=
True
except
Exception
,
e
:
print
e
resp
[
'error'
]
=
True
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