Kimchi-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- 3775 discussions
[PATCH] [Kimchi] Introducing s390x UI Interfaces module for Edit Guest under virtualization
by rajgupta@linux.vnet.ibm.com 12 Sep '16
by rajgupta@linux.vnet.ibm.com 12 Sep '16
12 Sep '16
From: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
Introducing s390x UI Interfaces module for Edit Guest under virtualization
Signed-off-by: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
---
ui/css/kimchi.css | 26 +++-
ui/css/src/modules/_edit-guests.scss | 23 ++-
ui/js/src/kimchi.guest_edit_main.js | 282 ++++++++++++++++++++++++++++++++---
ui/pages/guest-edit.html.tmpl | 40 +++++
4 files changed, 341 insertions(+), 30 deletions(-)
diff --git a/ui/css/kimchi.css b/ui/css/kimchi.css
index 6cf2cc9..9299c38 100644
--- a/ui/css/kimchi.css
+++ b/ui/css/kimchi.css
@@ -1028,7 +1028,7 @@ body.wok-gallery {
}
#guest-edit-window #form-guest-edit-interface .column-actions {
- width: 23%;
+ width: 20%;
}
#guest-edit-window #form-guest-edit-storage .column-actions {
@@ -1088,19 +1088,25 @@ body.wok-gallery {
#guest-edit-window form .header .cell.column-type,
#guest-edit-window form .task .cell.column-type,
#guest-edit-window form .body .cell.column-type {
- width: 11.35%;
+ width: 18%;
+}
+
+#guest-edit-window form .header .cell.column-mode,
+#guest-edit-window form .task .cell.column-mode,
+#guest-edit-window form .body .cell.column-mode {
+ width: 16%;
}
#guest-edit-window form .header .cell.column-mac,
#guest-edit-window form .task .cell.column-mac,
#guest-edit-window form .body .cell.column-mac {
- width: 14.5%;
+ width: 14%;
}
#guest-edit-window form .header .cell.column-ip,
#guest-edit-window form .task .cell.column-ip,
#guest-edit-window form .body .cell.column-ip {
- width: 31%;
+ width: 12%;
}
#guest-edit-window form .header .cell.column-sel,
@@ -1239,6 +1245,18 @@ body.wok-gallery {
width: 180px;
}
+#guest-edit-window form .header .cell.column-mode .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
+#guest-edit-window form .task .cell.column-mode .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
+#guest-edit-window form .body .cell.column-mode .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
+ width: 160px;
+}
+
+#guest-edit-window form .header .cell.column-type .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
+#guest-edit-window form .task .cell.column-type .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
+#guest-edit-window form .body .cell.column-type .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
+ width: 180px;
+}
+
.guest-edit-snapshot .hide,
.guest-edit-interface .hide {
display: none !important;
diff --git a/ui/css/src/modules/_edit-guests.scss b/ui/css/src/modules/_edit-guests.scss
index b7e6941..632d634 100644
--- a/ui/css/src/modules/_edit-guests.scss
+++ b/ui/css/src/modules/_edit-guests.scss
@@ -48,7 +48,7 @@
}
#form-guest-edit-interface {
.column-actions {
- width: 23%;
+ width: 20%;
}
}
#form-guest-edit-storage {
@@ -94,13 +94,16 @@
}
}
.cell.column-type {
- width: 11.35%;
+ width: 18%;
+ }
+ .cell.column-mode {
+ width: 16%;
}
.cell.column-mac {
- width: 14.5%;
+ width: 14%;
}
.cell.column-ip {
- width: 31%;
+ width: 12%;
}
.cell.column-sel {
width: 1.77%;
@@ -204,6 +207,18 @@
width: 180px;
}
+#guest-edit-window form .header .cell.column-mode .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
+#guest-edit-window form .task .cell.column-mode .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
+#guest-edit-window form .body .cell.column-mode .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
+ width: 160px;
+}
+
+#guest-edit-window form .header .cell.column-type .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
+#guest-edit-window form .task .cell.column-type .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn),
+#guest-edit-window form .body .cell.column-type .bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {
+ width: 180px;
+}
+
.guest-edit-snapshot .hide,
.guest-edit-interface .hide {
display: none !important;
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index dcaafb8..cc899ff 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -20,6 +20,11 @@ kimchi.guest_edit_main = function() {
var formTargetId;
var guestEditForm = $('#form-guest-edit-general');
var saveButton = $('#guest-edit-button-save');
+ var s390xArch = 's390x';
+ var macvtapNetworks = "";
+ var ovsNetworks = "";
+ var networkOptions = "";
+
clearTimeout(kimchi.vmTimeout);
$('#modalWindow').on('hidden.bs.modal', function() {
@@ -176,14 +181,28 @@ kimchi.guest_edit_main = function() {
});
});
var toggleEdit = function(item, on, itemId) {
+ if(kimchi.hostarch === s390xArch){
+ $("#label-mac-" + itemId, item).toggleClass("hide", on);
+ $("#edit-mac-" + itemId, item).toggleClass("hide", !on);
+ $("#label-network-" + itemId, item).toggleClass("hide", false);
+ $("#label-type-" + itemId, item).toggleClass("hide", false);
+ $("#label-mode-" + itemId, item).toggleClass("hide", false);
+ $("select", item).toggleClass("hide", true);
+ $(".bootstrap-select", item).toggleClass("hide", true);
+ $(".action-area", item).toggleClass("hide");
+
+ }else {
+
$("#label-mac-" + itemId, item).toggleClass("hide", on);
$("#edit-mac-" + itemId, item).toggleClass("hide", !on);
$("#label-network-" + itemId, item).toggleClass("hide", false);
$("select", item).toggleClass("hide", true);
$(".bootstrap-select", item).toggleClass("hide", true);
$(".action-area", item).toggleClass("hide");
+ }
};
var addItem = function(data) {
+ var oriID = data.id;
if (data.id === -1) {
data.id = $('#form-guest-edit-interface > .body').children().size();
}
@@ -192,13 +211,28 @@ kimchi.guest_edit_main = function() {
} else {
data.ips = data.ips;
}
- var itemNode = $.parseHTML(wok.substitute($('#interface-tmpl').html(), data));
- $(".body", "#form-guest-edit-interface").append(itemNode);
- $("select", itemNode).append(networkOptions);
- $("select", itemNode).selectpicker();
- if (data.network !== "") {
- $("select", itemNode).val(data.network);
+ if (kimchi.hostarch === s390xArch) {
+ data.mode = (data.mode) ? data.mode : 'None';
+ var itemNode = $.parseHTML(wok.substitute($('#interface-s390x-tmpl').html(), data));
+ $(".body", "#form-guest-edit-interface").append(itemNode);
+
+ $("select", "span.column-type", itemNode).empty().append(typeOptions);
+ $("select", "span.column-mode", itemNode).empty().append(modeOptions);
+ $("select", "span.column-network", itemNode).empty().append(macvtapNetworks);
+
+ $("select", "span.column-type", itemNode).val(data.type);
+ $("select", "span.column-network", itemNode).val(data.source);
+ $("select", "span.column-mode", itemNode).val(data.mode);
+
+ } else {
+ var itemNode = $.parseHTML(wok.substitute($('#interface-tmpl').html(), data));
+ $(".body", "#form-guest-edit-interface").append(itemNode);
+ $("select", "span.column-network", itemNode).append(networkOptions);
}
+
+ $("select", itemNode).selectpicker();
+
+
$('.edit', itemNode).attr('disabled', kimchi.thisVMState === "running");
$(".edit", itemNode).on('click', function(evt) {
evt.preventDefault();
@@ -214,22 +248,122 @@ kimchi.guest_edit_main = function() {
$(".save", itemNode).on('click', function(evt) {
evt.preventDefault();
var item = $(this).parent().parent();
- var interface = {
- network: $("select", item).val(),
- type: "network",
- mac: $(":text", item).val(),
- ips: $(".ipText", item).val()
- };
+
+ if (kimchi.hostarch === s390xArch) {
+ if (item.prop("id") === "") { //adding new interface
+ switch ($("span.column-type select", item).val()) {
+ case 'macvtap':
+ var interface = {
+ source: $("span.column-network select", item).val(),
+ type: $("span.column-type select", item).val(),
+ mac: $(":text", item).val(),
+ ips: $(".ipText", item).val(),
+ mode: $("span.column-mode select", item).val()
+ };
+ break;
+
+ case 'ovs':
+ var interface = {
+ source: $("span.column-network select", item).val(),
+ type: $("span.column-type select", item).val(),
+ mac: $(":text", item).val(),
+ ips: $(".ipText", item).val()
+ };
+ break;
+
+ case 'network':
+ var interface = {
+ network: $("span.column-network select", item).val(),
+ type: "network",
+ mac: $(":text", item).val(),
+ ips: $(".ipText", item).val()
+ };
+ break;
+ }
+ } else { //updating existing interface
+
+ switch ($("#label-type-" + data.id, item).text()) {
+ case 'macvtap':
+
+ var interface = {
+ source: $("#label-network-" + data.id, item).text(),
+ type: $("#label-type-" + data.id, item).text(),
+ mac: $(":text", item).val(),
+ ips: $(".ipText", item).val(),
+ mode: $("#label-mode-" + data.id, item).text()
+ };
+ break;
+
+ case 'ovs':
+ var interface = {
+ source: $("#label-network-" + data.id, item).text(),
+ type: $("#label-type-" + data.id, item).text(),
+ mac: $(":text", item).val(),
+ ips: $(".ipText", item).val()
+ };
+ break;
+
+ case 'network':
+ var interface = {
+ network: $("#label-network-" + data.id, item).text(),
+ type: "network",
+ mac: $(":text", item).val(),
+ ips: $(".ipText", item).val()
+ };
+ break;
+ }
+
+ }
+ } else { //in s86 arch
+ var interface = {
+ network: $("select", item).val(),
+ type: "network",
+ mac: $(":text", item).val(),
+ ips: $(".ipText", item).val()
+ };
+ }
+
var postUpdate = function(mac) {
$("#label-network-" + data.id, item).text(interface.network);
$("#label-mac-" + data.id, item).text(mac);
$("#edit-mac-" + data.id, item).val(mac);
toggleEdit(item, false, data.id);
};
+
+ var posts390xUpdate = function(result) {
+ switch(result.type){
+ case 'macvtap' :
+ $("#label-type-" + data.id, item).text(result.type);
+ $("#label-network-" + data.id, item).text(result.source);
+ $("#label-mode-" + data.id, item).text(result.mode);
+ break;
+
+ case 'ovs' :
+ $("#label-type-" + data.id, item).text(result.type);
+ $("#label-network-" + data.id, item).text(result.source);
+ $("#label-mode-" + data.id, item).text('None');
+ break;
+
+ case 'network' :
+ $("#label-type-" + data.id, item).text(result.type);
+ $("#label-network-" + data.id, item).text(result.network);
+ $("#label-mode-" + data.id, item).text('None');
+ break;
+ }
+
+ $("#label-mac-" + data.id, item).text(result.mac);
+ $("#edit-mac-" + data.id, item).val(result.mac);
+ toggleEdit(item, false, data.id);
+ };
+
if (item.prop("id") === "") {
kimchi.createGuestInterface(kimchi.selectedGuest, interface, function(data) {
item.prop("id", data.mac);
- postUpdate(data.mac);
+ if(kimchi.hostarch == s390xArch){
+ posts390xUpdate(data);
+ }else{
+ postUpdate(data.mac);
+ }
});
} else {
if (item.prop('id') === interface.mac) {
@@ -249,22 +383,126 @@ kimchi.guest_edit_main = function() {
var item = $(this).parent().parent();
$("label", item).text() === "" ? item.remove() : toggleEdit(item, false, data.id);
});
+
+ if (kimchi.hostarch === s390xArch) {
+ $("#interface-s390x-type-" + data.id).on('change', function() {
+ var itemNode = $(this).closest('div.item');
+ switch ($(this).val()) {
+ case 'macvtap':
+ $('#label-mode-' + data.id).addClass('hide');
+ $('span.column-mode .bootstrap-select', itemNode).toggleClass("hide", false);
+
+ $("span.column-network select", itemNode).empty().append(macvtapNetworks);
+ $("span.column-network select", itemNode).selectpicker('refresh');
+
+ break;
+ case 'ovs':
+ $('#label-mode-' + data.id).html('None');
+ $('#label-mode-' + data.id).removeClass('hide');
+ $('span.column-mode .bootstrap-select', itemNode).toggleClass("hide", true);
+
+ $("span.column-network select", itemNode).empty().append(ovsNetworks);
+ $("span.column-network select", itemNode).selectpicker('refresh');
+ break;
+ case 'network':
+ $('#label-mode-' + data.id).html('None');
+ $('#label-mode-' + data.id).removeClass('hide');
+ $('span.column-mode .bootstrap-select', itemNode).toggleClass("hide", true);
+
+ $("span.column-network select", itemNode).empty().append(networkOptions);
+ $("span.column-network select", itemNode).selectpicker('refresh');
+ break;
+ }
+ });
+ if (oriID === -1) {
+ $("#interface-s390x-type-" + data.id).trigger('change');
+ }
+ }
+
};
- var networkOptions = "";
+
+
kimchi.listNetworks(function(data) {
for (var i = 0; i < data.length; i++) {
var isSlected = i === 0 ? " selected" : "";
networkOptions += "<option" + isSlected + ">" + data[i].name + "</option>";
}
- kimchi.getGuestInterfaces(kimchi.selectedGuest, function(data) {
- for (var i = 0; i < data.length; i++) {
- data[i].viewMode = "";
- data[i].editMode = "hide";
- data[i].id = i;
- addItem(data[i]);
- }
- });
+
+ if (kimchi.hostarch === s390xArch) {
+
+ kimchi.listmacvtapNetworks(function(data) {
+ for (var i = 0; i < data.length; i++) {
+ var isSlected = i === 0 ? ' selected="selected"' : "";
+ macvtapNetworks += "<option" + isSlected + ">" + data[i].name + "</option>";
+ }
+
+ kimchi.listovsNetworks(function(data) {
+ for (var i = 0; i < data.length; i++) {
+ var isSlected = i === 0 ? " selected" : "";
+ ovsNetworks += "<option" + isSlected + ">" + data[i] + "</option>";
+ }
+
+ kimchi.getGuestInterfaces(kimchi.selectedGuest, function(data) {
+ for (var i = 0; i < data.length; i++) {
+ data[i].viewMode = "";
+ data[i].editMode = "hide";
+ data[i].id = i;
+ addItem(data[i]);
+ }
+ });
+ });
+ });
+ } else {
+ kimchi.getGuestInterfaces(kimchi.selectedGuest, function(data) {
+ for (var i = 0; i < data.length; i++) {
+ data[i].viewMode = "";
+ data[i].editMode = "hide";
+ data[i].id = i;
+ if (data[i].type == 'network')
+ addItem(data[i]);
+ }
+ });
+ }
});
+
+ if (kimchi.hostarch === s390xArch) {
+ $('#form-guest-edit-interface > div.header').hide();
+ $('#form-guest-edit-interface > div.s390x').show();
+
+ var typeOptionsdata = [{
+ label: "macvtap",
+ value: "macvtap"
+ }, {
+ label: "ovs",
+ value: "ovs"
+ }, {
+ label: "network",
+ value: "network"
+ }];
+ var typeOptions = '';
+
+ for (var i = 0; i < typeOptionsdata.length; i++) {
+ var isSlected = i === 0 ? ' selected="selected"' : "";
+ typeOptions += '<option' + isSlected + ' value="' + typeOptionsdata[i].value + '">' + typeOptionsdata[i].label + '</option>';
+ }
+
+ var modeOptionsdata = [{
+ label: "Bridge",
+ value: "bridge"
+ }, {
+ label: "Vepa",
+ value: "vepa"
+ }];
+ var modeOptions = '';
+
+ for (var i = 0; i < modeOptionsdata.length; i++) {
+ var isSlected = i === 0 ? " selected" : "";
+ modeOptions += '<option' + isSlected + ' value="' + modeOptionsdata[i].value + '">' + modeOptionsdata[i].label + '</option>';
+ }
+ } else {
+ $('#form-guest-edit-interface > div.header').show();
+ $('#form-guest-edit-interface > div.s390x').hide();
+ }
};
var setupPermission = function() {
diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl
index a9a468e..3a575dc 100644
--- a/ui/pages/guest-edit.html.tmpl
+++ b/ui/pages/guest-edit.html.tmpl
@@ -92,6 +92,14 @@
<span class="cell column-ip">$_("IP Address")</span>
<span class="cell column-actions"><span class="sr-only">$_("Actions")</span></span>
</div>
+ <div class="header s390x" style="display:none">
+ <span class="cell column-type">$_("Type")</span>
+ <span class="cell column-network">$_("Network/Interface")</span>
+ <span class="cell column-mode">$_("Mode")</span>
+ <span class="cell column-mac">$_("MAC Address")</span>
+ <span class="cell column-ip">$_("IP Address")</span>
+ <span class="cell column-actions"><span class="sr-only">$_("Actions")</span></span>
+ </div>
<div class="body"></div>
</form>
<form role="tabpanel" class="guest-edit-permission tab-pane" id="form-guest-edit-permission">
@@ -246,6 +254,38 @@
</span>
<div>
</script>
+<script id="interface-s390x-tmpl" type="text/html">
+ <div class="item" id="{mac}">
+ <span class="cell column-type">
+ <span id="label-type-{id}" class="{viewMode}">{type}</span>
+ <select id="interface-s390x-type-{id}" class="{editMode}"></select>
+ </span>
+ <span class="cell column-network">
+ <span id="label-network-{id}" class="{viewMode}">{network}{source}</span>
+ <select id="interface-s390x-network-{id}" class="{editMode}"></select>
+ </span>
+ <span class="cell column-mode">
+ <span id="label-mode-{id}" class="{viewMode}">{mode}</span>
+ <select id="interface-s390x-mode-{id}" class="{editMode}"></select>
+ </span>
+ <span class="cell column-mac">
+ <span id="label-mac-{id}" class="{viewMode}">{mac}</span>
+ <input class="form-control {editMode}" type="text"
+ id="edit-mac-{id}" class="form-control" name="{mac}" value="{mac}" />
+ </span>
+ <span class="cell column-ip">
+ <span class=ipText>{ips}</span>
+ </span>
+ <span class="cell {editMode} column-actions action-area">
+ <button class="btn btn-primary save">$_("Save")</button>
+ <button class="btn btn-primary cancel">$_("Remove")</button>
+ </span>
+ <span class="cell {viewMode} column-actions action-area">
+ <button class="btn btn-link edit"><i class="fa fa-pencil"></i> $_("Edit")</button>
+ <button class="btn btn-link delete"><i class="fa fa-minus-circle"></i> $_("Remove")</button>
+ </span>
+ <div>
+</script>
<script id="ldap-user-tmpl" type="text/html">
<div class="item" id="{user}">
<span class="cell">
--
2.1.0
2
1
[PATCH] [Kimchi] Introducing s390x UI Interfaces module for Edit Template under virtualization
by rajgupta@linux.vnet.ibm.com 12 Sep '16
by rajgupta@linux.vnet.ibm.com 12 Sep '16
12 Sep '16
From: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
Introducing s390x UI Interfaces module for Edit Template under virtualization
Signed-off-by: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.api.js | 44 ++++++
ui/js/src/kimchi.main.js | 5 +
ui/js/src/kimchi.template_edit_main.js | 260 +++++++++++++++++++++++++++++++--
ui/pages/template-edit.html.tmpl | 33 +++++
4 files changed, 327 insertions(+), 15 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 2f127aa..a69336a 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -596,6 +596,35 @@ var kimchi = {
});
},
+ listmacvtapNetworks : function(suc, err) {
+ wok.requestJSON({
+ url : 'plugins/kimchi/interfaces?type=^nic|bonding|vlan$',
+ type : 'GET',
+ contentType : 'application/json',
+ dataType : 'json',
+ resend : true,
+ success : suc,
+ error : err ? err : function(data) {
+ wok.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+ listovsNetworks : function(suc, err) {
+ wok.requestJSON({
+ url : 'plugins/kimchi/ovsbridges',
+ type : 'GET',
+ contentType : 'application/json',
+ dataType : 'json',
+ resend : true,
+ success : suc,
+ error : err ? err : function(data) {
+ wok.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+
toggleNetwork : function(name, on, suc, err) {
var action = on ? "activate" : "deactivate";
wok.requestJSON({
@@ -1271,3 +1300,18 @@ var kimchi = {
});
}
};
+
+/**
+ * Get the host information.
+ */
+kimchi.getHostDetails = function (suc,err) {
+ wok.requestJSON({
+ url : 'plugins/gingerbase/host',
+ type : 'GET',
+ resend: true,
+ contentType : 'application/json',
+ dataType : 'json',
+ success : suc,
+ error: err
+ });
+}
diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js
index b6de2cf..ae996f0 100644
--- a/ui/js/src/kimchi.main.js
+++ b/ui/js/src/kimchi.main.js
@@ -33,6 +33,11 @@ kimchi.getCapabilities(function(result) {
kimchi.capabilities = {};
});
+kimchi.hostarch = undefined;
+kimchi.getHostDetails(function(result) {
+ kimchi.hostarch = result["architecture"];
+});
+
$(function(){
$('body').removeClass('wok-list wok-gallery');
});
diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
index a2032cc..ec93d86 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -19,8 +19,13 @@ kimchi.template_edit_main = function() {
var templateEditMain = $('#edit-template-tabs');
var origDisks;
var origNetworks;
+ var origInterfaces;
+ var origmacvtapNetworks;
+ var origovsNetworks;
var templateDiskSize;
var baseImageTemplate;
+ var s390xArch = 's390x';
+
$('#template-name', templateEditMain).val(kimchi.selectedTemplate);
$('#edit-template-tabs a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
$('.tab-content').css('overflow', 'hidden');
@@ -47,6 +52,7 @@ kimchi.template_edit_main = function() {
var initTemplate = function(template) {
origDisks = template.disks;
origNetworks = template.networks;
+ origInterfaces = template.interfaces;
for (var i = 0; i < template.disks.length; i++) {
if (template.disks[i].base) {
template["vm-image"] = template.disks[i].base;
@@ -268,10 +274,173 @@ kimchi.template_edit_main = function() {
});
};
- var initProcessor = function() {
- var setCPUValue = function() {
- if (!$('#cores').hasClass("invalid-field") && $('#cores').val() != "") {
- var computedCpu = parseInt($("#cores").val()) * parseInt($("#threads").val());
+ var initInterface_s390x = function(result) {
+ $('#form-template-interface-s390x').show();
+ $('#form-template-interface').hide();
+ var networkItemNum = 0;
+ var addInterfaceItem = function(networkData) {
+ var networkName = networkData.networkV;
+ var nodeInterface = $.parseHTML(wok.substitute($('#template-interface-s390x-tmpl').html(), networkData));
+ $('.template-tab-body', '#form-template-interface-s390x').append(nodeInterface);
+ $('.delete', '#form-template-interface-s390x').on("click", function(event) {
+ event.preventDefault();
+ $(this).parent().parent().remove();
+ });
+
+ //initialize type option
+ var typeOptionsdata = {};
+ var typeOptions = '';
+ typeOptionsdata.macvtap = 'macvtap';
+ typeOptionsdata.ovs = 'ovs';
+ typeOptionsdata.network = 'network';
+
+ $.each(typeOptionsdata, function(key, value) {
+ if (value === networkData.type) {
+ typeOptions += '<option value="' + key + '" selected="selected">' + networkData.type + '</option>';
+ } else {
+ typeOptions += '<option value="' + key + '">' + value + '</option>';
+ }
+ });
+
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.type').append(typeOptions);
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.type').on('change', function() {
+ var itemNode = $(this).closest('div.item');
+
+ switch ($(this).val()) {
+ case 'macvtap':
+ $('span.mode .label-mode', itemNode).addClass('hide');
+ $('span.mode .bootstrap-select', itemNode).toggleClass("hide", false);
+
+ var networkOptions = '';
+ for (var i = 0; i < origmacvtapNetworks.length; i++) {
+ networkOptions += '<option>' + origmacvtapNetworks[i].name + '</option>';
+ }
+
+ $('span.network select', itemNode).empty().append(networkOptions);
+ $('span.network select', itemNode).selectpicker('refresh');
+
+ break;
+ case 'ovs':
+ $('span.mode .label-mode', itemNode).removeClass('hide');
+ $('span.mode .bootstrap-select', itemNode).toggleClass("hide", true);
+ var networkOptions = '';
+ for (var i = 0; i < origovsNetworks.length; i++) {
+ networkOptions += '<option>' + origovsNetworks[i] + '</option>';
+ }
+
+ $('span.network select', itemNode).empty().append(networkOptions);
+ $('span.network select', itemNode).selectpicker('refresh');
+
+ break;
+ case 'network':
+ $('span.mode .label-mode', itemNode).removeClass('hide');
+ $('span.mode .bootstrap-select', itemNode).toggleClass("hide", true);
+
+ var networkOptions = '';
+ for (var i = 0; i < result.length; i++) {
+ if (result[i].state === "active") {
+ networkOptions += '<option>' + result[i].name + '</option>';
+ }
+ }
+ $('span.network select', itemNode).empty().append(networkOptions);
+ $('span.network select', itemNode).selectpicker('refresh');
+ break;
+ }
+ });
+
+ switch (networkData.type) {
+ case 'macvtap':
+ //initialize network option
+
+ var networkOptions = '';
+ for (var i = 0; i < origmacvtapNetworks.length; i++) {
+ if (networkName === origmacvtapNetworks[i].name) {
+ networkOptions += '<option selected="selected">' + origmacvtapNetworks[i].name + '</option>';
+ }
+ networkOptions += '<option>' + origmacvtapNetworks[i].name + '</option>';
+ }
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.network').append(networkOptions);
+
+ //initialize Mode option for Macvtap
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').val(networkData.mode);
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').selectpicker('refresh');
+
+ $('span.mode .label-mode', nodeInterface).addClass('hide');
+ $('span.mode .bootstrap-select', nodeInterface).removeClass("hide");
+
+ break;
+
+ case 'ovs':
+ var networkOptions = '';
+ for (var i = 0; i < origovsNetworks.length; i++) {
+ if (networkName === origovsNetworks[i]) {
+ networkOptions += '<option selected="selected">' + origovsNetworks[i] + '</option>';
+ }
+ networkOptions += '<option>' + origovsNetworks[i] + '</option>';
+ }
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.network').append(networkOptions);
+
+ //initialize Mode option for ovs
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').selectpicker('refresh');
+ $('span.mode .label-mode', nodeInterface).removeClass('hide');
+ $('span.mode .bootstrap-select', nodeInterface).addClass("hide");
+ break;
+
+ case 'network':
+ var networkOptions = '';
+ for (var i = 0; i < result.length; i++) {
+ if (networkName === result[i].name) {
+ networkOptions += '<option selected="selected">' + result[i].name + '</option>';
+ }
+ if (result[i].state === "active" && networkName !== result[i].name) {
+ networkOptions += '<option>' + result[i].name + '</option>';
+ }
+ }
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.network').append(networkOptions);
+
+ //initialize Mode option for Network
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').selectpicker('refresh');
+ $('span.mode .label-mode', nodeInterface).removeClass('hide');
+ $('span.mode .bootstrap-select', nodeInterface).addClass("hide");
+ break;
+ }
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum).selectpicker();
+ networkItemNum += 1;
+ };
+ if (origInterfaces && origInterfaces.length > 0) {
+ for (var i = 0; i < origInterfaces.length; i++) {
+ addInterfaceItem({
+ networkID: 'networkID' + networkItemNum,
+ networkV: origInterfaces[i].name,
+ type: origInterfaces[i].type,
+ mode: origInterfaces[i].mode
+ });
+ }
+ }
+ if (result && result.length > 0) {
+ for (var i = 0; i < origNetworks.length; i++) {
+ addInterfaceItem({
+ networkID: 'networkID' + networkItemNum,
+ networkV: origNetworks[i],
+ type: 'network'
+ });
+ }
+ }
+ $('#template-edit-interface-add-button-s390x').on("click", function(event) {
+ event.preventDefault();
+ addInterfaceItem({
+ networkID: 'networkID' + networkItemNum,
+ networkV: 'default',
+ type: 'network',
+ mode: 'None'
+ });
+ });
+ };
+
+ var initProcessor = function(){
+ var setCPUValue = function(){
+ if(!$('#cores').hasClass("invalid-field")&&$('#cores').val()!=""){
+ var computedCpu = parseInt($("#cores").val())*parseInt($("#threads").val());
$("#vcpus").val(computedCpu);
if ($("#cpus-check").prop("checked")) {
//If topology is checked, set maxcpu to be the same as # of cpu otherwise, backend gives error
@@ -340,7 +509,18 @@ kimchi.template_edit_main = function() {
});
}
- kimchi.listNetworks(initInterface);
+ if(kimchi.hostarch === s390xArch){
+ kimchi.listmacvtapNetworks(function(macvtapnet){
+ origmacvtapNetworks = macvtapnet;
+ kimchi.listovsNetworks(function(ovsnet){
+ origovsNetworks = ovsnet;
+ kimchi.listNetworks(initInterface_s390x);
+ });
+ });
+ }else {
+ kimchi.listNetworks(initInterface);
+ }
+
kimchi.listStoragePools(initStorage);
initProcessor();
checkInvalids();
@@ -432,18 +612,68 @@ kimchi.template_edit_main = function() {
topology: {}
};
}
- var networks = $('.template-tab-body .item', '#form-template-interface');
+ if(kimchi.hostarch === s390xArch){
+
+ var interfaces = $('.template-tab-body .item', '#form-template-interface-s390x');
var networkForUpdate = new Array();
- $.each(networks, function(index, networkEntities) {
- var thisValue = $('select', networkEntities).val();
- networkForUpdate.push(thisValue);
+ var interfacceForUpdate = new Array();
+
+ $.each(interfaces, function(index, interfaceEntities) {
+ var fields = $('span.type select', interfaceEntities);
+ switch(fields.val()){
+ case 'network':
+ var thisValue = $('span.network select', interfaceEntities).val();
+ networkForUpdate.push(thisValue);
+ break;
+
+ case 'macvtap':
+ var thisdata = {};
+ thisdata.type = $('span.type select', interfaceEntities).val();
+ thisdata.name = $('span.network select', interfaceEntities).val();
+ thisdata.mode = $('span.mode select', interfaceEntities).val();
+
+ interfacceForUpdate.push(thisdata);
+ break;
+
+ case 'ovs':
+ var thisdata = {};
+ thisdata.type = $('span.type select', interfaceEntities).val();
+ thisdata.name = $('span.network select', interfaceEntities).val();
+ interfacceForUpdate.push(thisdata);
+ break;
+ }
+
+ if (networkForUpdate instanceof Array) {
+ data.networks = networkForUpdate;
+ } else if (networkForUpdate != null) {
+ data.networks = [networkForUpdate];
+ } else {
+ data.networks = [];
+ }
+
+ if (networkForUpdate instanceof Array) {
+ data.interfaces = interfacceForUpdate;
+ } else if (interfacceForUpdate != null) {
+ data.interfaces = [interfacceForUpdate];
+ } else {
+ data.interfaces = [];
+ }
});
- if (networkForUpdate instanceof Array) {
- data.networks = networkForUpdate;
- } else if (networkForUpdate != null) {
- data.networks = [networkForUpdate];
- } else {
- data.networks = [];
+
+ }else {
+ var networks = $('.template-tab-body .item', '#form-template-interface');
+ var networkForUpdate = new Array();
+ $.each(networks, function(index, networkEntities) {
+ var thisValue = $('select', networkEntities).val();
+ networkForUpdate.push(thisValue);
+ });
+ if (networkForUpdate instanceof Array) {
+ data.networks = networkForUpdate;
+ } else if (networkForUpdate != null) {
+ data.networks = [networkForUpdate];
+ } else {
+ data.networks = [];
+ }
}
if ($('.has-error', '#form-template-storage').length) {
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index 6cac885..4e08243 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -129,6 +129,15 @@
</div>
<div class="template-tab-body"></div>
</form>
+ <form id="form-template-interface-s390x" style="display:none">
+ <div class="template-tab-header">
+ <span class="template-interface-cell type">$_("Type")</span>
+ <span class="template-interface-cell network">$_("Network/Interface")</span>
+ <span class="template-interface-cell mode">$_("Mode")</span>
+ <button type="button" id="template-edit-interface-add-button-s390x" class="pull-right btn btn-primary"><i class="fa fa-plus-circle"></i> $_("Add Interface")</button>
+ </div>
+ <div class="template-tab-body"></div>
+ </form>
</div>
<div role="tabpanel" class="tab-pane" id="processor">
<form id="form-template-processor">
@@ -221,5 +230,29 @@
</span>
</div>
</script>
+<script id="template-interface-s390x-tmpl" type="text/html">
+ <div class="item" id={networkID}>
+ <span class="template-interface-cell type">
+ <select>
+ <!-- <option value="macvtap">macvtap</option>
+ <option value="ovs">ovs</option>
+ <option value="network">network</option> -->
+ </select>
+ </span>
+ <span class="template-interface-cell network">
+ <select></select>
+ </span>
+ <span class="template-interface-cell mode">
+ <span class="label-mode hide">None</span>
+ <select>
+ <option value="bridge">bridge</option>
+ <option value="vepa">vepa</option>
+ </select>
+ </span>
+ <span class="pull-right">
+ <button class="delete btn-primary btn"><i class="fa fa-minus-circle"></i> $_("Delete")</button>
+ </span>
+ </div>
+</script>
</body>
</html>
--
2.1.0
2
1
[RFC] Ginger and possible Wok and other plugins sidebar
by Samuel Henrique De Oliveira Guimaraes 08 Sep '16
by Samuel Henrique De Oliveira Guimaraes 08 Sep '16
08 Sep '16
Hi team,
I'm currently working on Ginger sidebar and I was creating a dynamic widget that we could eventually use on other plugins and move it to Wok but I'm facing some major issues with asynchronous requests and synchronous function calls so I would like to receive input from the whole community on this matter. Please take a look:
https://groups.google.com/d/msg/ginger-dev-list/Xx7IlutnP7Y/1eyLmsQEAAAJ
Regards,
Samuel
1
0
[PATCH v6] [Kimchi] Feature request (#860): Support Guest Autostart
by bianca@linux.vnet.ibm.com 08 Sep '16
by bianca@linux.vnet.ibm.com 08 Sep '16
08 Sep '16
From: Bianca Carvalho <bianca(a)linux.vnet.ibm.com>
Include 'autostart' option in API.json and vms.py (lookup and update)
using libvirt dom.setAutostart to set as true or false. Also edit
test_model.py to include those changes and updated API.md file.
Also included API tests to test_rest.py in test_edit_vm function.
Signed-off-by: Bianca Carvalho <bianca(a)linux.vnet.ibm.com>
---
API.json | 4 ++++
docs/API.md | 3 +++
model/vms.py | 11 ++++++++---
tests/test_mockmodel.py | 2 +-
tests/test_model.py | 8 +++++++-
tests/test_rest.py | 22 ++++++++++++++++++++++
6 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/API.json b/API.json
index 9ad60a2..0effe45 100644
--- a/API.json
+++ b/API.json
@@ -369,6 +369,10 @@
"error": "KCHVM0053E",
"type": "boolean"
},
+ "autostart": {
+ "description": "Enable/Disable guest autostart",
+ "type": "boolean"
+ },
"users": {
"description": "Array of users who have permission to the VM",
"type": "array",
diff --git a/docs/API.md b/docs/API.md
index 1c20466..4aaa243 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -151,6 +151,8 @@ server.
* bootorder: list of devices in boot order
* description: VM description
* title: VM title
+ * autostart: show if autostart is enabled.
+
* **DELETE**: Remove the Virtual Machine
* **PUT**: update the parameters of existing VM
* name: New name for this VM (only applied for shutoff VM)
@@ -184,6 +186,7 @@ server.
* bootmenu: prompts guest bootmenu. Bool type.
* description: VM description
* title: VM title
+ * autostart: enable/disable guest autostart (true or false params).
* **POST**: *See Virtual Machine Actions*
diff --git a/model/vms.py b/model/vms.py
index b889166..a87c133 100644
--- a/model/vms.py
+++ b/model/vms.py
@@ -80,12 +80,13 @@ DOM_STATE_MAP = {0: 'nostate',
7: 'pmsuspended'}
# update parameters which are updatable when the VM is online
-VM_ONLINE_UPDATE_PARAMS = ['graphics', 'groups', 'memory', 'users']
+VM_ONLINE_UPDATE_PARAMS = ['graphics', 'groups', 'memory', 'users',
+ 'autostart']
# update parameters which are updatable when the VM is offline
VM_OFFLINE_UPDATE_PARAMS = ['cpu_info', 'graphics', 'groups', 'memory',
'name', 'users', 'bootorder', 'bootmenu',
- 'description', 'title']
+ 'description', 'title', 'autostart']
XPATH_DOMAIN_DISK = "/domain/devices/disk[@device='disk']/source/@file"
XPATH_DOMAIN_DISK_BY_FILE = "./devices/disk[@device='disk']/source[@file='%s']"
@@ -270,6 +271,9 @@ class VMModel(object):
with lock:
dom = self.get_vm(name, self.conn)
+ if "autostart" in params:
+ dom.setAutostart(1 if params['autostart'] is True else 0)
+
# You can only change <maxMemory> offline, updating guest XML
if ("memory" in params) and ('maxmemory' in params['memory']) and\
(DOM_STATE_MAP[dom.info()[0]] != 'shutoff'):
@@ -1324,7 +1328,8 @@ class VMModel(object):
'access': 'full',
'persistent': True if dom.isPersistent() else False,
'bootorder': boot,
- 'bootmenu': bootmenu
+ 'bootmenu': bootmenu,
+ 'autostart': dom.autostart()
}
def _vm_get_disk_paths(self, dom):
diff --git a/tests/test_mockmodel.py b/tests/test_mockmodel.py
index 147942c..ffd383c 100644
--- a/tests/test_mockmodel.py
+++ b/tests/test_mockmodel.py
@@ -164,7 +164,7 @@ class MockModelTests(unittest.TestCase):
keys = set(('name', 'state', 'stats', 'uuid', 'memory', 'cpu_info',
'screenshot', 'icon', 'graphics', 'users', 'groups',
'access', 'persistent', 'bootorder', 'bootmenu', 'title',
- 'description'))
+ 'description', 'autostart'))
stats_keys = set(('cpu_utilization', 'mem_utilization',
'net_throughput', 'net_throughput_peak',
diff --git a/tests/test_model.py b/tests/test_model.py
index 05f046c..4421a0b 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -129,7 +129,7 @@ class ModelTests(unittest.TestCase):
keys = set(('name', 'state', 'stats', 'uuid', 'memory', 'cpu_info',
'screenshot', 'icon', 'graphics', 'users', 'groups',
'access', 'persistent', 'bootorder', 'bootmenu', 'title',
- 'description'))
+ 'description', 'autostart'))
stats_keys = set(('cpu_utilization', 'mem_utilization',
'net_throughput', 'net_throughput_peak',
@@ -1358,6 +1358,12 @@ class ModelTests(unittest.TestCase):
inst.vm_update(u'пeω-∨м', {"bootmenu": False})
self.assertEquals("no", inst.vm_lookup(u'пeω-∨м')['bootmenu'])
+ # enable/disable autostart
+ inst.vm_update(u'пeω-∨м', {"autostart": True})
+ self.assertEquals(1, inst.vm_lookup(u'пeω-∨м')['autostart'])
+ inst.vm_update(u'пeω-∨м', {"autostart": False})
+ self.assertEquals(0, inst.vm_lookup(u'пeω-∨м')['autostart'])
+
def test_get_interfaces(self):
inst = model.Model('test:///default',
objstore_loc=self.tmp_store)
diff --git a/tests/test_rest.py b/tests/test_rest.py
index 00ad7f3..fcbebce 100644
--- a/tests/test_rest.py
+++ b/tests/test_rest.py
@@ -311,6 +311,28 @@ class RestTests(unittest.TestCase):
resp = self.request('/plugins/kimchi/vms/∨м-црdαtеd', req, 'PUT')
self.assertEquals(400, resp.status)
+ # set vm autostart tests (powered off)
+ resp = self.request('/plugins/kimchi/vms/∨м-црdαtеd/start',
+ '{}', 'POST')
+ self.assertEquals(200, resp.status)
+ req = json.dumps({"autostart": True})
+ resp = self.request('/plugins/kimchi/vms/∨м-црdαtеd', req, 'PUT')
+ self.assertEquals(200, resp.status)
+ resp = self.request('/plugins/kimchi/vms/∨м-црdαtеd',
+ '{}', 'GET').read()
+ self.assertEquals(json.loads(resp)["autostart"], True)
+
+ # set vm autostart tests (running)
+ resp = self.request('/plugins/kimchi/vms/∨м-црdαtеd/poweroff',
+ '{}', 'POST')
+ self.assertEquals(200, resp.status)
+ req = json.dumps({"autostart": False})
+ resp = self.request('/plugins/kimchi/vms/∨м-црdαtеd', req, 'PUT')
+ self.assertEquals(200, resp.status)
+ resp = self.request('/plugins/kimchi/vms/∨м-црdαtеd',
+ '{}', 'GET').read()
+ self.assertEquals(json.loads(resp)["autostart"], False)
+
def test_vm_lifecycle(self):
# Create a Template
req = json.dumps({'name': 'test',
--
2.7.4
1
0
Re: [Kimchi-devel] Fwd: [PATCH] [Kimchi] Introducing s390x UI Interfaces module for Edit Template under virtualization
by Rajat Gupta 07 Sep '16
by Rajat Gupta 07 Sep '16
07 Sep '16
Please ignore following patch will be sending another patch with
corrections.
> -------- Forwarded Message --------
> Subject: [Kimchi-devel] [PATCH] [Kimchi] Introducing s390x UI
> Interfaces module for Edit Template under virtualization
> Date: Wed, 7 Sep 2016 15:56:48 +0530
> From: rajgupta(a)linux.vnet.ibm.com
> To: Kimchi Devel <kimchi-devel(a)ovirt.org>
>
>
>
> From: Rajat Gupta<rajgupta(a)linux.vnet.ibm.com>
>
> Introducing s390x UI Interfaces module for Edit Template under virtualization
>
> Signed-off-by: Rajat Gupta<rajgupta(a)linux.vnet.ibm.com>
> ---
> ui/js/src/kimchi.api.js | 58 ++++++++
> ui/js/src/kimchi.main.js | 5 +
> ui/js/src/kimchi.template_edit_main.js | 260 +++++++++++++++++++++++++++++++--
> ui/pages/template-edit.html.tmpl | 33 +++++
> 4 files changed, 341 insertions(+), 15 deletions(-)
>
> diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
> index 2f127aa..ce0e07c 100644
> --- a/ui/js/src/kimchi.api.js
> +++ b/ui/js/src/kimchi.api.js
> @@ -596,6 +596,35 @@ var kimchi = {
> });
> },
>
> + listmacvtapNetworks : function(suc, err) {
> + wok.requestJSON({
> + url : 'plugins/kimchi/interfaces?type=^nic|bonding|vlan$',
> + type : 'GET',
> + contentType : 'application/json',
> + dataType : 'json',
> + resend : true,
> + success : suc,
> + error : err ? err : function(data) {
> + wok.message.error(data.responseJSON.reason);
> + }
> + });
> + },
> +
> + listovsNetworks : function(suc, err) {
> + wok.requestJSON({
> + url : 'plugins/kimchi/ovsbridges',
> + type : 'GET',
> + contentType : 'application/json',
> + dataType : 'json',
> + resend : true,
> + success : suc,
> + error : err ? err : function(data) {
> + wok.message.error(data.responseJSON.reason);
> + }
> + });
> + },
> +
> +
> toggleNetwork : function(name, on, suc, err) {
> var action = on ? "activate" : "deactivate";
> wok.requestJSON({
> @@ -638,6 +667,20 @@ var kimchi = {
> });
> },
>
> + gets390xInterfaces : function(suc, err) {
> + wok.requestJSON({
> + url : 'plugins/kimchi/interfaces?type=^nic|bonding|vlan$',
> + type : 'GET',
> + contentType : 'application/json',
> + dataType : 'json',
> + resend : true,
> + success : suc,
> + error : err ? err : function(data) {
> + wok.message.error(data.responseJSON.reason);
> + }
> + });
> + },
> +
> getInterface : function(iface, suc, err, sync) {
> wok.requestJSON({
> url : 'plugins/kimchi/interfaces/' + encodeURIComponent(iface),
> @@ -1271,3 +1314,18 @@ var kimchi = {
> });
> }
> };
> +
> +/**
> + * Get the host information.
> + */
> +kimchi.getHostDetails = function (suc,err) {
> + wok.requestJSON({
> + url : 'plugins/gingerbase/host',
> + type : 'GET',
> + resend: true,
> + contentType : 'application/json',
> + dataType : 'json',
> + success : suc,
> + error: err
> + });
> +}
> diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js
> index b6de2cf..ae996f0 100644
> --- a/ui/js/src/kimchi.main.js
> +++ b/ui/js/src/kimchi.main.js
> @@ -33,6 +33,11 @@ kimchi.getCapabilities(function(result) {
> kimchi.capabilities = {};
> });
>
> +kimchi.hostarch = undefined;
> +kimchi.getHostDetails(function(result) {
> + kimchi.hostarch = result["architecture"];
> +});
> +
> $(function(){
> $('body').removeClass('wok-list wok-gallery');
> });
> diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
> index a2032cc..3cb32e8 100644
> --- a/ui/js/src/kimchi.template_edit_main.js
> +++ b/ui/js/src/kimchi.template_edit_main.js
> @@ -19,8 +19,13 @@ kimchi.template_edit_main = function() {
> var templateEditMain = $('#edit-template-tabs');
> var origDisks;
> var origNetworks;
> + var origInterfaces;
> + var origmacvtapNetworks;
> + var origovsNetworks;
> var templateDiskSize;
> var baseImageTemplate;
> + var s390xArch = 's390x';
> +
> $('#template-name', templateEditMain).val(kimchi.selectedTemplate);
> $('#edit-template-tabs a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
> $('.tab-content').css('overflow', 'hidden');
> @@ -47,6 +52,7 @@ kimchi.template_edit_main = function() {
> var initTemplate = function(template) {
> origDisks = template.disks;
> origNetworks = template.networks;
> + origInterfaces = template.interfaces;
> for (var i = 0; i < template.disks.length; i++) {
> if (template.disks[i].base) {
> template["vm-image"] = template.disks[i].base;
> @@ -268,10 +274,173 @@ kimchi.template_edit_main = function() {
> });
> };
>
> - var initProcessor = function() {
> - var setCPUValue = function() {
> - if (!$('#cores').hasClass("invalid-field") && $('#cores').val() != "") {
> - var computedCpu = parseInt($("#cores").val()) * parseInt($("#threads").val());
> + var initInterface_s390x = function(result) {
> + $('#form-template-interface-s390x').show();
> + $('#form-template-interface').hide();
> + var networkItemNum = 0;
> + var addInterfaceItem = function(networkData) {
> + var networkName = networkData.networkV;
> + var nodeInterface = $.parseHTML(wok.substitute($('#template-interface-s390x-tmpl').html(), networkData));
> + $('.template-tab-body', '#form-template-interface-s390x').append(nodeInterface);
> + $('.delete', '#form-template-interface-s390x').on("click", function(event) {
> + event.preventDefault();
> + $(this).parent().parent().remove();
> + });
> +
> + //initialize type option
> + var typeOptionsdata = {};
> + var typeOptions = '';
> + typeOptionsdata.macvtap = 'macvtap';
> + typeOptionsdata.ovs = 'ovs';
> + typeOptionsdata.network = 'network';
> +
> + $.each(typeOptionsdata, function(key, value) {
> + if (value === networkData.type) {
> + typeOptions += '<option value="' + key + '" selected="selected">' + networkData.type + '</option>';
> + } else {
> + typeOptions += '<option value="' + key + '">' + value + '</option>';
> + }
> + });
> +
> + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.type').append(typeOptions);
> + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.type').on('change', function() {
> + var itemNode = $(this).closest('div.item');
> +
> + switch ($(this).val()) {
> + case 'macvtap':
> + $('span.mode .label-mode', itemNode).addClass('hide');
> + $('span.mode .bootstrap-select', itemNode).toggleClass("hide", false);
> +
> + var networkOptions = '';
> + for (var i = 0; i < origmacvtapNetworks.length; i++) {
> + networkOptions += '<option>' + origmacvtapNetworks[i].name + '</option>';
> + }
> +
> + $('span.network select', itemNode).empty().append(networkOptions);
> + $('span.network select', itemNode).selectpicker('refresh');
> +
> + break;
> + case 'ovs':
> + $('span.mode .label-mode', itemNode).removeClass('hide');
> + $('span.mode .bootstrap-select', itemNode).toggleClass("hide", true);
> + var networkOptions = '';
> + for (var i = 0; i < origovsNetworks.length; i++) {
> + networkOptions += '<option>' + origovsNetworks[i] + '</option>'; //it should be origovsNetworks[i].name rajat
> + }
> +
> + $('span.network select', itemNode).empty().append(networkOptions);
> + $('span.network select', itemNode).selectpicker('refresh');
> +
> + break;
> + case 'network':
> + $('span.mode .label-mode', itemNode).removeClass('hide');
> + $('span.mode .bootstrap-select', itemNode).toggleClass("hide", true);
> +
> + var networkOptions = '';
> + for (var i = 0; i < result.length; i++) {
> + if (result[i].state === "active") {
> + networkOptions += '<option>' + result[i].name + '</option>';
> + }
> + }
> + $('span.network select', itemNode).empty().append(networkOptions);
> + $('span.network select', itemNode).selectpicker('refresh');
> + break;
> + }
> + });
> +
> + switch (networkData.type) {
> + case 'macvtap':
> + //initialize network option
> +
> + var networkOptions = '';
> + for (var i = 0; i < origmacvtapNetworks.length; i++) {
> + if (networkName === origmacvtapNetworks[i].name) {
> + networkOptions += '<option selected="selected">' + origmacvtapNetworks[i].name + '</option>';
> + }
> + networkOptions += '<option>' + origmacvtapNetworks[i].name + '</option>';
> + }
> + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.network').append(networkOptions);
> +
> + //initialize Mode option for Macvtap
> + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').val(networkData.mode);
> + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').selectpicker('refresh');
> +
> + $('span.mode .label-mode', nodeInterface).addClass('hide');
> + $('span.mode .bootstrap-select', nodeInterface).removeClass("hide");
> +
> + break;
> +
> + case 'ovs':
> + var networkOptions = '';
> + for (var i = 0; i < origovsNetworks.length; i++) {
> + if (networkName === origovsNetworks[i]) {
> + networkOptions += '<option selected="selected">' + origovsNetworks[i] + '</option>';
> + }
> + networkOptions += '<option>' + origovsNetworks[i] + '</option>';
> + }
> + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.network').append(networkOptions);
> +
> + //initialize Mode option for ovs
> + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').selectpicker('refresh');
> + $('span.mode .label-mode', nodeInterface).removeClass('hide');
> + $('span.mode .bootstrap-select', nodeInterface).addClass("hide");
> + break;
> +
> + case 'network':
> + var networkOptions = '';
> + for (var i = 0; i < result.length; i++) {
> + if (networkName === result[i].name) {
> + networkOptions += '<option selected="selected">' + result[i].name + '</option>';
> + }
> + if (result[i].state === "active" && networkName !== result[i].name) {
> + networkOptions += '<option>' + result[i].name + '</option>';
> + }
> + }
> + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.network').append(networkOptions);
> +
> + //initialize Mode option for Network
> + $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').selectpicker('refresh');
> + $('span.mode .label-mode', nodeInterface).removeClass('hide');
> + $('span.mode .bootstrap-select', nodeInterface).addClass("hide");
> + break;
> + }
> + $('select', '#form-template-interface-s390x #networkID' + networkItemNum).selectpicker();
> + networkItemNum += 1;
> + };
> + if (origInterfaces && origInterfaces.length > 0) {
> + for (var i = 0; i < origInterfaces.length; i++) {
> + addInterfaceItem({
> + networkID: 'networkID' + networkItemNum,
> + networkV: origInterfaces[i].name,
> + type: origInterfaces[i].type,
> + mode: origInterfaces[i].mode
> + });
> + }
> + }
> + if (result && result.length > 0) {
> + for (var i = 0; i < origNetworks.length; i++) {
> + addInterfaceItem({
> + networkID: 'networkID' + networkItemNum,
> + networkV: origNetworks[i],
> + type: 'network'
> + });
> + }
> + }
> + $('#template-edit-interface-add-button-s390x').on("click", function(event) {
> + event.preventDefault();
> + addInterfaceItem({
> + networkID: 'networkID' + networkItemNum,
> + networkV: 'default',
> + type: 'network',
> + mode: 'None'
> + });
> + });
> + };
> +
> + var initProcessor = function(){
> + var setCPUValue = function(){
> + if(!$('#cores').hasClass("invalid-field")&&$('#cores').val()!=""){
> + var computedCpu = parseInt($("#cores").val())*parseInt($("#threads").val());
> $("#vcpus").val(computedCpu);
> if ($("#cpus-check").prop("checked")) {
> //If topology is checked, set maxcpu to be the same as # of cpu otherwise, backend gives error
> @@ -340,7 +509,18 @@ kimchi.template_edit_main = function() {
> });
> }
>
> - kimchi.listNetworks(initInterface);
> + if(kimchi.hostarch === s390xArch){
> + kimchi.listmacvtapNetworks(function(macvtapnet){
> + origmacvtapNetworks = macvtapnet;
> + kimchi.listovsNetworks(function(ovsnet){
> + origovsNetworks = ovsnet;
> + kimchi.listNetworks(initInterface_s390x);
> + });
> + });
> + }else {
> + kimchi.listNetworks(initInterface);
> + }
> +
> kimchi.listStoragePools(initStorage);
> initProcessor();
> checkInvalids();
> @@ -432,18 +612,68 @@ kimchi.template_edit_main = function() {
> topology: {}
> };
> }
> - var networks = $('.template-tab-body .item', '#form-template-interface');
> + if(kimchi.hostarch === s390xArch){
> +
> + var interfaces = $('.template-tab-body .item', '#form-template-interface-s390x');
> var networkForUpdate = new Array();
> - $.each(networks, function(index, networkEntities) {
> - var thisValue = $('select', networkEntities).val();
> - networkForUpdate.push(thisValue);
> + var interfacceForUpdate = new Array();
> +
> + $.each(interfaces, function(index, interfaceEntities) {
> + var fields = $('span.type select', interfaceEntities);
> + switch(fields.val()){
> + case 'network':
> + var thisValue = $('span.network select', interfaceEntities).val();
> + networkForUpdate.push(thisValue);
> + break;
> +
> + case 'macvtap':
> + var thisdata = {};
> + thisdata.type = $('span.type select', interfaceEntities).val();
> + thisdata.name = $('span.network select', interfaceEntities).val();
> + thisdata.mode = $('span.mode select', interfaceEntities).val();
> +
> + interfacceForUpdate.push(thisdata);
> + break;
> +
> + case 'ovs':
> + var thisdata = {};
> + thisdata.type = $('span.type select', interfaceEntities).val();
> + thisdata.name = $('span.network select', interfaceEntities).val();
> + interfacceForUpdate.push(thisdata);
> + break;
> + }
> +
> + if (networkForUpdate instanceof Array) {
> + data.networks = networkForUpdate;
> + } else if (networkForUpdate != null) {
> + data.networks = [networkForUpdate];
> + } else {
> + data.networks = [];
> + }
> +
> + if (networkForUpdate instanceof Array) {
> + data.interfaces = interfacceForUpdate;
> + } else if (interfacceForUpdate != null) {
> + data.interfaces = [interfacceForUpdate];
> + } else {
> + data.interfaces = [];
> + }
> });
> - if (networkForUpdate instanceof Array) {
> - data.networks = networkForUpdate;
> - } else if (networkForUpdate != null) {
> - data.networks = [networkForUpdate];
> - } else {
> - data.networks = [];
> +
> + }else {
> + var networks = $('.template-tab-body .item', '#form-template-interface');
> + var networkForUpdate = new Array();
> + $.each(networks, function(index, networkEntities) {
> + var thisValue = $('select', networkEntities).val();
> + networkForUpdate.push(thisValue);
> + });
> + if (networkForUpdate instanceof Array) {
> + data.networks = networkForUpdate;
> + } else if (networkForUpdate != null) {
> + data.networks = [networkForUpdate];
> + } else {
> + data.networks = [];
> + }
> }
>
> if ($('.has-error', '#form-template-storage').length) {
> diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
> index 6cac885..4e08243 100644
> --- a/ui/pages/template-edit.html.tmpl
> +++ b/ui/pages/template-edit.html.tmpl
> @@ -129,6 +129,15 @@
> </div>
> <div class="template-tab-body"></div>
> </form>
> + <form id="form-template-interface-s390x" style="display:none">
> + <div class="template-tab-header">
> + <span class="template-interface-cell type">$_("Type")</span>
> + <span class="template-interface-cell network">$_("Network/Interface")</span>
> + <span class="template-interface-cell mode">$_("Mode")</span>
> + <button type="button" id="template-edit-interface-add-button-s390x" class="pull-right btn btn-primary"><i class="fa fa-plus-circle"></i> $_("Add Interface")</button>
> + </div>
> + <div class="template-tab-body"></div>
> + </form>
> </div>
> <div role="tabpanel" class="tab-pane" id="processor">
> <form id="form-template-processor">
> @@ -221,5 +230,29 @@
> </span>
> </div>
> </script>
> +<script id="template-interface-s390x-tmpl" type="text/html">
> + <div class="item" id={networkID}>
> + <span class="template-interface-cell type">
> + <select>
> + <!-- <option value="macvtap">macvtap</option>
> + <option value="ovs">ovs</option>
> + <option value="network">network</option> -->
> + </select>
> + </span>
> + <span class="template-interface-cell network">
> + <select></select>
> + </span>
> + <span class="template-interface-cell mode">
> + <span class="label-mode hide">None</span>
> + <select>
> + <option value="bridge">bridge</option>
> + <option value="vepa">vepa</option>
> + </select>
> + </span>
> + <span class="pull-right">
> + <button class="delete btn-primary btn"><i class="fa fa-minus-circle"></i> $_("Delete")</button>
> + </span>
> + </div>
> +</script>
> </body>
> </html>
> --
> 2.1.0
>
> _______________________________________________
> Kimchi-devel mailing list
> Kimchi-devel(a)ovirt.org
> http://lists.ovirt.org/mailman/listinfo/kimchi-devel
>
1
0
[PATCH] [Kimchi] Introducing s390x UI Interfaces module for Edit Template under virtualization
by rajgupta@linux.vnet.ibm.com 07 Sep '16
by rajgupta@linux.vnet.ibm.com 07 Sep '16
07 Sep '16
From: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
Introducing s390x UI Interfaces module for Edit Template under virtualization
Signed-off-by: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.api.js | 58 ++++++++
ui/js/src/kimchi.main.js | 5 +
ui/js/src/kimchi.template_edit_main.js | 260 +++++++++++++++++++++++++++++++--
ui/pages/template-edit.html.tmpl | 33 +++++
4 files changed, 341 insertions(+), 15 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 2f127aa..ce0e07c 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -596,6 +596,35 @@ var kimchi = {
});
},
+ listmacvtapNetworks : function(suc, err) {
+ wok.requestJSON({
+ url : 'plugins/kimchi/interfaces?type=^nic|bonding|vlan$',
+ type : 'GET',
+ contentType : 'application/json',
+ dataType : 'json',
+ resend : true,
+ success : suc,
+ error : err ? err : function(data) {
+ wok.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+ listovsNetworks : function(suc, err) {
+ wok.requestJSON({
+ url : 'plugins/kimchi/ovsbridges',
+ type : 'GET',
+ contentType : 'application/json',
+ dataType : 'json',
+ resend : true,
+ success : suc,
+ error : err ? err : function(data) {
+ wok.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
+
toggleNetwork : function(name, on, suc, err) {
var action = on ? "activate" : "deactivate";
wok.requestJSON({
@@ -638,6 +667,20 @@ var kimchi = {
});
},
+ gets390xInterfaces : function(suc, err) {
+ wok.requestJSON({
+ url : 'plugins/kimchi/interfaces?type=^nic|bonding|vlan$',
+ type : 'GET',
+ contentType : 'application/json',
+ dataType : 'json',
+ resend : true,
+ success : suc,
+ error : err ? err : function(data) {
+ wok.message.error(data.responseJSON.reason);
+ }
+ });
+ },
+
getInterface : function(iface, suc, err, sync) {
wok.requestJSON({
url : 'plugins/kimchi/interfaces/' + encodeURIComponent(iface),
@@ -1271,3 +1314,18 @@ var kimchi = {
});
}
};
+
+/**
+ * Get the host information.
+ */
+kimchi.getHostDetails = function (suc,err) {
+ wok.requestJSON({
+ url : 'plugins/gingerbase/host',
+ type : 'GET',
+ resend: true,
+ contentType : 'application/json',
+ dataType : 'json',
+ success : suc,
+ error: err
+ });
+}
diff --git a/ui/js/src/kimchi.main.js b/ui/js/src/kimchi.main.js
index b6de2cf..ae996f0 100644
--- a/ui/js/src/kimchi.main.js
+++ b/ui/js/src/kimchi.main.js
@@ -33,6 +33,11 @@ kimchi.getCapabilities(function(result) {
kimchi.capabilities = {};
});
+kimchi.hostarch = undefined;
+kimchi.getHostDetails(function(result) {
+ kimchi.hostarch = result["architecture"];
+});
+
$(function(){
$('body').removeClass('wok-list wok-gallery');
});
diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
index a2032cc..3cb32e8 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -19,8 +19,13 @@ kimchi.template_edit_main = function() {
var templateEditMain = $('#edit-template-tabs');
var origDisks;
var origNetworks;
+ var origInterfaces;
+ var origmacvtapNetworks;
+ var origovsNetworks;
var templateDiskSize;
var baseImageTemplate;
+ var s390xArch = 's390x';
+
$('#template-name', templateEditMain).val(kimchi.selectedTemplate);
$('#edit-template-tabs a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
$('.tab-content').css('overflow', 'hidden');
@@ -47,6 +52,7 @@ kimchi.template_edit_main = function() {
var initTemplate = function(template) {
origDisks = template.disks;
origNetworks = template.networks;
+ origInterfaces = template.interfaces;
for (var i = 0; i < template.disks.length; i++) {
if (template.disks[i].base) {
template["vm-image"] = template.disks[i].base;
@@ -268,10 +274,173 @@ kimchi.template_edit_main = function() {
});
};
- var initProcessor = function() {
- var setCPUValue = function() {
- if (!$('#cores').hasClass("invalid-field") && $('#cores').val() != "") {
- var computedCpu = parseInt($("#cores").val()) * parseInt($("#threads").val());
+ var initInterface_s390x = function(result) {
+ $('#form-template-interface-s390x').show();
+ $('#form-template-interface').hide();
+ var networkItemNum = 0;
+ var addInterfaceItem = function(networkData) {
+ var networkName = networkData.networkV;
+ var nodeInterface = $.parseHTML(wok.substitute($('#template-interface-s390x-tmpl').html(), networkData));
+ $('.template-tab-body', '#form-template-interface-s390x').append(nodeInterface);
+ $('.delete', '#form-template-interface-s390x').on("click", function(event) {
+ event.preventDefault();
+ $(this).parent().parent().remove();
+ });
+
+ //initialize type option
+ var typeOptionsdata = {};
+ var typeOptions = '';
+ typeOptionsdata.macvtap = 'macvtap';
+ typeOptionsdata.ovs = 'ovs';
+ typeOptionsdata.network = 'network';
+
+ $.each(typeOptionsdata, function(key, value) {
+ if (value === networkData.type) {
+ typeOptions += '<option value="' + key + '" selected="selected">' + networkData.type + '</option>';
+ } else {
+ typeOptions += '<option value="' + key + '">' + value + '</option>';
+ }
+ });
+
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.type').append(typeOptions);
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.type').on('change', function() {
+ var itemNode = $(this).closest('div.item');
+
+ switch ($(this).val()) {
+ case 'macvtap':
+ $('span.mode .label-mode', itemNode).addClass('hide');
+ $('span.mode .bootstrap-select', itemNode).toggleClass("hide", false);
+
+ var networkOptions = '';
+ for (var i = 0; i < origmacvtapNetworks.length; i++) {
+ networkOptions += '<option>' + origmacvtapNetworks[i].name + '</option>';
+ }
+
+ $('span.network select', itemNode).empty().append(networkOptions);
+ $('span.network select', itemNode).selectpicker('refresh');
+
+ break;
+ case 'ovs':
+ $('span.mode .label-mode', itemNode).removeClass('hide');
+ $('span.mode .bootstrap-select', itemNode).toggleClass("hide", true);
+ var networkOptions = '';
+ for (var i = 0; i < origovsNetworks.length; i++) {
+ networkOptions += '<option>' + origovsNetworks[i] + '</option>'; //it should be origovsNetworks[i].name rajat
+ }
+
+ $('span.network select', itemNode).empty().append(networkOptions);
+ $('span.network select', itemNode).selectpicker('refresh');
+
+ break;
+ case 'network':
+ $('span.mode .label-mode', itemNode).removeClass('hide');
+ $('span.mode .bootstrap-select', itemNode).toggleClass("hide", true);
+
+ var networkOptions = '';
+ for (var i = 0; i < result.length; i++) {
+ if (result[i].state === "active") {
+ networkOptions += '<option>' + result[i].name + '</option>';
+ }
+ }
+ $('span.network select', itemNode).empty().append(networkOptions);
+ $('span.network select', itemNode).selectpicker('refresh');
+ break;
+ }
+ });
+
+ switch (networkData.type) {
+ case 'macvtap':
+ //initialize network option
+
+ var networkOptions = '';
+ for (var i = 0; i < origmacvtapNetworks.length; i++) {
+ if (networkName === origmacvtapNetworks[i].name) {
+ networkOptions += '<option selected="selected">' + origmacvtapNetworks[i].name + '</option>';
+ }
+ networkOptions += '<option>' + origmacvtapNetworks[i].name + '</option>';
+ }
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.network').append(networkOptions);
+
+ //initialize Mode option for Macvtap
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').val(networkData.mode);
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').selectpicker('refresh');
+
+ $('span.mode .label-mode', nodeInterface).addClass('hide');
+ $('span.mode .bootstrap-select', nodeInterface).removeClass("hide");
+
+ break;
+
+ case 'ovs':
+ var networkOptions = '';
+ for (var i = 0; i < origovsNetworks.length; i++) {
+ if (networkName === origovsNetworks[i]) {
+ networkOptions += '<option selected="selected">' + origovsNetworks[i] + '</option>';
+ }
+ networkOptions += '<option>' + origovsNetworks[i] + '</option>';
+ }
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.network').append(networkOptions);
+
+ //initialize Mode option for ovs
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').selectpicker('refresh');
+ $('span.mode .label-mode', nodeInterface).removeClass('hide');
+ $('span.mode .bootstrap-select', nodeInterface).addClass("hide");
+ break;
+
+ case 'network':
+ var networkOptions = '';
+ for (var i = 0; i < result.length; i++) {
+ if (networkName === result[i].name) {
+ networkOptions += '<option selected="selected">' + result[i].name + '</option>';
+ }
+ if (result[i].state === "active" && networkName !== result[i].name) {
+ networkOptions += '<option>' + result[i].name + '</option>';
+ }
+ }
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.network').append(networkOptions);
+
+ //initialize Mode option for Network
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum + ' span.mode').selectpicker('refresh');
+ $('span.mode .label-mode', nodeInterface).removeClass('hide');
+ $('span.mode .bootstrap-select', nodeInterface).addClass("hide");
+ break;
+ }
+ $('select', '#form-template-interface-s390x #networkID' + networkItemNum).selectpicker();
+ networkItemNum += 1;
+ };
+ if (origInterfaces && origInterfaces.length > 0) {
+ for (var i = 0; i < origInterfaces.length; i++) {
+ addInterfaceItem({
+ networkID: 'networkID' + networkItemNum,
+ networkV: origInterfaces[i].name,
+ type: origInterfaces[i].type,
+ mode: origInterfaces[i].mode
+ });
+ }
+ }
+ if (result && result.length > 0) {
+ for (var i = 0; i < origNetworks.length; i++) {
+ addInterfaceItem({
+ networkID: 'networkID' + networkItemNum,
+ networkV: origNetworks[i],
+ type: 'network'
+ });
+ }
+ }
+ $('#template-edit-interface-add-button-s390x').on("click", function(event) {
+ event.preventDefault();
+ addInterfaceItem({
+ networkID: 'networkID' + networkItemNum,
+ networkV: 'default',
+ type: 'network',
+ mode: 'None'
+ });
+ });
+ };
+
+ var initProcessor = function(){
+ var setCPUValue = function(){
+ if(!$('#cores').hasClass("invalid-field")&&$('#cores').val()!=""){
+ var computedCpu = parseInt($("#cores").val())*parseInt($("#threads").val());
$("#vcpus").val(computedCpu);
if ($("#cpus-check").prop("checked")) {
//If topology is checked, set maxcpu to be the same as # of cpu otherwise, backend gives error
@@ -340,7 +509,18 @@ kimchi.template_edit_main = function() {
});
}
- kimchi.listNetworks(initInterface);
+ if(kimchi.hostarch === s390xArch){
+ kimchi.listmacvtapNetworks(function(macvtapnet){
+ origmacvtapNetworks = macvtapnet;
+ kimchi.listovsNetworks(function(ovsnet){
+ origovsNetworks = ovsnet;
+ kimchi.listNetworks(initInterface_s390x);
+ });
+ });
+ }else {
+ kimchi.listNetworks(initInterface);
+ }
+
kimchi.listStoragePools(initStorage);
initProcessor();
checkInvalids();
@@ -432,18 +612,68 @@ kimchi.template_edit_main = function() {
topology: {}
};
}
- var networks = $('.template-tab-body .item', '#form-template-interface');
+ if(kimchi.hostarch === s390xArch){
+
+ var interfaces = $('.template-tab-body .item', '#form-template-interface-s390x');
var networkForUpdate = new Array();
- $.each(networks, function(index, networkEntities) {
- var thisValue = $('select', networkEntities).val();
- networkForUpdate.push(thisValue);
+ var interfacceForUpdate = new Array();
+
+ $.each(interfaces, function(index, interfaceEntities) {
+ var fields = $('span.type select', interfaceEntities);
+ switch(fields.val()){
+ case 'network':
+ var thisValue = $('span.network select', interfaceEntities).val();
+ networkForUpdate.push(thisValue);
+ break;
+
+ case 'macvtap':
+ var thisdata = {};
+ thisdata.type = $('span.type select', interfaceEntities).val();
+ thisdata.name = $('span.network select', interfaceEntities).val();
+ thisdata.mode = $('span.mode select', interfaceEntities).val();
+
+ interfacceForUpdate.push(thisdata);
+ break;
+
+ case 'ovs':
+ var thisdata = {};
+ thisdata.type = $('span.type select', interfaceEntities).val();
+ thisdata.name = $('span.network select', interfaceEntities).val();
+ interfacceForUpdate.push(thisdata);
+ break;
+ }
+
+ if (networkForUpdate instanceof Array) {
+ data.networks = networkForUpdate;
+ } else if (networkForUpdate != null) {
+ data.networks = [networkForUpdate];
+ } else {
+ data.networks = [];
+ }
+
+ if (networkForUpdate instanceof Array) {
+ data.interfaces = interfacceForUpdate;
+ } else if (interfacceForUpdate != null) {
+ data.interfaces = [interfacceForUpdate];
+ } else {
+ data.interfaces = [];
+ }
});
- if (networkForUpdate instanceof Array) {
- data.networks = networkForUpdate;
- } else if (networkForUpdate != null) {
- data.networks = [networkForUpdate];
- } else {
- data.networks = [];
+
+ }else {
+ var networks = $('.template-tab-body .item', '#form-template-interface');
+ var networkForUpdate = new Array();
+ $.each(networks, function(index, networkEntities) {
+ var thisValue = $('select', networkEntities).val();
+ networkForUpdate.push(thisValue);
+ });
+ if (networkForUpdate instanceof Array) {
+ data.networks = networkForUpdate;
+ } else if (networkForUpdate != null) {
+ data.networks = [networkForUpdate];
+ } else {
+ data.networks = [];
+ }
}
if ($('.has-error', '#form-template-storage').length) {
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index 6cac885..4e08243 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -129,6 +129,15 @@
</div>
<div class="template-tab-body"></div>
</form>
+ <form id="form-template-interface-s390x" style="display:none">
+ <div class="template-tab-header">
+ <span class="template-interface-cell type">$_("Type")</span>
+ <span class="template-interface-cell network">$_("Network/Interface")</span>
+ <span class="template-interface-cell mode">$_("Mode")</span>
+ <button type="button" id="template-edit-interface-add-button-s390x" class="pull-right btn btn-primary"><i class="fa fa-plus-circle"></i> $_("Add Interface")</button>
+ </div>
+ <div class="template-tab-body"></div>
+ </form>
</div>
<div role="tabpanel" class="tab-pane" id="processor">
<form id="form-template-processor">
@@ -221,5 +230,29 @@
</span>
</div>
</script>
+<script id="template-interface-s390x-tmpl" type="text/html">
+ <div class="item" id={networkID}>
+ <span class="template-interface-cell type">
+ <select>
+ <!-- <option value="macvtap">macvtap</option>
+ <option value="ovs">ovs</option>
+ <option value="network">network</option> -->
+ </select>
+ </span>
+ <span class="template-interface-cell network">
+ <select></select>
+ </span>
+ <span class="template-interface-cell mode">
+ <span class="label-mode hide">None</span>
+ <select>
+ <option value="bridge">bridge</option>
+ <option value="vepa">vepa</option>
+ </select>
+ </span>
+ <span class="pull-right">
+ <button class="delete btn-primary btn"><i class="fa fa-minus-circle"></i> $_("Delete")</button>
+ </span>
+ </div>
+</script>
</body>
</html>
--
2.1.0
1
0
[PATCH V4] [Kimchi] Issue #992 : Create template on s390x without libvirt storage.
by archus@linux.vnet.ibm.com 06 Sep '16
by archus@linux.vnet.ibm.com 06 Sep '16
06 Sep '16
From: Harshal Patil <harshalp(a)linux.vnet.ibm.com>
V1:
This patch adds support for creating templates on s390x arch
without using libvirt related storage calls
V2:
Review comments
V3:
Review comments and refactoring
V4:
Rebase patch to latest upstream.
Signed-off-by: Harshal Patil <harshalp(a)linux.vnet.ibm.com>
---
docs/API.md | 2 +
i18n.py | 3 ++
model/storagepools.py | 13 ++++--
model/storagevolumes.py | 1 -
model/templates.py | 27 +++++++++---
model/vms.py | 9 +++-
osinfo.py | 35 +++++++++++++--
utils.py | 34 +++++++++++++++
vmtemplate.py | 111 +++++++++++++++++++++++++++++++-----------------
9 files changed, 179 insertions(+), 56 deletions(-)
diff --git a/docs/API.md b/docs/API.md
index 1c20466..cff623e 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -438,6 +438,7 @@ A interface represents available network interface on VM.
over current will be used exclusively for memory hotplug
* cdrom: A volume name or URI to an ISO image
* storagepool: URI of the storagepool where template allocates vm storage.
+ * path *(optional and only valid for s390x architecture)*: Storage path to store virtual disks without libvirt.
* networks *(optional)*: list of networks will be assigned to the new VM.
* interfaces *(optional)*: list of host network interfaces will be assigned to the new VM. Only applicable for s390x or s390 architecture.
* type: Type of host network interface. Type should be 'macvtap' for host network interface (Ethernet, Bond, VLAN) to be connected as direct MacVTap; or 'ovs' for openvswitch host network interface to be connected as virtual switch to a VM.
@@ -504,6 +505,7 @@ A interface represents available network interface on VM.
* format: Format of the image. Valid formats: qcow, qcow2, qed, raw, vmdk, vpc.
* pool: Storage pool information
* name: URI of the storagepool where template allocates vm disk.
+ * path *(optional and only valid for s390x architecture)*: Either pool or path to store the virtual disks should be specified.
* graphics *(optional)*: A dict of graphics paramenters of this template
* type: The type of graphics. It can be VNC or spice or None.
* vnc: Graphical display using the Virtual Network
diff --git a/i18n.py b/i18n.py
index 47c829e..b6533d4 100644
--- a/i18n.py
+++ b/i18n.py
@@ -203,6 +203,9 @@ messages = {
"KCHTMPL0037E": _("Interfaces should be list of interfaces. Each interface should have name, type and mode(optional, only applicable for interfcae type 'macvtap'."),
"KCHTMPL0038E": _("Interface expects an object with parameters: 'name', 'type' and 'mode'. Name should be name of host network interface (Ethernet, Bond, VLAN) for type 'macvtap' or the name of host openvswitch bridge interface for type 'ovs'. Mode (optional) is only applicable for interface type 'macvtap' to indicates whether packets will be delivered directly to target device (bridge) or to the external bridge (vepa-capable bridge)."),
"KCHTMPL0039E": _("Interfaces parameter only supported on s390x or s390 architecture."),
+ "KCHTMPL0040E": _("Storage without libvirt pool is not supported on this architecture"),
+ "KCHTMPL0041E": _("Error while creating the virtual disk for the guest. Details: %(err)s"),
+ "KCHTMPL0042E": _("When setting template disks without libvirt, following parameters are required: 'index', 'format', 'path', 'size'"),
"KCHPOOL0001E": _("Storage pool %(name)s already exists"),
"KCHPOOL0002E": _("Storage pool %(name)s does not exist"),
diff --git a/model/storagepools.py b/model/storagepools.py
index af92ec9..5942b31 100644
--- a/model/storagepools.py
+++ b/model/storagepools.py
@@ -33,7 +33,7 @@ from wok.plugins.kimchi.model.host import DeviceModel
from wok.plugins.kimchi.model.libvirtstoragepool import StoragePoolDef
from wok.plugins.kimchi.osinfo import defaults as tmpl_defaults
from wok.plugins.kimchi.scan import Scanner
-from wok.plugins.kimchi.utils import pool_name_from_uri
+from wok.plugins.kimchi.utils import pool_name_from_uri, is_s390x
ISO_POOL_NAME = u'kimchi_isos'
@@ -57,6 +57,7 @@ STORAGE_SOURCES = {'netfs': {'addr': '/pool/source/host/@name',
class StoragePoolsModel(object):
+
def __init__(self, **kargs):
self.conn = kargs['conn']
self.objstore = kargs['objstore']
@@ -72,6 +73,9 @@ class StoragePoolsModel(object):
def _check_default_pools(self):
pools = {}
+ if is_s390x():
+ return
+
default_pool = tmpl_defaults['disks'][0]['pool']['name']
default_pool = default_pool.split('/')[-1]
@@ -437,9 +441,10 @@ class StoragePoolModel(object):
for tmpl in templates:
t_info = session.get('template', tmpl)
for disk in t_info['disks']:
- t_pool = disk['pool']['name']
- if pool_name_from_uri(t_pool) == pool_name:
- return True
+ if 'pool' in disk:
+ t_pool = disk['pool']['name']
+ if pool_name_from_uri(t_pool) == pool_name:
+ return True
return False
def deactivate(self, name):
diff --git a/model/storagevolumes.py b/model/storagevolumes.py
index a6ce97b..2d68027 100644
--- a/model/storagevolumes.py
+++ b/model/storagevolumes.py
@@ -43,7 +43,6 @@ from wok.plugins.kimchi.model.diskutils import get_disk_used_by
from wok.plugins.kimchi.model.storagepools import StoragePoolModel
from wok.plugins.kimchi.utils import get_next_clone_name
-
VOLUME_TYPE_MAP = {0: 'file',
1: 'block',
2: 'directory',
diff --git a/model/templates.py b/model/templates.py
index 04e6626..a5d17af 100644
--- a/model/templates.py
+++ b/model/templates.py
@@ -28,13 +28,15 @@ import urlparse
from wok.exception import InvalidOperation, InvalidParameter
from wok.exception import NotFoundError, OperationFailed
-from wok.utils import probe_file_permission_as_user, run_setfacl_set_attr
+from wok.utils import probe_file_permission_as_user
+from wok.utils import run_setfacl_set_attr
from wok.xmlutils.utils import xpath_get_text
from wok.plugins.kimchi.config import get_kimchi_version
from wok.plugins.kimchi.kvmusertests import UserTests
from wok.plugins.kimchi.model.cpuinfo import CPUInfoModel
from wok.plugins.kimchi.utils import is_libvirtd_up, pool_name_from_uri
+from wok.plugins.kimchi.utils import create_disk_image
from wok.plugins.kimchi.vmtemplate import VMTemplate
ISO_TYPE = "ISO 9660 CD-ROM"
@@ -417,15 +419,26 @@ class LibvirtVMTemplate(VMTemplate):
def fork_vm_storage(self, vm_uuid):
# Provision storages:
- vol_list = self.to_volume_list(vm_uuid)
+ disk_and_vol_list = self.to_volume_list(vm_uuid)
try:
- for v in vol_list:
- pool = self._get_storage_pool(v['pool'])
- # outgoing text to libvirt, encode('utf-8')
- pool.createXML(v['xml'].encode('utf-8'), 0)
+ for v in disk_and_vol_list:
+ if v['pool'] is not None:
+ pool = self._get_storage_pool(v['pool'])
+ # outgoing text to libvirt, encode('utf-8')
+ pool.createXML(v['xml'].encode('utf-8'), 0)
+ else:
+ capacity = v['capacity']
+ format_type = v['format']
+ path = v['path']
+ create_disk_image(
+ format_type=format_type,
+ path=path,
+ capacity=capacity)
+
except libvirt.libvirtError as e:
raise OperationFailed("KCHVMSTOR0008E", {'error': e.message})
- return vol_list
+
+ return disk_and_vol_list
def set_cpu_info(self):
# undefined topology: consider these values to calculate maxvcpus
diff --git a/model/vms.py b/model/vms.py
index b889166..6a9b1d1 100644
--- a/model/vms.py
+++ b/model/vms.py
@@ -61,7 +61,7 @@ from wok.plugins.kimchi.model.utils import remove_metadata_node
from wok.plugins.kimchi.model.utils import set_metadata_node
from wok.plugins.kimchi.osinfo import defaults, MEM_DEV_SLOTS
from wok.plugins.kimchi.screenshot import VMScreenshot
-from wok.plugins.kimchi.utils import get_next_clone_name
+from wok.plugins.kimchi.utils import get_next_clone_name, is_s390x
from wok.plugins.kimchi.utils import template_name_from_uri
from wok.plugins.kimchi.xmlutils.bootorder import get_bootorder_node
from wok.plugins.kimchi.xmlutils.bootorder import get_bootmenu_node
@@ -1405,6 +1405,13 @@ class VMModel(object):
except libvirt.libvirtError as e:
wok_log.error('Unable to get storage volume by path: %s' %
e.message)
+ try:
+ if is_s390x() and os.path.exists(path):
+ os.remove(path)
+ except Exception as e:
+ wok_log.error('Unable to delete storage path: %s' %
+ e.message)
+
except Exception as e:
raise OperationFailed('KCHVOL0017E', {'err': e.message})
diff --git a/osinfo.py b/osinfo.py
index 3e56d97..8ec9480 100644
--- a/osinfo.py
+++ b/osinfo.py
@@ -159,6 +159,12 @@ def _get_tmpl_defaults():
'maxmemory': _get_default_template_mem()}
tmpl_defaults['storage']['disk.0'] = {'size': 10, 'format': 'qcow2',
'pool': 'default'}
+ is_on_s390x = True if _get_arch() == 's390x' else False
+
+ if is_on_s390x:
+ tmpl_defaults['storage']['disk.0']['path'] = '/var/lib/libvirt/images/'
+ del tmpl_defaults['storage']['disk.0']['pool']
+
tmpl_defaults['processor']['vcpus'] = 1
tmpl_defaults['processor']['maxvcpus'] = 1
tmpl_defaults['graphics'] = {'type': 'vnc', 'listen': '127.0.0.1'}
@@ -166,7 +172,12 @@ def _get_tmpl_defaults():
default_config = ConfigObj(tmpl_defaults)
# Load template configuration file
- config_file = os.path.join(kimchiPaths.sysconf_dir, 'template.conf')
+ if is_on_s390x:
+ config_file = os.path.join(
+ kimchiPaths.sysconf_dir,
+ 'template_s390x.conf')
+ else:
+ config_file = os.path.join(kimchiPaths.sysconf_dir, 'template.conf')
config = ConfigObj(config_file)
# Merge default configuration with file configuration
@@ -187,11 +198,27 @@ def _get_tmpl_defaults():
# Parse storage section to get disks values
storage_section = default_config.pop('storage')
defaults['disks'] = []
- for disk in storage_section.keys():
+
+ for index, disk in enumerate(storage_section.keys()):
data = storage_section[disk]
data['index'] = int(disk.split('.')[1])
- data['pool'] = {"name": '/plugins/kimchi/storagepools/' +
- storage_section[disk].pop('pool')}
+ # Right now 'Path' is only supported on s390x
+ if storage_section[disk].get('path') and is_on_s390x:
+ data['path'] = storage_section[disk].pop('path')
+ if 'size' not in storage_section[disk]:
+ data['size'] = tmpl_defaults['storage']['disk.0']['size']
+ else:
+ data['size'] = storage_section[disk].pop('size')
+
+ if 'format' not in storage_section[disk]:
+ data['format'] = tmpl_defaults['storage']['disk.0']['format']
+ else:
+ data['format'] = storage_section[disk].pop('format')
+ else:
+ storage_section[disk].get('pool')
+ data['pool'] = {"name": '/plugins/kimchi/storagepools/' +
+ storage_section[disk].pop('pool')}
+
defaults['disks'].append(data)
# Parse processor section to get vcpus and cpu_topology values
diff --git a/utils.py b/utils.py
index 26d3cf6..7129bfe 100644
--- a/utils.py
+++ b/utils.py
@@ -24,6 +24,7 @@ import platform
import re
import sqlite3
import time
+import os
import urllib2
from httplib import HTTPConnection, HTTPException
from urlparse import urlparse
@@ -31,6 +32,7 @@ from urlparse import urlparse
from wok.exception import InvalidParameter, OperationFailed
from wok.plugins.kimchi import config
from wok.plugins.kimchi.osinfo import get_template_default
+from wok.stringutils import encode_value
from wok.utils import run_command, wok_log
from wok.xmlutils.utils import xpath_get_text
@@ -272,3 +274,35 @@ def is_libvirtd_up():
output, error, rc = run_command(cmd, silent=True)
return True if output == 'active\n' else False
+
+
+def is_s390x():
+ """
+ Check if current arch is 's390x'
+ Returns:
+ """
+ if os.uname()[4] == 's390x':
+ return True
+
+ return False
+
+
+def create_disk_image(format_type, path, capacity):
+ """
+ Create a disk image for the Guest
+ Args:
+ format: Format of the storage. e.g. qcow2
+ path: Path where the virtual disk will be created
+ capacity: Capacity of the virtual disk in GBs
+
+ Returns:
+
+ """
+ out, err, rc = run_command(
+ ["/usr/bin/qemu-img", "create", "-f", format_type, "-o",
+ "preallocation=metadata", path, encode_value(capacity) + "G"])
+
+ if rc != 0:
+ raise OperationFailed("KCHTMPL0041E", {'err': err})
+
+ return
diff --git a/vmtemplate.py b/vmtemplate.py
index 07cebb9..20edbfb 100644
--- a/vmtemplate.py
+++ b/vmtemplate.py
@@ -31,7 +31,8 @@ from wok.exception import MissingParameter, OperationFailed
from wok.plugins.kimchi import imageinfo
from wok.plugins.kimchi import osinfo
from wok.plugins.kimchi.isoinfo import IsoImage
-from wok.plugins.kimchi.utils import check_url_path, pool_name_from_uri
+from wok.plugins.kimchi.utils import check_url_path, is_s390x
+from wok.plugins.kimchi.utils import pool_name_from_uri
from wok.plugins.kimchi.xmlutils.bootorder import get_bootorder_xml
from wok.plugins.kimchi.xmlutils.cpu import get_cpu_xml
from wok.plugins.kimchi.xmlutils.disk import get_disk_xml
@@ -42,6 +43,7 @@ from wok.plugins.kimchi.xmlutils.serial import get_serial_xml
class VMTemplate(object):
+
def __init__(self, args, scan=False, netboot=False):
"""
Construct a VM Template from a widely variable amount of information.
@@ -95,35 +97,55 @@ class VMTemplate(object):
disks = self.info.get('disks')
basic_disk = ['index', 'format', 'pool', 'size']
+ basic_path_disk = ['index', 'format', 'path', 'size']
ro_disk = ['index', 'format', 'pool', 'volume']
base_disk = ['index', 'base', 'pool', 'size', 'format']
for index, disk in enumerate(disks):
disk_info = dict(default_disk)
-
- pool = disk.get('pool', default_disk['pool'])
- pool_type = self._get_storage_type(pool['name'])
-
- if pool_type in ['iscsi', 'scsi']:
- disk_info = {'index': 0, 'format': 'raw', 'volume': None}
-
- disk_info.update(disk)
- pool_name = disk_info.get('pool', {}).get('name')
- if pool_name is None:
- raise MissingParameter('KCHTMPL0028E')
-
- keys = sorted(disk_info.keys())
- if ((keys != sorted(basic_disk)) and (keys != sorted(ro_disk)) and
- (keys != sorted(base_disk))):
- raise MissingParameter('KCHTMPL0028E')
-
- if pool_type in ['logical', 'iscsi', 'scsi']:
- if disk_info['format'] != 'raw':
- raise InvalidParameter('KCHTMPL0029E')
-
- disk_info['pool']['type'] = pool_type
- disk_info['index'] = disk_info.get('index', index)
- self.info['disks'][index] = disk_info
+ if disk.get('pool'):
+ pool = disk.get('pool', default_disk.get('pool'))
+ pool_type = self._get_storage_type(pool['name'])
+ if pool_type in ['iscsi', 'scsi']:
+ disk_info = {'index': 0, 'format': 'raw', 'volume': None}
+
+ # This check is required where 'path' disk
+ # exists and is replaced by 'pool' disk during
+ # template update
+ if 'path' in disk_info:
+ del disk_info['path']
+
+ disk_info.update(disk)
+ pool_name = disk_info.get('pool', {}).get('name')
+ if pool_name is None:
+ raise MissingParameter('KCHTMPL0028E')
+
+ keys = sorted(disk_info.keys())
+ if ((keys != sorted(basic_disk)) and
+ (keys != sorted(ro_disk)) and
+ (keys != sorted(base_disk)) and
+ (keys != sorted(basic_path_disk))):
+ raise MissingParameter('KCHTMPL0028E')
+
+ if pool_type in ['logical', 'iscsi', 'scsi']:
+ if disk_info['format'] != 'raw':
+ raise InvalidParameter('KCHTMPL0029E')
+
+ disk_info['pool']['type'] = pool_type
+ disk_info['index'] = disk_info.get('index', index)
+ self.info['disks'][index] = disk_info
+ elif is_s390x():
+ # For now support 'path' only on s390x
+ path = disk.get('path', default_disk['path'])
+ disk_info.update(disk)
+ keys = sorted(disk_info.keys())
+ if keys != sorted(basic_path_disk):
+ raise MissingParameter('KCHTMPL0042E')
+ disk_info['path'] = path
+ disk_info['index'] = disk_info.get('index', index)
+ self.info['disks'][index] = disk_info
+ else:
+ raise InvalidParameter('KCHTMPL0040E')
def _get_os_info(self, args, scan):
distro = version = 'unknown'
@@ -217,8 +239,9 @@ class VMTemplate(object):
params = dict(base_disk_params)
params['format'] = disk['format']
params['index'] = index
- params.update(locals().get('%s_disk_params' %
- disk['pool']['type'], {}))
+ if disk.get('pool'):
+ params.update(locals().get('%s_disk_params' %
+ disk['pool']['type'], {}))
volume = disk.get('volume')
if volume is not None:
@@ -226,9 +249,13 @@ class VMTemplate(object):
volume)
else:
img = "%s-%s.img" % (vm_uuid, params['index'])
- storage_path = self._get_storage_path(disk['pool']['name'])
+ if disk.get('pool'):
+ storage_path = self._get_storage_path(disk['pool']['name'])
+ params['pool_type'] = disk['pool']['type']
+ elif disk.get('path'):
+ storage_path = disk.get('path')
+ params['pool_type'] = None
params['path'] = os.path.join(storage_path, img)
- params['pool_type'] = disk['pool']['type']
disks_xml += get_disk_xml(params)[1]
return unicode(disks_xml, 'utf-8')
@@ -237,20 +264,24 @@ class VMTemplate(object):
ret = []
for i, d in enumerate(self.info['disks']):
# Create only .img. If storagepool is (i)SCSI, volumes will be LUNs
- if d['pool']['type'] in ["iscsi", "scsi"]:
+ if 'pool' in d and d['pool']['type'] in ["iscsi", "scsi"]:
continue
index = d.get('index', i)
volume = "%s-%s.img" % (vm_uuid, index)
- storage_path = self._get_storage_path(d['pool']['name'])
+ if 'path' in d:
+ storage_path = d['path']
+ else:
+ storage_path = self._get_storage_path(d['pool']['name'])
+
info = {'name': volume,
'capacity': d['size'],
'format': d['format'],
'path': '%s/%s' % (storage_path, volume),
- 'pool': d['pool']['name']}
+ 'pool': d['pool']['name'] if 'pool' in d else None}
- if 'logical' == d['pool']['type'] or \
+ if ('pool' in d and 'logical' == d['pool']['type']) or \
info['format'] not in ['qcow2', 'raw']:
info['allocation'] = info['capacity']
else:
@@ -467,8 +498,9 @@ class VMTemplate(object):
def validate(self):
for disk in self.info.get('disks'):
- pool_uri = disk.get('pool', {}).get('name')
- self._get_storage_pool(pool_uri)
+ if 'pool' in disk:
+ pool_uri = disk.get('pool', {}).get('name')
+ self._get_storage_pool(pool_uri)
self._network_validate()
self._iso_validate()
self.cpuinfo_validate()
@@ -519,10 +551,11 @@ class VMTemplate(object):
# validate storagepools and image-based templates integrity
for disk in self.info['disks']:
- pool_uri = disk['pool']['name']
- pool_name = pool_name_from_uri(pool_uri)
- if pool_name not in self._get_active_storagepools_name():
- invalid['storagepools'] = [pool_name]
+ if 'pool' in disk:
+ pool_uri = disk['pool']['name']
+ pool_name = pool_name_from_uri(pool_uri)
+ if pool_name not in self._get_active_storagepools_name():
+ invalid['storagepools'] = [pool_name]
if disk.get("base") is None:
continue
--
2.7.4
3
2
[RFC] integrety: storage pool deactivate/undefine needs to consider vm usage #355
by Ramon Medeiros 06 Sep '16
by Ramon Medeiros 06 Sep '16
06 Sep '16
Propose: do not deactive or undefine storage pool with vms being used.
Avoid undefine storage pool was already discussed.
Talking about deactive, we've got some questions:
1) Since the storage volume is available, the vm can run with storage
poll on or off. So, we are going only to avoid deactive pools that can
make storage volume unavailable, like nfs?
2) Or we are going to extend this rule to all storage pools?
--
Ramon Nunes Medeiros
Kimchi Developer
Linux Technology Center Brazil
IBM Systems & Technology Group
Phone : +55 19 2132 7878
ramonn(a)br.ibm.com
1
0
[PATCH v2][Kimchi 0/2] Do not delete storage pool with storage volumes assigned to guests
by Ramon Medeiros 06 Sep '16
by Ramon Medeiros 06 Sep '16
06 Sep '16
Changes:
v2:
Use path to determine if volume comes from storage pool
Do not use "get_disk_used_by". It will be usefull if we start querying
by volumes. Since, we cannot list volumes with inactivate storage pools.
Ramon Medeiros (2):
Do not remove storagepools linked to guests
Update tests
i18n.py | 1 +
model/storagepools.py | 22 ++++++++++++++++++++++
tests/test_rest.py | 21 +++++++++++++++++++++
3 files changed, 44 insertions(+)
--
2.5.5
3
6
[RFC] Should not be allowed to remove "default" storagepool and network
by Ramon Medeiros 06 Sep '16
by Ramon Medeiros 06 Sep '16
06 Sep '16
Propose: avoid to delete default network and storage pool:
files affected:
Create a error message at i18n.py
Check at delete() method on model to verify
Doubt:
Where is defined the default pool and network? I did not see it in
kimchi.conf
Should i create a entry to deal it?
--
Ramon Nunes Medeiros
Kimchi Developer
Linux Technology Center Brazil
IBM Systems & Technology Group
Phone : +55 19 2132 7878
ramonn(a)br.ibm.com
1
0