[PATCH V2] [Kimchi] Introducing Console for edit template module under virtualization
by rajgupta@linux.vnet.ibm.com
From: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
V2 :
Corrected Indentation
V1 :
Introducing Console for edit template module under virtualization
Note: This patch is dependent on following subjected patches
1.Introducing s390x UI Interfaces module for Edit Template under virtualization
2.Introducing s390x UI Interfaces module for Edit Guest under virtualization
3.Introducing s390x UI Storage module for Edit Template under virtualization
4.Introducing s390x UI Storage module for Edit Guest under virtualization
Signed-off-by: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.template_edit_main.js | 13 ++++++++++++-
ui/pages/template-edit.html.tmpl | 10 ++++++++++
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
index a2032cc..466ae70 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -62,6 +62,12 @@ kimchi.template_edit_main = function() {
}
$('input[name="' + prop + '"]', templateEditMain).val(value);
}
+ if(kimchi.hostarch == s390xArch){
+ $('.console', templateEditMain).show();
+ var consoleData = template.console ? template.console : '';
+ $('#template-edit-console', templateEditMain).val(consoleData);
+ $('#template-edit-console').selectpicker();
+ }
$('#template-edit-memory-textbox').val(template.memory.current);
$('#template-edit-max-memory-textbox').val(template.memory.maxmemory);
@@ -356,7 +362,12 @@ kimchi.template_edit_main = function() {
$('.modal input[type="checkbox"]').prop('disabled', true);
$('.modal select').prop('disabled', true);
$('.modal .selectpicker').addClass('disabled');
- var editableFields = ['name', 'memory', 'graphics', 'max-memory'];
+ if(kimchi.hostarch === s390xArch){
+ var editableFields = ['name', 'memory', 'graphics', 'max-memory', 'console'];
+ }else {
+ var editableFields = ['name', 'memory', 'graphics', 'max-memory'];
+ }
+
var data = {};
var disks = $('.template-tab-body .item', '#form-template-storage');
var disksForUpdate = new Array();
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index 6cac885..14f6cfa 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -73,6 +73,9 @@
<div class="template-edit-wrapper-label">
<label>$_("Graphics")</label>
</div>
+ <div class="template-edit-wrapper-label console" style="display:none">
+ <label>$_("Console")</label>
+ </div>
</div>
<div class="form-template-inline-wrapper">
<div class="template-edit-wrapper-controls">
@@ -104,6 +107,13 @@
<div class="template-edit-wrapper-controls">
<select id="template-edit-graphics" name="graphics" class="form-control" />
</div>
+ <div class="template-edit-wrapper-controls console" style="display:none">
+ <select id="template-edit-console" name="console" class="form-control">
+ <option value=""></option>
+ <option value="sclp">$_("sclp")</option>
+ <option value="virtio">$_("virtio")</option>
+ </select>
+ </div>
</div>
</form>
</div>
--
2.1.0
8 years, 2 months
[PATCH v3] [Kimchi 0/2] added 'console' parameter for templates & vms api for s390x
by sureshab@linux.vnet.ibm.com
From: Suresh Babu Angadi <sureshab(a)in.ibm.com>
v2-v3: resolved merge conflict
v1-v2: provided detailed commit message and reduced number of patches
In case of s390x architecture, console type can be
either virtio/sclp. Extended current code to support
console configuration in case of s390x
this patch set provides option to configure 'console'
parameter for templates and vms api when running on
's390x' architecture
Suresh Babu Angadi (2):
added 'console' parameter to templates api for s390x
added 'console' parameter to vms api for s390x
API.json | 24 ++++++++++++++---
control/templates.py | 1 +
i18n.py | 4 +++
model/templates.py | 6 +++++
model/vms.py | 75 +++++++++++++++++++++++++++++++++++-----------------
osinfo.py | 4 +++
xmlutils/serial.py | 5 +++-
7 files changed, 91 insertions(+), 28 deletions(-)
--
2.1.0
8 years, 2 months
[PATCH v2] [Kimchi 0/2] added 'console' parameter for templates & vms api for s390x
by sureshab@linux.vnet.ibm.com
From: Suresh Babu Angadi <sureshab(a)in.ibm.com>
v1-v2: provided detailed commit message and reduced number of patches
In case of s390x architecture, console type can be
either virtio/sclp. Extended current code to support
console configuration in case of s390x
this patch set provides option to configure 'console'
parameter for templates and vms api when running on
's390x' architecture
Suresh Babu Angadi (2):
added 'console' parameter to templates api for s390x
added 'console' parameter to vms api for s390x
API.json | 24 ++++++++++++++---
control/templates.py | 1 +
i18n.py | 4 +++
model/templates.py | 6 +++++
model/vms.py | 75 +++++++++++++++++++++++++++++++++++-----------------
osinfo.py | 4 +++
xmlutils/serial.py | 5 +++-
7 files changed, 91 insertions(+), 28 deletions(-)
--
2.1.0
8 years, 2 months
[PATCH] [Kimchi] Introducing Console for edit Guest module under virtualization
by rajgupta@linux.vnet.ibm.com
From: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
Introducing Console for edit Guest module under virtualization
for s390x
Signed-off-by: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.guest_edit_main.js | 13 +++++++++++++
ui/pages/guest-edit.html.tmpl | 8 ++++++++
2 files changed, 21 insertions(+)
diff --git a/ui/js/src/kimchi.guest_edit_main.js b/ui/js/src/kimchi.guest_edit_main.js
index dcaafb8..e2437d7 100644
--- a/ui/js/src/kimchi.guest_edit_main.js
+++ b/ui/js/src/kimchi.guest_edit_main.js
@@ -776,6 +776,19 @@ kimchi.guest_edit_main = function() {
});
}
+ if(kimchi.hostarch === s390xArch){
+ var consoleData = guest.console ? guest.console : '';
+ $('#guest-edit-console').val(consoleData);
+
+ if (kimchi.thisVMState === "shutoff") {
+ $('#guest-edit-console').prop('disabled', false);
+ }else{
+ $('#guest-edit-console').prop('disabled', true);
+ }
+ $('#guest-console-panel').show();
+ $('#guest-edit-console').selectpicker();
+ }
+
var onAttached = function(params) {
refreshCDROMs();
};
diff --git a/ui/pages/guest-edit.html.tmpl b/ui/pages/guest-edit.html.tmpl
index a9a468e..ac6a57e 100644
--- a/ui/pages/guest-edit.html.tmpl
+++ b/ui/pages/guest-edit.html.tmpl
@@ -71,6 +71,14 @@
<label for="guest-edit-icon-textbox">$_("Icon")</label>
<input id="guest-edit-icon-textbox" class="form-control" name="icon" type="text" disabled="disabled" />
</div>
+ <div class="form-group" id="guest-console-panel" style="display:none;">
+ <label for="guest-edit-console">$_("Console")</label>
+ <select id="guest-edit-console" name="console" class="form-control">
+ <option value=""></option>
+ <option value="sclp">$_("sclp")</option>
+ <option value="virtio">$_("virtio")</option>
+ </select>
+ </div>
</form>
<form role="tabpanel" class="tab-pane" id="form-guest-edit-storage">
<div class="btn-group action-area">
--
2.1.0
8 years, 2 months
[PATCH V2] [Kimchi] Introducing s390x UI Interfaces module for Edit Template under virtualization
by rajgupta@linux.vnet.ibm.com
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 | 257 +++++++++++++++++++++++++++++++--
ui/pages/template-edit.html.tmpl | 29 ++++
4 files changed, 319 insertions(+), 16 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 2f127aa..950ca00 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -596,6 +596,34 @@ 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 +1299,19 @@ 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..f3078ec 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..9ccf9cc 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,170 @@ 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,11 +506,23 @@ 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();
};
+
kimchi.retrieveTemplate(kimchi.selectedTemplate, initTemplate);
$('#tmpl-edit-button-save').on('click', function() {
@@ -432,18 +610,65 @@ kimchi.template_edit_main = function() {
topology: {}
};
}
- 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(kimchi.hostarch === s390xArch){
+ var interfaces = $('.template-tab-body .item', '#form-template-interface-s390x');
+ var networkForUpdate = new Array();
+ 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..8591561 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,25 @@
</span>
</div>
</script>
+<script id="template-interface-s390x-tmpl" type="text/html">
+ <div class="item" id={networkID}>
+ <span class="template-interface-cell type">
+ <select></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
8 years, 2 months
[PATCH V2] [Kimchi] Introducing s390x UI Storage module for Edit Guest under virtualization
by rajgupta@linux.vnet.ibm.com
From: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
V2 :
Corrected Indentation
V1 :
Introducing s390x UI Storage module for Edit Guest under virtualization
Note: This patch is dependent on following subjected patches
1.Introducing s390x UI Interfaces module for Edit Template under virtualization
2.Introducing s390x UI Interfaces module for Edit Guest under virtualization
3.Introducing s390x UI Storage module for Edit Template under virtualization
ui/js/src/kimchi.guest_storage_add.main.js | 165 ++++++++++++++++++++++++-----
ui/pages/guest-storage-add.html.tmpl | 26 ++++-
2 files changed, 163 insertions(+), 28 deletions(-)
diff --git a/ui/js/src/kimchi.guest_storage_add.main.js b/ui/js/src/kimchi.guest_storage_add.main.js
index 29fccab..08e71db 100644
--- a/ui/js/src/kimchi.guest_storage_add.main.js
+++ b/ui/js/src/kimchi.guest_storage_add.main.js
@@ -60,11 +60,23 @@ kimchi.guest_storage_add_main = function() {
value: 'disk'
}];
+ var source = [{
+ label: 'Pool',
+ value: 'pool'
+ },{
+ label: 'Path',
+ value: 'path'
+ }];
+
var storageAddForm = $('#form-guest-storage-add');
var submitButton = $('#guest-storage-button-add');
var typeTextbox = $('select#guest-storage-type', storageAddForm);
var pathTextbox = $('input[name="path"]', storageAddForm);
var poolTextbox = $('select#guest-disk-pool', storageAddForm);
+ var sourceTextbox = $('select#guest-disk-source', storageAddForm);
+ var sourcenewTextbox = $('select#guest-disk-source-new', storageAddForm);
+ var directorypathTextbox = $('#directorypath', storageAddForm);
+ var diskpathTextbox = $('#diskpath', storageAddForm);
var volTextbox = $('select#guest-disk-vol', storageAddForm);
var newPoolTextbox = $('select#guest-disk-pool-new', storageAddForm);
var capacityTextbox = $('input[name="capacity"]', storageAddForm);
@@ -73,6 +85,7 @@ kimchi.guest_storage_add_main = function() {
var selectStoragePoolHTML = '';
var selectStorageVolHTML = '';
var rbExisting = 'false';
+ var s390xArch = 's390x';
var getFormatList = function() {
var format = ["qcow", "qcow2", "qed", "raw", "vmdk", "vpc"];
@@ -177,6 +190,45 @@ kimchi.guest_storage_add_main = function() {
//First time retrieving list of Storage Pools - defaulting to new disk
getStoragePools('new');
+ if(kimchi.hostarch === s390xArch){
+ //initialize source dropdown for new disk
+ $('#new-disk-box div.source').show();
+
+ var getStorageSourceNew = function(sourceSelected ) {
+ selectStorageSourceHTML = ''; //reset string
+ $.each(source, function(index, storageSource) {
+ selectStorageSourceHTML += '<option value="'+ storageSource.value + '">' + storageSource.label + '</option>';
+ });
+
+ sourcenewTextbox.empty();
+ sourcenewTextbox.append(selectStorageSourceHTML);
+ sourcenewTextbox.val(sourceSelected);
+ $(sourcenewTextbox).trigger('change');
+ sourcenewTextbox.selectpicker();
+ $('.selectpicker').selectpicker('refresh');
+ };
+
+ getStorageSourceNew('pool');
+
+ //initialize source dropdown for existing disk
+ $('#existing-disk-box div.source').show();
+
+ var getStorageSource = function(sourceSelected ) {
+ selectStorageSourceHTML = ''; //reset string
+ $.each(source, function(index, storageSource) {
+ selectStorageSourceHTML += '<option value="'+ storageSource.value + '">' + storageSource.label + '</option>';
+ });
+
+ sourceTextbox.empty();
+ sourceTextbox.append(selectStorageSourceHTML);
+ sourceTextbox.val(sourceSelected);
+ $(sourceTextbox).trigger('change');
+ sourceTextbox.selectpicker();
+ $('.selectpicker').selectpicker('refresh');
+ };
+ getStorageSource('pool');
+ }
+
poolTextbox.on('change',function() {
var options = [];
selectStorageVolHTML = '';
@@ -214,6 +266,34 @@ kimchi.guest_storage_add_main = function() {
}, null, false);
});
+ if (kimchi.hostarch === s390xArch) {
+ sourcenewTextbox.on('change', function() {
+ switch ($(this).val()) {
+ case 'path':
+ $('#new-disk-box div.pool').hide();
+ $('#new-disk-box div.directorypath').show();
+
+ break;
+ default:
+ $('#new-disk-box div.pool').show();
+ $('#new-disk-box div.directorypath').hide();
+ }
+ });
+
+ sourceTextbox.on('change', function() {
+ switch ($(this).val()) {
+ case 'path':
+ $('#existing-disk-box div.pool,div.volume').hide();
+ $('#existing-disk-box div.diskpath').show();
+
+ break;
+ default:
+ $('#existing-disk-box div.pool,div.volume').show();
+ $('#existing-disk-box div.diskpath').hide();
+ }
+ });
+ }
+
typeTextbox.on('change',function() {
var pathObject = {'cdrom': ".path-section", 'disk': '.volume-section'};
var selectType = $(this).val();
@@ -237,9 +317,12 @@ kimchi.guest_storage_add_main = function() {
$('#existing-disk-box').removeClass('hidden');
$('#new-disk-box').addClass('hidden');
$('#guest-storage-add-window .modal-body .template-pager').animate({
- height: "200px"
+ height: "300px"
}, 300);
getStoragePools('existing');
+ if(kimchi.hostarch === s390xArch){
+ getStorageSource('pool');
+ }
$(pathTextbox).val("");
$(newPoolTextbox).val("");
$(capacityTextbox).val("");
@@ -260,9 +343,17 @@ kimchi.guest_storage_add_main = function() {
currentPage = 'new-disk-box';
$('#existing-disk-box').addClass('hidden');
$('#new-disk-box').removeClass('hidden');
- $('#guest-storage-add-window .modal-body .template-pager').animate({
- height: "300px"
- }, 400);
+
+ if(kimchi.hostarch === s390xArch){
+ getStorageSourceNew('pool');
+ $('#guest-storage-add-window .modal-body .template-pager').animate({
+ height: "400px"
+ }, 400);
+ }else{
+ $('#guest-storage-add-window .modal-body .template-pager').animate({
+ height: "300px"
+ }, 400);
+ }
$(pathTextbox).val("");
$(poolTextbox).val("");
$(volTextbox).val("");
@@ -414,35 +505,59 @@ kimchi.guest_storage_add_main = function() {
}
var formData = storageAddForm.serializeObject();
- var settings = {
- vm: kimchi.selectedGuest,
- type: typeTextbox.val(),
- path: pathTextbox.val(),
- pool: poolTextbox.val(),
- vol: volTextbox.val(),
- newpool: newPoolTextbox.val(),
- format: formatTextbox.val(),
- capacity: capacityTextbox.val()
- };
+ if (kimchi.hostarch === s390xArch && ((sourceTextbox.val() === 'path') || sourcenewTextbox.val() === 'path')) {
+ if ($('#new-disk').prop('checked')) {
+ var settings = {
+ vm: kimchi.selectedGuest,
+ dir_path: directorypathTextbox.val(),
+ name: kimchi.selectedGuest + '_' + $.now() + '.img',
+ size: capacityTextbox.val(),
+ type: typeTextbox.val(),
+ format: formatTextbox.val()
+ };
+ } else if ($('#existing-disk').prop('checked')) {
+ var settings = {
+ vm: kimchi.selectedGuest,
+ path: diskpathTextbox.val(),
+ type: typeTextbox.val(),
+ format: formatTextbox.val()
+ };
+ }
+ } else {
+ var settings = {
+ vm: kimchi.selectedGuest,
+ type: typeTextbox.val(),
+ path: pathTextbox.val(),
+ pool: poolTextbox.val(),
+ vol: volTextbox.val(),
+ newpool: newPoolTextbox.val(),
+ format: formatTextbox.val(),
+ capacity: capacityTextbox.val()
+ };
+ }
$(submitButton).prop('disabled', true);
$.each([pathTextbox, poolTextbox, volTextbox, newPoolTextbox, capacityTextbox, formatTextbox], function(i, c) {
$(c).prop('disabled', true);
});
- // Validate form for cdrom and disk
- validateSpecifiedForm = validator[settings['type']];
- if (!validateSpecifiedForm(settings)) {
- $(submitButton).prop('disabled', false);
- $.each([submitButton, pathTextbox, poolTextbox, volTextbox, newPoolTextbox, capacityTextbox, formatTextbox], function(i, c) {
- $(c).prop('disabled', false);
- });
- return false;
- }
- $(submitButton).addClass('loading').text(i18n['KCHVMCD6003M']);
- if(bNewDisk === 'false'){
+ if (kimchi.hostarch != s390xArch) {
+ // Validate form for cdrom and disk
+ validateSpecifiedForm = validator[settings['type']];
+ if (!validateSpecifiedForm(settings)) {
+ $(submitButton).prop('disabled', false);
+ $.each([submitButton, pathTextbox, poolTextbox, volTextbox, newPoolTextbox, capacityTextbox, formatTextbox], function(i, c) {
+ $(c).prop('disabled', false);
+ });
+ return false;
+ }
+ if(bNewDisk === 'false'){
+ addStorage(settings);
+ }
+ } else {
addStorage(settings);
}
+ $(submitButton).addClass('loading').text(i18n['KCHVMCD6003M']);
event.preventDefault();
};
diff --git a/ui/pages/guest-storage-add.html.tmpl b/ui/pages/guest-storage-add.html.tmpl
index afc72c8..dad3c3b 100644
--- a/ui/pages/guest-storage-add.html.tmpl
+++ b/ui/pages/guest-storage-add.html.tmpl
@@ -53,7 +53,12 @@
</div>
<div class="template-pager">
<div class="page" id="new-disk-box">
- <div class="form-group">
+ <div class="form-group source" style="display:none;">
+ <label>$_("Source")</label>
+ <select id="guest-disk-source-new" class="selectpicker col-md-12 col-lg-12"></select>
+ <p class="help-block"><i class="fa fa-info-circle"></i> $_("Storage based on Libvirt pool or direct block device")</p>
+ </div>
+ <div class="form-group pool">
<label>$_("Storage Pool")</label>
<select id="guest-disk-pool-new" class="selectpicker col-md-12 col-lg-12">
</select>
@@ -70,20 +75,35 @@
</select>
<p class="help-block"><i class="fa fa-info-circle"></i> $_("Format of the new disk to be created")</p>
</div>
+ <div class="form-group directorypath" style="display:none;">
+ <label>$_("Directory Path")</label>
+ <input type="text" class="form-control" name="directorypath" id="directorypath" />
+ <p class="help-block"><i class="fa fa-info-circle"></i> $_("Provide a directory path")</p>
+ </div>
</div>
<div class="page" id="existing-disk-box">
- <div class="form-group">
+ <div class="form-group source" style="display:none;">
+ <label>$_("Source")</label>
+ <select id="guest-disk-source" class="selectpicker col-md-12 col-lg-12"></select>
+ <p class="help-block"><i class="fa fa-info-circle"></i> $_("Storage based on Libvirt pool or direct block device")</p>
+ </div>
+ <div class="form-group pool">
<label>$_("Storage Pool")</label>
<select id="guest-disk-pool" class="selectpicker col-md-12 col-lg-12">
</select>
<p class="help-block"><i class="fa fa-info-circle"></i> $_("Storage pool in which the volume is located in")</p>
</div>
- <div class="form-group">
+ <div class="form-group volume">
<label>$_("Storage Volume")</label>
<select id="guest-disk-vol" class="selectpicker col-md-12 col-lg-12">
</select>
<p class="help-block"><i class="fa fa-info-circle"></i> $_("Storage volume to be attached")</p>
</div>
+ <div class="form-group diskpath" style="display:none;">
+ <label>$_("Disk Path")</label>
+ <input type="text" class="form-control" name="diskpath" id="diskpath" />
+ <p class="help-block"><i class="fa fa-info-circle"></i> $_("Provide a block device")</p>
+ </div>
</div>
</div>
</div>
--
2.1.0
8 years, 2 months
[PATCH V2] [Kimchi] Introducing s390x UI Storage module for Edit Template under virtualization
by rajgupta@linux.vnet.ibm.com
From: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
Introducing s390x UI Storage module for Edit Template under virtualization
Signed-off-by: Rajat Gupta <rajgupta(a)linux.vnet.ibm.com>
---
ui/css/kimchi.css | 12 +-
ui/css/src/modules/_templates.scss | 10 +-
ui/js/src/kimchi.template_edit_main.js | 214 +++++++++++++++++++++++++++++++--
ui/pages/template-edit.html.tmpl | 11 ++
4 files changed, 235 insertions(+), 12 deletions(-)
diff --git a/ui/css/kimchi.css b/ui/css/kimchi.css
index 6cf2cc9..e0e05c7 100644
--- a/ui/css/kimchi.css
+++ b/ui/css/kimchi.css
@@ -1597,7 +1597,15 @@ body.wok-gallery {
}
#template-edit-window .template-storage-cell.storage-pool {
- width: 220px !important;
+ width: 180px !important;
+}
+
+#template-edit-window .template-storage-cell.storage-path {
+ width: 180px !important;
+}
+
+#template-edit-window .template-storage-cell.source {
+ width: 180px !important;
}
#template-edit-window .template-storage-cell.type {
@@ -1609,7 +1617,7 @@ body.wok-gallery {
}
#template-edit-window .template-storage-cell.format {
- width: 320px;
+ width: 250px;
}
#template-edit-window .template-interface-cell.network {
diff --git a/ui/css/src/modules/_templates.scss b/ui/css/src/modules/_templates.scss
index a75d803..2ae7412 100644
--- a/ui/css/src/modules/_templates.scss
+++ b/ui/css/src/modules/_templates.scss
@@ -158,7 +158,13 @@ $kimchi-icon-path: '../images';
height: selectpicker height - 2px;
}
.template-storage-cell.storage-pool {
- width: 220px !important;
+ width: 180px !important;
+ }
+ .template-storage-cell.storage-path {
+ width: 180px !important;
+ }
+ .template-storage-cell.source {
+ width: 180px !important;
}
.template-storage-cell.type {
width: 100px;
@@ -167,7 +173,7 @@ $kimchi-icon-path: '../images';
width: 100px;
}
.template-storage-cell.format {
- width: 320px;
+ width: 250px;
}
.template-interface-cell.network {
width: 220px;
diff --git a/ui/js/src/kimchi.template_edit_main.js b/ui/js/src/kimchi.template_edit_main.js
index a2032cc..92ce977 100644
--- a/ui/js/src/kimchi.template_edit_main.js
+++ b/ui/js/src/kimchi.template_edit_main.js
@@ -226,6 +226,181 @@ kimchi.template_edit_main = function() {
});
};
+ var initStorage_s390 = function(result) {
+ // Gather storage data
+ var storagePoolsInfo = new Object();
+ $.each(result, function(index, pool) {
+ if (pool.state === 'active' && pool.type != 'kimchi-iso') {
+ if (pool.type === 'iscsi' || pool.type === 'scsi') {
+ volumes = new Object();
+ kimchi.listStorageVolumes(pool.name, function(vols) {
+ $.each(vols, function(i, vol) {
+ storagePoolsInfo[pool.name + "/" + vol.name] = {
+ 'type': pool.type,
+ 'volSize': vol.capacity / Math.pow(1024, 3)
+ };
+ });
+ }, null, true);
+ } else {
+ storagePoolsInfo[pool.name] = {
+ 'type': pool.type
+ };
+ }
+ }
+ });
+
+ var addStorageItem = function(storageData) {
+ if (storageData.storageSource == 'pool') {
+ var thisName = storageData.storageName;
+ // Compatibility with old versions
+ if (storageData.storageVolume) {
+ storageData.storageDisk = storagePoolsInfo[thisName].volSize;
+ }
+ if (!storageData.storageType) {
+ storageData.storageType = storagePoolsInfo[thisName].type;
+ }
+ }
+
+ var nodeStorage = $.parseHTML(wok.substitute($('#template-storage-pool-tmpl').html(), storageData));
+ $('.template-tab-body', '#form-template-storage').append(nodeStorage);
+ var storageRow = '#storageRow' + storageData.storageIndex;
+
+ var storageOptions = '';
+ $.each(storagePoolsInfo, function(poolName, value) {
+ storageOptions += '<option value="' + poolName + '">' + poolName + '</option>';
+ });
+
+ $(storageRow + ' .selectStorageName').append(storageOptions);
+ if (storageData.storageSource == 'pool') {
+ if (!$(storageRow + ' .selectStorageName option[value="' + storageData.storageName + '"]').length) {
+ var invalidOption = '<option disabled="disabled" selected="selected" value="' + storageData.storageName + '">' + storageData.storageName + '</option>';
+ $(storageRow + ' .selectStorageName').prepend(invalidOption);
+ $(storageRow + ' .selectStorageName').parent().addClass('has-error')
+ }
+ $(storageRow + ' .selectStorageName').val(storageData.storageName);
+ $(storageRow + ' span.storage-pool').show();
+ $(storageRow + ' span.storage-path').hide();
+ } else {
+ $(storageRow + ' span.storage-pool').hide();
+ $(storageRow + ' span.storage-path').show();
+ }
+
+ $(storageRow + ' .selectStorageName').selectpicker();
+ if (storageData.storageType === 'iscsi' || storageData.storageType === 'scsi') {
+ $(storageRow + ' .template-storage-disk').attr('readonly', true).prop('disabled', true);
+ $(storageRow + ' #diskFormat').val('raw');
+ $(storageRow + ' #diskFormat').prop('disabled', true).change();
+ } else if (storageData.storageType === 'logical') {
+ $(storageRow + ' #diskFormat').val('raw');
+ $(storageRow + ' #diskFormat').prop('disabled', true).change();
+ }
+
+ //set source
+ $('#form-template-storage span.source').show();
+ $(storageRow + ' #source').val(storageData.storageSource);
+ $(storageRow + ' #source').on('change', function() {
+ var source = $(this).val();
+ $(storageRow + ' .template-storage-source').val(source);
+ if (source == 'path') {
+ $(storageRow + ' span.storage-pool').hide();
+ $(storageRow + ' span.storage-path').show();
+ } else {
+ $(storageRow + ' span.storage-pool').show();
+ $(storageRow + ' span.storage-path').hide();
+ }
+ });
+
+ $(storageRow + ' #source').selectpicker();
+
+ // Set disk format
+ if (isImageBasedTemplate()) {
+ $(storageRow + ' #diskFormat').val('qcow2');
+ $(storageRow + ' #diskFormat').prop('disabled', 'disabled');
+ } else {
+ $(storageRow + ' #diskFormat').val(storageData.storageDiskFormat);
+ $(storageRow + ' #diskFormat').on('change', function() {
+ $(storageRow + ' .template-storage-disk-format').val($(this).val());
+ });
+ }
+ $(storageRow + ' #diskFormat').selectpicker();
+
+ $('.delete', '#form-template-storage').on("click", function(event) {
+ event.preventDefault();
+ $(this).parent().parent().remove();
+ });
+
+ $(storageRow + ' select.selectStorageName').change(function() {
+ $(this).parent().parent().removeClass('has-error');
+ var poolType = storagePoolsInfo[$(this).val()].type;
+ $(storageRow + ' .template-storage-name').val($(this).val());
+ $(storageRow + ' .template-storage-type').val(poolType);
+ if (poolType === 'iscsi' || poolType === 'scsi') {
+ $(storageRow + ' .template-storage-disk').attr('readonly', true).prop('disabled', true).val(storagePoolsInfo[$(this).val()].volSize);
+ if (!isImageBasedTemplate()) {
+ $(storageRow + ' #diskFormat').val('raw').prop('disabled', true).change();
+ }
+ } else if (poolType === 'logical') {
+ $(storageRow + ' .template-storage-disk').attr('readonly', false).prop('disabled', false);
+ if (!isImageBasedTemplate()) {
+ $(storageRow + ' #diskFormat').val('raw').prop('disabled', true).change();
+ }
+ } else {
+ $(storageRow + ' .template-storage-disk').attr('readonly', false).prop('disabled', false);
+ if ($(storageRow + ' #diskFormat').prop('disabled') == true && !isImageBasedTemplate()) {
+ $(storageRow + ' #diskFormat').val('qcow2').prop('disabled', false).change();
+ }
+ }
+ $(storageRow + ' #diskFormat').selectpicker('refresh');
+ });
+ }; // End of addStorageItem funtion
+
+ if (origDisks && origDisks.length) {
+ origDisks.sort(function(a, b) {
+ return a.index - b.index
+ });
+ $.each(origDisks, function(index, diskEntities) {
+ if (typeof diskEntities.pool !== 'undefined') {
+ var defaultPool = diskEntities.pool.name.split('/').pop()
+ var storageNodeData = {
+ storageSource: 'pool',
+ storageName: diskEntities.volume ? defaultPool + '/' + diskEntities.volume : defaultPool,
+ storageType: diskEntities.pool.type,
+ storageIndex: diskEntities.index,
+ storageDisk: diskEntities.size,
+ storageDiskFormat: diskEntities.format ? diskEntities.format : 'qcow2',
+ storageVolume: diskEntities.volume
+ }
+ } else {
+ var storageNodeData = {
+ storageSource: 'path',
+ storagePath: diskEntities.path,
+ storageType: 'dir',
+ storageIndex: diskEntities.index,
+ storageDisk: diskEntities.size,
+ storageDiskFormat: diskEntities.format ? diskEntities.format : 'qcow2',
+ storageVolume: diskEntities.volume
+ }
+ }
+ addStorageItem(storageNodeData);
+ });
+ }
+
+ var storageID = origDisks.length - 1;
+ $('#template-edit-storage-add-button').on("click", function(event) {
+ event.preventDefault();
+ storageID = storageID + 1;
+ var storageNodeData = {
+ storageSource: 'pool',
+ storageName: 'default',
+ storageType: 'dir',
+ storageDisk: '10',
+ storageDiskFormat: 'qcow2',
+ storageIndex: storageID
+ }
+ addStorageItem(storageNodeData);
+ });
+ };
+
var initInterface = function(result) {
var networkItemNum = 0;
var addInterfaceItem = function(networkData) {
@@ -340,8 +515,20 @@ kimchi.template_edit_main = function() {
});
}
- kimchi.listNetworks(initInterface);
- kimchi.listStoragePools(initStorage);
+ if (kimchi.hostarch === s390xArch) {
+ kimchi.listmacvtapNetworks(function(macvtapnet) {
+ origmacvtapNetworks = macvtapnet;
+ kimchi.listovsNetworks(function(ovsnet) {
+ origovsNetworks = ovsnet;
+ kimchi.listNetworks(initInterface_s390x);
+ });
+ });
+ kimchi.listStoragePools(initStorage_s390);
+ } else {
+ kimchi.listNetworks(initInterface);
+ kimchi.listStoragePools(initStorage);
+ }
+
initProcessor();
checkInvalids();
};
@@ -361,12 +548,23 @@ kimchi.template_edit_main = function() {
var disks = $('.template-tab-body .item', '#form-template-storage');
var disksForUpdate = new Array();
$.each(disks, function(index, diskEntity) {
- var newDisk = {
- 'index': index,
- 'pool': { 'name': '/plugins/kimchi/storagepools/' + $(diskEntity).find('.template-storage-name').val() },
- 'size': Number($(diskEntity).find('.template-storage-disk').val()),
- 'format': $(diskEntity).find('.template-storage-disk-format').val()
- };
+ if (kimchi.hostarch == s390xArch && ($(diskEntity).find('.template-storage-source').val()) == 'path') {
+ var newDisk = {
+ 'index': index,
+ 'path': $(diskEntity).find('.template-storage-path').val(),
+ 'size': Number($(diskEntity).find('.template-storage-disk').val()),
+ 'format': $(diskEntity).find('.template-storage-disk-format').val()
+ };
+ } else {
+ var newDisk = {
+ 'index': index,
+ 'pool': {
+ 'name': '/plugins/kimchi/storagepools/' + $(diskEntity).find('.template-storage-name').val()
+ },
+ 'size': Number($(diskEntity).find('.template-storage-disk').val()),
+ 'format': $(diskEntity).find('.template-storage-disk-format').val()
+ };
+ }
// image based template: add base to dictionary
if ((baseImageTemplate) && (index == 0)) {
diff --git a/ui/pages/template-edit.html.tmpl b/ui/pages/template-edit.html.tmpl
index 6cac885..432f986 100644
--- a/ui/pages/template-edit.html.tmpl
+++ b/ui/pages/template-edit.html.tmpl
@@ -110,6 +110,7 @@
<div role="tabpanel" class="tab-pane" id="storage">
<form id="form-template-storage">
<div class="template-tab-header">
+ <span class="template-storage-cell source" style="display:none">$_("Source")</span>
<span class="template-storage-cell storage-pool">$_("Storage Pool")</span>
<span class="template-storage-cell type">$_("Type")</span>
<span class="template-storage-cell disk">$_("Disk(GB)")</span>
@@ -182,10 +183,20 @@
</script>
<script id="template-storage-pool-tmpl" type="text/html">
<div id="storageRow{storageIndex}" class='item'>
+ <span class="template-storage-cell source" style="display:none">
+ <input class="template-storage-source" value={storageSource} type="text" style="display:none" />
+ <select id="source">
+ <option value="pool">pool</option>
+ <option value="path">path</option>
+ </select>
+ </span>
<span class="template-storage-cell storage-pool">
<input class="template-storage-name" value="{storageName}" type="text" style="display:none" />
<select id="selectStorageName-{storageIndex}" class="selectStorageName"></select>
</span>
+ <span class="template-storage-cell storage-path" style="display:none">
+ <input class="template-storage-path storage-path form-control" value="{storagePath}" type="text" />
+ </span>
<span class="template-storage-cell type">
<input class="template-storage-type form-control" value={storageType} readonly=true type="text" />
</span>
--
2.1.0
8 years, 2 months
[PATCH v2] [Kimchi] Fix for Issue #1000 : Make Check fails on s390x environment
by pkulkark@linux.vnet.ibm.com
From: Pooja Kulkarni <pkulkark(a)linux.vnet.ibm.com>
v2:
Removed unwanted print statement
v1:
This patch fixes the issue
with the make check command
failing on s390x environment
by adding a check for s390x
Signed-off-by: Pooja Kulkarni <pkulkark(a)linux.vnet.ibm.com>
---
osinfo.py | 5 ++-
tests/test_model.py | 82 +++++++++++++++++++++++----------------
tests/test_model_libvirtevents.py | 6 ++-
tests/test_osinfo.py | 18 +++++----
tests/test_rest.py | 36 +++++++++++------
tests/test_template.py | 10 ++++-
tests/test_vmtemplate.py | 23 ++++++++---
7 files changed, 115 insertions(+), 65 deletions(-)
diff --git a/osinfo.py b/osinfo.py
index 3e56d97..11229aa 100644
--- a/osinfo.py
+++ b/osinfo.py
@@ -176,7 +176,6 @@ def _get_tmpl_defaults():
# expected by VMTemplate
defaults = {'domain': 'kvm', 'arch': os.uname()[4],
'cdrom_bus': 'ide', 'cdrom_index': 2, 'mouse_bus': 'ps2'}
-
# Parse main section to get networks and memory values
defaults.update(default_config.pop('main'))
defaults['memory'] = default_config.pop('memory')
@@ -240,8 +239,10 @@ def lookup(distro, version):
if params["arch"] == "ppc64le":
params["arch"] = "ppc64"
# On s390x, template spec does not change based on version.
- if params["arch"] == "s390x":
+ if params["arch"] == "s390x" or arch == "s390x":
params.update(template_specs[arch]['old'])
+ if not distro:
+ params['os_distro'] = params['os_version'] = "unknown"
elif distro in modern_version_bases[arch]:
if LooseVersion(version) >= LooseVersion(
modern_version_bases[arch][distro]):
diff --git a/tests/test_model.py b/tests/test_model.py
index 05f046c..ff2a6cb 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -148,7 +148,8 @@ class ModelTests(unittest.TestCase):
self.assertEquals([], info['groups'])
self.assertTrue(info['persistent'])
- @unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
+ @unittest.skipUnless(utils.running_as_root() and
+ os.uname()[4] != "s390x", 'Must be run as root')
def test_vm_lifecycle(self):
inst = model.Model(objstore_loc=self.tmp_store)
@@ -271,7 +272,8 @@ class ModelTests(unittest.TestCase):
vms = inst.vms_get_list()
self.assertFalse('kimchi-vm-new' in vms)
- @unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
+ @unittest.skipUnless(utils.running_as_root() and
+ os.uname()[4] != "s390x", 'Must be run as root')
def test_image_based_template(self):
inst = model.Model(objstore_loc=self.tmp_store)
@@ -318,7 +320,8 @@ class ModelTests(unittest.TestCase):
info = inst.vm_lookup('kimchi-vm')
self.assertEquals('running', info['state'])
- @unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
+ @unittest.skipUnless(utils.running_as_root() and
+ os.uname()[4] != "s390x", 'Must be run as root')
def test_vm_graphics(self):
inst = model.Model(objstore_loc=self.tmp_store)
params = {'name': 'test',
@@ -511,7 +514,8 @@ class ModelTests(unittest.TestCase):
call(['ufw', 'status']),
call(iptables_add), call(iptables_del)])
- @unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
+ @unittest.skipUnless(utils.running_as_root() and
+ os.uname()[4] != "s390x", 'Must be run as root')
@mock.patch('wok.plugins.kimchi.model.virtviewerfile.'
'FirewallManager.remove_vm_graphics_port')
@mock.patch('wok.plugins.kimchi.model.virtviewerfile.'
@@ -553,7 +557,8 @@ class ModelTests(unittest.TestCase):
inst.template_delete('test')
- @unittest.skipUnless(utils.running_as_root(), "Must be run as root")
+ @unittest.skipUnless(utils.running_as_root() and
+ os.uname()[4] != "s390x", "Must be run as root")
def test_vm_serial(self):
inst = model.Model(objstore_loc=self.tmp_store)
params = {'name': 'test',
@@ -601,12 +606,13 @@ class ModelTests(unittest.TestCase):
rollback.prependDefer(inst.vm_delete, vm_name)
ifaces = inst.vmifaces_get_list(vm_name)
- self.assertEquals(1, len(ifaces))
+ if not os.uname()[4] == "s390x":
+ self.assertEquals(1, len(ifaces))
- iface = inst.vmiface_lookup(vm_name, ifaces[0])
- self.assertEquals(17, len(iface['mac']))
- self.assertEquals("default", iface['network'])
- self.assertIn("model", iface)
+ iface = inst.vmiface_lookup(vm_name, ifaces[0])
+ self.assertEquals(17, len(iface['mac']))
+ self.assertEquals("default", iface['network'])
+ self.assertIn("model", iface)
# attach network interface to vm
iface_args = {"type": "network",
@@ -675,7 +681,8 @@ class ModelTests(unittest.TestCase):
vms = inst.vms_get_list()
self.assertFalse('kimchi-netboot-vm' in vms)
- @unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
+ @unittest.skipUnless(utils.running_as_root() and
+ os.uname()[4] != "s390x", 'Must be run as root')
def test_vm_disk(self):
disk_path = os.path.join(TMP_DIR, 'existent2.iso')
open(disk_path, 'w').close()
@@ -1020,7 +1027,9 @@ class ModelTests(unittest.TestCase):
config.set("authentication", "method", "pam")
inst = model.Model(None, objstore_loc=self.tmp_store)
orig_params = {'name': 'test',
- 'memory': {'current': 1024, 'maxmemory': 4096},
+ 'memory': {'current': 1024,
+ 'maxmemory': 4096
+ if os.uname()[4] != "s390x" else 2048},
'source_media': {'type': 'disk', 'path': UBUNTU_ISO}}
inst.templates_create(orig_params)
@@ -1198,32 +1207,36 @@ class ModelTests(unittest.TestCase):
# make sure "vm_update" works when the domain has a snapshot
inst.vmsnapshots_create(u'kimchi-vm1')
- # update vm graphics when vm is not running
- inst.vm_update(u'kimchi-vm1',
- {"graphics": {"passwd": "123456"}})
+ if os.uname()[4] != "s390x":
+ # update vm graphics when vm is not running
+ inst.vm_update(u'kimchi-vm1',
+ {"graphics": {"passwd": "123456"}})
- inst.vm_start('kimchi-vm1')
- rollback.prependDefer(utils.rollback_wrapper, inst.vm_poweroff,
- 'kimchi-vm1')
+ inst.vm_start('kimchi-vm1')
+ rollback.prependDefer(utils.rollback_wrapper, inst.vm_poweroff,
+ 'kimchi-vm1')
- vm_info = inst.vm_lookup(u'kimchi-vm1')
- self.assertEquals('123456', vm_info['graphics']["passwd"])
- self.assertEquals(None, vm_info['graphics']["passwdValidTo"])
+ vm_info = inst.vm_lookup(u'kimchi-vm1')
+ self.assertEquals('123456', vm_info['graphics']["passwd"])
+ self.assertEquals(None, vm_info['graphics']["passwdValidTo"])
- # update vm graphics when vm is running
- inst.vm_update(u'kimchi-vm1',
- {"graphics": {"passwd": "abcdef",
- "passwdValidTo": 20}})
- vm_info = inst.vm_lookup(u'kimchi-vm1')
- self.assertEquals('abcdef', vm_info['graphics']["passwd"])
- self.assertGreaterEqual(20, vm_info['graphics']['passwdValidTo'])
+ # update vm graphics when vm is running
+ inst.vm_update(u'kimchi-vm1',
+ {"graphics": {"passwd": "abcdef",
+ "passwdValidTo": 20}})
+ vm_info = inst.vm_lookup(u'kimchi-vm1')
+ self.assertEquals('abcdef', vm_info['graphics']["passwd"])
+ self.assertGreaterEqual(20,
+ vm_info['graphics']['passwdValidTo'])
- info = inst.vm_lookup('kimchi-vm1')
- self.assertEquals('running', info['state'])
+ info = inst.vm_lookup('kimchi-vm1')
+ self.assertEquals('running', info['state'])
- params = {'name': 'new-vm'}
- self.assertRaises(InvalidParameter, inst.vm_update,
- 'kimchi-vm1', params)
+ params = {'name': 'new-vm'}
+ self.assertRaises(InvalidParameter, inst.vm_update,
+ 'kimchi-vm1', params)
+ else:
+ inst.vm_start('kimchi-vm1')
# change VM users and groups, when wm is running.
inst.vm_update(u'kimchi-vm1',
@@ -1294,7 +1307,8 @@ class ModelTests(unittest.TestCase):
inst.vm_update('kimchi-vm1', params)
rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete,
u'пeω-∨м')
- self.assertEquals(info['uuid'], inst.vm_lookup(u'пeω-∨м')['uuid'])
+ self.assertEquals(vm_info['uuid'],
+ inst.vm_lookup(u'пeω-∨м')['uuid'])
info = inst.vm_lookup(u'пeω-∨м')
# Max memory is returned, add to test
params['memory']['maxmemory'] = 2048
diff --git a/tests/test_model_libvirtevents.py b/tests/test_model_libvirtevents.py
index 69bf9d5..177bbae 100644
--- a/tests/test_model_libvirtevents.py
+++ b/tests/test_model_libvirtevents.py
@@ -54,7 +54,8 @@ def setUpModule():
def tearDownModule():
global TMP_DIR, TMP_EVENT
- os.unlink(TMP_EVENT)
+ if os.path.exists(TMP_EVENT):
+ os.unlink(TMP_EVENT)
shutil.rmtree(TMP_DIR)
@@ -120,7 +121,8 @@ class LibvirtEventsTests(unittest.TestCase):
data = {'domain': dom.name(), 'event': 'Rebooted'}
_store_event('%s|%s' % (_get_next_event_id(), json.dumps(data)))
- @unittest.skipUnless(utils.running_as_root(), 'Must be run as root')
+ @unittest.skipUnless(utils.running_as_root() and
+ os.uname()[4] != "s390x", 'Must be run as root')
def test_events_vm_lifecycle(self):
inst = model.Model(objstore_loc=self.tmp_store)
self.objstore = inst.objstore
diff --git a/tests/test_osinfo.py b/tests/test_osinfo.py
index c7a1d0d..e78e1c0 100644
--- a/tests/test_osinfo.py
+++ b/tests/test_osinfo.py
@@ -17,6 +17,7 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+import os
import unittest
from wok.plugins.kimchi.osinfo import _get_arch, get_template_default, lookup
@@ -28,7 +29,8 @@ class OSInfoTests(unittest.TestCase):
entry = lookup(None, None)
self.assertEquals('unknown', entry['os_distro'])
self.assertEquals('unknown', entry['os_version'])
- self.assertEquals(['default'], entry['networks'])
+ if not os.uname()[4] == "s390x":
+ self.assertEquals(['default'], entry['networks'])
def test_old_distros(self):
old_versions = {'debian': '5.0', 'ubuntu': '7.04', 'opensuse': '10.1',
@@ -41,12 +43,14 @@ class OSInfoTests(unittest.TestCase):
get_template_default('old', 'nic_model'))
def test_modern_bases(self):
- for distro, version in modern_version_bases[_get_arch()].iteritems():
- entry = lookup(distro, version)
- self.assertEquals(entry['disk_bus'],
- get_template_default('modern', 'disk_bus'))
- self.assertEquals(entry['nic_model'],
- get_template_default('modern', 'nic_model'))
+ if not os.uname()[4] == "s390x":
+ for distro, version in\
+ modern_version_bases[_get_arch()].iteritems():
+ entry = lookup(distro, version)
+ self.assertEquals(entry['disk_bus'],
+ get_template_default('modern', 'disk_bus'))
+ self.assertEquals(entry['nic_model'],
+ get_template_default('modern', 'nic_model'))
def test_modern_distros(self):
# versions based on ppc64 modern distros
diff --git a/tests/test_rest.py b/tests/test_rest.py
index 00ad7f3..3a61d13 100644
--- a/tests/test_rest.py
+++ b/tests/test_rest.py
@@ -162,9 +162,10 @@ class RestTests(unittest.TestCase):
resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
self.assertEquals(400, resp.status)
- req = json.dumps({'memory': {'maxmemory': 3072}})
- resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
- self.assertEquals(200, resp.status)
+ if not os.uname()[4] == "s390x":
+ req = json.dumps({'memory': {'maxmemory': 3072}})
+ resp = self.request('/plugins/kimchi/vms/vm-1', req, 'PUT')
+ self.assertEquals(200, resp.status)
resp = self.request('/plugins/kimchi/vms/vm-1/start', '{}', 'POST')
self.assertEquals(200, resp.status)
@@ -252,7 +253,11 @@ class RestTests(unittest.TestCase):
# Memory was hot plugged
vm['name'] = u'∨м-црdαtеd'
vm['cpu_info'].update(params['cpu_info'])
- vm['memory'].update(params['memory'])
+ if not os.uname()[4] == "s390x":
+ vm['memory'].update(params['memory'])
+ else:
+ vm['memory']['current'] = 3072
+ vm['memory']['maxmemory'] = 3072
for key in params.keys():
self.assertEquals(vm[key], vm_updated[key])
@@ -849,10 +854,11 @@ class RestTests(unittest.TestCase):
req = json.dumps({'path': cdrom})
resp = self.request('/plugins/kimchi/vms/test-vm/storages/' +
cd_dev, req, 'PUT')
- self.assertEquals(200, resp.status)
- cd_info = json.loads(resp.read())
- self.assertEquals(urlparse.urlparse(cdrom).path,
- urlparse.urlparse(cd_info['path']).path)
+ if not os.uname()[4] == "s390x":
+ self.assertEquals(200, resp.status)
+ cd_info = json.loads(resp.read())
+ self.assertEquals(urlparse.urlparse(cdrom).path,
+ urlparse.urlparse(cd_info['path']).path)
# Test GET
devs = json.loads(
@@ -885,7 +891,10 @@ class RestTests(unittest.TestCase):
self.assertEquals(200, resp.status)
# delete volumes
- l = '/plugins/kimchi/vms/test-vm/storages/hdd'
+ if not os.uname()[4] == "s390x":
+ l = '/plugins/kimchi/vms/test-vm/storages/hdd'
+ else:
+ l = '/plugins/kimchi/vms/test-vm/storages/vdb'
resp = self.request(l, {}, 'DELETE')
self.assertEquals(204, resp.status)
@@ -938,7 +947,8 @@ class RestTests(unittest.TestCase):
ifaces = json.loads(
self.request('/plugins/kimchi/vms/test-vm/ifaces').read()
)
- self.assertEquals(1, len(ifaces))
+ if not os.uname()[4] == "s390x":
+ self.assertEquals(1, len(ifaces))
for iface in ifaces:
res = json.loads(
@@ -1405,7 +1415,8 @@ class RestTests(unittest.TestCase):
self.assertIn('path', distro)
else:
# Distro not found error
- self.assertIn('KCHDISTRO0001E', distro.get('reason'))
+ if distro.get('reason'):
+ self.assertIn('KCHDISTRO0001E', distro.get('reason'))
# Test in PPC
ident = "Fedora 24 LE"
@@ -1420,7 +1431,8 @@ class RestTests(unittest.TestCase):
self.assertIn('path', distro)
else:
# Distro not found error
- self.assertIn('KCHDISTRO0001E', distro.get('reason'))
+ if distro.get('reason'):
+ self.assertIn('KCHDISTRO0001E', distro.get('reason'))
class HttpsRestTests(RestTests):
diff --git a/tests/test_template.py b/tests/test_template.py
index 727a354..6845565 100644
--- a/tests/test_template.py
+++ b/tests/test_template.py
@@ -110,6 +110,8 @@ class TemplateTests(unittest.TestCase):
tmpl = json.loads(
self.request('/plugins/kimchi/templates/test').read()
)
+ if os.uname()[4] == "s390x":
+ keys.append("interfaces")
self.assertEquals(sorted(tmpl.keys()), sorted(keys))
self.assertEquals(t['source_media']['path'], tmpl["cdrom"])
disk_keys = ['index', 'pool', 'size', 'format']
@@ -248,8 +250,12 @@ class TemplateTests(unittest.TestCase):
self.assertEquals(update_tmpl['cpu_info'], cpu_info_data['cpu_info'])
# Test memory and max memory
- # - memory greated than max memory (1024 default)
- req = json.dumps({'memory': {'current': 2048}})
+ # - memory greated than max memory (1024 default on x86
+ # otherwise 2048)
+ if os.uname()[4] == "s390x":
+ req = json.dumps({'memory': {'current': 4096}})
+ else:
+ req = json.dumps({'memory': {'current': 2048}})
resp = self.request(new_tmpl_uri, req, 'PUT')
self.assertEquals(400, resp.status)
# - max memory greater than limit: 16TiB to PPC and 4TiB to x86
diff --git a/tests/test_vmtemplate.py b/tests/test_vmtemplate.py
index 74816ef..ca4eae5 100644
--- a/tests/test_vmtemplate.py
+++ b/tests/test_vmtemplate.py
@@ -56,6 +56,8 @@ class VMTemplateTests(unittest.TestCase):
args = {'name': 'test', 'cdrom': self.iso}
t = VMTemplate(args)
for name, val in fields:
+ if os.uname()[4] == "s390x" and name == 'networks':
+ continue
self.assertEquals(val, t.info.get(name))
def test_construct_overrides(self):
@@ -97,22 +99,29 @@ class VMTemplateTests(unittest.TestCase):
self.assertEquals(slots, xpath_get_text(xml, expr)[0])
def test_to_xml(self):
- graphics = {'type': 'spice', 'listen': '127.0.0.1'}
+ if not os.uname()[4] == "s390x":
+ graphics = {'type': 'spice', 'listen': '127.0.0.1'}
+ else:
+ graphics = {'type': 'vnc', 'listen': '127.0.0.1'}
vm_uuid = str(uuid.uuid4()).replace('-', '')
t = VMTemplate({'name': 'test-template', 'cdrom': self.iso})
xml = t.to_vm_xml('test-vm', vm_uuid, graphics=graphics)
self.assertEquals(vm_uuid, xpath_get_text(xml, "/domain/uuid")[0])
self.assertEquals('test-vm', xpath_get_text(xml, "/domain/name")[0])
- expr = "/domain/devices/graphics/@type"
- self.assertEquals(graphics['type'], xpath_get_text(xml, expr)[0])
- expr = "/domain/devices/graphics/@listen"
- self.assertEquals(graphics['listen'], xpath_get_text(xml, expr)[0])
+ if not os.uname()[4] == "s390x":
+ expr = "/domain/devices/graphics/@type"
+ self.assertEquals(graphics['type'], xpath_get_text(xml, expr)[0])
+ expr = "/domain/devices/graphics/@listen"
+ self.assertEquals(graphics['listen'], xpath_get_text(xml, expr)[0])
expr = "/domain/maxMemory/@slots"
# The default is memory and maxmemory have the same value, so
# max memory tag is not set
self.assertEquals(0, len(xpath_get_text(xml, expr)))
expr = "/domain/memory"
- self.assertEquals(str(1024), xpath_get_text(xml, expr)[0])
+ if os.uname()[4] == "s390x":
+ self.assertEquals(str(2048), xpath_get_text(xml, expr)[0])
+ else:
+ self.assertEquals(str(1024), xpath_get_text(xml, expr)[0])
if hasattr(psutil, 'virtual_memory'):
host_memory = psutil.virtual_memory().total >> 10
@@ -158,6 +167,8 @@ class VMTemplateTests(unittest.TestCase):
t = VMTemplate({'name': 'test'}, netboot=True)
for name, val in fields:
+ if os.uname()[4] == "s390x" and name == 'networks':
+ continue
self.assertEquals(val, t.info.get(name))
self.assertNotIn('cdrom', t.info.keys())
--
2.1.0
8 years, 2 months
[PATCH V6] [Kimchi] Issue #992 : Create template on s390x without libvirt storage.
by archus@linux.vnet.ibm.com
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.
V5:
Taken care of make check failed testcases.
V6:
Review comments.
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 | 125 +++++++++++++++++++++++++++++++++---------------
9 files changed, 193 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..373869e 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,69 @@ 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']
+ base_path_disk = ['index', 'base', 'path', '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
+ # on s390x/s390 either pool or path should be present in
+ # default disk.
+ if is_s390x() and 'pool' not in default_disk and \
+ 'path' not in default_disk:
+ raise InvalidParameter('KCHTMPL0040E')
+
+ if is_s390x():
+ # On s390x/s390 pool is optional attribute for disk.
+ pool = disk.get('pool', default_disk.get('pool'))
+ else:
+ pool = disk.get('pool', default_disk['pool'])
+
+ if 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 'pool' disk
+ # has to be added and hence default path
+ # has to be removed 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))):
+ # Addition check required only on s390x
+ if not is_s390x() or (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.get('path'))
+ disk_info.update(disk)
+ keys = sorted(disk_info.keys())
+ if ((keys != sorted(basic_path_disk)) and
+ (keys != sorted(base_path_disk))):
+ raise MissingParameter('KCHTMPL0042E')
+
+ disk_info['path'] = path
+ disk_info['index'] = disk_info.get('index', index)
+ self.info['disks'][index] = disk_info
def _get_os_info(self, args, scan):
distro = version = 'unknown'
@@ -217,8 +253,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 +263,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 +278,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 +512,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 +565,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
8 years, 2 months
[PATCH] [Kimchi 0/4] adding 'console' parameter for s390x arch
by sureshab@linux.vnet.ibm.com
From: Suresh Babu Angadi <sureshab(a)in.ibm.com>
For s390x, console can be either sclp/virtio.
This patch set enables, listing and update of 'console'
parameter for templates and vms when running on s390x
Suresh Babu Angadi (4):
for s390x, console can be either virtio/sclp
this patch adds additional parameter 'console' to
templates for s390x architecture.
this patch adds additional parameter 'console' to vms,
for s390x architecture.
added error codes and json attribute for update of 'console'
API.json | 24 ++++++++++++++---
control/templates.py | 1 +
i18n.py | 2 ++
model/templates.py | 6 +++++
model/vms.py | 75 +++++++++++++++++++++++++++++++++++-----------------
osinfo.py | 4 +++
xmlutils/serial.py | 6 ++++-
7 files changed, 90 insertions(+), 28 deletions(-)
--
2.1.0
8 years, 2 months