Commit e0ab1b77 by Kálmán Viktor

dashboard: vm create with django forms

parent ab541167
from django import forms
from vm.models import InstanceTemplate
from storage.models import Disk
from firewall.models import Vlan
# from django.core.urlresolvers import reverse_lazy
from crispy_forms.helper import FormHelper
from crispy_forms.layout import (Layout, Div, BaseInput, # Submit
Field, HTML)
from crispy_forms.layout import TEMPLATE_PACK
from crispy_forms.utils import render_field
from django.template import Context
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _
# from crispy_forms.bootstrap import FormActions
VLANS = Vlan.objects.all()
class VmCreateForm(forms.Form):
template = forms.ModelChoiceField(queryset=InstanceTemplate.objects.all(),
empty_label="Select pls")
cpu_priority = forms.IntegerField()
cpu_count = forms.IntegerField()
ram_size = forms.IntegerField()
disks = forms.ModelMultipleChoiceField(
queryset=Disk.objects.exclude(type="qcow2-snap"),
)
managed_networks = forms.ModelMultipleChoiceField(queryset=VLANS)
unmanaged_networks = forms.ModelMultipleChoiceField(queryset=VLANS)
def __init__(self, *args, **kwargs):
super(VmCreateForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_show_labels = False
self.helper.layout = Layout(
Div(
Div(
Field('template', id="vm-create-template-select",
css_class="select form-control"),
css_class="col-sm-10",
),
css_class="row",
),
Div( # buttons
Div(
AnyTag(
"a",
HTML("%s " % _("Advanced")),
AnyTag(
"i",
css_class="vm-create-advanced-icon icon-caret-down"
),
css_class="btn btn-info vm-create-advanced-btn",
),
css_class="col-sm-5",
),
Div(
AnyTag( # tip: don't try to use Button class
"button",
AnyTag(
"i",
css_class="icon-play"
),
HTML(" Start"),
css_id="vm-create-submit",
css_class="btn btn-success",
),
css_class="col-sm-5 text-right",
),
css_class="row",
),
Div( # vm-create-advanced
Div(
Div(
AnyTag(
'h2',
HTML(_("Resources")),
),
css_class="col-sm-12",
),
css_class="row",
),
Div( # cpu priority
Div(
HTML('<label for="vm-cpu-priority-slider">'
'<i class="icon-trophy"></i> CPU priority'
'</label>'),
css_class="col-sm-3"
),
Div(
Field('cpu_priority', id="vm-cpu-priority-slider",
css_class="vm-slider",
data_slider_min="0", data_slider_max="100",
data_slider_step="1", data_slider_value="20",
data_slider_handle="square",
data_slider_tooltip="hide"),
css_class="col-sm-9"
),
css_class="row"
),
Div( # cpu count
Div(
HTML('<label for="cpu-count-slider">'
'<i class="icon-cogs"></i> CPU count'
'</label>'),
css_class="col-sm-3"
),
Div(
Field('cpu_count', id="vm-cpu-count-slider",
css_class="vm-slider",
data_slider_min="1", data_slider_max="8",
data_slider_step="1", data_slider_value="2",
data_slider_handle="square",
data_slider_tooltip="hide"),
css_class="col-sm-9"
),
css_class="row"
),
Div( # ram size
Div(
HTML('<label for="ram-slider">'
'<i class="icon-ticket"></i> RAM amount'
'</label>'),
css_class="col-sm-3"
),
Div(
Field('ram_size', id="vm-ram-size-slider",
css_class="vm-slider",
data_slider_min="128", data_slider_max="4096",
data_slider_step="128", data_slider_value="512",
data_slider_handle="square",
data_slider_tooltip="hide"),
css_class="col-sm-9"
),
css_class="row"
),
Div( # disks
Div(
AnyTag(
"h2",
HTML("Disks")
),
css_class="col-sm-4",
),
Div(
Div(
Field("disks", css_class="form-control",
id="vm-create-disk-add-form"),
css_class="js-hidden",
style="padding-top: 15px; max-width: 450px;",
),
Div(
AnyTag(
"h3",
HTML(_("No disks are added!")),
css_id="vm-create-disk-list",
),
AnyTag(
"h3",
Div(
AnyTag(
"select",
css_class="form-control",
css_id="vm-create-disk-add-select",
),
Div(
AnyTag(
"a",
AnyTag(
"i",
css_class="icon-plus-sign",
),
href="#",
css_id="vm-create-disk-add-button",
css_class="btn btn-success",
),
css_class="input-group-btn"
),
css_class="input-group",
style="max-width: 330px;",
),
css_id="vm-create-disk-add",
),
css_class="no-js-hidden",
),
css_class="col-sm-8",
style="padding-top: 3px;",
),
css_class="row",
), # end of disks
Div( # network
Div(
AnyTag(
"h2",
HTML(_("Network")),
),
css_class="col-sm-4",
),
Div(
Div( # js-hidden
AnyTag(
"h4",
HTML(_("Managed networks")),
),
Field(
"managed_networks",
css_class="form-control",
id="vm-create-network-add-managed",
),
AnyTag(
"h4",
HTML(_("Unmanaged networks")),
),
Field(
"unmanaged_networks",
css_class="form-control",
id="vm-create-network-add-unmanaged",
),
css_class="js-hidden",
style="padding-top: 15px; max-width: 450px;",
),
Div( # no-js-hidden
AnyTag(
"h3",
HTML(_("Not added to any network!")),
css_id="vm-create-network-list",
),
AnyTag(
"h3",
Div(
AnyTag(
"select",
css_class="form-control",
css_id="vm-create-network-add-select",
),
AnyTag(
"span",
WorkingBaseInput(
"",
"",
css_id=(
"vm-create-network-add"
"checkbox-managed"
),
input_type="checkbox",
title="",
data_original_title=(
_("Managed network?")
),
checked="checked",
),
css_class="input-group-addon",
),
Div(
AnyTag(
"a",
AnyTag(
"i",
css_class="icon-plus-sign",
),
css_id=("vm-create-network-add"
"-button"),
css_class="btn btn-success",
),
css_class="input-group-btn",
),
css_class="input-group",
style="max-width: 330px;",
),
css_class="vm-create-network-add"
),
css_class="no-js-hidden",
),
css_class="col-sm-8",
style="padding-top: 3px;",
),
css_class="row"
), # end of network
css_class="vm-create-advanced"
),
)
class LinkButton(BaseInput):
"""
Used to create a link button descriptor for the {% crispy %} template tag::
back = LinkButton('back', 'Back', reverse_lazy('index'))
.. note:: The first argument is also slugified and turned into the id for
the submit button.
"""
template = "bootstrap/layout/linkbutton.html"
field_classes = 'btn btn-default'
def __init__(self, name, text, url, *args, **kwargs):
self.href = url
super(LinkButton, self).__init__(name, text, *args, **kwargs)
class AnyTag(Div):
template = "crispy_forms/anytag.html"
def __init__(self, tag, *fields, **kwargs):
self.tag = tag
super(AnyTag, self).__init__(*fields, **kwargs)
def render(self, form, form_style, context, template_pack=TEMPLATE_PACK):
fields = ''
for field in self.fields:
fields += render_field(field, form, form_style, context,
template_pack=template_pack)
return render_to_string(self.template, Context({'tag': self,
'fields': fields}))
class WorkingBaseInput(BaseInput):
def __init__(self, name, value, input_type="text", **kwargs):
self.input_type = input_type
self.field_classes = "" # we need this for some reason
super(WorkingBaseInput, self).__init__(name, value, **kwargs)
...@@ -207,4 +207,23 @@ body { ...@@ -207,4 +207,23 @@ body {
/* port add buttons */ /* port add buttons */
.vm-details-network-port-add .input-group-addon, .vm-details-network-port-add .input-group-btn { .vm-details-network-port-add .input-group-addon, .vm-details-network-port-add .input-group-btn {
width: inherit ; width: inherit ;
} }
/* vm-create */
a.hover-black {
color:white;
}
.hover-black:hover {
color: black /*#d9534f*/;
text-decoration: none;
}
.no-js-hidden {
display: none;
}
#vm-create-network-addcheckbox-managed {
-webkit-transform: scale(1.3, 1.3); margin-top: 4px;
}
/* --- */
<{{ tag.tag }} {% if tag.css_id %}id="{{ tag.css_id }}"{% endif %}
{% if tag.css_class %}class="{{ tag.css_class }}"{% endif %} {{ tag.flat_attrs|safe }}>
{{ fields|safe }}
</{{ tag.tag }}>
{% load crispy_forms_tags %}
<style> <style>
.row { .row {
margin-bottom: 15px; margin-bottom: 15px;
} }
</style> </style>
<form method="POST" action="/dashboard/vm/create/">
{% csrf_token %}
<div class="row">
<div class="col-sm-10">
<select class="select form-control" id="vm-create-template-select" name="template-pk">
<option value="-1">Choose a VM template</option>
{% for template in templates %}
<option value="{{ template.pk }}">{{ template.name}}</option>
{% endfor %}
</select>
</div>
</div>
<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 --> <form method="POST" action="/dashboard/vm/create/">
<div class="row"> {% csrf_token %}
<div class="col-sm-4"> {% crispy vm_create_form %}
<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> </form>
...@@ -21,6 +21,7 @@ from django.utils.translation import ugettext as _ ...@@ -21,6 +21,7 @@ from django.utils.translation import ugettext as _
from django_tables2 import SingleTableView from django_tables2 import SingleTableView
from braces.views import LoginRequiredMixin from braces.views import LoginRequiredMixin
from .forms import VmCreateForm
from .tables import (VmListTable, NodeListTable) from .tables import (VmListTable, NodeListTable)
from vm.models import (Instance, InstanceTemplate, InterfaceTemplate, from vm.models import (Instance, InstanceTemplate, InterfaceTemplate,
InstanceActivity, Node, instance_activity) InstanceActivity, Node, instance_activity)
...@@ -362,7 +363,8 @@ class VmCreate(TemplateView): ...@@ -362,7 +363,8 @@ class VmCreate(TemplateView):
context.update({ context.update({
'templates': InstanceTemplate.objects.all(), 'templates': InstanceTemplate.objects.all(),
'vlans': Vlan.objects.all(), 'vlans': Vlan.objects.all(),
'disks': Disk.objects.exclude(type="qcow2-snap") 'disks': Disk.objects.exclude(type="qcow2-snap"),
'vm_create_form': VmCreateForm,
}) })
return context return context
...@@ -376,27 +378,31 @@ class VmCreate(TemplateView): ...@@ -376,27 +378,31 @@ class VmCreate(TemplateView):
resp = {} resp = {}
try: try:
pk = request.POST.get('template-pk') pk = request.POST.get('template')
template = InstanceTemplate.objects.get( template = InstanceTemplate.objects.get(
pk=pk) pk=pk)
except ValueError:
resp['error'] = True
resp['message'] = _("Select a VM from the list!")
except InstanceTemplate.DoesNotExist as e: except InstanceTemplate.DoesNotExist as e:
logger.warning('VmCreate.post: %s (pk=%d, user=%s)', logger.warning('VmCreate.post: %s (pk=%d, user=%s)',
unicode(e), unicode(request.user), pk) unicode(e), pk, unicode(request.user))
resp['error'] = True resp['error'] = True
else: else:
if request.user.has_perm('vm.set_resources'): if request.user.has_perm('vm.set_resources'):
ikwargs = { ikwargs = {
'num_cores': int(request.POST.get('cpu-count')), 'num_cores': int(request.POST.get('cpu_count')),
'ram_size': int(request.POST.get('ram-size')), 'ram_size': int(request.POST.get('ram_size')),
'priority': int(request.POST.get('cpu-priority')), 'priority': int(request.POST.get('cpu_priority')),
} }
try: try:
networks = [InterfaceTemplate(vlan=Vlan.objects.get(pk=l), networks = [InterfaceTemplate(vlan=Vlan.objects.get(pk=l),
managed=True) managed=True)
for l in request.POST.getlist('managed-vlans') for l in request.POST.getlist(
'managed_networks')
] ]
unmanaged = request.POST.getlist('unmanaged-vlans') unmanaged = request.POST.getlist('unmanaged_networks')
networks.extend([ networks.extend([
InterfaceTemplate(vlan=Vlan.objects.get(pk=l), InterfaceTemplate(vlan=Vlan.objects.get(pk=l),
managed=False) managed=False)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment