[PATCH] API.json: allow scsi storage devices
by Daniel Henrique Barboza
Kimchi does not allow scsi devices to be attached in a VM (devices
with names sdb,sdc ...). A simple change in API.json regex of
vmstorages_create fixes it.
Signed-off-by: Daniel Henrique Barboza <danielhb(a)linux.vnet.ibm.com>
---
src/kimchi/API.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json
index 1319531..4a3cd03 100644
--- a/src/kimchi/API.json
+++ b/src/kimchi/API.json
@@ -489,7 +489,7 @@
"dev": {
"description": "The storage device name",
"type": "string",
- "pattern": "^h|vd[b-z]$",
+ "pattern": "^h|s|vd[b-z]$",
"error": "KCHVMSTOR0001E"
},
"type": {
--
1.8.3.1
10 years, 3 months
[PATCH] Adjustments on upload/download UI
by Aline Manera
- Set dataType (dataType: 'json') instead of add Accept header
- Use .show() and .hide() to display or not the "Add Volume button"
- Allow any type of file to be uploaded
- Change upload/download handlers to query for running Tasks while
listing storage volumes in a pool
That way all users get the same view when a storage volume is being
downloaded or uploaded
This patch set was made based on:
[Kimchi-devel] [PATCH v2 0/4] UI:Download Remote Image Feature
Signed-off-by: Aline Manera <alinefm(a)linux.vnet.ibm.com>
---
ui/js/src/kimchi.api.js | 4 +-
ui/js/src/kimchi.storage_main.js | 195 +++++++++++++++---------
ui/js/src/kimchi.storagepool_add_volume_main.js | 154 ++-----------------
3 files changed, 131 insertions(+), 222 deletions(-)
diff --git a/ui/js/src/kimchi.api.js b/ui/js/src/kimchi.api.js
index 0e27987..3398bd4 100644
--- a/ui/js/src/kimchi.api.js
+++ b/ui/js/src/kimchi.api.js
@@ -1156,9 +1156,7 @@ var kimchi = {
data : fd,
processData : false,
contentType : false,
- headers : {
- Accept : 'application/json; charset=utf-8'
- },
+ dataType: 'json',
success : suc,
error : err
});
diff --git a/ui/js/src/kimchi.storage_main.js b/ui/js/src/kimchi.storage_main.js
index 6c1aade..910f08d 100644
--- a/ui/js/src/kimchi.storage_main.js
+++ b/ui/js/src/kimchi.storage_main.js
@@ -42,7 +42,6 @@ kimchi.doListStoragePools = function() {
}, function(err) {
kimchi.message.error(err.responseJSON.reason);
});
-
}
kimchi.storageBindClick = function() {
@@ -85,10 +84,10 @@ kimchi.storageBindClick = function() {
$(this).data('type') !== 'iscsi' &&
$(this).data('type') !== 'scsi';
if(canAddVolume) {
- $(this).removeClass('hidden');
+ $(this).show();
}
else {
- $(this).addClass('hidden');
+ $(this).hide();
}
});
@@ -198,33 +197,80 @@ kimchi._generateVolumeHTML = function(volume) {
return kimchi.substitute(volumeHtml, volume);
};
-kimchi._updateVolumeBoxUI = function(box, volume) {
- var html = kimchi._generateVolumeHTML(volume);
- $(box).replaceWith(html);
-};
-
kimchi.doListVolumes = function(poolObj) {
- var volumeDiv = $('#volume' + poolObj.data('name'));
+ var poolName = poolObj.data('name')
+
+ var getOngoingVolumes = function() {
+ var result = {}
+ var filter = 'status=running&target_uri=' + encodeURIComponent('^/storagepools/' + poolName + '/*')
+ kimchi.getTasksByFilter(filter, function(tasks) {
+ for(var i = 0; i < tasks.length; i++) {
+ var volumeName = tasks[i].target_uri.split('/').pop();
+ result[volumeName] = tasks[i];
+
+ if(kimchi.trackingTasks.indexOf(tasks[i].id) >= 0) {
+ continue;
+ }
+
+ kimchi.trackTask(tasks[i].id, function(result) {
+ kimchi.topic('kimchi/volumeTransferFinished').publish(result);
+ }, function(result) {
+ kimchi.topic('kimchi/volumeTransferError').publish(result);
+ }, function(result) {
+ kimchi.topic('kimchi/volumeTransferProgress').publish(result);
+ });
+ }
+ }, null, true);
+ return result;
+ };
+
+ var volumeDiv = $('#volume' + poolName);
$(volumeDiv).empty();
var slide = poolObj.next('.volumes');
var handleArrow = poolObj.children().last().children();
- kimchi.listStorageVolumes(poolObj.data('name'), function(result) {
- var volumeHtml = $('#volumeTmpl').html();
- if (result) {
- if (result.length) {
- var listHtml = '';
- $.each(result, function(index, value) {
- value.poolname = poolObj.data('name');
- listHtml += kimchi._generateVolumeHTML(value);
- });
- volumeDiv.html(listHtml);
- } else {
- volumeDiv.html("<div class='pool-empty'>" + i18n['KCHPOOL6002M'] + "</div>");
+
+ kimchi.listStorageVolumes(poolName, function(result) {
+ var listHtml = '';
+ var ongoingVolumes = [];
+ var ongoingVolumesMap = getOngoingVolumes();
+ $.each(ongoingVolumesMap, function(volumeName, task) {
+ ongoingVolumes.push(volumeName)
+ var volume = {
+ poolName: poolName,
+ ref_cnt: 0,
+ capacity: 0,
+ name: volumeName,
+ format: '',
+ bootable: null,
+ os_distro: '',
+ allocation: 0,
+ os_version: '',
+ path: '',
+ type: 'file'
+ };
+ listHtml += kimchi._generateVolumeHTML(volume);
+ });
+
+ $.each(result, function(index, value) {
+ if (ongoingVolumes.indexOf(value.name) == -1) {
+ value.poolname = poolName;
+ listHtml += kimchi._generateVolumeHTML(value);
}
- poolObj.removeClass('in');
- kimchi.changeArrow(handleArrow);
- slide.slideDown('slow');
+ });
+
+ if (listHtml.length > 0) {
+ volumeDiv.html(listHtml);
+ } else {
+ volumeDiv.html("<div class='pool-empty'>" + i18n['KCHPOOL6002M'] + "</div>");
}
+
+ $.each(ongoingVolumesMap, function(volumeName, task) {
+ kimchi.topic('kimchi/volumeTransferProgress').publish(task);
+ });
+
+ poolObj.removeClass('in');
+ kimchi.changeArrow(handleArrow);
+ slide.slideDown('slow');
}, function(err) {
kimchi.message.error(err.responseJSON.reason);
});
@@ -285,74 +331,75 @@ kimchi.storage_main = function() {
kimchi.doListStoragePools();
kimchi.initLogicalPoolExtend();
- kimchi.topic('kimchi/allVolumeTasksFinished').subscribe(function(data) {
- var sp = data['sp'];
- var poolNode = $('.storage-li[data-name="' + sp + '"]');
+ kimchi.topic('kimchi/storageVolumeAdded').subscribe(function() {
+ pool = kimchi.selectedSP;
+ var poolNode = $('.storage-li[data-name="' + pool + '"]');
kimchi.doListVolumes(poolNode);
});
- kimchi.topic('kimchi/volumeTransferStarted').subscribe(function(data) {
- var sp = data['sp'],
- type = data['type'],
- volumeName = data['volume'];
- var volumesContainer = $('#volume' + sp);
- var volume = {
- poolName: sp,
- ref_cnt: 0,
- capacity: 0,
- name: volumeName,
- format: '',
- bootable: true,
- os_distro: '',
- allocation: 0,
- os_version: '',
- path: '',
- type: 'file'
+ kimchi.topic('kimchi/volumeTransferProgress').subscribe(function(result) {
+ var extractProgressData = function(data) {
+ var sizeArray = /(\d+)\/(\d+)/g.exec(data) || [0, 0, 0];
+ var downloaded = sizeArray[1];
+ var percent = 0;
+ if(downloaded) {
+ var total = sizeArray[2];
+ if(!isNaN(total)) {
+ percent = downloaded / total * 100;
+ }
+ }
+ var formatted = kimchi.formatMeasurement(downloaded);
+ var size = (1.0 * formatted['v']).toFixed(1) + formatted['s'];
+ return {
+ size: size,
+ percent: percent
+ };
};
- if($('.volume-box', volumesContainer).length === 0) {
- volumesContainer.empty();
- }
- volumesContainer.prepend(kimchi._generateVolumeHTML(volume));
- var volumeBox = $('#volume' + sp + ' [data-volume-name="' + volumeName + '"]');
- $('.volume-progress', volumeBox).removeClass('hidden');
- $('.progress-status', volumeBox).text(
- type === 'download' ? i18n['KCHPOOL6014M'] : i18n['KCHPOOL6017M']
- );
- });
- kimchi.topic('kimchi/volumeTransferProgress').subscribe(function(data) {
- var sp = data['sp'],
- type = data['type'],
- volumeName = data['volume'],
- size = data['size'],
- percent = data['percent'];
- volumeBox = $('#volume' + sp + ' [data-volume-name="' + volumeName + '"]');
+ var uriElements = result.target_uri.split('/');
+ var poolName = uriElements[2];
+ var volumeName = uriElements.pop();
+ var progress = extractProgressData(result['message']);
+ var size = progress['size'];
+ var percent = progress['percent'];
+
+ volumeBox = $('#volume' + poolName + ' [data-volume-name="' + volumeName + '"]');
$('.progress-bar-inner', volumeBox).css({
width: percent + '%'
});
- $('.progress-status', volumeBox).text(
- type === 'download' ? i18n['KCHPOOL6014M'] : i18n['KCHPOOL6017M']
- );
$('.progress-transferred', volumeBox).text(size);
$('.volume-progress', volumeBox).removeClass('hidden');
});
- kimchi.topic('kimchi/volumeTransferFinished').subscribe(function(data) {
- var sp = data['sp'],
- volumeName = data['volume'],
- volumeBox = $('#volume' + sp + ' [data-volume-name="' + volumeName + '"]');
+ kimchi.topic('kimchi/volumeTransferFinished').subscribe(function(result) {
+ var uriElements = result.target_uri.split('/');
+ var poolName = uriElements[2];
+ var volumeName = uriElements.pop();
+ var volumeBox = $('#volume' + poolName + ' [data-volume-name="' + volumeName + '"]');
$('.volume-progress', volumeBox).addClass('hidden');
- kimchi.getStoragePoolVolume(sp, volumeName, function(volume) {
- kimchi._updateVolumeBoxUI(volumeBox, volume);
+ kimchi.getStoragePoolVolume(poolName, volumeName, function(volume) {
+ var html = kimchi._generateVolumeHTML(volume);
+ $(volumeBox).replaceWith(html);
}, function(err) {
kimchi.message.error(err.responseJSON.reason);
});
});
- kimchi.topic('kimchi/volumeTransferError').subscribe(function(data) {
- var sp = data['sp'],
- volumeName = data['volume'],
- volumeBox = $('#volume' + sp + ' [data-volume-name="' + volumeName + '"]');
+ kimchi.topic('kimchi/volumeTransferError').subscribe(function(result) {
+ // Error message from Async Task status
+ if (result['message']) {
+ var errText = result['message'];
+ }
+ // Error message from standard kimchi exception
+ else {
+ var errText = result['responseJSON']['reason'];
+ }
+ result && kimchi.message.error(errText);
+
+ var uriElements = result.target_uri.split('/');
+ var poolName = uriElements[2];
+ var volumeName = uriElements.pop();
+ volumeBox = $('#volume' + poolName + ' [data-volume-name="' + volumeName + '"]');
$('.progress-status', volumeBox).text(i18n['KCHPOOL6016M']);
});
};
diff --git a/ui/js/src/kimchi.storagepool_add_volume_main.js b/ui/js/src/kimchi.storagepool_add_volume_main.js
index 9435e28..590ccde 100644
--- a/ui/js/src/kimchi.storagepool_add_volume_main.js
+++ b/ui/js/src/kimchi.storagepool_add_volume_main.js
@@ -31,8 +31,7 @@ kimchi.sp_add_volume_main = function() {
var isValidFile = function() {
var fileName = $(localFileBox).val();
- return fileName &&
- /[Ii][Ss][Oo]/g.test(fileName.split('.').pop());
+ return fileName.length > 0;
};
$(typeRadios).change(function(event) {
@@ -55,142 +54,6 @@ kimchi.sp_add_volume_main = function() {
$(addButton).prop('disabled', !isValidFile());
});
- if(!kimchi.volumeTransferTracker) {
- kimchi.volumeTransferTracker = (function() {
- var tasks = {},
- sps = {};
- var addTask = function(task) {
- var taskID = task['id'];
- tasks[taskID] = task;
- var sp = task['sp'];
- if(sps[sp] === undefined) {
- sps[sp] = 1;
- }
- else {
- sps[sp]++;
- }
- };
- var getTask = function(taskID) {
- return tasks[taskID];
- };
- var removeTask = function(task) {
- var taskID = task['id'];
- var sp = tasks[taskID]['sp'];
- delete tasks[taskID];
- if(--sps[sp] === 0) {
- delete sps[sp];
- kimchi.topic('kimchi/allVolumeTasksFinished').publish({
- sp: sp
- });
- }
- };
- return {
- add: addTask,
- get: getTask,
- remove: removeTask
- };
- })();
- }
- var taskTracker = kimchi.volumeTransferTracker;
-
- var makeCallback = function(trackType, sp, transType, callback) {
- return function(resp) {
- var taskID = resp['id'];
- var volumeName = resp['target_uri'].split('/').pop();
- if(trackType === 'add') {
- taskTracker.add({
- id: taskID,
- sp: sp,
- volume: volumeName
- });
- }
- callback(transType, resp);
- };
- };
-
- var extractProgressData = function(data) {
- var sizeArray = /(\d+)\/(\d+)/g.exec(data) || [0, 0, 0];
- var downloaded = sizeArray[1];
- var percent = 0;
- if(downloaded) {
- var total = sizeArray[2];
- if(!isNaN(total)) {
- percent = downloaded / total * 100;
- }
- }
- var formatted = kimchi.formatMeasurement(downloaded);
- var size = (1.0 * formatted['v']).toFixed(1) + formatted['s'];
- return {
- size: size,
- percent: percent
- };
- };
-
- var onFinished = function(type, result) {
- var progress = extractProgressData(resp['message']);
- var task = taskTracker.get([result['id']]);
- kimchi.topic('kimchi/volumeTransferFinished').publish($.extend(progress, {
- sp: task['sp'],
- type: type,
- volume: task['volume']
- }));
- taskTracker.remove({
- id: result['id']
- });
- };
-
- var onProgress = function(type, resp) {
- var progress = extractProgressData(resp['message']);
- var task = taskTracker.get([resp['id']]);
- kimchi.topic('kimchi/volumeTransferProgress').publish($.extend(progress, {
- sp: task['sp'],
- type: type,
- volume: task['volume']
- }));
- };
-
- var onTransferError = function(type, result) {
- if(!result) {
- return;
- }
- var msg = result && (result['message'] || (
- result['responseJSON'] && result['responseJSON']['reason'])
- );
- kimchi.message.error(msg);
-
- if(!result['target_uri']) {
- return;
- }
- var task = taskTracker.get(result['id']);
- kimchi.topic('kimchi/volumeTransferError').publish({
- sp: task['sp'],
- type: type,
- volume: task['volume']
- });
- taskTracker.remove({
- id: result['id']
- });
- };
-
- var onAccepted = function(type, resp) {
- var taskID = resp['id'];
- var task = taskTracker.get(taskID);
- kimchi.window.close();
- kimchi.topic('kimchi/volumeTransferStarted').publish({
- sp: task['sp'],
- type: type,
- volume: task['volume']
- });
-
- kimchi.trackTask(taskID, function(resp) {
- onFinished(type, resp);
- }, function(resp) {
- onTransferError(type, resp);
- }, function(resp) {
- onProgress(type, resp);
- });
- };
-
var onError = function(result) {
$(this).prop('disabled', false);
$(typeRadios).prop('disabled', false);
@@ -208,11 +71,11 @@ kimchi.sp_add_volume_main = function() {
var volumeName = volumeURL.split(/(\\|\/)/g).pop();
kimchi.downloadVolumeToSP({
sp: kimchi.selectedSP,
- name: volumeName,
url: volumeURL
- }, makeCallback('add', kimchi.selectedSP, 'download', onAccepted),
- onError
- );
+ }, function(result) {
+ kimchi.window.close();
+ kimchi.topic('kimchi/storageVolumeAdded').publish();
+ }, onError);
};
var uploadFile = function() {
@@ -224,9 +87,10 @@ kimchi.sp_add_volume_main = function() {
kimchi.uploadVolumeToSP({
sp: kimchi.selectedSP,
formData: fd
- }, makeCallback('add', kimchi.selectedSP, 'upload', onAccepted),
- onError
- );
+ }, function(result) {
+ kimchi.window.close();
+ kimchi.topic('kimchi/storageVolumeAdded').publish();
+ }, onError);
};
$(addButton).on('click', function(event) {
--
1.9.3
10 years, 3 months
[PATCH] bug fix: Pass the right data format to run_command()
by Aline Manera
run_command() expects a list of command and arguments instead of a
string.
Fix it to avoid error on Kimchi start up on openSUSE systems:
[Errno 2] No such file or directory
Failed to run command: z y p p e r - - h e l p.
Signed-off-by: Aline Manera <alinefm(a)linux.vnet.ibm.com>
---
src/kimchi/swupdate.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/kimchi/swupdate.py b/src/kimchi/swupdate.py
index 5ea36f1..5b24ce0 100644
--- a/src/kimchi/swupdate.py
+++ b/src/kimchi/swupdate.py
@@ -56,7 +56,7 @@ class SoftwareUpdate(object):
kimchi_log.info("Loading AptUpdate features.")
self._pkg_mnger = AptUpdate()
except ImportError:
- zypper_help = "zypper --help"
+ zypper_help = ["zypper", "--help"]
(stdout, stderr, returncode) = run_command(zypper_help)
if returncode == 0:
kimchi_log.info("Loading ZypperUpdate features.")
--
1.9.3
10 years, 3 months
[PATCH] python 2.6 compatibility: Use 'with' statement only with one context
by Aline Manera
python 2.6 does not allow specifying multiple contexts in one 'with'
statement. And it is used by RHEL6.5
Fix it by specifying just one context per 'with' statement.
Signed-off-by: Aline Manera <alinefm(a)linux.vnet.ibm.com>
---
src/kimchi/model/storagevolumes.py | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/src/kimchi/model/storagevolumes.py b/src/kimchi/model/storagevolumes.py
index 4d0c231..50055a3 100644
--- a/src/kimchi/model/storagevolumes.py
+++ b/src/kimchi/model/storagevolumes.py
@@ -168,24 +168,24 @@ class StorageVolumesModel(object):
pool = pool_model.lookup(pool_name)
file_path = os.path.join(pool['path'], name)
- with contextlib.closing(urllib2.urlopen(url)) as response,\
- open(file_path, 'w') as volume_file:
- remote_size = response.info().getheader('Content-Length', '-')
- downloaded_size = 0
+ with contextlib.closing(urllib2.urlopen(url)) as response:
+ with open(file_path, 'w') as volume_file:
+ remote_size = response.info().getheader('Content-Length', '-')
+ downloaded_size = 0
- try:
- while True:
- chunk_data = response.read(READ_CHUNK_SIZE)
- if not chunk_data:
- break
-
- volume_file.write(chunk_data)
- downloaded_size += len(chunk_data)
- cb('%s/%s' % (downloaded_size, remote_size))
- except Exception, e:
- raise OperationFailed('KCHVOL0007E', {'name': name,
- 'pool': pool_name,
- 'err': e.message})
+ try:
+ while True:
+ chunk_data = response.read(READ_CHUNK_SIZE)
+ if not chunk_data:
+ break
+
+ volume_file.write(chunk_data)
+ downloaded_size += len(chunk_data)
+ cb('%s/%s' % (downloaded_size, remote_size))
+ except Exception, e:
+ raise OperationFailed('KCHVOL0007E', {'name': name,
+ 'pool': pool_name,
+ 'err': e.message})
StoragePoolModel.get_storagepool(pool_name, self.conn).refresh()
cb('OK', True)
--
1.9.3
10 years, 3 months
[PATCH 0/4] UI: Download Remote Image Feature
by Hongliang Wang
Implemented download remote image feature.
Seems something wrong with /tasks response. The "message" is always "OK" and
I can't retrieve the progress information.
Dependancies:
* [PATCH] storagevolume: Use default value for param 'name' when appropriate
Hongliang Wang (4):
Download Remote Image UI: Add Common API to kimchi.api.js
Download Remote Image UI: Add Corresponding Window
Download Remote Image UI: Updated i18n Strings
Download Remote Image UI: Implemented the Feature
ui/css/theme-default/storage.css | 31 ++++++-
ui/css/theme-default/storagepool-add-volume.css | 36 ++++++++
ui/js/src/kimchi.api.js | 49 +++++++++++
ui/js/src/kimchi.storage_main.js | 77 +++++++++++++++--
ui/js/src/kimchi.storagepool_add_volume_main.js | 110 ++++++++++++++++++++++++
ui/pages/i18n.json.tmpl | 3 +
ui/pages/storagepool-add-volume.html.tmpl | 80 +++++++++++++++++
ui/pages/tabs/storage.html.tmpl | 12 ++-
8 files changed, 388 insertions(+), 10 deletions(-)
create mode 100644 ui/css/theme-default/storagepool-add-volume.css
create mode 100644 ui/js/src/kimchi.storagepool_add_volume_main.js
create mode 100644 ui/pages/storagepool-add-volume.html.tmpl
--
1.8.1.4
10 years, 3 months
[PATCH 0/2 V2] Update messages and po files
by Aline Manera
Aline Manera (2):
Update messages
Update po files according to Transifex translations.
po/de_DE.po | 201 +++++----
po/en_US.po | 1106 ++++++++++++++++++++++-------------------------
po/es_ES.po | 203 +++++----
po/fr_FR.po | 1087 +++++++++++++++++++++++-----------------------
po/it_IT.po | 204 +++++----
po/ja_JP.po | 204 +++++----
po/kimchi.pot | 134 ++++--
po/ko_KR.po | 206 +++++----
po/pt_BR.po | 624 ++++++++++++++------------
po/ru_RU.po | 245 ++++++-----
po/zh_CN.po | 209 +++++----
po/zh_TW.po | 478 ++++++--------------
src/kimchi/i18n.py | 68 +--
ui/pages/i18n.json.tmpl | 22 +-
14 files changed, 2504 insertions(+), 2487 deletions(-)
--
1.9.3
10 years, 3 months
[PATCH v2] storagevolume: Use default value for param 'name' when appropriate
by Crístian Viana
The changelog from the previous patchset (v1) is:
- Update the default name method when uploading a file.
- Add a default name method for an unexpected operation based on the current time.
- Rebase to the latest commit.
Crístian Viana (1):
storagevolume: Use default value for param 'name' when appropriate
src/kimchi/API.json | 2 --
src/kimchi/mockmodel.py | 24 ++++++++++++++++++-----
src/kimchi/model/storagevolumes.py | 32 ++++++++++++++++++++++++++-----
tests/test_model.py | 18 ++++++++++++------
tests/test_rest.py | 39 +++++++++++++++++++++-----------------
5 files changed, 80 insertions(+), 35 deletions(-)
--
1.9.3
10 years, 3 months
[PATCH] storagevolume: Use default value for param 'name' when appropriate
by Crístian Viana
The parameter 'name' is only required when creating storage volumes with
the parameter 'capacity' (i.e. an empty volume). When creating volumes
with 'url' or 'file', the volume name will have a default value if 'name'
is not specified.
Use a default name when creating storage volumes from a file or from a URL.
The default name will be the file's or the URL's basename.
Signed-off-by: Crístian Viana <vianac(a)linux.vnet.ibm.com>
---
src/kimchi/API.json | 2 --
src/kimchi/mockmodel.py | 19 ++++++++++++++-----
src/kimchi/model/storagevolumes.py | 26 +++++++++++++++++++++-----
tests/test_model.py | 17 +++++++++++------
tests/test_rest.py | 16 ++++++++++++----
5 files changed, 58 insertions(+), 22 deletions(-)
diff --git a/src/kimchi/API.json b/src/kimchi/API.json
index 8a95804..1319531 100644
--- a/src/kimchi/API.json
+++ b/src/kimchi/API.json
@@ -156,13 +156,11 @@
},
"storagevolumes_create": {
"type": "object",
- "error": "KCHVOL0016E",
"properties": {
"name": {
"description": "The name of the Storage Volume",
"type": "string",
"minLength": 1,
- "required": true,
"error": "KCHVOL0013E"
},
"capacity": {
diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py
index 15a75af..ef09a5b 100644
--- a/src/kimchi/mockmodel.py
+++ b/src/kimchi/mockmodel.py
@@ -482,8 +482,9 @@ class MockModel(object):
def storagevolumes_create(self, pool_name, params):
vol_source = ['file', 'url', 'capacity']
+ require_name_params = ['capacity']
- name = params['name']
+ name = params.get('name')
index_list = list(i for i in range(len(vol_source))
if vol_source[i] in params)
@@ -491,12 +492,20 @@ class MockModel(object):
raise InvalidParameter("KCHVOL0018E",
{'param': ",".join(vol_source)})
+ create_param = vol_source[index_list[0]]
+
+ if name is None:
+ if create_param in require_name_params:
+ raise InvalidParameter('KCHVOL0016E')
+
+ name = os.path.basename(create_param)
+ params['name'] = name
+
try:
- create_func = getattr(self, "_create_volume_with_" +
- vol_source[index_list[0]])
+ create_func = getattr(self, '_create_volume_with_%s' %
+ create_param)
except AttributeError:
- raise InvalidParameter("KCHVOL0019E",
- {'param': vol_source[index_list[0]]})
+ raise InvalidParameter("KCHVOL0019E", {'param': create_param})
pool = self._get_storagepool(pool_name)
if pool.info['type'] in READONLY_POOL_TYPE:
diff --git a/src/kimchi/model/storagevolumes.py b/src/kimchi/model/storagevolumes.py
index ef8e684..ec610ac 100644
--- a/src/kimchi/model/storagevolumes.py
+++ b/src/kimchi/model/storagevolumes.py
@@ -44,6 +44,9 @@ VOLUME_TYPE_MAP = {0: 'file',
DOWNLOAD_CHUNK_SIZE = 1048576 # 1 MiB
+REQUIRE_NAME_PARAMS = ['capacity']
+
+
class StorageVolumesModel(object):
def __init__(self, **kargs):
self.conn = kargs['conn']
@@ -53,7 +56,7 @@ class StorageVolumesModel(object):
def create(self, pool_name, params):
vol_source = ['file', 'url', 'capacity']
- name = params['name']
+ name = params.get('name')
index_list = list(i for i in range(len(vol_source))
if vol_source[i] in params)
@@ -61,12 +64,25 @@ class StorageVolumesModel(object):
raise InvalidParameter("KCHVOL0018E",
{'param': ",".join(vol_source)})
+ create_param = vol_source[index_list[0]]
+
+ if name is None:
+ # the methods listed in 'REQUIRE_NAME_PARAMS' cannot have
+ # 'name' == None
+ if create_param in REQUIRE_NAME_PARAMS:
+ raise InvalidParameter('KCHVOL0016E')
+
+ # if 'name' is omitted - except for the methods listed in
+ # 'REQUIRE_NAME_PARAMS' - the default volume name will be the
+ # file/URL basename.
+ name = os.path.basename(create_param)
+ params['name'] = name
+
try:
- create_func = getattr(self, "_create_volume_with_" +
- vol_source[index_list[0]])
+ create_func = getattr(self, '_create_volume_with_%s' %
+ create_param)
except AttributeError:
- raise InvalidParameter("KCHVOL0019E",
- {'param': vol_source[index_list[0]]})
+ raise InvalidParameter("KCHVOL0019E", {'param': create_param})
pool_info = StoragePoolModel(conn=self.conn,
objstore=self.objstore).lookup(pool_name)
diff --git a/tests/test_model.py b/tests/test_model.py
index 4e9ba97..ecb0a8a 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -526,10 +526,13 @@ class ModelTests(unittest.TestCase):
vols = inst.storagevolumes_get_list(pool)
num = len(vols) + 2
- params = {'name': vol,
- 'capacity': 1024,
+ params = {'capacity': 1024,
'allocation': 512,
'format': 'raw'}
+ # 'name' is required for this type of volume
+ self.assertRaises(InvalidParameter, inst.storagevolumes_create,
+ pool, params)
+ params['name'] = vol
task_id = inst.storagevolumes_create(pool, params)['id']
self._wait_task(inst, task_id)
self.assertEquals('finished', inst.task_lookup(task_id)['status'])
@@ -560,20 +563,22 @@ class ModelTests(unittest.TestCase):
# download remote volume
# 1) try an invalid URL
- params = {'name': 'foo', 'url': 'http://www.invalid.url'}
+ params = {'url': 'http://www.invalid.url'}
taskid = inst.storagevolumes_create(pool, params)['id']
self._wait_task(inst, taskid)
self.assertEquals('failed', inst.task_lookup(taskid)['status'])
# 2) download Kimchi's "COPYING" from Github and compare its
# content to the corresponding local file's
url = 'https://github.com/kimchi-project/kimchi/raw/master/COPYING'
- params = {'name': 'copying', 'url': url}
- taskid = inst.storagevolumes_create(pool, params)['id']
+ params = {'url': url}
+ task_response = inst.storagevolumes_create(pool, params)
+ taskid = task_response['id']
+ vol_name = task_response['target_uri'].split('/')[-1]
self._wait_task(inst, taskid)
self.assertEquals('finished', inst.task_lookup(taskid)['status'])
rollback.prependDefer(inst.storagevolume_delete, pool,
params['name'])
- vol_path = os.path.join(args['path'], params['name'])
+ vol_path = os.path.join(args['path'], vol_name)
self.assertTrue(os.path.isfile(vol_path))
with open(vol_path) as vol_file:
vol_content = vol_file.read()
diff --git a/tests/test_rest.py b/tests/test_rest.py
index ae1c971..a3dcf87 100644
--- a/tests/test_rest.py
+++ b/tests/test_rest.py
@@ -489,6 +489,14 @@ class RestTests(unittest.TestCase):
resp = self.request('/storagepools/tmp/activate', req, 'POST')
self.assertEquals(200, resp.status)
+ # 'name' is required for this type of volume
+ req = json.dumps({'capacity': 1024,
+ 'allocation': 512,
+ 'type': 'disk',
+ 'format': 'raw'})
+ resp = self.request('/storagepools/tmp/storagevolumes',
+ req, 'POST')
+ self.assertEquals(400, resp.status)
req = json.dumps({'name': "attach-volume",
'capacity': 1024,
'allocation': 512,
@@ -1027,16 +1035,16 @@ class RestTests(unittest.TestCase):
self.assertEquals('/var/lib/libvirt/images/volume-1',
storagevolume['path'])
- req = json.dumps({'name': 'downloaded',
- 'url': 'https://anyurl.wor.kz'})
+ req = json.dumps({'url': 'https://anyurl.wor.kz'})
resp = self.request('/storagepools/pool-1/storagevolumes', req, 'POST')
self.assertEquals(202, resp.status)
task = json.loads(resp.read())
self._wait_task(task['id'])
task = json.loads(self.request('/tasks/%s' % task['id']).read())
self.assertEquals('finished', task['status'])
- resp = self.request('/storagepools/pool-1/storagevolumes/downloaded',
- '{}', 'GET')
+ vol_name = task['target_uri'].split('/')[-1]
+ resp = self.request('/storagepools/pool-1/storagevolumes/%s' %
+ vol_name, '{}', 'GET')
self.assertEquals(200, resp.status)
# Now remove the StoragePool from mock model
--
1.9.3
10 years, 3 months
Re: [Kimchi-devel] [kimchi] Kimchi failed to start on rhel 6 (#412)
by Yu Xin Huo
Still fail to start with new error below, updated #412, please fix it
and apply the fix asap.
Loaded plugins: ibm-check-lotus-updates, ibm-repository, refresh-packagekit,
: versionlock
Traceback (most recent call last):
File "./src/kimchid", line 95, in <module>
sys.exit(main(sys.argv[1:]))
File "./src/kimchid", line 92, in main
kimchi.server.main(options)
File "/root/codebase-kimchi/test/kimchi/src/kimchi/server.py", line
179, in main
srv = Server(options)
File "/root/codebase-kimchi/test/kimchi/src/kimchi/server.py", line
128, in __init__
model_instance = model.Model()
File "/root/codebase-kimchi/test/kimchi/src/kimchi/model/model.py",
line 58, in __init__
module = import_module('model.' + mod_name)
File "/root/codebase-kimchi/test/kimchi/src/kimchi/utils.py", line
139, in import_module
return __import__(module_name, globals(), locals(), [''])
File
"/root/codebase-kimchi/test/kimchi/src/kimchi/model/storagevolumes.py",
line 171
with contextlib.closing(urllib2.urlopen(url)) as response,\
^
SyntaxError: invalid syntax
On 9/11/2014 1:52 AM, Aline Manera wrote:
>
> Closed #412 <https://github.com/kimchi-project/kimchi/issues/412>.
>
> —
> Reply to this email directly or view it on GitHub
> <https://github.com/kimchi-project/kimchi/issues/412#event-163779687>.
>
10 years, 3 months
[PATCH 0/2] Update messages and po files
by Aline Manera
Aline Manera (2):
Update messages
Update po files according to Transifex translations.
po/de_DE.po | 201 +++++----
po/en_US.po | 1106 ++++++++++++++++++++++-------------------------
po/es_ES.po | 203 +++++----
po/fr_FR.po | 1087 +++++++++++++++++++++++-----------------------
po/it_IT.po | 204 +++++----
po/ja_JP.po | 204 +++++----
po/kimchi.pot | 134 ++++--
po/ko_KR.po | 206 +++++----
po/pt_BR.po | 624 ++++++++++++++------------
po/ru_RU.po | 245 ++++++-----
po/zh_CN.po | 209 +++++----
po/zh_TW.po | 478 ++++++--------------
src/kimchi/i18n.py | 68 +--
ui/pages/i18n.json.tmpl | 22 +-
14 files changed, 2504 insertions(+), 2487 deletions(-)
--
1.9.3
10 years, 3 months