[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": {
…
[View More] "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
[View Less]
10 years, 8 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 &…
[View More]lt;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
[View Less]
10 years, 8 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/…
[View More]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
[View Less]
10 years, 8 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/…
[View More]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
[View Less]
10 years, 8 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
…
[View More]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
[View Less]
10 years, 8 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 +++++----
…
[View More] 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
[View Less]
10 years, 8 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 ++++++++++++++++++++++++++-----
…
[View More]tests/test_model.py | 18 ++++++++++++------
tests/test_rest.py | 39 +++++++++++++++++++++-----------------
5 files changed, 80 insertions(+), 35 deletions(-)
--
1.9.3
[View Less]
10 years, 8 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/…
[View More]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
[View Less]
10 years, 8 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 = …
[View More]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>.
>
[View Less]
10 years, 8 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 +++++----
…
[View More] 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
[View Less]
10 years, 8 months