[PATCH] bug fix: guest iface does not return model if no model is found
by shaohef@linux.vnet.ibm.com
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
On some distros, libvirt will not set model automatically.
if no model is found, guest iface will not return this field.
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
Signed-off-by: Aline Manera <alinefm(a)br.ibm.com>
---
docs/API.md | 2 +-
src/kimchi/model.py | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/docs/API.md b/docs/API.md
index f6f89f9..580728c 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -180,7 +180,7 @@ A interface represents available network interface on VM.
* bridge *(optional)*: the name of resource bridge, only be available when the
interface type is bridge.
* mac: Media Access Control Address of the VM interface.
- * model: model of emulated network interface card. It will be one of these models:
+ * model *(optional)*: model of emulated network interface card. It will be one of these models:
ne2k_pci, i82551, i82557b, i82559er, rtl8139, e1000, pcnet and virtio.
* network *(optional)*: the name of resource network, only be available when the
interface type is network.
diff --git a/src/kimchi/model.py b/src/kimchi/model.py
index 63e748e..a3a2576 100644
--- a/src/kimchi/model.py
+++ b/src/kimchi/model.py
@@ -1001,7 +1001,8 @@ class Model(object):
info['type'] = iface.attrib['type']
info['mac'] = iface.mac.get('address')
- info['model'] = iface.model.get('type')
+ if iface.find("model"):
+ info['model'] = iface.model.get('type')
if info['type'] == 'network':
info['network'] = iface.source.get('network')
if info['type'] == 'bridge':
--
1.8.4.2
10 years, 10 months
[PATCH 0/7] VM supports interfaces
by shaohef@linux.vnet.ibm.com
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
$ curl -u user -H 'Accept: application/json' -H 'Content-type: application/json' \
http://localhost:800/vms/test-vm-8/ifaces/
[
{
"mac":"52:54:00:00:00:08",
"model":"virtio",
"type":"network",
"network":"default",
"name":"52:54:00:00:00:08"
}
]
$ curl -u user -H 'Accept: application/json' -H 'Content-type: application/json' \
http://localhost:800/vms/test-vm-8/ifaces/52:54:00:00:00:08
{
"mac":"52:54:00:00:00:08",
"model":"virtio",
"type":"network",
"network":"default",
"name":"52:54:00:00:00:08"
}
ShaoHe Feng (7):
Add a control.vm module
add a method to load vms sub collection automatically
VM supports interfaces: update API
VM supports interfaces: update model
VM supports interfaces: update controller
VM supports interfaces: update mockmodel
VM supports interfaces: update testcase
Makefile.am | 1 +
configure.ac | 1 +
contrib/kimchi.spec.fedora.in | 1 +
contrib/kimchi.spec.suse.in | 1 +
docs/API.md | 47 ++++++++++++++++++++++++++++
src/kimchi/control/Makefile.am | 2 ++
src/kimchi/control/vm/Makefile.am | 32 +++++++++++++++++++
src/kimchi/control/vm/__init__.py | 66 +++++++++++++++++++++++++++++++++++++++
src/kimchi/control/vm/ifaces.py | 48 ++++++++++++++++++++++++++++
src/kimchi/control/vms.py | 9 ++++++
src/kimchi/mockmodel.py | 31 ++++++++++++++++++
src/kimchi/model.py | 31 ++++++++++++++++++
tests/test_model.py | 19 +++++++++++
tests/test_rest.py | 31 ++++++++++++++++++
14 files changed, 320 insertions(+)
create mode 100644 src/kimchi/control/vm/Makefile.am
create mode 100644 src/kimchi/control/vm/__init__.py
create mode 100644 src/kimchi/control/vm/ifaces.py
--
1.8.4.2
10 years, 10 months
[PATCH] bug fix: Use cherrypy host to run feature tests instead of localhost
by Aline Manera
From: Aline Manera <alinefm(a)br.ibm.com>
When user specifies a different IP/hostname to run kimchi, the feature
tests related to ISO streaming will fail as it points to localhost and
kimchi is running in other address.
Fix it by using cherrypy host to run the feature tests.
Signed-off-by: Aline Manera <alinefm(a)br.ibm.com>
---
src/kimchi/featuretests.py | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/kimchi/featuretests.py b/src/kimchi/featuretests.py
index 32ad2ec..1557dd9 100644
--- a/src/kimchi/featuretests.py
+++ b/src/kimchi/featuretests.py
@@ -93,8 +93,10 @@ class FeatureTests(object):
@staticmethod
def qemu_supports_iso_stream():
- cmd = "qemu-io -r http://127.0.0.1:%d/images/icon-fedora.png \
- -c 'read -v 0 512'" % cherrypy.server.socket_port
+ host = cherrypy.server.socket_host
+ port = cherrypy.server.socket_port
+ cmd = "qemu-io -r http://%s:%d/images/icon-fedora.png \
+ -c 'read -v 0 512'" % (host, port)
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
stdout, stderr = proc.communicate()
@@ -102,8 +104,10 @@ class FeatureTests(object):
@staticmethod
def qemu_iso_stream_dns():
- cmd = ["qemu-io", "-r", "http://localhost:%d/images/icon-fedora.png" %
- cherrypy.server.socket_port, "-c", "'read -v 0 512'"]
+ host = cherrypy.server.socket_host
+ port = cherrypy.server.socket_port
+ cmd = ["qemu-io", "-r", "http://%s:%d/images/icon-fedora.png" %
+ (host, port), "-c", "'read -v 0 512'"]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
thread = threading.Thread(target=proc.communicate)
--
1.7.10.4
10 years, 10 months
[PATCH v2 0/3]
by Mark Wu
This series of patches reorganize kimchi's path vars generation code
to allow plugin use kimchi s ui handler.
Changes:
v2:
Rebase
Remove the optimization for plugin paths since it just have a few
instantiations.
Mark Wu (3):
Reorganize the kimchi's paths gereneration code
Add test cases for paths generation code
Allow plugin use kimchi's ui handler
src/kimchi/cachebust.py | 4 +-
src/kimchi/config.py.in | 155 +++++++++++++++++++-----------------------------
src/kimchi/root.py | 23 ++++---
src/kimchi/server.py | 14 +++--
src/kimchi/template.py | 17 ++++--
src/kimchi/utils.py | 6 +-
src/kimchid.in | 7 ++-
tests/test_config.py | 73 +++++++++++++++++++++++
tests/test_plugin.py | 4 +-
9 files changed, 178 insertions(+), 125 deletions(-)
create mode 100644 tests/test_config.py
--
1.8.4.2
10 years, 10 months
[PATCH] bug fix: test case can not find plugin, fix it
by shaohef@linux.vnet.ibm.com
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
$ sudo ./run_tests.sh test_rest
Failed to import plugin plugins.sample.Drawings
That's because plugin is not in src/
Add the plugin path in run_tests.sh
Remove the plugin path from test_plugin.py
Signed-off-by: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
---
tests/run_tests.sh.in | 4 ++--
tests/test_plugin.py | 3 ---
2 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/tests/run_tests.sh.in b/tests/run_tests.sh.in
index 2baf66d..038e8fa 100644
--- a/tests/run_tests.sh.in
+++ b/tests/run_tests.sh.in
@@ -31,7 +31,7 @@ else
fi
if [ "$HAVE_UNITTEST" != "yes" -o "$PYTHON_VER" == "2.6" ]; then
- PYTHONPATH=../src:./ unit2 $ARGS
+ PYTHONPATH=../src:./:../ unit2 $ARGS
else
- PYTHONPATH=../src python -m unittest $ARGS
+ PYTHONPATH=../src:../ python -m unittest $ARGS
fi
diff --git a/tests/test_plugin.py b/tests/test_plugin.py
index 42c87a9..607dd55 100644
--- a/tests/test_plugin.py
+++ b/tests/test_plugin.py
@@ -22,7 +22,6 @@
import json
import os
-import sys
import unittest
@@ -32,7 +31,6 @@ from functools import partial
import kimchi.mockmodel
import kimchi.server
import utils
-from kimchi import config
test_server = None
@@ -48,7 +46,6 @@ def setUpModule():
host = '127.0.0.1'
port = utils.get_free_port('http')
ssl_port = None
- sys.path.append(config.get_prefix())
test_server = utils.run_server(host, port, ssl_port, test_mode=True,
model=model)
--
1.8.4.2
10 years, 10 months
[PATCH V3 0/6] VM supports interfaces
by shaohef@linux.vnet.ibm.com
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
V2 -> V3
rebase
V1 -> V2
use the "mac" to identify the iface and remove "name" parameter
$ curl -u user -H 'Accept: application/json' -H 'Content-type: application/json' \
http://localhost:800/vms/test-vm-8/ifaces/
[
{
"mac":"52:54:00:00:00:08",
"model":"virtio",
"type":"network",
"network":"default",
"name":"52:54:00:00:00:08"
}
]
$ curl -u user -H 'Accept: application/json' -H 'Content-type: application/json' \
http://localhost:800/vms/test-vm-8/ifaces/52:54:00:00:00:08
{
"mac":"52:54:00:00:00:08",
"model":"virtio",
"type":"network",
"network":"default",
"name":"52:54:00:00:00:08"
}
ShaoHe Feng (6):
Add a control.vm module
VM supports interfaces: update API
VM supports interfaces: update model
VM supports interfaces: update controller
VM supports interfaces: update mockmodel
VM supports interfaces: update testcase
Makefile.am | 1 +
configure.ac | 1 +
contrib/kimchi.spec.fedora.in | 1 +
contrib/kimchi.spec.suse.in | 1 +
docs/API.md | 46 +++++++++++++++++++++++++++++++++++++
src/kimchi/control/Makefile.am | 2 ++
src/kimchi/control/vm/Makefile.am | 32 ++++++++++++++++++++++++++
src/kimchi/control/vm/__init__.py | 30 ++++++++++++++++++++++++
src/kimchi/control/vm/ifaces.py | 48 +++++++++++++++++++++++++++++++++++++++
src/kimchi/control/vms.py | 3 +++
src/kimchi/mockmodel.py | 33 +++++++++++++++++++++++++++
src/kimchi/model.py | 35 ++++++++++++++++++++++++++++
tests/test_model.py | 19 ++++++++++++++++
tests/test_rest.py | 31 +++++++++++++++++++++++++
14 files changed, 283 insertions(+)
create mode 100644 src/kimchi/control/vm/Makefile.am
create mode 100644 src/kimchi/control/vm/__init__.py
create mode 100644 src/kimchi/control/vm/ifaces.py
--
1.8.4.2
10 years, 10 months
[PATCH 0/3] Allow plugin use kimchi s ui handler
by Mark Wu
This series of patches reorganize kimchi's path vars generation code
to allow plugin use kimchi s ui handler.
Mark Wu (3):
Reorganize the kimchi's paths gereneration code
Add test cases for paths generation code
Allow plugin use kimchi's ui handler
src/kimchi/cachebust.py | 4 +-
src/kimchi/config.py.in | 164 ++++++++++++++++++++----------------------------
src/kimchi/root.py | 39 +++++++-----
src/kimchi/server.py | 14 +++--
src/kimchi/template.py | 17 +++--
src/kimchi/utils.py | 6 +-
src/kimchid.in | 7 ++-
tests/test_config.py | 73 +++++++++++++++++++++
tests/test_plugin.py | 4 +-
9 files changed, 196 insertions(+), 132 deletions(-)
create mode 100644 tests/test_config.py
--
1.8.4.2
10 years, 10 months
[PATCH V7] Add nfs server and target UI in create storage pool
by zhoumeina
v6-v7 Fix """ in storagepool-add.html.tmpl
v5-v6 Fix bug in IE10.
Fix bug in Firefox 17.
v4-v5 Change some html nits.
V3-V4 add value in jquery widget.
move all storage all page style to css files.
v2-v3 Make nfs server inputbox to combobox
Edit jquery widgets to fix some small nits in it.
change some parameter according to the changes from
back end.
v1-v2 Fix some bug in this patch, make it working and retest
This patch is working adding a select box in create nfs pool,
when user don't want to input the server ip or name, he can
simply select "used the server I have used before" and choose
a server in a select box, this is more convinent.
In order to show server target I did a select box in UI, but sometimes
maybe the export path number is large. So I made a filter-select
widget to make user easier to choose the export path he want.
This is the first jquery widget. And let us make all common widget to
jquery widget from now on.
Signed-off-by: zhoumeina <zhoumein(a)linux.vnet.ibm.com>
---
ui/css/theme-default/button.css | 28 ++++--
ui/css/theme-default/form.css | 6 ++
ui/css/theme-default/popover.css | 1 +
ui/css/theme-default/storage.css | 29 ++++++-
ui/js/Makefile.am | 4 +-
ui/js/src/kimchi.api.js | 27 ++++++-
ui/js/src/kimchi.popable.js | 2 +-
ui/js/src/kimchi.storagepool_add_main.js | 65 +++++++++++---
ui/js/src/kimchi.utils.js | 11 +++
ui/js/widgets/combobox.js | 130 ++++++++++++++++++++++++++++
ui/js/widgets/filter-select.js | 139 ++++++++++++++++++++++++++++++
ui/js/widgets/select-menu.js | 86 ++++++++++++++++++
ui/pages/i18n.html.tmpl | 6 +-
ui/pages/storagepool-add.html.tmpl | 59 +++++++------
14 files changed, 538 insertions(+), 55 deletions(-)
create mode 100644 ui/js/widgets/combobox.js
create mode 100644 ui/js/widgets/filter-select.js
create mode 100644 ui/js/widgets/select-menu.js
diff --git a/ui/css/theme-default/button.css b/ui/css/theme-default/button.css
index c7ed3f6..4d1a808 100644
--- a/ui/css/theme-default/button.css
+++ b/ui/css/theme-default/button.css
@@ -247,30 +247,38 @@
.btn-select {
display: inline-block;
position: relative;
- height: 38px;
+ height: 30px;
padding-right: 20px;
- margin: 5px;
vertical-align: top;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
- border-radius: 5px;
- background: #eee;
- box-shadow: -1px -1px 1px #666, 1px 1px 1px #fff, 2px 2px 2px rgba(0, 0, 0, .15) inset;
+ background: #fff;
+ box-shadow: -1px -1px 1px #666, 1px 1px 1px #fff, 1px 1px 1px rgba(0, 0, 0, .15) inset;
font-size: 13px;
- line-height: 38px;
+ line-height: 30px;
text-align: left;
cursor: pointer;
}
-.btn-select .text {
- padding: 0 10px;
+.btn-select .input {
+ border: 0 solid #CCCCCC;
+ margin-right: 10px;
+ font-size: 16px;
+ height: 30px;
+ line-height: 30px;
+ width: 100%;
+ position: absolute;
+ padding: 0 5px;
}
+.btn-select input.invalid-field {
+ border: 1px solid #FF4444;
+}
.btn-select .arrow {
position: absolute;
width: 15px;
- height: 38px;
- line-height: 38px;
+ height: 30px;
+ line-height: 30px;
top: 0;
right: 5px;
background: url(../images/theme-default/arrow-down-black.png) no-repeat center center;
diff --git a/ui/css/theme-default/form.css b/ui/css/theme-default/form.css
index 28e30a5..d1a3885 100644
--- a/ui/css/theme-default/form.css
+++ b/ui/css/theme-default/form.css
@@ -49,4 +49,10 @@
.form-section input.invalid-field[type="text"] {
border-color: #FF4444;
+}
+
+.text-help {
+ font-size: 12px;
+ color: #333;
+ margin: 0 0 5px 5px;
}
\ No newline at end of file
diff --git a/ui/css/theme-default/popover.css b/ui/css/theme-default/popover.css
index 95eb183..e91ccc0 100644
--- a/ui/css/theme-default/popover.css
+++ b/ui/css/theme-default/popover.css
@@ -31,6 +31,7 @@
left: 0;
display: none;
cursor: default;
+ width: 100%;
}
.popover:BEFORE {
diff --git a/ui/css/theme-default/storage.css b/ui/css/theme-default/storage.css
index d81dc75..62e1540 100644
--- a/ui/css/theme-default/storage.css
+++ b/ui/css/theme-default/storage.css
@@ -529,7 +529,7 @@
width: 300px;
display: inline-block;
vertical-align: top;
- padding: 5px 5px 5px 20px;
+ padding: 5px 5px 5px 22px;
}
.storage-type-wrapper-controls input[type="text"] {
@@ -548,11 +548,36 @@
.storage-type-wrapper-controls > .dropdown {
margin: 5px 0 0 1px;
- width: 250px;
+ width: 150px;
}
.storage-type-wrapper-controls input[type="text"][disabled] {
color: #bbb;
background-color: #fafafa;
cursor: not-allowed;
+}
+
+.storage-add-input-width {
+ width: 285px;
+}
+
+.form-section .storage-field {
+ overflow: visible;
+}
+
+.storage-base-input-width {
+ width: 300px;
+}
+
+.storage-window {
+ width: 600px;
+ height: 700px;
+}
+
+.storage-port-width {
+ width:40px;
+}
+
+.storage-auth-width {
+ width: 150px;
}
\ No newline at end of file
diff --git a/ui/js/Makefile.am b/ui/js/Makefile.am
index 6808226..65254da 100644
--- a/ui/js/Makefile.am
+++ b/ui/js/Makefile.am
@@ -20,7 +20,7 @@
SUBDIRS = novnc
-EXTRA_DIST = src
+EXTRA_DIST = src widgets
jsdir = $(datadir)/kimchi/ui/js
@@ -31,7 +31,7 @@ dist_js_DATA = \
modernizr.custom.2.6.2.min.js \
$(NULL)
-kimchi.min.js: src/*.js
+kimchi.min.js: widgets/*.js src/*.js
cat $(sort $^) > $@
CLEANFILES = kimchi.min.js
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index a4608ff..8d006d2 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -683,5 +683,30 @@ var kimchi = {
success : suc,
error : err
});
+ },
+
+ getStorageServers: function(type, suc, err) {
+ var url = kimchi.url + 'storageservers?target_type=' + type;
+ kimchi.requestJSON({
+ url : url,
+ type : 'GET',
+ contentType : 'application/json',
+ dataType : 'json',
+ success : suc,
+ error : err
+ });
+ },
+
+ getStorageTargets: function(server,type, suc, err) {
+ var url = kimchi.url + 'storageservers/' + server + '/storagetargets?target_type=' + type;
+ kimchi.requestJSON({
+ url : url,
+ type : 'GET',
+ contentType : 'application/json',
+ timeout: 2000,
+ dataType : 'json',
+ success : suc,
+ error : err
+ });
}
-};
+};
\ No newline at end of file
diff --git a/ui/js/src/kimchi.popable.js b/ui/js/src/kimchi.popable.js
index 153d32c..2a843be 100644
--- a/ui/js/src/kimchi.popable.js
+++ b/ui/js/src/kimchi.popable.js
@@ -25,7 +25,7 @@ kimchi.popable = function() {
$(document).on("click", ".popable", function(e) {
var isOpen = $(this).hasClass('open');
$(".popable").removeClass('open');
- if (!isOpen) {
+ if (!isOpen && $(this).find('ul').html() !== '') {
$(this).addClass('open');
}
diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js
index 24de979..a4d4648 100644
--- a/ui/js/src/kimchi.storagepool_add_main.js
+++ b/ui/js/src/kimchi.storagepool_add_main.js
@@ -23,12 +23,13 @@
kimchi.storagepool_add_main = function() {
kimchi.initStorageAddPage();
$('#form-pool-add').on('submit', kimchi.addPool);
- $('#form-nfs-pool-add').on('submit', kimchi.addnfsPool);
$('#pool-doAdd').on('click', kimchi.addPool);
- $('#pool-nfs-doAdd').on('click', kimchi.addnfsPool);
};
kimchi.initStorageAddPage = function() {
+ $('#poolTypeId').selectMenu();
+ $('#serverComboboxId').combobox();
+ $('#targetFilterSelectId').filterselect();
var options = [ {
label : "DIR",
value : "dir"
@@ -54,8 +55,53 @@ kimchi.initStorageAddPage = function() {
});
$('.host-partition').html(listHtml);
}
- kimchi.select('storagePool-list', options);
- $('#poolType').change(function() {
+ $('#poolTypeId').selectMenu("setData", options);
+ kimchi.getStorageServers('netfs', function(data) {
+ var serverContent = [];
+ if (data.length > 0) {
+ $.each(data, function(index, value) {
+ serverContent.push({
+ label : value.addr,
+ value : value.addr
+ });
+ });
+ }
+ $('#serverComboboxId').combobox("setData", serverContent);
+ $('input[name=nfsServerType]').change(function() {
+ if ($(this).val() === 'input') {
+ $('#nfsServerInputDiv').removeClass('tmpl-html');
+ $('#nfsServerChooseDiv').addClass('tmpl-html');
+ } else {
+ $('#nfsServerInputDiv').addClass('tmpl-html');
+ $('#nfsServerChooseDiv').removeClass('tmpl-html');
+ }
+ });
+ $('#nfsserverId').on("change",function() {
+ if ($(this).val() !== '' && kimchi.isServer($(this).val())) {
+ $('#nfspathId').prop('disabled',false);
+ $(this).removeClass("invalid-field");
+ } else {
+ $(this).addClass("invalid-field");
+ $('#nfspathId').prop( "disabled",true);
+ }
+ $('#targetFilterSelectId').filterselect('clear');
+ });
+ $('#nfspathId').focus(function() {
+ var targetContent = [];
+ kimchi.getStorageTargets($('#nfsserverId').val(), 'netfs', function(data) {
+ if (data.length > 0) {
+ $.each(data, function(index, value) {
+ targetContent.push({
+ label : value.target,
+ value : value.target
+ });
+ });
+ }
+ $('#targetFilterSelectId').filterselect("setData", targetContent);
+ });
+ });
+ });
+ $('#poolTypeInputId').change(function() {
if ($(this).val() === 'dir') {
$('.path-section').removeClass('tmpl-html');
$('.logical-section').addClass('tmpl-html');
@@ -93,7 +139,7 @@ kimchi.initStorageAddPage = function() {
kimchi.validateForm = function() {
var name = $('#poolId').val();
- var poolType = $("#poolType").val();
+ var poolType = $("#poolTypeInputId").val();
if ('' === name) {
kimchi.message.error(i18n['msg.pool.edit.name.blank']);
return false;
@@ -111,7 +157,6 @@ kimchi.validateForm = function() {
} else {
return kimchi.validateLogicalForm();
}
-
};
kimchi.validateDirForm = function () {
@@ -162,11 +207,7 @@ kimchi.validateServer = function(serverField) {
kimchi.message.error(i18n['msg.pool.edit.server.blank']);
return false;
}
- var domain = "([0-9a-z_!~*'()-]+\.)*([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\.[a-z]{2,6}"
- var ip = "(\\d{1,3}\.){3}\\d{1,3}"
- regex = new RegExp('^' + domain + '|' + ip + '$')
-
- if (!regex.test(serverField)) {
+ if(!kimchi.isServer(serverField)) {
kimchi.message.error(i18n['msg.validate.pool.edit.server']);
return false;
}
@@ -186,7 +227,7 @@ kimchi.addPool = function(event) {
if (kimchi.validateForm()) {
var formData = $('#form-pool-add').serializeObject();
delete formData.authname;
- var poolType = $("#poolType").val();
+ var poolType = $('#poolTypeId').selectMenu('value');
if (poolType === 'dir') {
formData.path = $('#pathId').val();
} else if (poolType === 'logical') {
diff --git a/ui/js/src/kimchi.utils.js b/ui/js/src/kimchi.utils.js
index a23bf51..3cf36b9 100644
--- a/ui/js/src/kimchi.utils.js
+++ b/ui/js/src/kimchi.utils.js
@@ -168,3 +168,14 @@ kimchi.isUnsignedNumeric = function(number) {
var reg = /^d+(.d+)?$/
return reg.test(number);
}
+
+kimchi.isServer = function(server) {
+ var domain = "([0-9a-z_!~*'()-]+\.)*([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\.[a-z]{2,6}";
+ var ip = "(\\d{1,3}\.){3}\\d{1,3}";
+ regex = new RegExp('^' + domain + '|' + ip + '$');
+ if (!regex.test(server)) {
+ return false;
+ } else {
+ return true;
+ }
+};
diff --git a/ui/js/widgets/combobox.js b/ui/js/widgets/combobox.js
new file mode 100644
index 0000000..2782f62
--- /dev/null
+++ b/ui/js/widgets/combobox.js
@@ -0,0 +1,130 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Authors:
+ * zhoumeina <zhoumein(a)linux.vnet.ibm.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+(function($) {
+ $.widget('kimchi.combobox', {
+ _create : function() {
+ this.selectDiv = this.element;
+ this.listControl = this.selectDiv.find('ul').first();
+ this.listControl.html('');
+ this.target = this.selectDiv.find('input').first();
+ this.selectDiv.addClass('btn-select dropdown popable');
+ this.target.addClass('input');
+ this.target.width(this.selectDiv.width()+10);
+ this.listControl.addClass('select-list');
+ this.listControl.parent().addClass('popover');
+ },
+
+ setData : function(options) {
+ var that = this;
+ var value = this.target.val();
+ var selectedClass = 'active';
+ var itemTag = 'li';
+ if (options.length > 0) {
+ that.target.after($('<span class="arrow"></span>'));
+ that.listControl.on('click', itemTag, function(e) {
+ that.listControl.children().removeClass(selectedClass);
+ $(this).addClass(selectedClass);
+ var oldValue = that.target.val();
+ var newValue = $(this).data('value');
+ that.target.val(newValue);
+ if (oldValue !== newValue) {
+ that.target.change();
+ }
+ });
+
+ that.selectDiv.click(function(e) {
+ that.listControl.html('');
+ var items = that._dataList(options);
+ $.each(items, function(index, item) {
+ that.listControl.append(item);
+ })
+ });
+
+ that.target.keyup(function(event) {
+ that.listControl.html('');
+ var items = that._dataList(options);
+ var temp = 0;
+ $.each(items, function(index, item) {
+ if (item.text().indexOf(that.target.val()) == 0) {
+ that.listControl.append(item);
+ temp++;
+ }
+ });
+ if (temp > 0 && that.listControl.html() !== '') {
+ that._open();
+ } else {
+ that._close();
+ }
+ });
+ }
+ },
+
+ value : function(value) {
+ if (value === undefined) {
+ return this.target.val();
+ }
+ this.target.val(value);
+ },
+
+ _dataList : function(options) {
+ var item;
+ var itemTag = 'li';
+ var selectedClass = 'active';
+ var items = [];
+ var that = this;
+ $.each(options, function(index, option) {
+ item = $('<' + itemTag + '>' + option.label +'</' + itemTag + '>');
+ item.data('value', option.value);
+ if (option.value === that.target.val()) {
+ item.addClass(selectedClass);
+ }
+ items.push(item);
+ });
+ return items;
+ },
+
+ clear : function() {
+ this.target.val("");
+ },
+
+ _open : function() {
+ var isOpen = this.selectDiv.hasClass('open');
+ if (!isOpen) {
+ this.selectDiv.addClass('open');
+ }
+ },
+
+ _close : function() {
+ var isOpen = this.selectDiv.hasClass('open');
+ if (isOpen) {
+ this.selectDiv.removeClass('open');
+ }
+ },
+
+ destroy : function() {
+ this.selectDiv.removeClass('btn-select dropdown popable');
+ this.target.removeClass('input');
+ this.listControl.removeClass('select-list');
+ this.listControl.parent().removeClass('popover');
+ $.Widget.prototype.destroy.call(this);
+ }
+ });
+}(jQuery));
\ No newline at end of file
diff --git a/ui/js/widgets/filter-select.js b/ui/js/widgets/filter-select.js
new file mode 100644
index 0000000..44030a1
--- /dev/null
+++ b/ui/js/widgets/filter-select.js
@@ -0,0 +1,139 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Authors:
+ * zhoumeina <zhoumein(a)linux.vnet.ibm.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+(function($) {
+ $.widget('kimchi.filterselect', {
+ _create : function() {
+ this.selectDiv = this.element;
+ this.listControl = this.selectDiv.find('ul').first();
+ this.listControl.html('');
+ this.target = this.selectDiv.find('input').first();
+ this.selectDiv.addClass('btn-select dropdown popable');
+ this.target.addClass('input');
+ this.target.width(this.selectDiv.width()+10);
+ this.listControl.addClass('select-list');
+ this.listControl.parent().addClass('popover');
+ },
+
+ setData : function(options) {
+ var that = this;
+ var value = this.target.val();
+ var selectedClass = 'active';
+ var itemTag = 'li';
+ if (options.length > 0) {
+ that.target.after($('<span class="arrow"></span>'));
+ that.listControl.on('click', itemTag, function(e) {
+ that.listControl.children().removeClass(selectedClass);
+ $(this).addClass(selectedClass);
+ var oldValue = that.target.val();
+ var newValue = $(this).data('value');
+ that.target.val(newValue);
+ if (oldValue !== newValue) {
+ that.target.change();
+ that.target.removeClass("invalid-field");
+ }
+ });
+
+ that.selectDiv.click(function(e) {
+ that.listControl.html('');
+ var items = that._dataList(options);
+ if (items.length === 0) {
+ that.listControl.html(i18n['msg.no.mapping.result']);
+ } else {
+ $.each(items, function(index, item) {
+ that.listControl.append(item);
+ });
+ }
+ });
+
+ that.target.keyup(function(event) {
+ that.listControl.html('');
+ var items = that._dataList(options);
+ var temp = 0;
+ $.each(items, function(index, item) {
+ if (item.text().indexOf(that.target.val()) == 0) {
+ that.listControl.append(item);
+ temp++;
+ }
+ });
+ if (that.listControl.html() === '') {
+ that.target.addClass("invalid-field");
+ that.listControl.html(i18n['msg.no.mapping.result']);
+ } else {
+ that.target.removeClass("invalid-field");
+ }
+ if (temp > 0) {
+ that._open();
+ }
+ });
+ }
+ },
+
+ value : function(value) {
+ if (value === undefined) {
+ return this.target.val();
+ }
+ this.target.val(value);
+ },
+
+ _dataList : function(options) {
+ var item;
+ var itemTag = 'li';
+ var selectedClass = 'active';
+ var items = [];
+ var that = this;
+ $.each(options, function(index, option) {
+ item = $('<' + itemTag + '>' + option.label +'</' + itemTag + '>');
+ item.data('value', option.value);
+ if (option.value === that.target.val()) {
+ item.addClass(selectedClass);
+ }
+ items.push(item);
+ });
+ return items;
+ },
+
+ clear : function() {
+ this.target.val("");
+ },
+
+ _open : function() {
+ var isOpen = this.selectDiv.hasClass('open');
+ if (!isOpen) {
+ this.selectDiv.addClass('open');
+ }
+ },
+
+ _close : function() {
+ var isOpen = this.selectDiv.hasClass('open');
+ if (isOpen) {
+ this.selectDiv.removeClass('open');
+ }
+ },
+
+ destroy : function() {
+ this.selectDiv.removeClass('btn-select dropdown popable');
+ this.target.removeClass('input');
+ this.listControl.removeClass('select-list');
+ this.listControl.parent().removeClass('popover')
+ $.Widget.prototype.destroy.call(this);
+ }
+ });
+}(jQuery));
\ No newline at end of file
diff --git a/ui/js/widgets/select-menu.js b/ui/js/widgets/select-menu.js
new file mode 100644
index 0000000..c9a1b87
--- /dev/null
+++ b/ui/js/widgets/select-menu.js
@@ -0,0 +1,86 @@
+/*
+ * Project Kimchi
+ *
+ * Copyright IBM, Corp. 2013
+ *
+ * Authors:
+ * zhoumeina <zhoumein(a)linux.vnet.ibm.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+(function($) {
+ $.widget('kimchi.selectMenu', {
+
+ _create : function() {
+ this.selectDiv = this.element;
+ this.listControl = this.selectDiv.find('ul').first();
+ this.listControl.html('');
+ this.target = this.selectDiv.find('input').first();
+ this.label = this.selectDiv.find('span').first();
+ this.selectDiv.addClass('btn-select dropdown popable');
+ this.target.addClass('input');
+ this.label.addClass('input');
+ this.listControl.addClass('select-list');
+ this.listControl.parent().addClass('popover');
+ },
+
+ setData : function (options) {
+ var that = this;
+ var value = this.target.val();
+ var selectedClass = 'active';
+ var itemTag = 'li';
+ var item;
+ if (options.length > 0) {
+ $.each(options, function(index, option) {
+ item = $('<' + itemTag + '>' + option.label +'</' + itemTag + '>');
+ item.data('value', option.value);
+ if(option.value === value) {
+ item.addClass(selectedClass);
+ that.label.text(option.label);
+ }
+ that.listControl.append(item);
+ });
+ that.listControl.on('click', itemTag, function() {
+ that.listControl.children().removeClass(selectedClass);
+ $(this).addClass(selectedClass);
+ that.label.text($(this).text());
+ var oldValue = that.target.val();
+ var newValue = $(this).data('value');
+ that.target.val(newValue);
+ if(oldValue !== newValue) {
+ that.target.change();
+ }
+ });
+ } else {
+ kimchi.message.error(i18n['selectmenu.data.error']);
+ }
+ },
+
+ value : function(data) {
+ if (data === undefined) {
+ return this.target.val();
+ }
+ this.target.val(data.value);
+ this.label.val(data.label);
+ },
+
+ destroy : function() {
+ this.selectDiv.removeClass('btn-select dropdown popable');
+ this.target.removeClass('input');
+ this.label.removeClass('input');
+ this.listControl.removeClass('select-list');
+ this.listControl.parent().removeClass('popover');
+ $.Widget.prototype.destroy.call(this);
+ }
+ });
+}(jQuery));
\ No newline at end of file
diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl
index 603f8d7..37b4114 100644
--- a/ui/pages/i18n.html.tmpl
+++ b/ui/pages/i18n.html.tmpl
@@ -122,7 +122,11 @@ var i18n = {
" there, are you sure to continue? ")",
'msg.pool.edit.iscsitarget.blank': "$_("The iSCSI target can not be blank.")",
'msg.pool.edit.server.blank':"$_("Server name can not be blank.")",
- 'msg.validate.pool.edit.server':"$_("This is not a valid Server Name or IP. please, modify it.")"
+ 'msg.validate.pool.edit.server':"$_("This is not a valid Server Name or IP. please, modify it.")",
+ 'select_default': "$_("Please choose")",
+ 'msg.no.mapping.result': "$_("No such data exsit.")",
+ 'msg.no.result' : "$_("No valid result")",
+ 'selectmenu.data.error' : "$_("options needed.")"
};
</script>
</body>
diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl
index e8dac43..363d097 100644
--- a/ui/pages/storagepool-add.html.tmpl
+++ b/ui/pages/storagepool-add.html.tmpl
@@ -27,7 +27,7 @@
<!DOCTYPE html>
<html>
<body>
- <div class="window" style="width: 600px; height: 700px;">
+ <div class="window storage-window">
<header>
<h1 class="title">$_("Define a New Storage Pool")</h1>
<div class="close">X</div>
@@ -40,18 +40,17 @@
<p class="text-help">
$_("The name used to identify the storage pools, and it should not be empty.")
</p>
- <input id="poolId" required="required" type="text" class="text" style="width: 300px"
- name="name">
+ <input id="poolId" required="required" type="text" class="text storage-base-input-width" name="name">
</div>
</section>
<section class="form-section">
<h2>2. $_("Storage Pool Type")</h2>
<div class="storage-type-wrapper-controls">
- <div class="btn dropdown popable">
- <input id="poolType" name="type" type="hidden" value="dir"/>
- <span class="text" id="pool-type-label"></span><span class="arrow"></span>
- <div class="popover" style="width: 100%">
- <ul class="select-list" id="storagePool-list" data-target="poolType" data-label="pool-type-label">
+ <div id="poolTypeId">
+ <input id="poolTypeInputId" name="type" type="hidden" value="dir"/>
+ <span id="pool-type-label"></span><span class="arrow"></span>
+ <div>
+ <ul id="storagePool-list">
</ul>
</div>
</div>
@@ -65,30 +64,38 @@
$_("The path of the Storage Pool. Each Storage Pool must have a unique path.")</p>
<p class="text-help">
$_("Kimchi will try to create the directory when it does not already exist in your system.")</p>
- <input id="pathId" type="text" class="text" required="required" style="width: 300px">
+ <input id="pathId" type="text" class="text storage-base-input-width">
</div>
<div class="clear"></div>
</section>
</div>
<div class="nfs-section tmpl-html">
<section class="form-section">
- <h2>3. $_("NFS server IP")</h2>
- <div class="field">
+ <h2>3. $_("NFS Server IP")</h2>
+ <div class="field storage-field">
<p class="text-help">
- $_("NFS server IP or hostname. It should not be empty.")</p>
- <input id="nfsserverId" required="required" type="text" class="text"
- style="width: 300px">
+ $_("NFS server IP or hostname. It can be input or chosen from history.")</p>
+ <div id="serverComboboxId" class="storage-add-input-width">
+ <input id="nfsserverId"/>
+ <div>
+ <ul id="nfs-server-used">
+ </ul>
+ </div>
+ </div>
</div>
</section>
<section class="form-section">
<h2>4. $_("NFS Path")</h2>
- <div class="field">
- <p class="text-help">$_("The nfs exported path on nfs server")</p>
- <input id="nfspathId" required="required" type="text" class="text"
- style="width: 300px">
- <input type="hidden" id="localpathId" class="text" value="none">
- </div>
- <div class="clear"></div>
+ <div class="field storage-field">
+ <p class="text-help">$_("The nfs exported path on nfs server.")</p>
+ <div id="targetFilterSelectId" class="storage-add-input-width">
+ <input id="nfspathId" class="input" disabled/>
+ <div>
+ <ul id="nfs-server-target">
+ </ul>
+ </div>
+ </div>
+ </div>
</section>
</div>
<div class="logical-section tmpl-html">
@@ -103,15 +110,15 @@
<div class="field">
<p class="text-help">
$_("iSCSI server IP or hostname. It should not be empty.")</p>
- <input id="iscsiserverId" placeholder="$_("Server")" type="text" class="text" style="width: 300px">
- <input id="iscsiportId" placeholder="$_("Port")" type="text" class="text" style="width:40px" maxlength='4'>
+ <input id="iscsiserverId" placeholder="$_("Server")" type="text" class="text storage-base-input-width">
+ <input id="iscsiportId" placeholder="$_("Port")" type="text" class="text storage-port-width" maxlength="4">
</div>
</section>
<section class="form-section">
<h2>4. $_("Target")</h2>
<div class="field">
<p class="text-help">$_("The iSCSI target on iSCSI server")</p>
- <input id="iscsiTargetId" type="text" class="text" style="width: 300px">
+ <input id="iscsiTargetId" type="text" class="text storage-base-input-width">
</div>
</section>
<section class="form-section">
@@ -123,8 +130,8 @@
<section class="authenticationfield form-section tmpl-html">
<h2>5. $_("iSCSI Authentication")</h2>
<div class="field">
- <input id="usernameId" placeholder="$_("User Name")" type="text" class="text" style="width: 150px">
- <input id="passwordId" placeholder="$_("Password")" type="text" class="text" style="width: 150px">
+ <input id="usernameId" placeholder="$_("User Name")" type="text" class="text storage-auth-width">
+ <input id="passwordId" placeholder="$_("Password")" type="text" class="text storage-auth-width">
</div>
</section>
</div>
--
1.7.1
10 years, 10 months
[PATCH V4 0/4] improve controller
by shaohef@linux.vnet.ibm.com
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
V3 -> V4
rebase
fix typo
move the improvement function from src/kimchi/utils.py to src/kimchi/control/utils.py
V2 -> V3
use the CapWords convention to name class name.
add the import statement in alphabetical order
use __import__ to import the moudle instead of imp.load_module
imp.load_module does more than importing the module:
if the module was already imported, it is equivalent to a reload()!
we can use the imp.load_module as follow:
try:
module = sys.modules[module_name]
except KeyError:
mod_fobj, mod_absp, mod_desc = imp.find_module(mod_name, [path])
module = imp.load_module(module_name, mod_fobj, mod_absp, mod_desc)
V1 -> V2
fix typo.
remove print
use url_auth instead of _url_sub_node_auth
improve the commit description
add a method to load root sub collections/resouces automatically
ShaoHe Feng (4):
improve controller: add a method to load root sub collections/resouces
automatically
improve controller: tag the collections/resouces of root with
@UrlSubNode
improve controller: Root loads collections/resouces automatically
improve controller: set authentication automatically
src/kimchi/control/__init__.py | 8 ++++++++
src/kimchi/control/config.py | 2 ++
src/kimchi/control/debugreports.py | 2 ++
src/kimchi/control/host.py | 2 ++
src/kimchi/control/interfaces.py | 2 ++
src/kimchi/control/networks.py | 2 ++
src/kimchi/control/plugins.py | 2 ++
src/kimchi/control/storagepools.py | 2 ++
src/kimchi/control/tasks.py | 2 ++
src/kimchi/control/templates.py | 2 ++
src/kimchi/control/utils.py | 39 ++++++++++++++++++++++++++++++++++++++
src/kimchi/control/vms.py | 3 ++-
src/kimchi/root.py | 28 +++++----------------------
src/kimchi/server.py | 12 +++++-------
14 files changed, 77 insertions(+), 31 deletions(-)
--
1.8.4.2
10 years, 10 months
[PATCH V3 0/4] improve controller
by shaohef@linux.vnet.ibm.com
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
V2 -> V3
use the CapWords convention to name class name.
add the import statement in alphabetical order
use __import__ to import the moudle instead of imp.load_module
imp.load_module does more than importing the module:
if the module was already imported, it is equivalent to a reload()!
we can use the imp.load_module as follow:
try:
module = sys.modules[module_name]
except KeyError:
mod_fobj, mod_absp, mod_desc = imp.find_module(mod_name, [path])
module = imp.load_module(module_name, mod_fobj, mod_absp, mod_desc)
V1 -> V2
fix typo.
remove print
use url_auth instead of _url_sub_node_auth
improve the commit description
add a method to load root sub collections/resouces automatically
ShaoHe Feng (4):
improve controller: add a method to load root sub collections/resouces
automatically
improve controller: tag the collections/resouces of root with
@UrlSubNode
improve controller: Root loads collections/resouces automatically
improve controller: set authentication automatically
src/kimchi/control/__init__.py | 8 ++++++++
src/kimchi/control/config.py | 2 ++
src/kimchi/control/debugreports.py | 2 ++
src/kimchi/control/host.py | 2 ++
src/kimchi/control/interfaces.py | 2 ++
src/kimchi/control/networks.py | 2 ++
src/kimchi/control/plugins.py | 2 ++
src/kimchi/control/storagepools.py | 2 ++
src/kimchi/control/tasks.py | 2 ++
src/kimchi/control/templates.py | 2 ++
src/kimchi/control/vms.py | 2 ++
src/kimchi/root.py | 26 +++++---------------------
src/kimchi/server.py | 12 +++++-------
src/kimchi/utils.py | 38 ++++++++++++++++++++++++++++++++++++++
14 files changed, 76 insertions(+), 28 deletions(-)
--
1.8.4.2
10 years, 10 months