[PATCH v4 0/7] Async Disk Creation

If a guest has a large disk, and uses a filesystem that requires preallocation, it can take several minutes to create a VM. During that time, kimchi is tied up by the VM creation. This patch changes the VMs Collection to be an AsyncCollection. Another change required for this was to create a more granular way to query tasks. Currently it is not possible (using the API) to query tasks for the same collection or resource type that may have different operations. For example, VM cloning is also an asynchronous operation. For the guests tab, the UI was querying all running tasks and displaying them with the Cloning label. This picked up VMs that were being created as well. For more information about how the tasks can be queried, see the updated API doc and the UI change. Christy Perez (7): Granular Task Queries: Backend Granular task query test updates Granular Task Queries: UI Create guests asynchronously: Backend Async vm creation test updates VMs Async Create: UI Translation update to add 'Creating' docs/API.md | 16 ++++++ po/de_DE.po | 103 ++++++++++++++++++++----------------- po/en_US.po | 83 +++++++++++++++++------------- po/es_ES.po | 102 +++++++++++++++++++----------------- po/fr_FR.po | 102 +++++++++++++++++++----------------- po/it_IT.po | 102 +++++++++++++++++++----------------- po/ja_JP.po | 102 +++++++++++++++++++----------------- po/kimchi.pot | 84 +++++++++++++++++------------- po/ko_KR.po | 102 +++++++++++++++++++----------------- po/pt_BR.po | 102 +++++++++++++++++++----------------- po/ru_RU.po | 102 +++++++++++++++++++----------------- po/zh_CN.po | 102 +++++++++++++++++++----------------- po/zh_TW.po | 102 +++++++++++++++++++----------------- src/kimchi/control/vms.py | 4 +- src/kimchi/mockmodel.py | 7 +-- src/kimchi/model/debugreports.py | 4 +- src/kimchi/model/host.py | 4 +- src/kimchi/model/storagepools.py | 2 +- src/kimchi/model/storagevolumes.py | 12 +++-- src/kimchi/model/vms.py | 33 +++++++++--- src/kimchi/model/vmsnapshots.py | 5 +- tests/test_authorization.py | 23 +++++---- tests/test_mockmodel.py | 12 +++-- tests/test_model.py | 60 ++++++++++++++------- tests/test_model_storagevolume.py | 2 +- tests/test_rest.py | 77 ++++++++++++++++++++------- ui/css/theme-default/list.css | 18 +++++++ ui/js/src/kimchi.guest_main.js | 29 +++++++++-- ui/pages/guest.html.tmpl | 3 ++ 29 files changed, 886 insertions(+), 613 deletions(-) -- 2.1.0

You can filter tasks by their state (running) and/or a target_uri. If you want to see all cloning VM tasks, you can only query for running tasks with /vm in the target_uri. This patch adds an action keyword to the target_uris for existing tasks. This will make it possible to query other types of tasks for the same resource. Signed-off-by: Christy Perez <christy@linux.vnet.ibm.com> --- docs/API.md | 16 ++++++++++++++++ src/kimchi/mockmodel.py | 7 ++++--- src/kimchi/model/debugreports.py | 4 ++-- src/kimchi/model/host.py | 4 ++-- src/kimchi/model/storagepools.py | 2 +- src/kimchi/model/storagevolumes.py | 12 +++++++----- src/kimchi/model/vms.py | 5 ++--- src/kimchi/model/vmsnapshots.py | 5 +++-- 8 files changed, 37 insertions(+), 18 deletions(-) diff --git a/docs/API.md b/docs/API.md index 3f7925f..1f8e769 100644 --- a/docs/API.md +++ b/docs/API.md @@ -651,6 +651,22 @@ server. * failed: The task failed * message: Human-readable details about the Task status * target_uri: Resource URI related to the Task + The target uri may end with an action descriptor: + * VM task descriptions: + * clone + * create + * VM Snapshot description + * create + * Storage descriptions: + * create + * clone + * Pool descriptions: + * create + * scan + * Debugreport descriptions: + * create + * Host SW Update descriptions: + * update * **POST**: *See Task Actions* **Actions (POST):** diff --git a/src/kimchi/mockmodel.py b/src/kimchi/mockmodel.py index 413ac5d..2b1b214 100644 --- a/src/kimchi/mockmodel.py +++ b/src/kimchi/mockmodel.py @@ -244,7 +244,7 @@ def _get_volume_path(self, pool, vol): return MockModel._libvirt_get_vol_path(pool, vol) def _gen_debugreport_file(self, name): - return add_task('/debugreports/%s' % name, self._create_log, + return add_task('/debugreports/%s/create' % name, self._create_log, self.objstore, name) def _create_log(self, cb, name): @@ -333,7 +333,8 @@ def _mock_packageupdate_lookup(self, pkg_name): return self._mock_swupdate.pkgs[pkg_name] def _mock_host_swupdate(self, args=None): - task_id = add_task('/host/swupdate', self._mock_swupdate.doUpdate, + task_id = add_task('/host/swupdate/update', + self._mock_swupdate.doUpdate, self.objstore) return self.task_lookup(task_id) @@ -385,7 +386,7 @@ def _mock_vm_clone(self, name): def _mock_vmsnapshots_create(self, vm_name, params): name = params.get('name', unicode(int(time.time()))) params = {'vm_name': vm_name, 'name': name} - taskid = add_task(u'/vms/%s/snapshots/%s' % (vm_name, name), + taskid = add_task(u'/vms/%s/snapshots/%s/create' % (vm_name, name), self._vmsnapshots_create_task, self.objstore, params) return self.task_lookup(taskid) diff --git a/src/kimchi/model/debugreports.py b/src/kimchi/model/debugreports.py index 5f74da8..19b4de5 100644 --- a/src/kimchi/model/debugreports.py +++ b/src/kimchi/model/debugreports.py @@ -62,8 +62,8 @@ def _gen_debugreport_file(self, name): gen_cmd = self.get_system_report_tool() if gen_cmd is not None: - return add_task('/debugreports/%s' % name, gen_cmd, self.objstore, - name) + return add_task('/debugreports/%s/create' % name, gen_cmd, + self.objstore, name) raise OperationFailed("KCHDR0002E") diff --git a/src/kimchi/model/host.py b/src/kimchi/model/host.py index 4419bb3..f429415 100644 --- a/src/kimchi/model/host.py +++ b/src/kimchi/model/host.py @@ -115,8 +115,8 @@ def swupdate(self, *name): raise OperationFailed('KCHPKGUPD0001E') kimchi_log.debug('Host is going to be updated.') - taskid = add_task('/host/swupdate', swupdate.doUpdate, self.objstore, - None) + taskid = add_task('/host/swupdate/update', swupdate.doUpdate, + self.objstore, None) return self.task.lookup(taskid) def shutdown(self, args=None): diff --git a/src/kimchi/model/storagepools.py b/src/kimchi/model/storagepools.py index b85f3b4..094c841 100644 --- a/src/kimchi/model/storagepools.py +++ b/src/kimchi/model/storagepools.py @@ -167,7 +167,7 @@ def _do_deep_scan(self, params): params['path'] = self.scanner.scan_dir_prepare(params['name']) scan_params['pool_path'] = params['path'] - task_id = add_task('/storagepools/%s' % ISO_POOL_NAME, + task_id = add_task('/storagepools/%s/scan' % ISO_POOL_NAME, self.scanner.start_scan, self.objstore, scan_params) # Record scanning-task/storagepool mapping for future querying try: diff --git a/src/kimchi/model/storagevolumes.py b/src/kimchi/model/storagevolumes.py index 0480496..9f93f10 100644 --- a/src/kimchi/model/storagevolumes.py +++ b/src/kimchi/model/storagevolumes.py @@ -116,8 +116,10 @@ def create(self, pool_name, params): raise InvalidParameter('KCHVOL0001E', {'name': name}) params['pool'] = pool_name - targeturi = '/storagepools/%s/storagevolumes/%s' % (pool_name, name) - taskid = add_task(targeturi, create_func, self.objstore, params) + targeturi = '/storagepools/%s/storagevolumes/%s/create' \ + % (pool_name, name) + taskid = add_task(targeturi, create_func, self.objstore, + params) return self.task.lookup(taskid) def _create_volume_with_file(self, cb, params): @@ -413,9 +415,9 @@ def clone(self, pool, name, new_pool=None, new_name=None): 'name': name, 'new_pool': new_pool, 'new_name': new_name} - taskid = add_task(u'/storagepools/%s/storagevolumes/%s' % - (pool, new_name), self._clone_task, self.objstore, - params) + taskid = add_task(u'/storagepools/%s/storagevolumes/%s/clone' % + (pool, new_name), self._clone_task, + self.objstore, params) return self.task.lookup(taskid) def _clone_task(self, cb, params): diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index 4c5f443..1ae841d 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -332,9 +332,8 @@ def clone(self, name): new_name = get_next_clone_name(current_vm_names, name) # create a task with the actual clone function - taskid = add_task(u'/vms/%s' % new_name, self._clone_task, - self.objstore, - {'name': name, 'new_name': new_name}) + taskid = add_task(u'/vms/%s/clone' % new_name, self._clone_task, + self.objstore, {'name': name, 'new_name': new_name}) return self.task.lookup(taskid) diff --git a/src/kimchi/model/vmsnapshots.py b/src/kimchi/model/vmsnapshots.py index 3a92cdc..c4cc663 100644 --- a/src/kimchi/model/vmsnapshots.py +++ b/src/kimchi/model/vmsnapshots.py @@ -72,8 +72,9 @@ def create(self, vm_name, params={}): name = params.get('name', unicode(int(time.time()))) task_params = {'vm_name': vm_name, 'name': name} - taskid = add_task(u'/vms/%s/snapshots/%s' % (vm_name, name), - self._create_task, self.objstore, task_params) + taskid = add_task(u'/vms/%s/snapshots/%s/create' % (vm_name, name), + self._create_task, self.objstore, + task_params) return self.task.lookup(taskid) def _create_task(self, cb, params): -- 2.1.0

Signed-off-by: Christy Perez <christy@linux.vnet.ibm.com> --- tests/test_model.py | 6 +++--- tests/test_model_storagevolume.py | 2 +- tests/test_rest.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_model.py b/tests/test_model.py index f80f1c9..cf55549 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -160,7 +160,7 @@ def test_vm_lifecycle(self): self.assertEquals(snap, current_snap) task = inst.vmsnapshots_create(u'kimchi-vm') - snap_name = task['target_uri'].split('/')[-1] + snap_name = task['target_uri'].split('/')[-2] rollback.prependDefer(inst.vmsnapshot_delete, u'kimchi-vm', snap_name) inst.task_wait(task['id']) @@ -1142,9 +1142,9 @@ def test_vm_clone(self): # and make sure both of them complete successfully task1 = inst.vm_clone(name) task2 = inst.vm_clone(name) - clone1_name = task1['target_uri'].split('/')[-1] + clone1_name = task1['target_uri'].split('/')[-2] rollback.prependDefer(inst.vm_delete, clone1_name) - clone2_name = task2['target_uri'].split('/')[-1] + clone2_name = task2['target_uri'].split('/')[-2] rollback.prependDefer(inst.vm_delete, clone2_name) inst.task_wait(task1['id']) task1 = inst.task_lookup(task1['id']) diff --git a/tests/test_model_storagevolume.py b/tests/test_model_storagevolume.py index a3c3ce3..11fd90d 100644 --- a/tests/test_model_storagevolume.py +++ b/tests/test_model_storagevolume.py @@ -124,7 +124,7 @@ def _task_lookup(taskid): resp = self.request(vol_uri + '/clone', '{}', 'POST') self.assertEquals(202, resp.status) task = json.loads(resp.read()) - cloned_vol_name = task['target_uri'].split('/')[-1] + cloned_vol_name = task['target_uri'].split('/')[-2] rollback.prependDefer(model.storagevolume_delete, pool_name, cloned_vol_name) wait_task(_task_lookup, task['id']) diff --git a/tests/test_rest.py b/tests/test_rest.py index 812afb7..c759a52 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -370,7 +370,7 @@ def test_vm_lifecycle(self): wait_task(self._task_lookup, task['id']) task = json.loads(self.request('/tasks/%s' % task['id'], '{}').read()) self.assertEquals('finished', task['status']) - clone_vm_name = task['target_uri'].split('/')[-1] + clone_vm_name = task['target_uri'].split('/')[-2] self.assertTrue(re.match(u'test-vm-clone-\d+', clone_vm_name)) resp = self.request('/vms/test-vm', '{}') @@ -423,7 +423,7 @@ def test_vm_lifecycle(self): resp = self.request('/vms/test-vm/snapshots', '{}', 'POST') self.assertEquals(202, resp.status) task = json.loads(resp.read()) - snap_name = task['target_uri'].split('/')[-1] + snap_name = task['target_uri'].split('/')[-2] wait_task(self._task_lookup, task['id']) resp = self.request('/tasks/%s' % task['id'], '{}', 'GET') task = json.loads(resp.read()) @@ -1724,7 +1724,7 @@ def test_upload(self): task = r.json() wait_task(self._task_lookup, task['id'], 15) uri = '/storagepools/default-pool/storagevolumes/%s' - resp = self.request(uri % task['target_uri'].split('/')[-1]) + resp = self.request(uri % task['target_uri'].split('/')[-2]) self.assertEquals(200, resp.status) -- 2.1.0

Update the clone tasks GET call. Signed-off-by: Christy Perez <christy@linux.vnet.ibm.com> --- ui/js/src/kimchi.guest_main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index 21caf1b..e21b51f 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -203,10 +203,10 @@ kimchi.listVmsAuto = function() { } var getCloningGuests = function(){ var guests = []; - kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/vms/*'), function(tasks) { + kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/vms/.+/clone'), function(tasks) { for(var i=0;i<tasks.length;i++){ var guestUri = tasks[i].target_uri; - var guestName = guestUri.substring(guestUri.lastIndexOf('/')+1, guestUri.length); + var guestName = guestUri.split('/')[2] guests.push($.extend({}, kimchi.sampleGuestObject, {name: guestName, isCloning: true})); if(kimchi.trackingTasks.indexOf(tasks[i].id)==-1) kimchi.trackTask(tasks[i].id, null, function(err){ -- 2.1.0

Signed-off-by: Christy Perez <christy@linux.vnet.ibm.com> --- src/kimchi/control/vms.py | 4 ++-- src/kimchi/model/vms.py | 28 +++++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py index 5068b7c..8a31dc0 100644 --- a/src/kimchi/control/vms.py +++ b/src/kimchi/control/vms.py @@ -17,13 +17,13 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -from kimchi.control.base import Collection, Resource +from kimchi.control.base import AsyncCollection, Resource from kimchi.control.utils import internal_redirect, UrlSubNode from kimchi.control.vm import sub_nodes @UrlSubNode('vms', True) -class VMs(Collection): +class VMs(AsyncCollection): def __init__(self, model): super(VMs, self).__init__(model) self.resource = VM diff --git a/src/kimchi/model/vms.py b/src/kimchi/model/vms.py index 1ae841d..e5b0aa7 100644 --- a/src/kimchi/model/vms.py +++ b/src/kimchi/model/vms.py @@ -80,6 +80,7 @@ def __init__(self, **kargs): self.conn = kargs['conn'] self.objstore = kargs['objstore'] self.caps = CapabilitiesModel(**kargs) + self.task = TaskModel(**kargs) @staticmethod def _update_guests_stats(names, conn): @@ -183,7 +184,6 @@ def _get_disk_io_rate(vm_uuid, dom, seconds): 'diskWrKB': diskWrKB}) def create(self, params): - conn = self.conn.get() t_name = template_name_from_uri(params['template']) vm_uuid = str(uuid.uuid4()) vm_list = self.get_list() @@ -205,6 +205,26 @@ def create(self, params): t.validate() + taskid = add_task(u'/vms/%s/create' % name, + self._create_task, self.objstore, + {'vm_uuid': vm_uuid, 'template': t, 'name': name}) + + return self.task.lookup(taskid) + + def _create_task(self, cb, params): + """ + params: A dict with the following values: + - vm_uuid: The UUID of the VM being created + - template: The template being used to create the VM + - name: The name for the new VM + """ + + vm_uuid = params['vm_uuid'] + t = params['template'] + name = params['name'] + conn = self.conn.get() + + cb('Storing VM icon') # Store the icon for displaying later icon = t.info.get('icon') if icon: @@ -219,6 +239,7 @@ def create(self, params): # If storagepool is SCSI, volumes will be LUNs and must be passed by # the user from UI or manually. + cb('Provisioning storage for new VM') vol_list = [] if t._get_storage_type() not in ["iscsi", "scsi"]: vol_list = t.fork_vm_storage(vm_uuid) @@ -231,6 +252,7 @@ def create(self, params): graphics=graphics, volumes=vol_list) + cb('Defining new VM') try: conn.defineXML(xml.encode('utf-8')) except libvirt.libvirtError as e: @@ -241,10 +263,10 @@ def create(self, params): raise OperationFailed("KCHVM0007E", {'name': name, 'err': e.get_error_message()}) + cb('Updating VM metadata') VMModel.vm_update_os_metadata(VMModel.get_vm(name, self.conn), t.info, self.caps.metadata_support) - - return name + cb('OK', True) def get_list(self): return VMsModel.get_vms(self.conn) -- 2.1.0

Signed-off-by: Christy Perez <christy@linux.vnet.ibm.com> --- tests/test_authorization.py | 23 +++++++++------ tests/test_mockmodel.py | 12 ++++++-- tests/test_model.py | 54 ++++++++++++++++++++++++---------- tests/test_rest.py | 71 ++++++++++++++++++++++++++++++++++----------- 4 files changed, 115 insertions(+), 45 deletions(-) diff --git a/tests/test_authorization.py b/tests/test_authorization.py index 4fcc496..eae837c 100644 --- a/tests/test_authorization.py +++ b/tests/test_authorization.py @@ -26,7 +26,7 @@ import kimchi.mockmodel from iso_gen import construct_fake_iso from utils import get_free_port, patch_auth, request -from utils import run_server +from utils import run_server, wait_task test_server = None @@ -118,19 +118,24 @@ def test_nonroot_access(self): # Non-root users can only get vms authorized to them model.templates_create({'name': u'test', 'cdrom': fake_iso}) - model.vms_create({'name': u'test-me', 'template': '/templates/test'}) + task_info = model.vms_create({'name': u'test-me', + 'template': '/templates/test'}) + wait_task(model.task_lookup, task_info['id']) + model.vm_update(u'test-me', {'users': [kimchi.mockmodel.fake_user.keys()[0]], 'groups': []}) - model.vms_create({'name': u'test-usera', - 'template': '/templates/test'}) + task_info = model.vms_create({'name': u'test-usera', + 'template': '/templates/test'}) + wait_task(model.task_lookup, task_info['id']) non_root = list(set(model.users_get_list()) - set(['root']))[0] model.vm_update(u'test-usera', {'users': [non_root], 'groups': []}) - model.vms_create({'name': u'test-groupa', - 'template': '/templates/test'}) + task_info = model.vms_create({'name': u'test-groupa', + 'template': '/templates/test'}) + wait_task(model.task_lookup, task_info['id']) a_group = model.groups_get_list()[0] model.vm_update(u'test-groupa', {'groups': [a_group]}) @@ -143,9 +148,9 @@ def test_nonroot_access(self): self.assertEquals(403, resp.status) # Create a vm using mockmodel directly to test Resource access - model.vms_create({'name': 'kimchi-test', - 'template': '/templates/test'}) - + task_info = model.vms_create({'name': 'kimchi-test', + 'template': '/templates/test'}) + wait_task(model.task_lookup, task_info['id']) resp = self.request('/vms/kimchi-test', '{}', 'PUT') self.assertEquals(403, resp.status) resp = self.request('/vms/kimchi-test', '{}', 'DELETE') diff --git a/tests/test_mockmodel.py b/tests/test_mockmodel.py index 29354aa..443df42 100644 --- a/tests/test_mockmodel.py +++ b/tests/test_mockmodel.py @@ -169,7 +169,9 @@ def test_screenshot_refresh(self): req = json.dumps({'name': 'test', 'cdrom': fake_iso}) request(host, ssl_port, '/templates', req, 'POST') req = json.dumps({'name': 'test-vm', 'template': '/templates/test'}) - request(host, ssl_port, '/vms', req, 'POST') + resp = request(host, ssl_port, '/vms', req, 'POST') + task = json.loads(resp.read()) + wait_task(model.task_lookup, task['id']) # Test screenshot refresh for running vm request(host, ssl_port, '/vms/test-vm/start', '{}', 'POST') @@ -197,7 +199,9 @@ def test_vm_list_sorted(self): def add_vm(name): # Create a VM req = json.dumps({'name': name, 'template': '/templates/test'}) - request(host, ssl_port, '/vms', req, 'POST') + task = json.loads(request(host, ssl_port, '/vms', req, + 'POST').read()) + wait_task(model.task_lookup, task['id']) vms = [u'abc', u'bca', u'cab', u'xba'] for vm in vms: @@ -209,7 +213,9 @@ def add_vm(name): def test_vm_info(self): model.templates_create({'name': u'test', 'cdrom': fake_iso}) - model.vms_create({'name': u'test-vm', 'template': '/templates/test'}) + task = model.vms_create({'name': u'test-vm', + 'template': '/templates/test'}) + wait_task(model.task_lookup, task['id']) vms = model.vms_get_list() self.assertEquals(2, len(vms)) self.assertIn(u'test-vm', vms) diff --git a/tests/test_model.py b/tests/test_model.py index cf55549..69fd01a 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -117,8 +117,11 @@ def test_vm_lifecycle(self): rollback.prependDefer(inst.template_delete, 'test') params = {'name': 'kimchi-vm', 'template': '/templates/test'} - inst.vms_create(params) + task = inst.vms_create(params) rollback.prependDefer(inst.vm_delete, 'kimchi-vm') + inst.task_wait(task['id'], 10) + task = inst.task_lookup(task['id']) + self.assertEquals('finished', task['status']) vms = inst.vms_get_list() self.assertTrue('kimchi-vm' in vms) @@ -235,7 +238,8 @@ def test_image_based_template(self): session.store('template', tmpl_name, tmpl_info) params = {'name': 'kimchi-vm', 'template': '/templates/img-tmpl'} - inst.vms_create(params) + task = inst.vms_create(params) + inst.task_wait(task['id']) rollback.prependDefer(inst.vm_delete, 'kimchi-vm') vms = inst.vms_get_list() @@ -254,7 +258,8 @@ def test_vm_graphics(self): inst.templates_create(params) with RollbackContext() as rollback: params = {'name': 'kimchi-vnc', 'template': '/templates/test'} - inst.vms_create(params) + task1 = inst.vms_create(params) + inst.task_wait(task1['id']) rollback.prependDefer(inst.vm_delete, 'kimchi-vnc') info = inst.vm_lookup('kimchi-vnc') @@ -264,7 +269,8 @@ def test_vm_graphics(self): graphics = {'type': 'spice', 'listen': '127.0.0.1'} params = {'name': 'kimchi-spice', 'template': '/templates/test', 'graphics': graphics} - inst.vms_create(params) + task2 = inst.vms_create(params) + inst.task_wait(task2['id']) rollback.prependDefer(inst.vm_delete, 'kimchi-spice') info = inst.vm_lookup('kimchi-spice') @@ -281,7 +287,8 @@ def test_vm_ifaces(self): inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') params = {'name': 'kimchi-ifaces', 'template': '/templates/test'} - inst.vms_create(params) + task = inst.vms_create(params) + inst.task_wait(task['id']) rollback.prependDefer(inst.vm_delete, 'kimchi-ifaces') # Create a network @@ -387,7 +394,8 @@ def _attach_disk(expect_bus='virtio'): inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') params = {'name': vm_name, 'template': '/templates/test'} - inst.vms_create(params) + task1 = inst.vms_create(params) + inst.task_wait(task1['id']) rollback.prependDefer(inst.vm_delete, vm_name) prev_count = len(inst.vmstorages_get_list(vm_name)) @@ -430,7 +438,8 @@ def _attach_disk(expect_bus='virtio'): rollback.prependDefer(inst.template_delete, 'old_distro_template') params = {'name': vm_name, 'template': '/templates/old_distro_template'} - inst.vms_create(params) + task2 = inst.vms_create(params) + inst.task_wait(task2['id']) rollback.prependDefer(inst.vm_delete, vm_name) # Attach will choose IDE bus for old distro @@ -451,7 +460,8 @@ def test_vm_cdrom(self): inst.templates_create(params) rollback.prependDefer(inst.template_delete, 'test') params = {'name': vm_name, 'template': '/templates/test'} - inst.vms_create(params) + task = inst.vms_create(params) + inst.task_wait(task['id']) rollback.prependDefer(inst.vm_delete, vm_name) prev_count = len(inst.vmstorages_get_list(vm_name)) @@ -549,7 +559,8 @@ def test_vm_storage_provisioning(self): rollback.prependDefer(inst.template_delete, 'test') params = {'name': 'test-vm-1', 'template': '/templates/test'} - inst.vms_create(params) + task = inst.vms_create(params) + inst.task_wait(task['id']) rollback.prependDefer(inst.vm_delete, 'test-vm-1') vm_info = inst.vm_lookup(params['name']) @@ -601,12 +612,14 @@ def test_template_storage_customise(self): inst.template_update('test', params) params = {'name': 'test-vm-1', 'template': '/templates/test'} + # @TODO: What is invalid here? Rewrite test for that. self.assertRaises(InvalidParameter, inst.vms_create, params) inst.storagepool_activate(pool) rollback.prependDefer(inst.storagepool_deactivate, pool) - inst.vms_create(params) + task = inst.vms_create(params) + inst.task_wait(task['id']) rollback.prependDefer(inst.vm_delete, 'test-vm-1') vm_info = inst.vm_lookup(params['name']) disk_path = '/tmp/kimchi-images/%s-0.img' % vm_info['uuid'] @@ -789,7 +802,10 @@ def test_template_update(self): 'new-test', params) params = {'name': 'some-vm', 'template': '/templates/new-test'} - self.assertEquals('some-vm', inst.vms_create(params)) + task = inst.vms_create(params) + inst.task_wait(task['id']) + vm_name = task['target_uri'].split('/')[-1] + self.assertEquals('some-vm', vm_name) rollback.prependDefer(inst.vm_delete, 'some-vm') iface_args = {'type': 'network', 'network': u'kīмсhī-пet'} @@ -808,10 +824,12 @@ def test_vm_edit(self): with RollbackContext() as rollback: params_1 = {'name': 'kimchi-vm1', 'template': '/templates/test'} params_2 = {'name': 'kimchi-vm2', 'template': '/templates/test'} - inst.vms_create(params_1) + task1 = inst.vms_create(params_1) + inst.task_wait(task1['id']) rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, 'kimchi-vm1') - inst.vms_create(params_2) + task2 = inst.vms_create(params_2) + inst.task_wait(task2['id']) rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, 'kimchi-vm2') @@ -1091,11 +1109,13 @@ def test_delete_running_vm(self): rollback.prependDefer(inst.template_delete, 'test') params = {'name': u'kīмсhī-∨м', 'template': u'/templates/test'} - inst.vms_create(params) + task = inst.vms_create(params) + inst.task_wait(task['id']) rollback.prependDefer(utils.rollback_wrapper, inst.vm_delete, u'kīмсhī-∨м') inst.vm_start(u'kīмсhī-∨м') + self.assertEquals(inst.vm_lookup(u'kīмсhī-∨м')['state'], 'running') rollback.prependDefer(utils.rollback_wrapper, inst.vm_poweroff, u'kīмсhī-∨м') @@ -1114,7 +1134,8 @@ def test_vm_list_sorted(self): rollback.prependDefer(inst.template_delete, 'test') params = {'name': 'kimchi-vm', 'template': '/templates/test'} - inst.vms_create(params) + task = inst.vms_create(params) + inst.task_wait(task['id']) rollback.prependDefer(inst.vm_delete, 'kimchi-vm') vms = inst.vms_get_list() @@ -1186,7 +1207,8 @@ def test_use_test_host(self): params = {'name': 'kimchi-vm', 'template': '/templates/test'} - inst.vms_create(params) + task = inst.vms_create(params) + inst.task_wait(task['id']) rollback.prependDefer(inst.vm_delete, 'kimchi-vm') vms = inst.vms_get_list() diff --git a/tests/test_rest.py b/tests/test_rest.py index c759a52..f46bd56 100644 --- a/tests/test_rest.py +++ b/tests/test_rest.py @@ -190,7 +190,9 @@ def test_get_vms(self): req = json.dumps({'name': name, 'template': '/templates/test', 'users': test_users, 'groups': test_groups}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) vms = json.loads(self.request('/vms').read()) self.assertEquals(11, len(vms)) @@ -208,7 +210,9 @@ def test_edit_vm(self): req = json.dumps({'name': 'vm-1', 'template': '/templates/test'}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) vm = json.loads(self.request('/vms/vm-1').read()) self.assertEquals('vm-1', vm['name']) @@ -325,7 +329,9 @@ def test_vm_lifecycle(self): # Create a VM req = json.dumps({'name': 'test-vm', 'template': '/templates/test'}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + self.assertEquals(202, resp.status) # Verify the VM vm = json.loads(self.request('/vms/test-vm').read()) @@ -479,7 +485,9 @@ def test_vm_graphics(self): # Create a VM with default args req = json.dumps({'name': 'test-vm', 'template': '/templates/test'}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) # Verify the VM vm = json.loads(self.request('/vms/test-vm').read()) self.assertEquals('127.0.0.1', vm['graphics']['listen']) @@ -493,7 +501,9 @@ def test_vm_graphics(self): req = json.dumps({'name': 'test-vm', 'template': '/templates/test', 'graphics': graphics}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) # Verify the VM vm = json.loads(self.request('/vms/test-vm').read()) self.assertEquals('127.0.0.1', vm['graphics']['listen']) @@ -507,7 +517,9 @@ def test_vm_graphics(self): req = json.dumps({'name': 'test-vm', 'template': '/templates/test', 'graphics': graphics}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) # Verify the VM vm = json.loads(self.request('/vms/test-vm').read()) self.assertEquals('fe00::0', vm['graphics']['listen']) @@ -521,7 +533,9 @@ def test_vm_graphics(self): req = json.dumps({'name': 'test-vm', 'template': '/templates/test', 'graphics': graphics}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) # Verify the VM vm = json.loads(self.request('/vms/test-vm').read()) self.assertEquals('127.0.0.1', vm['graphics']['listen']) @@ -563,7 +577,9 @@ def test_vm_storage_devices(self): req = json.dumps({'name': 'test-vm', 'template': '/templates/test'}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) # Delete the VM rollback.prependDefer(self.request, '/vms/test-vm', '{}', 'DELETE') @@ -708,7 +724,9 @@ def test_vm_iface(self): req = json.dumps({'name': 'test-vm', 'template': '/templates/test'}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) # Delete the VM rollback.prependDefer(self.request, '/vms/test-vm', '{}', 'DELETE') @@ -782,7 +800,10 @@ def test_vm_customise_storage(self): req = json.dumps({'name': 'test-vm', 'template': '/templates/test', 'storagepool': '/storagepools/alt'}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + resp = self.request('/vms/test-vm', {}, 'GET') vm_info = json.loads(resp.read()) # Test template not changed after vm customise its pool @@ -835,7 +856,9 @@ def test_scsi_fc_storage(self): req = json.dumps({'name': 'test-vm', 'template': '/templates/test_fc_pool'}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) # Start the VM resp = self.request('/vms/test-vm/start', '{}', 'POST') @@ -886,8 +909,11 @@ def test_template_customise_storage(self): # Create a VM req = json.dumps({'name': 'test-vm', 'template': '/templates/test'}) resp = self.request('/vms', req, 'POST') + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + resp = self.request('/vms/test-vm', {}, 'GET') vm = json.loads(resp.read()) - self.assertEquals(201, resp.status) + self.assertEquals(200, resp.status) # Verify the volume was created vol_uri = '/storagepools/alt/storagevolumes/%s-0.img' % vm['uuid'] @@ -969,8 +995,10 @@ def test_unnamed_vms(self): # Create 5 unnamed vms from this template for i in xrange(1, 6): req = json.dumps({'template': '/templates/test'}) - vm = json.loads(self.request('/vms', req, 'POST').read()) - self.assertEquals('test-vm-%i' % i, vm['name']) + task = json.loads(self.request('/vms', req, 'POST').read()) + wait_task(self._task_lookup, task['id']) + resp = self.request('/vms/test-vm-%i' % i, {}, 'GET') + self.assertEquals(resp.status, 200) count = len(json.loads(self.request('/vms').read())) self.assertEquals(6, count) @@ -1002,7 +1030,10 @@ def test_create_vm_with_img_based_template(self): self.assertEquals(201, resp.status) req = json.dumps({'template': '/templates/test'}) - json.loads(self.request('/vms', req, 'POST').read()) + resp = self.request('/vms', req, 'POST') + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) # Test storage volume created with backing store of base file resp = json.loads( @@ -1318,6 +1349,8 @@ def test_screenshot_refresh(self): resp = self.request('/templates', req, 'POST') req = json.dumps({'name': 'test-vm', 'template': '/templates/test'}) resp = self.request('/vms', req, 'POST') + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) # Test screenshot for shut-off state vm resp = self.request('/vms/test-vm/screenshot') @@ -1647,10 +1680,14 @@ def test_get_param(self): # Create a VM req = json.dumps({'name': 'test-vm1', 'template': '/templates/test'}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) + self.assertEquals(202, resp.status) req = json.dumps({'name': 'test-vm2', 'template': '/templates/test'}) resp = self.request('/vms', req, 'POST') - self.assertEquals(201, resp.status) + self.assertEquals(202, resp.status) + task = json.loads(resp.read()) + wait_task(self._task_lookup, task['id']) resp = request(host, ssl_port, '/vms') self.assertEquals(200, resp.status) -- 2.1.0

Since the VMs are now created asyncronously, add the UI code to show the vm task as is done with cloning tasks. I copied the clone bits and changed names to create. Signed-off-by: Christy Perez <christy@linux.vnet.ibm.com> --- ui/css/theme-default/list.css | 18 ++++++++++++++++++ ui/js/src/kimchi.guest_main.js | 25 ++++++++++++++++++++++--- ui/pages/guest.html.tmpl | 3 +++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/ui/css/theme-default/list.css b/ui/css/theme-default/list.css index 7b32ea6..62d1539 100644 --- a/ui/css/theme-default/list.css +++ b/ui/css/theme-default/list.css @@ -306,3 +306,21 @@ margin-left: 5px; text-shadow: -1px -1px 1px #CCCCCC, 1px 1px 1px #FFFFFF; } + +.guest-create { + margin: 10px; +} + +.guest-create .icon { + background: url('../../images/theme-default/kimchi-loading15x15.gif') no-repeat; + display: inline-block; + width: 20px; + height: 20px; + vertical-align: middle; +} + +.guest-create .text { + color: #666666; + margin-left: 5px; + text-shadow: -1px -1px 1px #CCCCCC, 1px 1px 1px #FFFFFF; +} diff --git a/ui/js/src/kimchi.guest_main.js b/ui/js/src/kimchi.guest_main.js index e21b51f..f4bc3b3 100644 --- a/ui/js/src/kimchi.guest_main.js +++ b/ui/js/src/kimchi.guest_main.js @@ -201,6 +201,21 @@ kimchi.listVmsAuto = function() { if (kimchi.vmTimeout) { clearTimeout(kimchi.vmTimeout); } + var getCreatingGuests = function(){ + var guests = []; + kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/vms/.+/create'), function(tasks) { + for(var i=0;i<tasks.length;i++){ + var guestUri = tasks[i].target_uri; + var guestName = guestUri.split('/')[2] + guests.push($.extend({}, kimchi.sampleGuestObject, {name: guestName, isCreating: true})); + if(kimchi.trackingTasks.indexOf(tasks[i].id)==-1) + kimchi.trackTask(tasks[i].id, null, function(err){ + kimchi.message.error(err.message); + }, null); + } + }, null, true); + return guests; + }; var getCloningGuests = function(){ var guests = []; kimchi.getTasksByFilter('status=running&target_uri='+encodeURIComponent('^/vms/.+/clone'), function(tasks) { @@ -219,6 +234,7 @@ kimchi.listVmsAuto = function() { kimchi.listVMs(function(result, textStatus, jqXHR) { if (result && textStatus=="success") { result = getCloningGuests().concat(result); + result = getCreatingGuests().concat(result); if(result.length) { var listHtml = ''; var guestTemplate = kimchi.guestTemplate; @@ -278,7 +294,7 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { imgLoad.attr('src',load_src); //Link the stopped tile to the start action, the running tile to open the console - if(!vmObject.isCloning){ + if(!(vmObject.isCloning || vmObject.isCreating)){ if (vmRunningBool) { liveTile.off("click", kimchi.vmstart); liveTile.on("click", kimchi.openVmConsole); @@ -326,7 +342,7 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { } //Setup action event handlers - if(!vmObject.isCloning){ + if(!(vmObject.isCloning || vmObject.isCreating)){ guestActions.find("[name=vm-start]").on({click : kimchi.vmstart}); guestActions.find("[name=vm-poweroff]").on({click : kimchi.vmpoweroff}); if (vmRunningBool) { //If the guest is not running, do not enable reset @@ -359,7 +375,10 @@ kimchi.createGuestLi = function(vmObject, prevScreenImage, openMenu) { }else{ guestActions.find('.btn').attr('disabled', true); - result.find('.guest-clone').removeClass('hide-content'); + if(vmObject.isCloning) + result.find('.guest-clone').removeClass('hide-content'); + else + result.find('.guest-create').removeClass('hide-content'); $('.popover', guestActions.find("div[name=actionmenu]")).remove(); } diff --git a/ui/pages/guest.html.tmpl b/ui/pages/guest.html.tmpl index 3cc2fad..0c5d414 100644 --- a/ui/pages/guest.html.tmpl +++ b/ui/pages/guest.html.tmpl @@ -29,6 +29,9 @@ <div class="guest-clone hide-content"> <span class="icon"></span><span class="text">$_("Cloning")...</span> </div> + <div class="guest-create hide-content"> + <span class="icon"></span><span class="text">$_("Creating")...</span> + </div> </div> <div name="cpu_utilization" class="sortable"> <div class="circleGauge"></div> -- 2.1.0

Signed-off-by: Christy Perez <christy@linux.vnet.ibm.com> --- po/de_DE.po | 103 ++++++++++++++++++++++++++++++++-------------------------- po/en_US.po | 83 ++++++++++++++++++++++++++-------------------- po/es_ES.po | 102 +++++++++++++++++++++++++++++++-------------------------- po/fr_FR.po | 102 +++++++++++++++++++++++++++++++-------------------------- po/it_IT.po | 102 +++++++++++++++++++++++++++++++-------------------------- po/ja_JP.po | 102 +++++++++++++++++++++++++++++++-------------------------- po/kimchi.pot | 84 ++++++++++++++++++++++++++--------------------- po/ko_KR.po | 102 +++++++++++++++++++++++++++++++-------------------------- po/pt_BR.po | 102 +++++++++++++++++++++++++++++++-------------------------- po/ru_RU.po | 102 +++++++++++++++++++++++++++++++-------------------------- po/zh_CN.po | 102 +++++++++++++++++++++++++++++++-------------------------- po/zh_TW.po | 102 +++++++++++++++++++++++++++++++-------------------------- 12 files changed, 655 insertions(+), 533 deletions(-) diff --git a/po/de_DE.po b/po/de_DE.po index 6a3b7df..777f48f 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-25 16:00-0300\n" +"POT-Creation-Date: 2015-03-04 16:25-0600\n" "PO-Revision-Date: 2013-07-11 17:32-0400\n" "Last-Translator: Crístian Viana <vianac@linux.vnet.ibm.com>\n" "Language-Team: English\n" @@ -958,6 +958,14 @@ msgstr "" msgid "Unable to choose a virtual machine name" msgstr "" +#, python-format +msgid "Invalid data value '%(value)s'" +msgstr "" + +#,python-format +msgid "Invalid data unit '%(unit)s'" +msgstr "" + msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" msgstr "Ungültiger Speichertyp. Unterstützte Typen: 'cdrom'" @@ -1338,6 +1346,39 @@ msgstr "Abbrechen" msgid "revert" msgstr "" +msgid "Cloning" +msgstr "Klonen" + +msgid "Creating" +msgstr "Erstellen" + +msgid "Start" +msgstr "Starten" + +msgid "Reset" +msgstr "Zurücksetzen" + +msgid "Power Off" +msgstr "" + +msgid "Actions" +msgstr "Aktionen" + +msgid "Connect" +msgstr "Verbinden" + +msgid "Clone" +msgstr "" + +msgid "Edit" +msgstr "Bearbeiten" + +msgid "Shut Down" +msgstr "Herunterfahren" + +msgid "Delete" +msgstr "Löschen" + msgid "Add a Storage Device to VM" msgstr "Speichereinheit zur virtuellen Maschine hinzufügen" @@ -1368,36 +1409,6 @@ msgstr "Der ISO-Dateipfad auf dem Server für die CD-ROM." msgid "Attach" msgstr "Anhängen" -msgid "Cloning" -msgstr "" - -msgid "Start" -msgstr "Starten" - -msgid "Reset" -msgstr "Zurücksetzen" - -msgid "Power Off" -msgstr "" - -msgid "Actions" -msgstr "Aktionen" - -msgid "Connect" -msgstr "Verbinden" - -msgid "Clone" -msgstr "" - -msgid "Edit" -msgstr "Bearbeiten" - -msgid "Shut Down" -msgstr "Herunterfahren" - -msgid "Delete" -msgstr "Löschen" - msgid "The username or password you entered is incorrect. Please try again." msgstr "" "Der Benutzername oder das Kennwort, den bzw. das Sie eingegeben haben, ist " @@ -1924,21 +1935,6 @@ msgstr "Ja" msgid "No" msgstr "Nein" -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - msgid "Define a New Storage Pool" msgstr "Neuen Speicherpool definieren" @@ -2017,6 +2013,21 @@ msgstr "SCSI-Adapter" msgid "Please, wait..." msgstr "Bitte warten..." +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + msgid "Add Template" msgstr "Vorlage hinzufügen" diff --git a/po/en_US.po b/po/en_US.po index 6efb22c..8123f59 100644 --- a/po/en_US.po +++ b/po/en_US.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-25 16:00-0300\n" +"POT-Creation-Date: 2015-03-04 16:25-0600\n" "PO-Revision-Date: 2013-07-11 17:32-0400\n" "Last-Translator: Crístian Viana <vianac@linux.vnet.ibm.com>\n" "Language-Team: English\n" @@ -850,6 +850,14 @@ msgstr "" msgid "Unable to choose a virtual machine name" msgstr "" +#, python-format +msgid "Invalid data value '%(value)s'" +msgstr "" + +#, python-format +msgid "Invalid data unit '%(unit)s'" +msgstr "" + msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" msgstr "" @@ -1214,64 +1222,67 @@ msgstr "" msgid "revert" msgstr "" -msgid "Add a Storage Device to VM" +msgid "Cloning" msgstr "" -msgid "Device Type" +msgid "Creating" msgstr "" -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgid "Start" msgstr "" -msgid "Storage Pool" +msgid "Reset" msgstr "" -msgid "Storage pool which volume located in" +msgid "Power Off" msgstr "" -msgid "Storage Volume" +msgid "Actions" msgstr "" -msgid "Storage volume to be attached" +msgid "Connect" msgstr "" -msgid "File Path" +msgid "Clone" msgstr "" -msgid "The ISO file path in the server for CDROM." +msgid "Edit" msgstr "" -msgid "Attach" +msgid "Shut Down" msgstr "" -msgid "Cloning" +msgid "Delete" msgstr "" -msgid "Start" +msgid "Add a Storage Device to VM" msgstr "" -msgid "Reset" +msgid "Device Type" msgstr "" -msgid "Power Off" +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." msgstr "" -msgid "Actions" +msgid "Storage Pool" msgstr "" -msgid "Connect" +msgid "Storage pool which volume located in" msgstr "" -msgid "Clone" +msgid "Storage Volume" msgstr "" -msgid "Edit" +msgid "Storage volume to be attached" msgstr "" -msgid "Shut Down" +msgid "File Path" msgstr "" -msgid "Delete" +msgid "The ISO file path in the server for CDROM." +msgstr "" + +msgid "Attach" msgstr "" msgid "The username or password you entered is incorrect. Please try again." @@ -1765,21 +1776,6 @@ msgstr "" msgid "No" msgstr "" -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - msgid "Define a New Storage Pool" msgstr "" @@ -1850,6 +1846,21 @@ msgstr "" msgid "Please, wait..." msgstr "" +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + msgid "Add Template" msgstr "" diff --git a/po/es_ES.po b/po/es_ES.po index e3c567f..ffefb97 100644 --- a/po/es_ES.po +++ b/po/es_ES.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-25 16:00-0300\n" +"POT-Creation-Date: 2015-03-04 16:25-0600\n" "PO-Revision-Date: 2013-07-11 17:32-0400\n" "Last-Translator: Crístian Viana <vianac@linux.vnet.ibm.com>\n" "Language-Team: English\n" @@ -971,6 +971,13 @@ msgstr "" msgid "Unable to choose a virtual machine name" msgstr "" +#, python-format +msgid "Invalid data value '%(value)s'" +msgstr "" + +msgid "Invalid data unit '%(unit)s'" +msgstr "" + msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" msgstr "Tipo de almacenamiento no válido. Tipos soportados: 'cdrom'" @@ -1356,39 +1363,12 @@ msgstr "Cancelar" msgid "revert" msgstr "" -msgid "Add a Storage Device to VM" -msgstr "Añadir un dispositivo de almacenamiento a VM" - -msgid "Device Type" -msgstr "Tipo de dispositivo" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "El tipo de dispositivo. Actualmente sólo está soportado \"cdrom\"." - -msgid "Storage Pool" -msgstr "Agrupación de almacenamiento" - -msgid "Storage pool which volume located in" -msgstr "La vía de acceso de la agrupación de almacenamiento debe ser una serie" - -msgid "Storage Volume" -msgstr "Nombre de agrupación de almacenamiento" - -msgid "Storage volume to be attached" -msgstr "El nombre de volumen de almacenamiento debe ser una serie" - -msgid "File Path" -msgstr "Vía de acceso de archivo" - -msgid "The ISO file path in the server for CDROM." -msgstr "La vía de acceso del archivo ISO en el servidor para el CDROM." - -msgid "Attach" -msgstr "Conectar" - msgid "Cloning" msgstr "" +msgid "Creating" +msgstr "Creando" + msgid "Start" msgstr "Iniciar" @@ -1416,6 +1396,36 @@ msgstr "Concluir" msgid "Delete" msgstr "Suprimir" +msgid "Add a Storage Device to VM" +msgstr "Añadir un dispositivo de almacenamiento a VM" + +msgid "Device Type" +msgstr "Tipo de dispositivo" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "El tipo de dispositivo. Actualmente sólo está soportado \"cdrom\"." + +msgid "Storage Pool" +msgstr "Agrupación de almacenamiento" + +msgid "Storage pool which volume located in" +msgstr "La vía de acceso de la agrupación de almacenamiento debe ser una serie" + +msgid "Storage Volume" +msgstr "Nombre de agrupación de almacenamiento" + +msgid "Storage volume to be attached" +msgstr "El nombre de volumen de almacenamiento debe ser una serie" + +msgid "File Path" +msgstr "Vía de acceso de archivo" + +msgid "The ISO file path in the server for CDROM." +msgstr "La vía de acceso del archivo ISO en el servidor para el CDROM." + +msgid "Attach" +msgstr "Conectar" + msgid "The username or password you entered is incorrect. Please try again." msgstr "" "El nombre de usuario o contraseña que ha especificado es incorrecto. Por " @@ -1943,21 +1953,6 @@ msgstr "Sí" msgid "No" msgstr "No" -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - msgid "Define a New Storage Pool" msgstr "Definir una agrupación de almacenamiento nueva" @@ -2034,6 +2029,21 @@ msgstr "Adaptador SCSI" msgid "Please, wait..." msgstr "Por favor, espere..." +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + msgid "Add Template" msgstr "Añadir plantilla" diff --git a/po/fr_FR.po b/po/fr_FR.po index b27ec76..ef7b12c 100644 --- a/po/fr_FR.po +++ b/po/fr_FR.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-25 16:00-0300\n" +"POT-Creation-Date: 2015-03-04 16:25-0600\n" "PO-Revision-Date: 2014-08-27 21:30+0000\n" "Last-Translator: BobSynfig\n" "Language-Team: French (http://www.transifex.com/projects/p/kimchi/language/" @@ -982,6 +982,13 @@ msgstr "" msgid "Unable to choose a virtual machine name" msgstr "Impossible de sélectionner un nom de machine virtuelle" +#, python-format +msgid "Invalid data value '%(value)s'" +msgstr "" + +msgid "Invalid data unit '%(unit)s'" +msgstr "" + msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" msgstr "Type de stockage invalide. Les Types supportés sont: 'cdrom', 'disk'" @@ -1369,6 +1376,39 @@ msgstr "Annuler" msgid "revert" msgstr "" +msgid "Cloning" +msgstr "" + +msgid "Creating" +msgstr "Création en cours..." + +msgid "Start" +msgstr "Démarrer" + +msgid "Reset" +msgstr "Réinitialiser" + +msgid "Power Off" +msgstr "Mettre hors tension" + +msgid "Actions" +msgstr "Actions" + +msgid "Connect" +msgstr "Connecter" + +msgid "Clone" +msgstr "Cloner" + +msgid "Edit" +msgstr "Éditer" + +msgid "Shut Down" +msgstr "Éteindre" + +msgid "Delete" +msgstr "Supprimer" + msgid "Add a Storage Device to VM" msgstr "Ajouter un Périphérique de Stockage à la VM" @@ -1400,36 +1440,6 @@ msgstr "Le chemin de fichier ISO sur le serveur comme CDROM." msgid "Attach" msgstr "Attacher" -msgid "Cloning" -msgstr "" - -msgid "Start" -msgstr "Démarrer" - -msgid "Reset" -msgstr "Réinitialiser" - -msgid "Power Off" -msgstr "Mettre hors tension" - -msgid "Actions" -msgstr "Actions" - -msgid "Connect" -msgstr "Connecter" - -msgid "Clone" -msgstr "Cloner" - -msgid "Edit" -msgstr "Éditer" - -msgid "Shut Down" -msgstr "Éteindre" - -msgid "Delete" -msgstr "Supprimer" - msgid "The username or password you entered is incorrect. Please try again." msgstr "" "Le nom d'utilisateur ou le mot de passe que vous avez entré est incorrect. " @@ -1965,21 +1975,6 @@ msgstr "Oui" msgid "No" msgstr "Non" -msgid "Add a Volume to Storage Pool" -msgstr "iAjouter un Volume au Pool de Stockage" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "Saisir une URL distante ici" - -msgid "Upload a file" -msgstr "Charger un fichier" - -msgid "Choose the file you want to upload." -msgstr "" - msgid "Define a New Storage Pool" msgstr "Définir un Nouveau Pool de Stockage" @@ -2058,6 +2053,21 @@ msgstr "Adaptateur SCSI" msgid "Please, wait..." msgstr "Veuillez patienter..." +msgid "Add a Volume to Storage Pool" +msgstr "iAjouter un Volume au Pool de Stockage" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "Saisir une URL distante ici" + +msgid "Upload a file" +msgstr "Charger un fichier" + +msgid "Choose the file you want to upload." +msgstr "" + msgid "Add Template" msgstr "Ajouter un Modèle" diff --git a/po/it_IT.po b/po/it_IT.po index 81e49f8..5cbb016 100644 --- a/po/it_IT.po +++ b/po/it_IT.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-25 16:00-0300\n" +"POT-Creation-Date: 2015-03-04 16:25-0600\n" "PO-Revision-Date: 2013-07-11 17:32-0400\n" "Last-Translator: Crístian Viana <vianac@linux.vnet.ibm.com>\n" "Language-Team: English\n" @@ -942,6 +942,13 @@ msgstr "" msgid "Unable to choose a virtual machine name" msgstr "" +#, python-format +msgid "Invalid data value '%(value)s'" +msgstr "" + +msgid "Invalid data unit '%(unit)s'" +msgstr "" + msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" msgstr "Tipo di memoria non valido. I tipi supportati sono: 'cdrom'" @@ -1325,39 +1332,12 @@ msgstr "Annulla" msgid "revert" msgstr "" -msgid "Add a Storage Device to VM" -msgstr "Aggiungi un dispositivo di memoria alla VM" - -msgid "Device Type" -msgstr "Tipo dispositivo" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "Il tipo di dispositivo. Attualmente, è supportato solo \"cdrom\"." - -msgid "Storage Pool" -msgstr "Pool di memoria" - -msgid "Storage pool which volume located in" -msgstr "Il percorso del pool di memoria deve essere una stringa" - -msgid "Storage Volume" -msgstr "Nome pool di memoria" - -msgid "Storage volume to be attached" -msgstr "Il nome del volume di memoria deve essere una stringa" - -msgid "File Path" -msgstr "Percorso file" - -msgid "The ISO file path in the server for CDROM." -msgstr "Il percorso file ISO nel server per CDROM." - -msgid "Attach" -msgstr "Allega" - msgid "Cloning" msgstr "" +msgid "Creating" +msgstr "" + msgid "Start" msgstr "Avvia" @@ -1385,6 +1365,36 @@ msgstr "Arresta" msgid "Delete" msgstr "Elimina" +msgid "Add a Storage Device to VM" +msgstr "Aggiungi un dispositivo di memoria alla VM" + +msgid "Device Type" +msgstr "Tipo dispositivo" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "Il tipo di dispositivo. Attualmente, è supportato solo \"cdrom\"." + +msgid "Storage Pool" +msgstr "Pool di memoria" + +msgid "Storage pool which volume located in" +msgstr "Il percorso del pool di memoria deve essere una stringa" + +msgid "Storage Volume" +msgstr "Nome pool di memoria" + +msgid "Storage volume to be attached" +msgstr "Il nome del volume di memoria deve essere una stringa" + +msgid "File Path" +msgstr "Percorso file" + +msgid "The ISO file path in the server for CDROM." +msgstr "Il percorso file ISO nel server per CDROM." + +msgid "Attach" +msgstr "Allega" + msgid "The username or password you entered is incorrect. Please try again." msgstr "" "Il nome utente o la password immessi non sono corretti. Ripetere " @@ -1910,21 +1920,6 @@ msgstr "Sì" msgid "No" msgstr "No" -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - msgid "Define a New Storage Pool" msgstr "Definisci un nuovo pool di memoria" @@ -2004,6 +1999,21 @@ msgstr "Adattatore SCSI" msgid "Please, wait..." msgstr "Attendere..." +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + msgid "Add Template" msgstr "Aggiungi modello" diff --git a/po/ja_JP.po b/po/ja_JP.po index e29de8c..4940e5c 100644 --- a/po/ja_JP.po +++ b/po/ja_JP.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-25 16:00-0300\n" +"POT-Creation-Date: 2015-03-04 16:25-0600\n" "PO-Revision-Date: 2013-07-11 17:32-0400\n" "Last-Translator: Crístian Viana <vianac@linux.vnet.ibm.com>\n" "Language-Team: English\n" @@ -951,6 +951,13 @@ msgstr "" msgid "Unable to choose a virtual machine name" msgstr "" +#, python-format +msgid "Invalid data value '%(value)s'" +msgstr "" + +msgid "Invalid data unit '%(unit)s'" +msgstr "" + msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" msgstr "" "ストレージ・タイプが無効です。サポートされているタイプは「cdrom」です。" @@ -1333,39 +1340,12 @@ msgstr "取消" msgid "revert" msgstr "" -msgid "Add a Storage Device to VM" -msgstr "VM にストレージ・デバイスを追加" - -msgid "Device Type" -msgstr "デバイス・タイプ" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "デバイス・タイプ。現在サポートされているのは \"cdrom\" のみです。" - -msgid "Storage Pool" -msgstr "ストレージ・プール" - -msgid "Storage pool which volume located in" -msgstr "ストレージ・プール・パスはストリングでなければなりません" - -msgid "Storage Volume" -msgstr "ストレージ・プール名" - -msgid "Storage volume to be attached" -msgstr "ストレージ・ボリューム名はストリングでなければなりません" - -msgid "File Path" -msgstr "ファイル・パス" - -msgid "The ISO file path in the server for CDROM." -msgstr "サーバー内での CDROM の ISO ファイル・パス。" - -msgid "Attach" -msgstr "接続" - msgid "Cloning" msgstr "" +msgid "Creating" +msgstr "" + msgid "Start" msgstr "開始" @@ -1393,6 +1373,36 @@ msgstr "シャットダウン" msgid "Delete" msgstr "削除" +msgid "Add a Storage Device to VM" +msgstr "VM にストレージ・デバイスを追加" + +msgid "Device Type" +msgstr "デバイス・タイプ" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "デバイス・タイプ。現在サポートされているのは \"cdrom\" のみです。" + +msgid "Storage Pool" +msgstr "ストレージ・プール" + +msgid "Storage pool which volume located in" +msgstr "ストレージ・プール・パスはストリングでなければなりません" + +msgid "Storage Volume" +msgstr "ストレージ・プール名" + +msgid "Storage volume to be attached" +msgstr "ストレージ・ボリューム名はストリングでなければなりません" + +msgid "File Path" +msgstr "ファイル・パス" + +msgid "The ISO file path in the server for CDROM." +msgstr "サーバー内での CDROM の ISO ファイル・パス。" + +msgid "Attach" +msgstr "接続" + msgid "The username or password you entered is incorrect. Please try again." msgstr "入力したユーザー名またはパスワードが誤っています。やり直してください。" @@ -1907,21 +1917,6 @@ msgstr " はい" msgid "No" msgstr " いいえ" -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - msgid "Define a New Storage Pool" msgstr "新規ストレージ・プールの定義" @@ -1999,6 +1994,21 @@ msgstr "SCSI アダプター" msgid "Please, wait..." msgstr "お待ちください..." +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + msgid "Add Template" msgstr "テンプレートの追加" diff --git a/po/kimchi.pot b/po/kimchi.pot index ee30a71..a6512f7 100755 --- a/po/kimchi.pot +++ b/po/kimchi.pot @@ -3,12 +3,11 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # -#, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-25 16:00-0300\n" +"POT-Creation-Date: 2015-03-04 16:25-0600\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -850,6 +849,14 @@ msgstr "" msgid "Unable to choose a virtual machine name" msgstr "" +#, python-format +msgid "Invalid data value '%(value)s'" +msgstr "" + +#, python-format +msgid "Invalid data unit '%(unit)s'" +msgstr "" + msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" msgstr "" @@ -1214,64 +1221,67 @@ msgstr "" msgid "revert" msgstr "" -msgid "Add a Storage Device to VM" +msgid "Cloning" msgstr "" -msgid "Device Type" +msgid "Creating" msgstr "" -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgid "Start" msgstr "" -msgid "Storage Pool" +msgid "Reset" msgstr "" -msgid "Storage pool which volume located in" +msgid "Power Off" msgstr "" -msgid "Storage Volume" +msgid "Actions" msgstr "" -msgid "Storage volume to be attached" +msgid "Connect" msgstr "" -msgid "File Path" +msgid "Clone" msgstr "" -msgid "The ISO file path in the server for CDROM." +msgid "Edit" msgstr "" -msgid "Attach" +msgid "Shut Down" msgstr "" -msgid "Cloning" +msgid "Delete" msgstr "" -msgid "Start" +msgid "Add a Storage Device to VM" msgstr "" -msgid "Reset" +msgid "Device Type" msgstr "" -msgid "Power Off" +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." msgstr "" -msgid "Actions" +msgid "Storage Pool" msgstr "" -msgid "Connect" +msgid "Storage pool which volume located in" msgstr "" -msgid "Clone" +msgid "Storage Volume" msgstr "" -msgid "Edit" +msgid "Storage volume to be attached" msgstr "" -msgid "Shut Down" +msgid "File Path" msgstr "" -msgid "Delete" +msgid "The ISO file path in the server for CDROM." +msgstr "" + +msgid "Attach" msgstr "" msgid "The username or password you entered is incorrect. Please try again." @@ -1765,21 +1775,6 @@ msgstr "" msgid "No" msgstr "" -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - msgid "Define a New Storage Pool" msgstr "" @@ -1850,6 +1845,21 @@ msgstr "" msgid "Please, wait..." msgstr "" +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + msgid "Add Template" msgstr "" diff --git a/po/ko_KR.po b/po/ko_KR.po index 53fb4bf..671235d 100644 --- a/po/ko_KR.po +++ b/po/ko_KR.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-25 16:00-0300\n" +"POT-Creation-Date: 2015-03-04 16:25-0600\n" "PO-Revision-Date: 2013-07-11 17:32-0400\n" "Last-Translator: Crístian Viana <vianac@linux.vnet.ibm.com>\n" "Language-Team: English\n" @@ -898,6 +898,13 @@ msgstr "%(seconds)s초 후에 '%(cmd)s' 명령 실행 중 제한시간이 초과 msgid "Unable to choose a virtual machine name" msgstr "" +#, python-format +msgid "Invalid data value '%(value)s'" +msgstr "" + +msgid "Invalid data unit '%(unit)s'" +msgstr "" + msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" msgstr "올바르지 않은 스토리지 유형입니다. 지원되는 유형: 'cdrom'" @@ -1264,39 +1271,12 @@ msgstr "취소" msgid "revert" msgstr "" -msgid "Add a Storage Device to VM" -msgstr "스토리지 장치를 VM에 추가" - -msgid "Device Type" -msgstr "장치 유형" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "장치 유형입니다. 현재 \"cdrom\"만 지원됩니다." - -msgid "Storage Pool" -msgstr "스토리지 풀" - -msgid "Storage pool which volume located in" -msgstr "스토리지 풀 경로는 문자열이어야 합니다." - -msgid "Storage Volume" -msgstr "스토리지 풀 이름" - -msgid "Storage volume to be attached" -msgstr "스토리지 볼륨 이름은 문자열이어야 합니다." - -msgid "File Path" -msgstr "파일 경로" - -msgid "The ISO file path in the server for CDROM." -msgstr "CDROM을 위한 서버의 ISO 파일 경로입니다." - -msgid "Attach" -msgstr "연결" - msgid "Cloning" msgstr "" +msgid "Creating" +msgstr "" + msgid "Start" msgstr "시작" @@ -1324,6 +1304,36 @@ msgstr "시스템 종료" msgid "Delete" msgstr "삭제" +msgid "Add a Storage Device to VM" +msgstr "스토리지 장치를 VM에 추가" + +msgid "Device Type" +msgstr "장치 유형" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "장치 유형입니다. 현재 \"cdrom\"만 지원됩니다." + +msgid "Storage Pool" +msgstr "스토리지 풀" + +msgid "Storage pool which volume located in" +msgstr "스토리지 풀 경로는 문자열이어야 합니다." + +msgid "Storage Volume" +msgstr "스토리지 풀 이름" + +msgid "Storage volume to be attached" +msgstr "스토리지 볼륨 이름은 문자열이어야 합니다." + +msgid "File Path" +msgstr "파일 경로" + +msgid "The ISO file path in the server for CDROM." +msgstr "CDROM을 위한 서버의 ISO 파일 경로입니다." + +msgid "Attach" +msgstr "연결" + msgid "The username or password you entered is incorrect. Please try again." msgstr "" "입력한 사용자 이름 또는 비밀번호가 올바르지 않습니다. 다시 시도하십시오." @@ -1834,21 +1844,6 @@ msgstr "예" msgid "No" msgstr "아니오" -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - msgid "Define a New Storage Pool" msgstr "새 스토리지 풀 정의" @@ -1922,6 +1917,21 @@ msgstr "SCSI 어댑터" msgid "Please, wait..." msgstr "잠시 기다려 주십시오." +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + msgid "Add Template" msgstr "템플리트 추가" diff --git a/po/pt_BR.po b/po/pt_BR.po index 0514b62..9653fc9 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -20,7 +20,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 1.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-25 16:00-0300\n" +"POT-Creation-Date: 2015-03-04 16:25-0600\n" "PO-Revision-Date: 2014-12-02 12:15+0000\n" "Last-Translator: Crístian Deives dos Santos Viana <cristiandeives@gmail." "com>\n" @@ -978,6 +978,13 @@ msgstr "" msgid "Unable to choose a virtual machine name" msgstr "Não foi possível escolher um nome para a máquina virtual" +#, python-format +msgid "Invalid data value '%(value)s'" +msgstr "" + +msgid "Invalid data unit '%(unit)s'" +msgstr "" + msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" msgstr "Tipo de storage inválido. Tipos suportados: 'cdrom', 'disco'" @@ -1384,6 +1391,39 @@ msgstr "Cancelar" msgid "revert" msgstr "Reverter" +msgid "Cloning" +msgstr "Clonando" + +msgid "Creating" +msgstr "Criando..." + +msgid "Start" +msgstr "Iniciar" + +msgid "Reset" +msgstr "Reiniciar" + +msgid "Power Off" +msgstr "Forçar desligamento" + +msgid "Actions" +msgstr "Ações" + +msgid "Connect" +msgstr "Conectar" + +msgid "Clone" +msgstr "Clonar" + +msgid "Edit" +msgstr "Editar" + +msgid "Shut Down" +msgstr "Desligar" + +msgid "Delete" +msgstr "Remover" + msgid "Add a Storage Device to VM" msgstr "Adicionar um dispositivo de storage à VM" @@ -1415,36 +1455,6 @@ msgstr "O caminho do arquivo ISO para o CDROM no servidor." msgid "Attach" msgstr "Adicionar" -msgid "Cloning" -msgstr "Clonando" - -msgid "Start" -msgstr "Iniciar" - -msgid "Reset" -msgstr "Reiniciar" - -msgid "Power Off" -msgstr "Forçar desligamento" - -msgid "Actions" -msgstr "Ações" - -msgid "Connect" -msgstr "Conectar" - -msgid "Clone" -msgstr "Clonar" - -msgid "Edit" -msgstr "Editar" - -msgid "Shut Down" -msgstr "Desligar" - -msgid "Delete" -msgstr "Remover" - msgid "The username or password you entered is incorrect. Please try again." msgstr "" "O usuário ou senha inseridos estão incorretos. Por favor, tente novamente." @@ -1981,21 +1991,6 @@ msgstr "Sim" msgid "No" msgstr "Não" -msgid "Add a Volume to Storage Pool" -msgstr "Adicionar um volume ao Storage Pool" - -msgid "Fetch from remote URL" -msgstr "Fazer download de uma URL remota" - -msgid "Enter the remote URL here." -msgstr "Digite a URL remota aqui." - -msgid "Upload a file" -msgstr "Fazer upload de um arquivo" - -msgid "Choose the file you want to upload." -msgstr "Escolha o arquivo que você quer fazer upload." - msgid "Define a New Storage Pool" msgstr "Definir novo Storage Pool" @@ -2069,6 +2064,21 @@ msgstr "Adaptador SCSI" msgid "Please, wait..." msgstr "Por favor, aguarde..." +msgid "Add a Volume to Storage Pool" +msgstr "Adicionar um volume ao Storage Pool" + +msgid "Fetch from remote URL" +msgstr "Fazer download de uma URL remota" + +msgid "Enter the remote URL here." +msgstr "Digite a URL remota aqui." + +msgid "Upload a file" +msgstr "Fazer upload de um arquivo" + +msgid "Choose the file you want to upload." +msgstr "Escolha o arquivo que você quer fazer upload." + msgid "Add Template" msgstr "Adicionar Modelo" diff --git a/po/ru_RU.po b/po/ru_RU.po index 389c853..a4accb5 100644 --- a/po/ru_RU.po +++ b/po/ru_RU.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-25 16:00-0300\n" +"POT-Creation-Date: 2015-03-04 16:25-0600\n" "PO-Revision-Date: 2014-08-28 17:32+0000\n" "Last-Translator: Aline Manera <aline.manera@gmail.com>\n" "Language-Team: Russian (http://www.transifex.com/projects/p/kimchi/language/" @@ -893,6 +893,13 @@ msgstr "Истек тайм-аут выполнения команды %(cmd)s ( msgid "Unable to choose a virtual machine name" msgstr "" +#, python-format +msgid "Invalid data value '%(value)s'" +msgstr "" + +msgid "Invalid data unit '%(unit)s'" +msgstr "" + msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" msgstr "Недопустимый тип памяти. Поддерживаемые типы: cdrom" @@ -1266,39 +1273,12 @@ msgstr "Отмена" msgid "revert" msgstr "" -msgid "Add a Storage Device to VM" -msgstr "Добавить устройство хранения в VM" - -msgid "Device Type" -msgstr "Тип устройства" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "Тип устройства. В данный момент поддерживается только \"cdrom\"." - -msgid "Storage Pool" -msgstr "Пул памяти" - -msgid "Storage pool which volume located in" -msgstr "Путь к пулу памяти должен быть строкой" - -msgid "Storage Volume" -msgstr "Имя пула памяти" - -msgid "Storage volume to be attached" -msgstr "Имя тома должно быть строкой" - -msgid "File Path" -msgstr "Путь к файлу" - -msgid "The ISO file path in the server for CDROM." -msgstr "Путь к файлу ISO для CDROM на сервере." - -msgid "Attach" -msgstr "Подключить" - msgid "Cloning" msgstr "" +msgid "Creating" +msgstr "" + msgid "Start" msgstr "Запустить" @@ -1326,6 +1306,36 @@ msgstr "Завершить работу" msgid "Delete" msgstr "Удалить" +msgid "Add a Storage Device to VM" +msgstr "Добавить устройство хранения в VM" + +msgid "Device Type" +msgstr "Тип устройства" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "Тип устройства. В данный момент поддерживается только \"cdrom\"." + +msgid "Storage Pool" +msgstr "Пул памяти" + +msgid "Storage pool which volume located in" +msgstr "Путь к пулу памяти должен быть строкой" + +msgid "Storage Volume" +msgstr "Имя пула памяти" + +msgid "Storage volume to be attached" +msgstr "Имя тома должно быть строкой" + +msgid "File Path" +msgstr "Путь к файлу" + +msgid "The ISO file path in the server for CDROM." +msgstr "Путь к файлу ISO для CDROM на сервере." + +msgid "Attach" +msgstr "Подключить" + msgid "The username or password you entered is incorrect. Please try again." msgstr "Указано неверное имя пользователя или пароль. Введите еще раз." @@ -1839,21 +1849,6 @@ msgstr "Да" msgid "No" msgstr "Нет" -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - msgid "Define a New Storage Pool" msgstr "Создать пул памяти" @@ -1926,6 +1921,21 @@ msgstr "Адаптер SCSI" msgid "Please, wait..." msgstr "Подождите..." +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + msgid "Add Template" msgstr "Добавить шаблон" diff --git a/po/zh_CN.po b/po/zh_CN.po index fa9e5d2..e695487 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -20,7 +20,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-25 16:00-0300\n" +"POT-Creation-Date: 2015-03-04 16:25-0600\n" "PO-Revision-Date: 2013-06-27 10:48+0000\n" "Last-Translator: ShaoHe Feng <shaohef@linux.vnet.ibm.com>\n" "Language-Team: ShaoHe Feng <shaohef@linux.vnet.ibm.com>\n" @@ -881,6 +881,13 @@ msgstr "命令'%(cmd)s'运行%(seconds)s秒后超时。" msgid "Unable to choose a virtual machine name" msgstr "未能选择一个虚拟机名称" +#, python-format +msgid "Invalid data value '%(value)s'" +msgstr "" + +msgid "Invalid data unit '%(unit)s'" +msgstr "" + msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" msgstr "无效的存储类型。支持类型为:'cdrom','disk'" @@ -1247,39 +1254,12 @@ msgstr "取消" msgid "revert" msgstr "恢复" -msgid "Add a Storage Device to VM" -msgstr "为虚拟机添加一个存储设备" - -msgid "Device Type" -msgstr "设备类型" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "设备类型。目前支持设备类型:\"cdrom\"和\"disk\"。 " - -msgid "Storage Pool" -msgstr "存储池" - -msgid "Storage pool which volume located in" -msgstr "存储卷所在的存储池" - -msgid "Storage Volume" -msgstr "存储卷" - -msgid "Storage volume to be attached" -msgstr "被添加的存储卷" - -msgid "File Path" -msgstr "文件路径" - -msgid "The ISO file path in the server for CDROM." -msgstr "服务器端CDROM所使用的ISO文件路径" - -msgid "Attach" -msgstr "装载" - msgid "Cloning" msgstr "正在制作副本" +msgid "Creating" +msgstr "" + msgid "Start" msgstr "启用" @@ -1307,6 +1287,36 @@ msgstr "关机" msgid "Delete" msgstr "删除" +msgid "Add a Storage Device to VM" +msgstr "为虚拟机添加一个存储设备" + +msgid "Device Type" +msgstr "设备类型" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "设备类型。目前支持设备类型:\"cdrom\"和\"disk\"。 " + +msgid "Storage Pool" +msgstr "存储池" + +msgid "Storage pool which volume located in" +msgstr "存储卷所在的存储池" + +msgid "Storage Volume" +msgstr "存储卷" + +msgid "Storage volume to be attached" +msgstr "被添加的存储卷" + +msgid "File Path" +msgstr "文件路径" + +msgid "The ISO file path in the server for CDROM." +msgstr "服务器端CDROM所使用的ISO文件路径" + +msgid "Attach" +msgstr "装载" + msgid "The username or password you entered is incorrect. Please try again." msgstr "用户名或密码错误,请重新输入。" @@ -1805,21 +1815,6 @@ msgstr "是" msgid "No" msgstr "否" -msgid "Add a Volume to Storage Pool" -msgstr "为存储池添加一个卷" - -msgid "Fetch from remote URL" -msgstr "从远程URL获取" - -msgid "Enter the remote URL here." -msgstr "在这里输入远程URL。" - -msgid "Upload a file" -msgstr "上传一个文件" - -msgid "Choose the file you want to upload." -msgstr "选择需要上传的文件。" - msgid "Define a New Storage Pool" msgstr "定义一个新的存储池" @@ -1890,6 +1885,21 @@ msgstr "SCSI适配器" msgid "Please, wait..." msgstr "请等待..." +msgid "Add a Volume to Storage Pool" +msgstr "为存储池添加一个卷" + +msgid "Fetch from remote URL" +msgstr "从远程URL获取" + +msgid "Enter the remote URL here." +msgstr "在这里输入远程URL。" + +msgid "Upload a file" +msgstr "上传一个文件" + +msgid "Choose the file you want to upload." +msgstr "选择需要上传的文件。" + msgid "Add Template" msgstr "创建模板" diff --git a/po/zh_TW.po b/po/zh_TW.po index a41a046..426e991 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: kimchi 0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-25 16:00-0300\n" +"POT-Creation-Date: 2015-03-04 16:25-0600\n" "PO-Revision-Date: 2013-07-11 17:32-0400\n" "Last-Translator: Crístian Viana <vianac@linux.vnet.ibm.com>\n" "Language-Team: English\n" @@ -853,6 +853,13 @@ msgstr "執行指令 '%(cmd)s' %(seconds)s 秒之後逾時" msgid "Unable to choose a virtual machine name" msgstr "" +#, python-format +msgid "Invalid data value '%(value)s'" +msgstr "" + +msgid "Invalid data unit '%(unit)s'" +msgstr "" + msgid "Invalid storage type. Types supported: 'cdrom', 'disk'" msgstr "儲存體類型無效。受支援的類型:'cdrom'" @@ -1217,39 +1224,12 @@ msgstr "取消 " msgid "revert" msgstr "" -msgid "Add a Storage Device to VM" -msgstr "將儲存裝置新增至 VM" - -msgid "Device Type" -msgstr "裝置類型" - -msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." -msgstr "裝置類型。目前僅支援 \"cdrom\"。" - -msgid "Storage Pool" -msgstr "儲存區" - -msgid "Storage pool which volume located in" -msgstr "儲存區路徑必須是字串" - -msgid "Storage Volume" -msgstr "儲存區名稱" - -msgid "Storage volume to be attached" -msgstr "儲存磁區名稱必須是字串" - -msgid "File Path" -msgstr "檔案路徑" - -msgid "The ISO file path in the server for CDROM." -msgstr "CDROM 的 ISO 檔案路徑在伺服器中。" - -msgid "Attach" -msgstr "連接" - msgid "Cloning" msgstr "" +msgid "Creating" +msgstr "" + msgid "Start" msgstr "開始" @@ -1277,6 +1257,36 @@ msgstr "關閉" msgid "Delete" msgstr "刪除" +msgid "Add a Storage Device to VM" +msgstr "將儲存裝置新增至 VM" + +msgid "Device Type" +msgstr "裝置類型" + +msgid "The device type. Currently, \"cdrom\" and \"disk\" are supported." +msgstr "裝置類型。目前僅支援 \"cdrom\"。" + +msgid "Storage Pool" +msgstr "儲存區" + +msgid "Storage pool which volume located in" +msgstr "儲存區路徑必須是字串" + +msgid "Storage Volume" +msgstr "儲存區名稱" + +msgid "Storage volume to be attached" +msgstr "儲存磁區名稱必須是字串" + +msgid "File Path" +msgstr "檔案路徑" + +msgid "The ISO file path in the server for CDROM." +msgstr "CDROM 的 ISO 檔案路徑在伺服器中。" + +msgid "Attach" +msgstr "連接" + msgid "The username or password you entered is incorrect. Please try again." msgstr "您輸入的使用者名稱或密碼不正確。請重試。" @@ -1779,21 +1789,6 @@ msgstr "是" msgid "No" msgstr "否" -msgid "Add a Volume to Storage Pool" -msgstr "" - -msgid "Fetch from remote URL" -msgstr "" - -msgid "Enter the remote URL here." -msgstr "" - -msgid "Upload a file" -msgstr "" - -msgid "Choose the file you want to upload." -msgstr "" - msgid "Define a New Storage Pool" msgstr "定義新的儲存區" @@ -1864,6 +1859,21 @@ msgstr "SCSI 配接卡" msgid "Please, wait..." msgstr "請稍候..." +msgid "Add a Volume to Storage Pool" +msgstr "" + +msgid "Fetch from remote URL" +msgstr "" + +msgid "Enter the remote URL here." +msgstr "" + +msgid "Upload a file" +msgstr "" + +msgid "Choose the file you want to upload." +msgstr "" + msgid "Add Template" msgstr "新增範本" -- 2.1.0

The subject is wrong. I resent a duplicate set of patches with the correct subject (Async Guest Creation). On 04/17/2015 10:23 AM, Christy Perez wrote:
If a guest has a large disk, and uses a filesystem that requires preallocation, it can take several minutes to create a VM. During that time, kimchi is tied up by the VM creation.
This patch changes the VMs Collection to be an AsyncCollection.
Another change required for this was to create a more granular way to query tasks. Currently it is not possible (using the API) to query tasks for the same collection or resource type that may have different operations. For example, VM cloning is also an asynchronous operation. For the guests tab, the UI was querying all running tasks and displaying them with the Cloning label. This picked up VMs that were being created as well. For more information about how the tasks can be queried, see the updated API doc and the UI change.
Christy Perez (7): Granular Task Queries: Backend Granular task query test updates Granular Task Queries: UI Create guests asynchronously: Backend Async vm creation test updates VMs Async Create: UI Translation update to add 'Creating'
docs/API.md | 16 ++++++ po/de_DE.po | 103 ++++++++++++++++++++----------------- po/en_US.po | 83 +++++++++++++++++------------- po/es_ES.po | 102 +++++++++++++++++++----------------- po/fr_FR.po | 102 +++++++++++++++++++----------------- po/it_IT.po | 102 +++++++++++++++++++----------------- po/ja_JP.po | 102 +++++++++++++++++++----------------- po/kimchi.pot | 84 +++++++++++++++++------------- po/ko_KR.po | 102 +++++++++++++++++++----------------- po/pt_BR.po | 102 +++++++++++++++++++----------------- po/ru_RU.po | 102 +++++++++++++++++++----------------- po/zh_CN.po | 102 +++++++++++++++++++----------------- po/zh_TW.po | 102 +++++++++++++++++++----------------- src/kimchi/control/vms.py | 4 +- src/kimchi/mockmodel.py | 7 +-- src/kimchi/model/debugreports.py | 4 +- src/kimchi/model/host.py | 4 +- src/kimchi/model/storagepools.py | 2 +- src/kimchi/model/storagevolumes.py | 12 +++-- src/kimchi/model/vms.py | 33 +++++++++--- src/kimchi/model/vmsnapshots.py | 5 +- tests/test_authorization.py | 23 +++++---- tests/test_mockmodel.py | 12 +++-- tests/test_model.py | 60 ++++++++++++++------- tests/test_model_storagevolume.py | 2 +- tests/test_rest.py | 77 ++++++++++++++++++++------- ui/css/theme-default/list.css | 18 +++++++ ui/js/src/kimchi.guest_main.js | 29 +++++++++-- ui/pages/guest.html.tmpl | 3 ++ 29 files changed, 886 insertions(+), 613 deletions(-)
participants (1)
-
Christy Perez