[PATCH 1/2] Dynamically generate template parameters for different distros
by Mark Wu
We define hard coded template for different distros. It's not
flexible to generate templates for other platforms or new distros.
This patch changes to dynamically generate vm template. With
this change, it can support new distro, like Fedora20, without any
modifications.
Signed-off-by: Mark Wu <wudxw(a)linux.vnet.ibm.com>
---
src/kimchi/osinfo.py | 174 ++++++++++-------------------------------------
src/kimchi/vmtemplate.py | 2 +-
tests/test_osinfo.py | 28 ++++++--
3 files changed, 60 insertions(+), 144 deletions(-)
diff --git a/src/kimchi/osinfo.py b/src/kimchi/osinfo.py
index 20a93a6..b141d9e 100644
--- a/src/kimchi/osinfo.py
+++ b/src/kimchi/osinfo.py
@@ -22,136 +22,23 @@
import copy
import os
+from distutils.version import LooseVersion
+
+
+common_spec = {'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1, 'memory': 1024,
+ 'disks': [{'index': 0, 'size': 10}], 'cdrom_bus': 'ide',
+ 'cdrom_index': 2}
+
+
+modern_spec = dict(common_spec, disk_bus='virtio', nic_model='virtio')
+
+
+old_spec = dict(common_spec, disk_bus='ide', nic_model='e1000')
+
+
+modern_version_bases = {'debian': '6.0', 'ubuntu': '7.10', 'opensuse': '10.3',
+ 'centos': '5.3', 'rhel': '6.0', 'fedora': '16'}
-osinfo = [
- # Entries are searched in order and the first match will be returned
- ('debian', {
- 'version': lambda d,v: bool(d == 'debian' and v in ('6.0', '7.0')),
- 'icon': 'images/icon-debian.png',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'virtio', 'nic_model': 'virtio',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
- ('debian-old', {
- 'version': lambda d,v: bool(d == 'debian'),
- 'icon': 'images/icon-debian.png',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'ide', 'nic_model': 'e1000',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
- ('ubuntu', {
- 'version': lambda d,v: bool(d == 'ubuntu' and v in
- ('7.10', '8.04', '8.10', '9.04', '9.10', '10.04', '10.10',
- '11.04', '11.10', '12.04', '12.10', '13.04', '13.10')),
- 'icon': 'images/icon-ubuntu.png',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'virtio', 'nic_model': 'virtio',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
- ('ubuntu-old', {
- 'version': lambda d,v: bool(d == 'ubuntu'),
- 'icon': 'images/icon-ubuntu.png',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'ide', 'nic_model': 'e1000',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
- ('opensuse', {
- 'version': lambda d,v: bool(d == 'opensuse' and v in
- ('10.3', '11.0', '11.1', '11.2', '11.3', '11.4', '12.1', '12.2',
- '12.3',)),
- 'icon': 'images/icon-opensuse.png',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'virtio', 'nic_model': 'virtio',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
- ('opensuse-old', {
- 'version': lambda d,v: bool(d == 'opensuse'),
- 'icon': 'images/icon-opensuse.png',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'ide', 'nic_model': 'e1000',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
- ('fedora', {
- 'version': lambda d,v: bool(d == 'fedora' and v in
- ('16', '17', '18', '19')),
- 'icon': 'images/icon-fedora.png',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'virtio', 'nic_model': 'virtio',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
- ('fedora-old', {
- 'version': lambda d,v: bool(d == 'fedora'),
- 'icon': 'images/icon-fedora.png',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'ide', 'nic_model': 'e1000',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
- ('rhel', {
- 'version': lambda d,v: bool(d == 'rhel' and
- v.startswith('6.')),
- 'icon': 'images/icon-vm.png',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'virtio', 'nic_model': 'virtio',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
- ('rhel-old', {
- 'version': lambda d,v: bool(d == 'rhel'),
- 'icon': 'images/icon-vm.png',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'ide', 'nic_model': 'e1000',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
- ('centos', {
- 'version': lambda d,v: bool(d == 'centos' and
- (v in ('5.3', '5.4', '5.5') or v.startswith('6.'))),
- 'icon': 'images/icon-centos.png',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'virtio', 'nic_model': 'virtio',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
- ('centos-old', {
- 'version': lambda d,v: bool(d == 'centos'),
- 'icon': 'images/icon-centos.png',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'ide', 'nic_model': 'e1000',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
- ('unknown', {
- 'version': lambda d,v: True,
- 'icon': 'images/icon-vm.png',
- 'os_distro': 'unknown', 'os_version': 'unknown',
- 'cpus': 1, 'cpu_cores': 1, 'cpu_threads': 1,
- 'memory': 1024,
- 'cdrom': '',
- 'disks': [{'index': 0, 'size': 10}],
- 'disk_bus': 'ide', 'nic_model': 'e1000',
- 'cdrom_bus': 'ide', 'cdrom_index': 2,
- }),
-]
isolinks = {
'debian': {
@@ -181,13 +68,22 @@ def lookup(distro, version):
'defaults' and merging the parameters given for the identified OS. If
known, a link to a remote install CD is added.
"""
- for name, entry in osinfo:
- # Test if this entry is a valid match
- if entry['version'](distro, version):
- params = copy.copy(defaults)
- params['os_distro'] = distro
- params['os_version'] = version
- params.update(entry)
- params['cdrom'] = isolinks.get(distro, {}).get(version, '')
- del params['version'] # Don't pass around the version function
- return (name, params)
+ params = copy.copy(defaults)
+ params['os_distro'] = distro
+ params['os_version'] = version
+ params['cdrom'] = isolinks.get(distro, {}).get(version, '')
+
+ for name, base_version in modern_version_bases.iteritems():
+ if name == distro:
+ params['icon'] = 'images/icon-%s.png' % distro
+ if LooseVersion(version) >= LooseVersion(base_version):
+ params.update(modern_spec)
+ else:
+ params.update(old_spec)
+ break
+ else:
+ params['icon'] = 'images/icon-vm.png'
+ params['os_distro'] = params['os_version'] = "unknown"
+ params.update(old_spec)
+
+ return params
diff --git a/src/kimchi/vmtemplate.py b/src/kimchi/vmtemplate.py
index dd43faa..f92af49 100644
--- a/src/kimchi/vmtemplate.py
+++ b/src/kimchi/vmtemplate.py
@@ -70,7 +70,7 @@ class VMTemplate(object):
# Fetch defaults based on the os distro and version
os_distro = args.get('os_distro', iso_distro)
os_version = args.get('os_version', iso_version)
- name, entry = osinfo.lookup(os_distro, os_version)
+ entry = osinfo.lookup(os_distro, os_version)
self.info.update(entry)
# Override with the passed in parameters
diff --git a/tests/test_osinfo.py b/tests/test_osinfo.py
index f92567d..da3e1d2 100644
--- a/tests/test_osinfo.py
+++ b/tests/test_osinfo.py
@@ -25,16 +25,36 @@ from kimchi.osinfo import *
class OSInfoTests(unittest.TestCase):
def test_default_lookup(self):
- name, entry = lookup(None, None)
- self.assertEquals(name, 'unknown')
+ entry = lookup(None, None)
self.assertEquals('unknown', entry['os_distro'])
self.assertEquals('unknown', entry['os_version'])
self.assertEquals('default', entry['network'])
def test_fedora_lookup(self):
cd = 'http://fedora.mirrors.tds.net/pub/fedora/releases/17/Live/x86_64/Fedora-1...'
- name, entry = lookup('fedora', '17')
- self.assertEquals(name, 'fedora')
+ entry = lookup('fedora', '17')
self.assertEquals(10, entry['disks'][0]['size'])
self.assertEquals(cd, entry['cdrom'])
self.assertEquals('/storagepools/default', entry['storagepool'])
+
+ def test_old_distros(self):
+ old_versions = {'debian': '5.0', 'ubuntu': '7.04', 'opensuse': '10.1',
+ 'centos': '5.1', 'rhel': '5.1', 'fedora': '15'}
+ for distro, version in old_versions.iteritems():
+ entry = lookup(distro, version)
+ self.assertEquals(entry['disk_bus'], 'ide')
+ self.assertEquals(entry['nic_model'], 'e1000')
+
+ def test_modern_bases(self):
+ for distro, version in modern_version_bases.iteritems():
+ entry = lookup(distro, version)
+ self.assertEquals(entry['disk_bus'], 'virtio')
+ self.assertEquals(entry['nic_model'], 'virtio')
+
+ def test_modern_distros(self):
+ old_versions = {'debian': '7.0', 'ubuntu': '12.04', 'opensuse': '12.3',
+ 'centos': '6.4', 'rhel': '6.3', 'fedora': '18'}
+ for distro, version in old_versions.iteritems():
+ entry = lookup(distro, version)
+ self.assertEquals(entry['disk_bus'], 'virtio')
+ self.assertEquals(entry['nic_model'], 'virtio')
--
1.8.3.1
11 years
[PATCH V4 0/5] Add spice backend support for kimchi
by apporc
v4-v3:
1. Remove not used module "copy" in vmtemplate.py(Thanks Aline)
2. Fix alignment problem in model.py(Thanks Aline)
3. Use type property of jsonschema to validate both ipv4 and ipv6(Thanks Aline)
REF: http://stackoverflow.com/questions/14550235/json-schema-away-to-specify-a...
4. Use "$ref" to simply API.json, remove dumplicate content(Thanks Rodrigo)
v3-v2:
1. Rebase to upstream
2. Improve/simplify some code according to reviewers' advice(Thanks Royce, Markwu and Aline).
3. Reimplement parameters validation using jsonschema.
4. Remove unnecessary test code in model.py.
5. Split patch to several smaller commits according to logic(Thanks Royce).
v2-v1: Rebased to upstream and resend
v1: Add spice backend support for kimchi
apporc (5):
Add spice backend support for kimchi
Update mockmodel for spice support
Validate graphics parameters input by users
Update test case for graphics support
Add graphics parameters description in API.md
docs/API.md | 43 ++++++++++++++++++++++-
src/kimchi/API.json | 30 +++++++++++++++--
src/kimchi/controller.py | 14 +++++---
src/kimchi/mockmodel.py | 49 ++++++++++++++++++---------
src/kimchi/model.py | 43 +++++++++++++----------
src/kimchi/osinfo.py | 5 +--
src/kimchi/vmtemplate.py | 31 +++++++++++++++--
tests/test_mockmodel.py | 2 ++
tests/test_model.py | 27 ++++++++++++++-
tests/test_rest.py | 88 +++++++++++++++++++++++++++++++++++++++++++++---
tests/test_vmtemplate.py | 42 ++++++++++++++++++++---
11 files changed, 319 insertions(+), 55 deletions(-)
--
1.8.1.2
11 years
[PATCH v2 0/5] Support creating iSCSI storage pool
by Zhou Zheng Sheng
Hi,
This patch series is about creating iSCSI storage pool. I firstly
refactored a little bit to make the storage pool creation API nicer,
then add unit test for pool XML generation. The front-end is also
changed to suit the new back-end API. Then I implement iSCSI pool XML
generation and also add a test to actually create a iSCSI pool and
delete it.
v1 -> v2
I take Royce's advice and arrange pool source information under a
"source" key. A pool definition is now like the following.
{'type': 'netfs', 'name': 'XXX,
'source': {'host': 'X.X.X.X', 'path': '/export/path'}}
or
{'type': 'logical', 'name': 'XXX,
'source': {'devices': ['/dev/sdX', '/dev/sdY']}}
Sheldon thinks the pool XML generation code should be put into a
separated file. I also see Bing Bu's email on refactoring.
Ming says we can make the hard coded path constants configurable.
I think in future we may also add code for validating the pool
source, for example, try to mount an NFS export or login iSCSI
target. All these worth an overall refactor so they are not the
scope of this patch series. I think we can do this after the iSCSI
support is ready.
As Pradeep suggested, I add test to create and delete iSCSI storage
pool in test_model.py. It requires an existing iSCSI target on
localhost. You can use targetcli to create one, or it just skips the
test if it detects no target to use.
Thanks for all your review! I want to hear your comments on the new
API schema, so I can make it stable and save time for front-end work.
Zhou Zheng Sheng (5):
storagepool: dispatch _get_pool_xml() to respective
_get_XXX_storagepool_xml() function
storagepool: rename and consolidate arguments of creating (back end)
storagepool: rename and consolidate arguments of creating (front end)
storagepool: Support Creating iSCSI storagepool in model.py
test_model: test creating iSCSI storage pool
Makefile.am | 2 +
docs/API.md | 24 +++--
src/kimchi/Makefile.am | 1 +
src/kimchi/iscsi.py | 57 +++++++++++
src/kimchi/model.py | 160 +++++++++++++++++++++----------
tests/Makefile.am | 1 +
tests/test_model.py | 91 ++++++++++--------
tests/test_storagepool.py | 111 +++++++++++++++++++++
ui/js/src/kimchi.storagepool_add_main.js | 13 ++-
9 files changed, 361 insertions(+), 99 deletions(-)
create mode 100644 src/kimchi/iscsi.py
create mode 100644 tests/test_storagepool.py
--
1.7.11.7
11 years
[PATCH v3 1/2] logical pool fixes: only list leaf devices, and read file instead of run "cat"
by Zhou Zheng Sheng
Some devices are parent of other devices. We should just list the leaf
devices but not parent devices. For example, if a disk contains
partitions, we should only list the partitions. If a disk is held by
multipath device, we should not list the disk.
Currently we strip the last charactter from "vda1" to get "vda" and
ignore the parent "vda" device. This may fails on disk contains lots of
logical partitions, for example "vda10"'s parent is not "vda1". Another
problem is this method can not find the parent-child relation ship
between a multipath device and its slaves.
The most accurate information is on sysfs, and lsblk lists all children
device of the requested device based on sysfs. So when "lsblk -P
devices" prints only one line, it's the device itself, when it prints
more lines, they are the children devices. This patch use this method to
detect if a device a leaf one.
This patch also avoids start new "cat" process to read uevent file, it
opens the uevent file and read it directly.
v2:
Assign string literal to constants thus avoid breaking the line.
v3:
Save N lsblk invocations when list all devices by collecting major:min
and device node path in one run. N is number of block devices.
Use short-circuiting operator "and" instead of all to save extra lsblk
invocation.
Signed-off-by: Zhou Zheng Sheng <zhshzhou(a)linux.vnet.ibm.com>
---
src/kimchi/disks.py | 83 ++++++++++++++++++++++++++++++++---------------------
1 file changed, 50 insertions(+), 33 deletions(-)
diff --git a/src/kimchi/disks.py b/src/kimchi/disks.py
index a054961..34b9e01 100644
--- a/src/kimchi/disks.py
+++ b/src/kimchi/disks.py
@@ -27,27 +27,13 @@ from kimchi.exception import OperationFailed
from kimchi.utils import kimchi_log
-def _get_partition_path(name):
- """ Returns device path given a partition name """
- dev_path = None
- maj_min = None
-
- keys = ["NAME", "MAJ:MIN"]
- dev_list = _get_lsblk_devs(keys)
-
- for dev in dev_list:
- if dev['name'] == name:
- maj_min = dev['maj:min']
- break
+def _get_dev_node_path(maj_min):
+ """ Returns device node path given the device number 'major:min' """
+ uevent = "/sys/dev/block/%s/uevent" % maj_min
+ with open(uevent) as ueventf:
+ content = ueventf.read()
- uevent_cmd = "cat /sys/dev/block/%s/uevent" % maj_min
- uevent = subprocess.Popen(uevent_cmd, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, shell=True)
- out, err = uevent.communicate()
- if uevent.returncode != 0:
- raise OperationFailed("Error getting partition path for %s", name)
-
- data = dict(re.findall(r'(\S+)=(".*?"|\S+)', out.replace("\n", " ")))
+ data = dict(re.findall(r'(\S+)=(".*?"|\S+)', content.replace("\n", " ")))
return "/dev/%s" % data["DEVNAME"]
@@ -63,6 +49,39 @@ def _get_lsblk_devs(keys, devs=[]):
return _parse_lsblk_output(out, keys)
+def _get_dev_major_min(name):
+ maj_min = None
+
+ keys = ["NAME", "MAJ:MIN"]
+ dev_list = _get_lsblk_devs(keys)
+
+ for dev in dev_list:
+ if dev['name'] == name:
+ maj_min = dev['maj:min']
+ break
+ else:
+ msg = "Failed to find major and minor number for %s" % name
+ raise OperationFailed(msg)
+
+ return maj_min
+
+
+def _is_dev_leaf(devNodePath):
+ try:
+ # By default, lsblk prints a device information followed by children
+ # device information
+ childrenCount = len(
+ _get_lsblk_devs(["NAME"], [devNodePath])) - 1
+ except OperationFailed as e:
+ # lsblk is known to fail on multipath devices
+ # Assume these devices contain children
+ kimchi_log.error(
+ "Error getting device info for %s: %s", devNodePath, e)
+ return False
+ else:
+ return childrenCount == 0
+
+
def _parse_lsblk_output(output, keys):
# output is on format key="value",
# where key can be NAME, TYPE, FSTYPE, SIZE, MOUNTPOINT, etc
@@ -82,32 +101,30 @@ def _parse_lsblk_output(output, keys):
def get_partitions_names():
names = []
- ignore_names = []
- keys = ["NAME", "TYPE", "FSTYPE", "MOUNTPOINT"]
+ keys = ["NAME", "TYPE", "FSTYPE", "MOUNTPOINT", "MAJ:MIN"]
# output is on format key="value",
# where key can be NAME, TYPE, FSTYPE, MOUNTPOINT
for dev in _get_lsblk_devs(keys):
# split()[0] to avoid the second part of the name, after the
# whiteline
name = dev['name'].split()[0]
- # Only list unmounted and unformated partition or disk.
- if not all([dev['type'] in ['part', 'disk'],
- dev['fstype'] == "",
- dev['mountpoint'] == ""]):
-
- # the whole disk must be ignored in it has at least one
- # mounted/formatted partition
- if dev['type'] == 'part':
- ignore_names.append(name[:-1])
+ devNodePath = _get_dev_node_path(dev['maj:min'])
+ # Only list unmounted and unformated and leaf and (partition or disk)
+ # leaf means a partition, a disk has no partition, or a disk not held
+ # by any multipath device.
+ if not (dev['type'] in ['part', 'disk'] and
+ dev['fstype'] == "" and
+ dev['mountpoint'] == "" and
+ _is_dev_leaf(devNodePath)):
continue
names.append(name)
- return list(set(names) - set(ignore_names))
+ return names
def get_partition_details(name):
- dev_path = _get_partition_path(name)
+ dev_path = _get_dev_node_path(_get_dev_major_min(name))
keys = ["TYPE", "FSTYPE", "SIZE", "MOUNTPOINT"]
try:
--
1.7.11.7
11 years
[PATCH V1 2/2] Add a new jquery filter-select widget
by zhoumeina
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/js/widgets/filter-select.js | 110 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 110 insertions(+), 0 deletions(-)
create mode 100644 ui/js/widgets/filter-select.js
diff --git a/ui/js/widgets/filter-select.js b/ui/js/widgets/filter-select.js
new file mode 100644
index 0000000..f58b208
--- /dev/null
+++ b/ui/js/widgets/filter-select.js
@@ -0,0 +1,110 @@
+/*
+ * 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", {
+ options: {
+ key: 0,
+ value: 0
+ },
+
+ _create : function() {
+ this.listControl = this.element;
+ this.element.html("");
+ var targetId = this.listControl.data('target');
+ var labelId = this.listControl.data('label');
+ this.target = $('#' + targetId);
+ this.label = $('#' + labelId);
+ this.selectDiv = this.listControl.parent().parent();
+ },
+
+ _setOption : function(key,value) {},
+
+ setData : function (options) {
+ var that = this;
+ var value = this.target.val();
+ var selectedClass = 'active';
+ var itemTag = 'li';
+
+ that.listControl.on('click', itemTag, function() {
+ that.listControl.children().removeClass(selectedClass);
+ that.listControl.addClass(selectedClass);
+ that.target.text($(this).text());
+ 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);
+ })
+ var isOpen = that.selectDiv.hasClass('open');
+ that.selectDiv.removeClass('open');
+ if (!isOpen) {
+ that.selectDiv.addClass('open');
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ });
+
+ that.target.keyup( function() {
+ that.listControl.html("");
+ var items = that._dataList(options);
+ $.each(items, function(index,item){
+ if (item.html().indexOf(that.target.val()) != -1) {
+ that.listControl.append(item);
+ }
+ });
+ if (that.listControl.html() === ''){
+ that.listControl.html(i18n['msg.storagepool.unvalid.path']);
+ }
+ });
+ },
+
+ _dataList : function (options) {
+ var item;
+ var itemTag = 'li';
+ var selectedClass = 'active';
+ var items = [];
+ var that = this;
+ $.each(options, function(index, option) {
+ item = $('<' + itemTag + '></' + itemTag + '>');
+ item.text(option.label);
+ item.data('value', option.value);
+ if(option.value === that.target.val()) {
+ item.addClass(selectedClass);
+ }
+ items.push(item);
+ });
+ return items;
+ },
+
+ destroy : function() {
+ // call the base destroy function
+ $.Widget.prototype.destroy.call(this);
+ }
+ });
+}(jQuery));
\ No newline at end of file
--
1.7.1
11 years
[PATCH V1 1/2] Add nfs server and target UI in create storage pool
by zhoumeina
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.
Signed-off-by: zhoumeina <zhoumein(a)linux.vnet.ibm.com>
---
ui/css/theme-default/button.css | 11 +++----
ui/css/theme-default/form.css | 6 ++++
ui/css/theme-default/storage.css | 4 +-
ui/js/Makefile.am | 4 +-
ui/js/src/kimchi.api.js | 26 +++++++++++++++++-
ui/js/src/kimchi.storagepool_add_main.js | 43 ++++++++++++++++++++++++++++++
ui/pages/i18n.html.tmpl | 4 ++-
ui/pages/storagepool-add.html.tmpl | 39 +++++++++++++++++++++------
8 files changed, 116 insertions(+), 21 deletions(-)
diff --git a/ui/css/theme-default/button.css b/ui/css/theme-default/button.css
index c7ed3f6..f99679a 100644
--- a/ui/css/theme-default/button.css
+++ b/ui/css/theme-default/button.css
@@ -247,17 +247,16 @@
.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;
+ background: #fff;
box-shadow: -1px -1px 1px #666, 1px 1px 1px #fff, 2px 2px 2px rgba(0, 0, 0, .15) inset;
font-size: 13px;
- line-height: 38px;
+ line-height: 30px;
text-align: left;
cursor: pointer;
}
@@ -269,8 +268,8 @@
.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 c24b277..9db4bba 100644
--- a/ui/css/theme-default/form.css
+++ b/ui/css/theme-default/form.css
@@ -45,3 +45,9 @@
line-height: 30px;
padding: 0 5px;
}
+
+.text-help {
+ font-size: 12px;
+ color: #333;
+ margin: 0 0 5px 5px;
+}
diff --git a/ui/css/theme-default/storage.css b/ui/css/theme-default/storage.css
index d81dc75..ae89f1b 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,7 +548,7 @@
.storage-type-wrapper-controls > .dropdown {
margin: 5px 0 0 1px;
- width: 250px;
+ width: 150px;
}
.storage-type-wrapper-controls input[type="text"][disabled] {
diff --git a/ui/js/Makefile.am b/ui/js/Makefile.am
index 337e369..8dfd4d6 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
@@ -32,7 +32,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 fbcf4a2..46072cd 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -681,5 +681,29 @@ 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?type=' + type;
+ kimchi.requestJSON({
+ url : url,
+ type : 'GET',
+ contentType : 'application/json',
+ dataType : 'json',
+ success : suc,
+ error : err
+ });
}
-};
+};
\ No newline at end of file
diff --git a/ui/js/src/kimchi.storagepool_add_main.js b/ui/js/src/kimchi.storagepool_add_main.js
index b31610a..fb6ec89 100644
--- a/ui/js/src/kimchi.storagepool_add_main.js
+++ b/ui/js/src/kimchi.storagepool_add_main.js
@@ -52,6 +52,22 @@ kimchi.initStorageAddPage = function() {
$('.host-partition').html(listHtml);
}
kimchi.select('storagePool-list', options);
+ kimchi.getStorageServers('netfs', function(data) {
+ var serverContent = [];
+ serverContent.push({
+ label : i18n['select_default'],
+ value : ''
+ });
+ if (data.length > 0) {
+ $.each(data, function(index, value) {
+ serverContent.push({
+ label : value,
+ value : value
+ });
+ });
+ }
+ kimchi.select('nfs-server-used', serverContent);
+ });
$('#poolType').change(function() {
if ($(this).val() === 'dir') {
$('.path-section').removeClass('tmpl-html');
@@ -67,6 +83,33 @@ kimchi.initStorageAddPage = function() {
$('.nfs-section').addClass('tmpl-html');
}
});
+ $('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');
+ }
+ });
+ $('#nfsServerSelect').change(function() {
+ $('#nfsserverId').val($(this).val());
+ });
+ $('#nfsserverId').blur(function() {
+ kimchi.getStorageTargets($(this).val(),'netfs', function(data) {
+ var serverContent = [];
+ if (data.length > 0) {
+ $.each(data, function(index, value) {
+ serverContent.push({
+ label : value,
+ value : value
+ });
+ });
+ }
+ $('#nfs-server-target').filterselect();
+ $('#nfs-server-target').filterselect("setData",options);
+ });
+ });
});
};
diff --git a/ui/pages/i18n.html.tmpl b/ui/pages/i18n.html.tmpl
index c1fc3d1..222459e 100644
--- a/ui/pages/i18n.html.tmpl
+++ b/ui/pages/i18n.html.tmpl
@@ -121,7 +121,9 @@ var i18n = {
'action_create': "$_("Create")",
'msg_warning': "$_("Warning")",
'msg.logicalpool.confirm.delete': "$_("It will format your disk and you will loose any data in"
- " there, are you sure to continue? ")"
+ " there, are you sure to continue? ")",
+ 'select_default': "$_("Please choose")",
+ 'msg.storagepool.unvalid.path': "$_("This is not a valid path")"
};
</script>
</body>
diff --git a/ui/pages/storagepool-add.html.tmpl b/ui/pages/storagepool-add.html.tmpl
index 5a2dd45..2b522ff 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: 600px;">
+ <div class="window" style="width: 800px; height: 600px;">
<header>
<h1 class="title">$_("Define a New Storage Pool")</h1>
<div class="close">X</div>
@@ -47,7 +47,7 @@
<section class="form-section">
<h2>2. $_("Storage Pool Type")</h2>
<div class="storage-type-wrapper-controls">
- <div class="btn dropdown popable">
+ <div class="btn-select 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%">
@@ -74,22 +74,43 @@
<section class="form-section">
<h2>3. $_("NFS server IP")</h2>
<div class="field">
+ <input type="radio" id="nfsServerInput" value="input" name="nfsServerType" checked="true">
+ <label>$_("I want to input the server myself.")</label>
+ <input type="radio" id="nfsServerChoose" value="choose" name="nfsServerType">
+ <label>$_("I want to choose a server I used before.")</label>
+ </div>
+ <div id="nfsServerInputDiv" class="field">
<p class="text-help">
$_("NFS server IP or hostname. It should not be empty.")</p>
<input id="nfsserverId" type="text" class="text"
style="width: 300px">
</div>
+ <div id="nfsServerChooseDiv" class="field tmpl-html" style="overflow:visible">
+ <p class="text-help">
+ $_("Please choose the nfs server you want to create storage pool.")</p>
+ <div class="btn-select dropdown" style="width: 285px">
+ <input id="nfsServerSelect" type="hidden"/>
+ <span class="text" id="nfs-server-label"></span><span class="arrow"></span>
+ <div class="popover" style="width: 100%">
+ <ul class="select-list" id="nfs-server-used" data-target="nfsServerSelect" data-label="nfs-server-label">
+ </ul>
+ </div>
+ </div>
+ </div>
</section>
<section class="form-section">
<h2>4. $_("NFS Path")</h2>
- <div class="field">
+ <div class="field" style="overflow:visible">
<p class="text-help">$_("The nfs exported path on nfs server")</p>
- <input id="nfspathId" type="text" class="text"
- style="width: 300px">
- <input type="hidden" id="localpathId" class="text"
- value="none">
- </div>
- <div class="clear"></div>
+ <div class="btn-select dropdown popable" style="width: 285px">
+ <input id="nfspathId" class="text" style="width:293px;"/>
+ <span class="text" id="nfs-target-label"></span><span class="arrow"></span>
+ <div class="popover" style="width: 100%">
+ <ul class="select-list" id="nfs-server-target" data-target="nfspathId" data-label="nfs-target-label">
+ </ul>
+ </div>
+ </div>
+ </div>
</section>
</div>
<div class="logical-section tmpl-html">
--
1.7.1
11 years
[PATCH V1 0/2] Add the nfs pool server and target select UI(new jquery widget)
by zhoumeina
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.
zhoumeina (2):
Add nfs server and target UI in create storage pool
Add a new jquery filter-select widget
ui/css/theme-default/button.css | 11 ++--
ui/css/theme-default/form.css | 6 ++
ui/css/theme-default/storage.css | 4 +-
ui/js/Makefile.am | 4 +-
ui/js/src/kimchi.api.js | 26 +++++++-
ui/js/src/kimchi.storagepool_add_main.js | 43 ++++++++++++
ui/js/widgets/filter-select.js | 110 ++++++++++++++++++++++++++++++
ui/pages/i18n.html.tmpl | 4 +-
ui/pages/storagepool-add.html.tmpl | 39 ++++++++---
9 files changed, 226 insertions(+), 21 deletions(-)
create mode 100644 ui/js/widgets/filter-select.js
11 years
[PATCH 00/16] Reorganize controller module
by Aline Manera
From: Aline Manera <alinefm(a)br.ibm.com>
The current implemenation put all resources implementation into controller.py
file. That way this file tends to increase to infinity as more resources are
added to Kimchi.
This patch splits controller module (controller.py) into small modules.
So each resource will have its own controller implementation under /control
It will make maintenance easier and anyone can easily identify where any resource
is implemented.
This patch set does not change any logic - just move classes from controller
to a new module.
Aline Manera (16):
Move generate_action_handler() function to Resource() class
Move common functions for Resource and Collection to control/utils.py
Move login() and logout() functions from controller.py to root.py
Move basic controller resources to control/base.py
Move all resources related to vms to control/vms.py
Move all resources related to templates to control/templates.py
Move all resources related to debug reports to
control/debugreports.py
Move all resources related to storage pools to
control/storagepools.py
Move all resources related to storage volume to
control/storagevolumes.py
Move all resources related to interfaces to control/interfaces.py
Move all resources related to networks to control/networks.py
Move all resources related to config to control/config.py
Move all resources related to host to control/host.py
Move all resources related to plugins to control/plugins.py
Move all resources related to tasks to control/tasks.py
Use new control modules in root.py
Makefile.am | 13 +
src/kimchi/control/__init__.py | 21 +
src/kimchi/control/base.py | 290 +++++++++++++
src/kimchi/control/config.py | 65 +++
src/kimchi/control/debugreports.py | 52 +++
src/kimchi/control/host.py | 61 +++
src/kimchi/control/interfaces.py | 44 ++
src/kimchi/control/networks.py | 48 +++
src/kimchi/control/plugins.py | 44 ++
src/kimchi/control/storagepools.py | 125 ++++++
src/kimchi/control/storagevolumes.py | 79 ++++
src/kimchi/control/tasks.py | 41 ++
src/kimchi/control/templates.py | 51 +++
src/kimchi/control/utils.py | 103 +++++
src/kimchi/control/vms.py | 64 +++
src/kimchi/controller.py | 755 ----------------------------------
src/kimchi/root.py | 61 ++-
17 files changed, 1147 insertions(+), 770 deletions(-)
create mode 100644 src/kimchi/control/__init__.py
create mode 100644 src/kimchi/control/base.py
create mode 100644 src/kimchi/control/config.py
create mode 100644 src/kimchi/control/debugreports.py
create mode 100644 src/kimchi/control/host.py
create mode 100644 src/kimchi/control/interfaces.py
create mode 100644 src/kimchi/control/networks.py
create mode 100644 src/kimchi/control/plugins.py
create mode 100644 src/kimchi/control/storagepools.py
create mode 100644 src/kimchi/control/storagevolumes.py
create mode 100644 src/kimchi/control/tasks.py
create mode 100644 src/kimchi/control/templates.py
create mode 100644 src/kimchi/control/utils.py
create mode 100644 src/kimchi/control/vms.py
delete mode 100644 src/kimchi/controller.py
--
1.7.10.4
11 years
[PATCH V3 0/3] check and set search permission for a directory
by shaohef@linux.vnet.ibm.com
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
V2 -> V3
read the quem process pid from pid file instead of from iterating the
process list.
V1 -> V2
resend: qemu user tests
rebase: add a method to fix search permissions
ShaoHe Feng (3):
move RollbackContext from tests/utils to src/kimchi/utils
qemu user tests: probe the username of qemu process started by libvirt
add a method to fix search permissions
src/kimchi/kvmusertests.py | 66 ++++++++++++++++++
src/kimchi/utils.py | 162 ++++++++++++++++++++++++++++++++++++++++++++-
tests/utils.py | 47 +------------
3 files changed, 229 insertions(+), 46 deletions(-)
create mode 100644 src/kimchi/kvmusertests.py
--
1.8.4.2
11 years
RFC: If we want to import third-part widgets to enhance kimchi UI
by zhoumeina
As we know that as the development of kimchi UI, more and more new
feature merged. And we need more UI widgets to support our feature. Just
like charts, tooltips, filter select
and so on. and also will be more complex.
And our way to solve this problem is trying to make a widget by css, do
we want to continue this way?
or trying to find some common jquery third-part widget?
Appreciate anycomments.
<http://fanyi.baidu.com/###>
Appreciate anycomments
11 years