Commit 10fc46ee by Kálmán Viktor

dashboard: new vm create modal

parent 66c1cfd4
...@@ -23,48 +23,53 @@ VLANS = Vlan.objects.all() ...@@ -23,48 +23,53 @@ VLANS = Vlan.objects.all()
DISKS = Disk.objects.exclude(type="qcow2-snap") DISKS = Disk.objects.exclude(type="qcow2-snap")
class VmCreateForm(forms.Form): class VmCustomizeForm(forms.Form):
template = forms.ModelChoiceField(queryset=InstanceTemplate.objects.all(), name = forms.CharField()
empty_label="Select pls")
cpu_priority = forms.IntegerField() cpu_priority = forms.IntegerField()
cpu_count = forms.IntegerField() cpu_count = forms.IntegerField()
ram_size = forms.IntegerField() ram_size = forms.IntegerField()
disks = forms.ModelMultipleChoiceField( disks = forms.ModelMultipleChoiceField(
queryset=DISKS, queryset=None, required=True)
required=False
)
networks = forms.ModelMultipleChoiceField( networks = forms.ModelMultipleChoiceField(
queryset=VLANS, required=False) queryset=None, required=False)
template = forms.CharField()
customized = forms.CharField() # dummy flag field
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(VmCreateForm, self).__init__(*args, **kwargs) self.user = kwargs.pop("user", None)
self.template = kwargs.pop("template", None)
super(VmCustomizeForm, self).__init__(*args, **kwargs)
# set displayed disk and network list
self.fields['disks'].queryset = Disk.get_objects_with_level(
'user', self.user).exclude(type="qcow2-snap")
self.fields['networks'].queryset = Vlan.get_objects_with_level(
'user', self.user)
# set initial for disk and network list
self.initial['disks'] = self.template.disks.all()
self.initial['networks'] = InterfaceTemplate.objects.filter(
template=self.template).values_list("vlan", flat=True)
# set initial for resources
self.initial['cpu_priority'] = self.template.priority
self.initial['cpu_count'] = self.template.num_cores
self.initial['ram_size'] = self.template.ram_size
# initial name and template pk
self.initial['name'] = self.template.name
self.initial['template'] = self.template.pk
self.initial['customized'] = self.template.pk
self.helper = FormHelper(self) self.helper = FormHelper(self)
self.helper.form_show_labels = False self.helper.form_show_labels = False
self.helper.layout = Layout( self.helper.layout = Layout(
Div( Field("template", type="hidden"),
Div( Field("customized", type="hidden"),
Field('template', id="vm-create-template-select",
css_class="select form-control"),
css_class="col-sm-10",
),
css_class="row",
),
Div( # buttons Div( # buttons
Div( 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 AnyTag( # tip: don't try to use Button class
"button", "button",
AnyTag( AnyTag(
...@@ -72,193 +77,200 @@ class VmCreateForm(forms.Form): ...@@ -72,193 +77,200 @@ class VmCreateForm(forms.Form):
css_class="icon-play" css_class="icon-play"
), ),
HTML(" Start"), HTML(" Start"),
css_id="vm-create-submit", css_id="vm-create-customized-start",
css_class="btn btn-success", css_class="btn btn-success",
), ),
css_class="col-sm-5 text-right", css_class="col-sm-11 text-right",
), ),
css_class="row", css_class="row",
), ),
Div( # vm-create-advanced Div(
Div( Div(
Div( Field("name"),
AnyTag( css_class="col-sm-5",
'h2',
HTML(_("Resources")),
),
css_class="col-sm-12",
),
css_class="row",
), ),
Div( # cpu priority css_class="row",
Div( ),
HTML('<label for="vm-cpu-priority-slider">' Div(
'<i class="icon-trophy"></i> CPU priority' Div(
'</label>'), AnyTag(
css_class="col-sm-3" 'h2',
), HTML(_("Resources")),
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" css_class="col-sm-12",
), ),
Div( # cpu count css_class="row",
Div( ),
HTML('<label for="cpu-count-slider">' Div( # cpu priority
'<i class="icon-cogs"></i> CPU count' Div(
'</label>'), HTML('<label for="vm-cpu-priority-slider">'
css_class="col-sm-3" '<i class="icon-trophy"></i> CPU priority'
), '</label>'),
Div( css_class="col-sm-3"
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(
Div( Field('cpu_priority', id="vm-cpu-priority-slider",
HTML('<label for="ram-slider">' css_class="vm-slider",
'<i class="icon-ticket"></i> RAM amount' data_slider_min="0", data_slider_max="100",
'</label>'), data_slider_step="1",
css_class="col-sm-3" data_slider_value=self.template.priority,
), data_slider_handle="square",
Div( data_slider_tooltip="hide"),
Field('ram_size', id="vm-ram-size-slider", css_class="col-sm-9"
css_class="vm-slider", ),
data_slider_min="128", data_slider_max="4096", css_class="row"
data_slider_step="128", data_slider_value="512", ),
data_slider_handle="square", Div( # cpu count
data_slider_tooltip="hide"), Div(
css_class="col-sm-9" 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=self.template.num_cores,
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=self.template.ram_size,
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="row" css_class="col-sm-4",
), ),
Div( # disks Div(
Div( Div(
AnyTag( Field("disks", css_class="form-control",
"h2", id="vm-create-disk-add-form"),
HTML("Disks") css_class="js-hidden",
), style="padding-top: 15px; max-width: 450px;",
css_class="col-sm-4",
), ),
Div( Div(
Div( AnyTag(
Field("disks", css_class="form-control", "h3",
id="vm-create-disk-add-form"), HTML(_("No disks are added!")),
css_class="js-hidden", css_id="vm-create-disk-list",
style="padding-top: 15px; max-width: 450px;",
), ),
Div( AnyTag(
AnyTag( "h3",
"h3", Div(
HTML(_("No disks are added!")), AnyTag(
css_id="vm-create-disk-list", "select",
), css_class="form-control",
AnyTag( css_id="vm-create-disk-add-select",
"h3", ),
Div( Div(
AnyTag( AnyTag(
"select", "a",
css_class="form-control",
css_id="vm-create-disk-add-select",
),
Div(
AnyTag( AnyTag(
"a", "i",
AnyTag( css_class="icon-plus-sign",
"i",
css_class="icon-plus-sign",
),
href="#",
css_id="vm-create-disk-add-button",
css_class="btn btn-success",
), ),
css_class="input-group-btn" href="#",
css_id="vm-create-disk-add-button",
css_class="btn btn-success",
), ),
css_class="input-group", css_class="input-group-btn"
style="max-width: 330px;",
), ),
css_id="vm-create-disk-add", css_class="input-group",
style="max-width: 330px;",
), ),
css_class="no-js-hidden", css_id="vm-create-disk-add",
), ),
css_class="col-sm-8", css_class="no-js-hidden",
style="padding-top: 3px;",
), ),
css_class="row", css_class="col-sm-8",
), # end of disks style="padding-top: 3px;",
Div( # network ),
Div( css_class="row",
AnyTag( ), # end of disks
"h2", Div( # network
HTML(_("Network")), Div(
AnyTag(
"h2",
HTML(_("Network")),
),
css_class="col-sm-4",
),
Div(
Div( # js-hidden
Field(
"networks",
css_class="form-control",
id="vm-create-network-add-vlan",
), ),
css_class="col-sm-4", css_class="js-hidden",
style="padding-top: 15px; max-width: 450px;",
), ),
Div( Div( # no-js-hidden
Div( # js-hidden AnyTag(
Field( "h3",
"networks", HTML(_("Not added to any network!")),
css_class="form-control", css_id="vm-create-network-list",
id="vm-create-network-add-vlan",
),
css_class="js-hidden",
style="padding-top: 15px; max-width: 450px;",
), ),
Div( # no-js-hidden AnyTag(
AnyTag( "h3",
"h3", Div(
HTML(_("Not added to any network!")), AnyTag(
css_id="vm-create-network-list", "select",
), css_class=("form-control "
AnyTag( "font-awesome-font"),
"h3", css_id="vm-create-network-add-select",
),
Div( Div(
AnyTag( AnyTag(
"select", "a",
css_class=("form-control "
"font-awesome-font"),
css_id="vm-create-network-add-select",
),
Div(
AnyTag( AnyTag(
"a", "i",
AnyTag( css_class="icon-plus-sign",
"i",
css_class="icon-plus-sign",
),
css_id=("vm-create-network-add"
"-button"),
css_class="btn btn-success",
), ),
css_class="input-group-btn", css_id=("vm-create-network-add"
"-button"),
css_class="btn btn-success",
), ),
css_class="input-group", css_class="input-group-btn",
style="max-width: 330px;",
), ),
css_class="vm-create-network-add" css_class="input-group",
style="max-width: 330px;",
), ),
css_class="no-js-hidden", css_class="vm-create-network-add"
), ),
css_class="col-sm-8", css_class="no-js-hidden",
style="padding-top: 3px;",
), ),
css_class="row" css_class="col-sm-8",
), # end of network style="padding-top: 3px;",
css_class="vm-create-advanced" ),
), css_class="row"
), # end of network
) )
......
...@@ -2,24 +2,72 @@ var vlans = []; ...@@ -2,24 +2,72 @@ var vlans = [];
var disks = []; var disks = [];
$(function() { $(function() {
vmCreateLoaded(); vmCustomizeLoaded();
}); });
function vmCreateLoaded() { function vmCreateLoaded() {
$('.vm-create-advanced').hide(); $(".vm-create-template-details").hide();
$('.vm-create-advanced-btn').click(function() {
$('.vm-create-advanced').stop().slideToggle(); $(".vm-create-template-summary").click(function() {
if ($('.vm-create-advanced-icon').hasClass('icon-caret-down')) { $(this).next(".vm-create-template-details").slideToggle();
$('.vm-create-advanced-icon').removeClass('icon-caret-down').addClass('icon-caret-up');
} else {
$('.vm-create-advanced-icon').removeClass('icon-caret-up').addClass('icon-caret-down');
}
}); });
$(".customize-vm").click(function() {
var template = $(this).data("template-pk");
console.log(template);
$('#vm-create-template-select').change(function() { $.get("/dashboard/vm/create/?template=" + template, function(data) {
vmCreateTemplateChange(this); var r = $('#create-modal'); r.next('div').remove(); r.remove();
$('body').append(data);
vmCreateLoaded();
addSliderMiscs();
$('#create-modal').modal('show');
$('#create-modal').on('hidden.bs.modal', function() {
$('#create-modal').remove();
});
});
return false;
}); });
/* start vm button clicks */
$('.vm-create-start').click(function() {
template = $(this).data("template-pk");
$.ajax({
url: '/dashboard/vm/create/',
headers: {"X-CSRFToken": getCookie('csrftoken')},
type: 'POST',
data: {'template': template},
success: function(data, textStatus, xhr) {
if(data.redirect) {
window.location.replace(data.redirect + '#activity');
}
else {
var r = $('#create-modal'); r.next('div').remove(); r.remove();
$('body').append(data);
vmCreateLoaded();
addSliderMiscs();
$('#create-modal').modal('show');
$('#create-modal').on('hidden.bs.modal', function() {
$('#create-modal').remove();
});
}
},
error: function(xhr, textStatus, error) {
var r = $('#create-modal'); r.next('div').remove(); r.remove();
if (xhr.status == 500) {
addMessage("500 Internal Server Error", "danger");
} else {
addMessage(xhr.status + " Unknown Error", "danger");
}
}
});
return false;
});
}
function vmCustomizeLoaded() {
/* network thingies */ /* network thingies */
/* add network */ /* add network */
...@@ -86,15 +134,24 @@ function vmCreateLoaded() { ...@@ -86,15 +134,24 @@ function vmCreateLoaded() {
/* copy networks from hidden select */ /* copy networks from hidden select */
$('#vm-create-network-add-vlan option').each(function() { $('#vm-create-network-add-vlan option').each(function() {
var managed = $(this).text().indexOf("mana") == 0; var managed = $(this).text().indexOf("mana") == 0;
var text = $(this).text(); var raw_text = $(this).text();
var pk = $(this).val(); var pk = $(this).val();
if(managed) { if(managed) {
text = text.replace("managed -", "&#xf0ac;"); text = raw_text.replace("managed -", "&#xf0ac;");
} else { } else {
text = text.replace("unmanaged -", "&#xf0c1;"); text = raw_text.replace("unmanaged -", "&#xf0c1;");
} }
var html = '<option data-managed="' + (managed ? 1 : 0) + '" value="' + pk + '">' + text + '</option>'; var html = '<option data-managed="' + (managed ? 1 : 0) + '" value="' + pk + '">' + text + '</option>';
$('#vm-create-network-add-select').append(html);
if($('#vm-create-network-list span').length < 1) {
$("#vm-create-network-list").html("");
}
if($(this).is(":selected")) {
$("#vm-create-network-list").append(vmCreateNetworkLabel(pk, raw_text.replace("unmanaged -", "").replace("managed -", ""), managed));
} else {
$('#vm-create-network-add-select').append(html);
}
}); });
...@@ -168,8 +225,20 @@ function vmCreateLoaded() { ...@@ -168,8 +225,20 @@ function vmCreateLoaded() {
}); });
/* copy disks from hidden select */ /* copy disks from hidden select */
$('#vm-create-disk-add-select').html($('#vm-create-disk-add-form').html()); $('#vm-create-disk-add-form option').each(function() {
var text = $(this).text();
var pk = $(this).val();
var html = '<option value="' + pk + '">' + text + '</option>';
if($('#vm-create-disk-list span').length < 1) {
$("#vm-create-disk-list").html("");
}
if($(this).is(":selected")) {
$("#vm-create-disk-list").append(vmCreateDiskLabel(pk, text));
} else {
$('#vm-create-disk-add-select').append(html);
}
});
/* build up disk list */ /* build up disk list */
$('#vm-create-disk-add-select option').each(function() { $('#vm-create-disk-add-select option').each(function() {
...@@ -179,8 +248,8 @@ function vmCreateLoaded() { ...@@ -179,8 +248,8 @@ function vmCreateLoaded() {
}); });
}); });
/* add button */ /* start vm button clicks */
$('#vm-create-submit').click(function() { $('#vm-create-customized-start').click(function() {
$.ajax({ $.ajax({
url: '/dashboard/vm/create/', url: '/dashboard/vm/create/',
headers: {"X-CSRFToken": getCookie('csrftoken')}, headers: {"X-CSRFToken": getCookie('csrftoken')},
...@@ -219,97 +288,6 @@ function vmCreateLoaded() { ...@@ -219,97 +288,6 @@ function vmCreateLoaded() {
$('.js-hidden').hide(); $('.js-hidden').hide();
} }
function vmCreateTemplateChange(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
$('#vm-cpu-priority-slider').slider("setValue", data['priority']);
$('#vm-cpu-count-slider').slider("setValue", data['num_cores']);
$('#vm-ram-size-slider').slider("setValue", data['ram_size']);
/* slider doesn't have change event ........................ */
refreshSliders();
/* clear selections */
$("#vm-create-network-add-vlan").find('option').prop('selected', false);
$('#vm-create-disk-add-form').find('option').prop('selected', false);
/* clear the network select */
$("#vm-create-network-add-select").html('');
/* 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]
$('#vm-create-network-list').append(
vmCreateNetworkLabel(nn.vlan_pk, nn.vlan, nn.managed)
);
$('#vm-create-network-add-vlan option[value="' + nn.vlan_pk + '"]').prop('selected', true);
added_vlans.push(nn.vlan_pk);
}
/* remove already added vlans from dropdown or add new ones */
$('#vm-create-network-add-select').html('');
// this is working because the vlans array already has the icon's hex code
for(var i=0; i < vlans.length; i++)
if(added_vlans.indexOf(vlans[i].pk) == -1) {
var html = '<option data-managed="' + (vlans[i].managed ? 1 : 0) + '" value="' + vlans[i].pk + '">' + vlans[i].name + '</option>';
$('#vm-create-network-add-select').append(html);
}
/* enable the network add button if there are not added vlans */
if(added_vlans.length != vlans.length) {
$('#vm-create-network-add-button').attr('disabled', false);
} else {
$('#vm-create-network-add-select').html('<option value="-1">No more networks!</option>');
$('#vm-create-network-add-button').attr('disabled', true);
}
/* if there are no added vlans print it out */
if(added_vlans.length < 1) {
$('#vm-create-network-list').html("Not added to any network!");
}
/* append disks */
$('#vm-create-disk-list').html('');
var added_disks = []
for(var d = 0; d<data['disks'].length; d++) {
dd = data['disks'][d]
$('#vm-create-disk-list').append(
vmCreateDiskLabel(dd.pk, dd.name)
);
$('#vm-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 */
$('#vm-create-disk-add-select').html('');
for(var i=0; i < disks.length; i++)
if(added_disks.indexOf(disks[i].pk) == -1)
$('#vm-create-disk-add-select').append($('<option>', {
value: disks[i].pk,
text: disks[i].name
}));
/* enable the disk add button if there are not added disks */
if(added_disks.length != disks.length) {
$('#vm-create-disk-add-button').attr('disabled', false);
} else {
$('#vm-create-disk-add-select').html('<option value="-1">We are out of &lt;options&gt; hehe</option>');
$('#vm-create-disk-add-button').attr('disabled', true);
}
}
}
});
}
function vmCreateNetworkLabel(pk, name, managed) { function vmCreateNetworkLabel(pk, name, managed) {
return '<span id="vlan-' + pk + '" class="label label-' + (managed ? 'primary' : 'default') + '"><i class="icon-' + (managed ? 'globe' : 'link') + '"></i> ' + name + ' <a href="#" class="hover-black vm-create-remove-network"><i class="icon-remove-sign"></i></a></span> '; return '<span id="vlan-' + pk + '" class="label label-' + (managed ? 'primary' : 'default') + '"><i class="icon-' + (managed ? 'globe' : 'link') + '"></i> ' + name + ' <a href="#" class="hover-black vm-create-remove-network"><i class="icon-remove-sign"></i></a></span> ';
......
{% load sizefieldtags %}
<div class="vm-create-template-list">
{% for t in templates %}
<div class="vm-create-template">
<div class="vm-create-template-summary">
{{ t.name }}
<span class="pull-right"><i class="icon-{{ t.os_type }}"></i> {{ t.system }}</span>
</div>
<div class="vm-create-template-details">
<ul>
<li>
<i class="icon-gears"></i> CPU
<div class="progress pull-right">
<div class="progress-bar progress-bar-success" role="progressbar"
aria-valuenow="{{ t.num_cores }}" aria-valuemin="0" aria-valuemax="8" style="width: 80%">
<span class="progress-bar-text">{{ t.num_cores }} cores</span>
</div>
</div>
</li>
<li>
<i class="icon-ticket"></i> Memory
<div class="progress pull-right">
<div class="progress-bar progress-bar-info" role="progressbar"
aria-valuenow="{{ t.ram_size }}" aria-valuemin="0" aria-valuemax="4096"
style="width: 80%">
<span class="progress-bar-text">{{ t.ram_size }} MB</span>
</div>
</div>
</li>
<li>
<i class="icon-file"></i> Disks
<span style="float: right;">
{% for d in t.disks.all %}{{ d.name }} ({{ d.size|filesize }}){% if not forloop.last %}, {% endif %}{% endfor %}
</span>
</li>
<li>
<i class="icon-globe"></i> Network:
<span style="float: right;">
{% for i in t.interface_set.all %}{{ i.vlan.name }}{% if not forloop.last %}, {% endif %}{% endfor %}
</span>
</li>
<li>
<i class="icon-tag"></i> Típus: {{ t.lease.name }}
<span style="float: right;">
<i class="icon-pause"></i> {{ t.lease.get_readable_suspend_time }}
<i class="icon-remove"></i> {{ t.lease.get_readable_delete_time }}
</span>
</li>
<li>
<i class="icon-hand-right"></i> Description:
<span style="float: right; max-width: 350px;">
{{ t.description }}
</span>
<div class="clearfix"></div>
</li>
</ul>
<div style="margin-top: 20px; padding: 0 15px; width: 100%">
<a class="btn btn-primary btn-xs customize-vm" data-template-pk="{{ t.pk }}" href="{% url "dashboard.views.vm-create" %}?template={{ t.pk }}"><i class="icon-wrench"></i> Customize</a>
<form class="pull-right text-right" method="POST" action="{% url "dashboard.views.vm-create" %}">
{% csrf_token %}
<input type="hidden" name="template" value="{{ t.pk }}"/>
<button class="btn btn-success btn-xs vm-create-start" data-template-pk="{{ t.pk }}" type="submit"><i class="icon-play"></i> Start</button>
</form>
</div>
</div>
</div>
{% endfor %}
</div>
<style>
.row {
margin-bottom: 15px;
}
.vm-create-template {
max-width: 800px;
border: 1px solid black;
border-bottom: none;
}
.vm-create-template-list .vm-create-template:last-child {
border-bottom: 1px solid black;
}
.vm-create-template-summary {
padding: 15px;
cursor: pointer;
}
.vm-create-template:nth-child(odd) .vm-create-template-summary {
background: #F5F5F5;
}
.vm-create-template-list .vm-create-template-summary:hover {
background: #D2D2D2;
}
.vm-create-template-details {
border-top: 1px dashed #D3D3D3;
padding: 15px;
}
.vm-create-template-details ul {
list-style: none;
padding: 0 15px;
}
.vm-create-template-details li {
border-bottom: 1px dotted #aaa;
padding: 5px 0px;
}
.progress {
position: relative;
width: 200px;
height: 12px;
margin-bottom: 0px;
margin-top: 5px;
}
.progress-bar-text {
position: absolute;
display: block;
width: 100%;
color: white;
/* outline */
text-shadow:
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
font-size: 10px;
}
</style>
{% block "extra-js" %}
<script>
$('.progress-bar').each(function() {
var min = $(this).attr('aria-valuemin');
var max = $(this).attr('aria-valuemax');
var now = $(this).attr('aria-valuenow');
var siz = (now-min)*100/(max-min);
$(this).css('width', siz+'%');
});
</script>
{% endblock %}
{% load crispy_forms_tags %}
{% load sizefieldtags %}
{% crispy vm_create_form %}
<script src="/static/dashboard/vm-create.js"></script>
<div class="modal fade" id="create-modal" tabindex="-1" role="dialog"> <div class="modal fade" id="create-modal" tabindex="-1" role="dialog">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
{% if box_title and ajax_title %}
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">{{ box_title }}</h4> <h4 class="modal-title">{{ box_title }}</h4>
</div> </div>
{% endif %}
<div class="modal-body"> <div class="modal-body">
{% include template %} {% include template %}
</div> </div>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
{% endblock %} {% endblock %}
{% block extra_js %} {% block extra_js %}
{% if template == "dashboard/vm-create.html" %} {% if template == "dashboard/_vm-create-1.html" %}
<script src="{{ STATIC_URL }}dashboard/vm-create.js"></script> <script src="{{ STATIC_URL }}dashboard/vm-create.js"></script>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% load crispy_forms_tags %}
<style>
.row {
margin-bottom: 15px;
}
</style>
<form method="POST" action="/dashboard/vm/create/">
{% csrf_token %}
{% crispy vm_create_form %}
</form>
...@@ -28,7 +28,8 @@ from django_tables2 import SingleTableView ...@@ -28,7 +28,8 @@ from django_tables2 import SingleTableView
from braces.views import LoginRequiredMixin, SuperuserRequiredMixin from braces.views import LoginRequiredMixin, SuperuserRequiredMixin
from .forms import ( from .forms import (
VmCreateForm, TemplateForm, LeaseForm, NodeForm, HostForm, DiskAddForm, VmCustomizeForm, TemplateForm, LeaseForm, NodeForm, HostForm,
DiskAddForm,
) )
from .tables import (VmListTable, NodeListTable, NodeVmListTable, from .tables import (VmListTable, NodeListTable, NodeVmListTable,
TemplateListTable, LeaseListTable, GroupListTable,) TemplateListTable, LeaseListTable, GroupListTable,)
...@@ -36,7 +37,6 @@ from vm.models import (Instance, InstanceTemplate, InterfaceTemplate, ...@@ -36,7 +37,6 @@ from vm.models import (Instance, InstanceTemplate, InterfaceTemplate,
InstanceActivity, Node, instance_activity, Lease, InstanceActivity, Node, instance_activity, Lease,
Interface) Interface)
from firewall.models import Vlan, Host, Rule from firewall.models import Vlan, Host, Rule
from storage.models import Disk
from dashboard.models import Favourite from dashboard.models import Favourite
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -952,7 +952,7 @@ class GroupDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView): ...@@ -952,7 +952,7 @@ class GroupDelete(LoginRequiredMixin, SuperuserRequiredMixin, DeleteView):
class VmCreate(LoginRequiredMixin, TemplateView): class VmCreate(LoginRequiredMixin, TemplateView):
form_class = VmCreateForm form_class = VmCustomizeForm
form = None form = None
def get_template_names(self): def get_template_names(self):
...@@ -962,51 +962,66 @@ class VmCreate(LoginRequiredMixin, TemplateView): ...@@ -962,51 +962,66 @@ class VmCreate(LoginRequiredMixin, TemplateView):
return ['dashboard/nojs-wrapper.html'] return ['dashboard/nojs-wrapper.html']
def get(self, request, form=None, *args, **kwargs): def get(self, request, form=None, *args, **kwargs):
if form is None: form_error = form is not None
form = self.form_class() template = (form.template.pk if form_error
form.fields['disks'].queryset = Disk.get_objects_with_level( else request.GET.get("template"))
'user', request.user).exclude(type="qcow2-snap")
form.fields['networks'].queryset = Vlan.get_objects_with_level(
'user', request.user)
templates = InstanceTemplate.get_objects_with_level('user', templates = InstanceTemplate.get_objects_with_level('user',
request.user) request.user)
form.fields['template'].queryset = templates if form is None and template:
form = self.form_class(user=request.user,
template=templates.get(pk=template))
context = self.get_context_data(**kwargs) context = self.get_context_data(**kwargs)
context.update({ if template:
'template': 'dashboard/vm-create.html', context.update({
'box_title': 'Create a VM', 'template': 'dashboard/_vm-create-2.html',
'vm_create_form': form, 'box_title': _('Customize VM'),
}) 'ajax_title': False,
'vm_create_form': form,
'template_o': templates.get(pk=template),
})
else:
context.update({
'template': 'dashboard/_vm-create-1.html',
'box_title': _('Create a VM'),
'ajax_title': False,
'templates': templates.all(),
})
return self.render_to_response(context) return self.render_to_response(context)
def post(self, request, *args, **kwargs): def __create_normal(self, request, *args, **kwargs):
form = self.form_class(request.POST) user = request.user
template = InstanceTemplate.objects.get(
pk=request.POST.get("template"))
# permission check
if not template.has_level(request.user, 'user'):
raise PermissionDenied()
inst = Instance.create_from_template(
template=template, owner=user)
return self.__deploy(request, inst)
def __create_customized(self, request, *args, **kwargs):
user = request.user
form = self.form_class(
request.POST, user=request.user,
template=InstanceTemplate.objects.get(
pk=request.POST.get("template")
)
)
if not form.is_valid(): if not form.is_valid():
return self.get(request, form, *args, **kwargs) return self.get(request, form, *args, **kwargs)
post = form.cleaned_data post = form.cleaned_data
user = request.user
try:
limit = user.profile.instance_limit
except Exception as e:
logger.debug('No profile or instance limit: %s', e)
else:
current = Instance.active.filter(owner=user).count()
logger.debug('current use: %d, limit: %d', current, limit)
if limit < current:
messages.error(request,
_('Instance limit (%d) exceeded.') % limit)
if request.is_ajax():
return HttpResponse(json.dumps({'redirect': '/'}),
content_type="application/json")
else:
return redirect('/')
template = post['template'] template = InstanceTemplate.objects.get(pk=post['template'])
if not template.has_level(request.user, 'user'): # permission check
if not template.has_level(user, 'user'):
raise PermissionDenied() raise PermissionDenied()
if request.user.has_perm('vm.set_resources'): if request.user.has_perm('vm.set_resources'):
ikwargs = { ikwargs = {
'name': post['name'],
'num_cores': post['cpu_count'], 'num_cores': post['cpu_count'],
'ram_size': post['ram_size'], 'ram_size': post['ram_size'],
'priority': post['cpu_priority'], 'priority': post['cpu_priority'],
...@@ -1017,17 +1032,45 @@ class VmCreate(LoginRequiredMixin, TemplateView): ...@@ -1017,17 +1032,45 @@ class VmCreate(LoginRequiredMixin, TemplateView):
inst = Instance.create_from_template( inst = Instance.create_from_template(
template=template, owner=user, networks=networks, template=template, owner=user, networks=networks,
disks=disks, **ikwargs) disks=disks, **ikwargs)
return self.__deploy(request, inst)
else: else:
inst = Instance.create_from_template( raise PermissionDenied()
template=template, owner=user)
inst.deploy_async(user=request.user) def __deploy(self, request, instance, *args, **kwargs):
instance.deploy_async(user=request.user)
messages.success(request, _('VM successfully created!')) messages.success(request, _('VM successfully created!'))
path = inst.get_absolute_url() path = instance.get_absolute_url()
if request.is_ajax(): if request.is_ajax():
return HttpResponse(json.dumps({'redirect': path}), return HttpResponse(json.dumps({'redirect': path}),
content_type="application/json") content_type="application/json")
else: else:
return redirect(path) return redirect("%s#activity" % path)
def post(self, request, *args, **kwargs):
user = request.user
# limit chekcs
try:
limit = user.profile.instance_limit
except Exception as e:
logger.debug('No profile or instance limit: %s', e)
else:
current = Instance.active.filter(owner=user).count()
logger.debug('current use: %d, limit: %d', current, limit)
if limit < current:
messages.error(request,
_('Instance limit (%d) exceeded.') % limit)
if request.is_ajax():
return HttpResponse(json.dumps({'redirect': '/'}),
content_type="application/json")
else:
return redirect('/')
create_func = (self.__create_normal if
request.POST.get("customized") is None else
self.__create_customized)
return create_func(request, *args, **kwargs)
class NodeCreate(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView): class NodeCreate(LoginRequiredMixin, SuperuserRequiredMixin, TemplateView):
......
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