def create(self, vmid, params): dev_name = params['name'] dev_info = self.dev_model.lookup(dev_name) if dev_info['device_type'] == 'pci': taskid = AsyncTask( u'/plugins/kimchi/vms/%s/hostdevs/' % VMModel.get_vm(vmid, self.conn).name(), self._attach_pci_device, {'vmid': vmid, 'dev_info': dev_info, 'lock': threading.RLock()}, ).id return self.task.lookup(taskid) with RollbackContext() as rollback: try: dev = self.conn.get().nodeDeviceLookupByName(dev_name) dev.dettach() except Exception: raise OperationFailed('KCHVMHDEV0005E', {'name': dev_name}) else: rollback.prependDefer(dev.reAttach) rollback.commitAll() taskid = AsyncTask( u'/plugins/kimchi/vms/%s/hostdevs/' % VMModel.get_vm(vmid, self.conn).name(), '_attach_%s_device' % dev_info['device_type'], {'vmid': vmid, 'dev_info': dev_info, 'lock': threading.RLock()}, ).id return self.task.lookup(taskid)
def test_tasks(self): id1 = AsyncTask('/plugins/ginger/tasks/1', self._async_op).id id2 = AsyncTask('/plugins/ginger/tasks/2', self._except_op).id id3 = AsyncTask('/plugins/ginger/tasks/3', self._intermid_op).id target_uri = urllib2.quote('^/plugins/ginger/tasks/*', safe="") filter_data = 'status=running&target_uri=%s' % target_uri tasks = json.loads( self.request('/plugins/ginger/tasks?%s' % filter_data).read()) self.assertEquals(3, len(tasks)) tasks = json.loads(self.request('/plugins/ginger/tasks').read()) tasks_ids = [t['id'] for t in tasks] self.assertEquals(set([id1, id2, id3]) - set(tasks_ids), set([])) wait_task(self._task_lookup, id2) foo2 = json.loads( self.request('/plugins/ginger/tasks/%s' % id2).read()) keys = ['id', 'status', 'message', 'target_uri'] self.assertEquals(sorted(keys), sorted(foo2.keys())) self.assertEquals('failed', foo2['status']) wait_task(self._task_lookup, id3) foo3 = json.loads( self.request('/plugins/ginger/tasks/%s' % id3).read()) self.assertEquals('in progress', foo3['message']) self.assertEquals('running', foo3['status'])
def create(self, params): uuid_uuid4 = uuid.uuid4() if isinstance(uuid_uuid4, unicode): uuid_uuid4 = uuid_uuid4.encode('utf-8') archive_id = str(uuid_uuid4) stamp = int(time.mktime(time.localtime())) # Though formally we ask front-end to not send "include" at all when # it's empty, but in implementation we try to be tolerant. # Front-end can also send [] to indicate the "include" is empty. include = params.get('include') exclude = params.get('exclude', []) if not include: include = self._default_include if not exclude: exclude = self._default_exclude ar_params = { 'identity': archive_id, 'include': include, 'exclude': exclude, 'description': params.get('description', ''), 'checksum': {}, 'timestamp': stamp, 'file': '' } taskid = AsyncTask(u'/backup/create/%s' % (archive_id), self._create_task, ar_params).id return self.task.lookup(taskid)
def _mock_vmsnapshots_create(self, vm_name, params): name = params.get('name', unicode(int(time.time()))) params = {'vm_name': vm_name, 'name': name} taskid = AsyncTask( u'/plugins/kimchi/vms/%s/snapshots/%s' % (vm_name, name), self._vmsnapshots_create_task, params).id return self.task_lookup(taskid)
def _do_deep_scan(self, params): scan_params = dict(ignore_list=[]) scan_params['scan_path'] = params['path'] params['type'] = 'dir' for pool in self.get_list(): try: res = StoragePoolModel(conn=self.conn, objstore=self.objstore).lookup(pool) if res['state'] == 'active': scan_params['ignore_list'].append(res['path']) except Exception as e: wok_log.debug(f'Exception {e} occured when get ignore path') params['path'] = self.scanner.scan_dir_prepare(params['name']) scan_params['pool_path'] = params['path'] task_id = AsyncTask( f'/plugins/kimchi/storagepools/{ISO_POOL_NAME}', self.scanner.start_scan, scan_params, ).id # Record scanning-task/storagepool mapping for future querying try: with self.objstore as session: session.store('scanning', params['name'], task_id, get_kimchi_version()) return task_id except Exception as e: raise OperationFailed('KCHPOOL0037E', {'err': e.message})
def delete(self, vmid, dev_name): dom = VMModel.get_vm(vmid, self.conn) xmlstr = dom.XMLDesc(0) root = objectify.fromstring(xmlstr) try: hostdev = root.devices.hostdev except AttributeError: raise NotFoundError('KCHVMHDEV0001E', { 'vmid': vmid, 'dev_name': dev_name}) task_params = { 'vmid': vmid, 'dev_name': dev_name, 'dom': dom, 'hostdev': hostdev, 'lock': threading.RLock(), } task_uri = u'/plugins/kimchi/vms/%s/hostdevs/%s' % ( VMModel.get_vm(vmid, self.conn).name(), dev_name, ) taskid = AsyncTask(task_uri, self._detach_device, task_params).id return self.task.lookup(taskid)
def _gen_debugreport_file(self, name): gen_cmd = self.get_system_report_tool() if gen_cmd is not None: return AsyncTask('/plugins/gingerbase/debugreports/%s' % name, gen_cmd, name).id raise OperationFailed('GGBDR0002E')
def trigger(self, name): """ Trigger LUN scanning """ taskid = AsyncTask('/plugins/gingers390/lunscan/trigger', utils.trigger_lun_scan, {}).id return self.task.lookup(taskid)
def lookup(self, *name): try: swupdate = SoftwareUpdate() except: raise OperationFailed('GGBPKGUPD0004E') taskid = AsyncTask('/plugins/gingerbase/host/swupdateprogress', swupdate.tailUpdateLogs).id return self.task.lookup(taskid)
def format(self, name, fstype): if utils._is_mntd(name): raise OperationFailed('GINPART00004E') task_params = {'name': name, 'fstype': fstype} taskid = AsyncTask(u'/partitions/%s/fstype%s' % (name, fstype), self._format_task, task_params).id return self.task.lookup(taskid)
def create(self, params): if 'pv_name' not in params: raise MissingParameter("GINPV00001E") pvname = params['pv_name'] taskid = AsyncTask(u'/pvs/pv_name/%s' % (pvname), self._create_task, params).id return self.task.lookup(taskid)
def test_async_tasks_model(self): class task_except(Exception): pass def abnormal_op(cb, params): try: raise task_except except: cb("Exception raised", False) inst = model.Model() taskid = AsyncTask('', self._quick_op, 'Hello').id inst.task_wait(taskid) self.assertEquals('finished', inst.task_lookup(taskid)['status']) self.assertEquals('Hello', inst.task_lookup(taskid)['message']) params = { 'delay': 3, 'result': False, 'message': 'It was not meant to be' } taskid = AsyncTask('', self._long_op, params).id self.assertEquals('running', inst.task_lookup(taskid)['status']) self.assertEquals('The request is being processing.', inst.task_lookup(taskid)['message']) inst.task_wait(taskid) self.assertEquals('failed', inst.task_lookup(taskid)['status']) self.assertEquals('It was not meant to be', inst.task_lookup(taskid)['message']) taskid = AsyncTask('', abnormal_op, {}).id inst.task_wait(taskid) self.assertEquals('Exception raised', inst.task_lookup(taskid)['message']) self.assertEquals('failed', inst.task_lookup(taskid)['status']) taskid = AsyncTask('', self._continuous_ops, {'result': True}).id self.assertEquals('running', inst.task_lookup(taskid)['status']) inst.task_wait(taskid, timeout=10) self.assertEquals('finished', inst.task_lookup(taskid)['status'])
def create(self, params): if 'vg_name' not in params: raise MissingParameter('GINLV00001E') vgname = params['vg_name'] if 'size' not in params: raise MissingParameter('GINLV00002E') taskid = AsyncTask(u'/lvs/vg_name/%s' % (vgname), self._create_linear_task, params).id return self.task.lookup(taskid)
def create(self, params): if 'vg_name' not in params: raise MissingParameter("GINVG00013E") vgname = params['vg_name'] if "pv_paths" not in params: raise MissingParameter("GINVG00014E") taskid = AsyncTask(u'/vgs/vg_name/%s' % (vgname), self._create_task, params).id return self.task.lookup(taskid)
def _mock_vm_migrate(self, name, remote_host, user=None, password=None, enable_rdma=None): if enable_rdma is None: enable_rdma = False params = {'remote_host': remote_host, 'enable_rdma': enable_rdma} taskid = AsyncTask(u'/plugins/kimchi/vms/%s/migrate' % name, self._vmmigrate_create_task, params).id return self.task_lookup(taskid)
def enable_sriov(self, name, args): kernel_mod = netinfo.get_interface_kernel_module(name) if kernel_mod not in ['mlx5_core', 'mlx5-core']: raise InvalidOperation("GINNET0076E", { 'name': name, 'module': kernel_mod }) num_vfs = self._mlx5_SRIOV_precheck(name, args) params = {'name': name, 'num_vfs': num_vfs} task_id = AsyncTask('/plugins/ginger/network/%s/enable_sriov' % name, self._mlx5_SRIOV_enable_task, params).id return self.task.lookup(task_id)
def swupdate(self, *name): try: swupdate = SoftwareUpdate() except Exception: raise OperationFailed('GGBPKGUPD0004E') pkgs = swupdate.getNumOfUpdates() if pkgs == 0: wok_log.debug(messages['GGBPKGUPD0001E']) return {'message': messages['GGBPKGUPD0001E']} wok_log.debug('Host is going to be updated.') taskid = AsyncTask('/plugins/gingerbase/host/swupdate', swupdate.doUpdate).id return self.task.lookup(taskid)
def test_kill_async_task(self): def continuous_ops(cb, params): for i in range(30): cb(f'...step {i} OK') time.sleep(2) cb('FINAL step OK', params.get('result', True)) def kill_function(): print('... killing task...... BUUUUUUM') taskid = AsyncTask('', continuous_ops, { 'result': True}, kill_function).id self.assertEqual('running', self._task_lookup(taskid)['status']) time.sleep(10) tasks_queue[taskid].kill() self.assertEqual('killed', self._task_lookup(taskid)['status'])
def upgrade(self, name): """ Execute the update of a specific package (and its dependencies, if necessary) in the system. @param: Name @return: task """ if self.host_swupdate is None: raise OperationFailed('GGBPKGUPD0004E') self.pkgs2update = self.host_swupdate.getUpdates() pkgs_list = self._resolve_dependencies(name) msg = 'The following packages will be updated: ' + ', '.join(pkgs_list) wok_log.debug(msg) taskid = AsyncTask('/plugins/gingerbase/host/packagesupdate/%s/upgrade' % name, self.host_swupdate.doUpdate, pkgs_list).id return self.task.lookup(taskid)
def create(self, params): file_loc = '' if 'file_loc' not in params or not params['file_loc']: raise InvalidParameter('GINSP00001E') if 'type' not in params: raise InvalidParameter('GINSP00002E') else: if params['type'] == 'file' and 'size' not in params: raise InvalidParameter('GINSP00003E') if params['type'] == 'device' or params['type'] == 'file': taskid = AsyncTask(u'/swaps/file_loc/%s' % (file_loc), self._create_task, params).id return self.task.lookup(taskid) else: raise InvalidParameter('GINSP00004E')
def remove(self, name, devices): """ Remove one or more device IDs from blacklist. :param devices: List of devices :return: task json """ # Check the type of devices. if not (isinstance(devices, list)): wok_log.error('Input is not of type list. Input: %s' % devices) raise InvalidParameter( 'GS390XINVINPUT', {'reason': 'input must ' 'be of type' ' list'}) wok_log.info('Create task for removing devices \"% s\" from ignore' 'list' % devices) taskid = AsyncTask('/plugins/gingers390x/cioignore/remove', _remove_devices, devices).id return self.task.lookup(taskid)
def unconfigure(self, interface): """ method to un-configure network device - remove or bring the network device offline and unpersist it :param interface: name of the network interface :return: returns task json """ wok_log.info('Un-configuring network device %s' % interface) if isinstance(interface, unicode): # as str() cannot be done on non ascii unicode # it needs encoded value interface = interface.encode('utf-8') device = str(interface).strip() if ENCCW in device: # filtering out device id from interface device = device.replace(ENCCW, '') taskid = AsyncTask( '/plugins/gingers390x/nwdevices/%s/unconfigure' % interface, _unconfigure_interface, device).id return self.task.lookup(taskid)
def test_kill_async_task(self): def continuous_ops(cb, params): for i in range(30): cb(f'...step {i} OK') time.sleep(2) cb('FINAL step OK', params.get('result', True)) def kill_function(): print('... killing task...... BUUUUUUM') taskid = AsyncTask('', continuous_ops, { 'result': True }, kill_function).id tasks = json.loads(self.request('/tasks').read()) self.assertLessEqual(1, len(tasks)) time.sleep(10) resp = self.request(f'/tasks/{taskid}', '{}', 'DELETE') self.assertEqual(204, resp.status) task = json.loads(self.request(f'/tasks/{taskid}').read()) self.assertEqual('killed', task['status'])
def configure(self, interface, osa_portno): """ method to configure network device - bring the network device online and persist it :param interface: name of the network interface :return: returns task json """ wok_log.info('Configuring network device %s' % interface) if isinstance(interface, unicode): # as str() cannot be done on non ascii unicode # it needs encoded value interface = interface.encode('utf-8') device = str(interface).strip() if ENCCW in device: # filtering out device id from interface device = device.replace(ENCCW, '') params = {'osa_portno': osa_portno, 'interface': device} taskid = AsyncTask( '/plugins/gingers390x/nwdevices/%s/configure' % interface, _configure_interface, params).id return self.task.lookup(taskid)
def create(self, vm_name, params=None): """Create a snapshot with the current domain state. The VM must be stopped and contain only disks with format 'qcow2'; otherwise an exception will be raised. Parameters: vm_name -- the name of the VM where the snapshot will be created. params -- a dict with the following values: "name": The snapshot name (optional). If omitted, a default value based on the current time will be used. Return: A Task running the operation. """ if params is None: params = {} vir_dom = VMModel.get_vm(vm_name, self.conn) if DOM_STATE_MAP[vir_dom.info()[0]] != u'shutoff': raise InvalidOperation('KCHSNAP0001E', {'vm': vm_name}) # if the VM has a non-CDROM disk with type 'raw', abort. for storage_name in self.vmstorages.get_list(vm_name): storage = self.vmstorage.lookup(vm_name, storage_name) type = storage['type'] format = storage['format'] if type != u'cdrom' and format != u'qcow2': raise InvalidOperation('KCHSNAP0010E', { 'vm': vm_name, 'format': format }) name = params.get('name', unicode(int(time.time()))) task_params = {'vm_name': vm_name, 'name': name} taskid = AsyncTask( u'/plugins/kimchi/vms/%s/snapshots/%s' % (vm_name, name), self._create_task, task_params).id return self.task.lookup(taskid)
def upgrade(self, ident, fw_path=None, pow_ok=None): if detect_live_vm(): raise OperationFailed('GINFW0001E') # Process argumets provided by user: firmware path and overwrite-perm if fw_path is None: raise OperationFailed('GINFW0003E') ms = magic.open(magic.NONE) ms.load() if ms.file(fw_path).lower().startswith('rpm'): # First unpack the rpm to get the fw img file command = ['rpm', '-U', '--force', '--ignoreos', fw_path] output, error, rc = run_command(command) if rc: # rpm returns num failed pkgs on failure or neg for unknown raise OperationFailed('GINFW0002E', {'rc': rc, 'err': error}) # The image file should now be in /tmp/fwupdate/ # and match the rpm name. image_file, ext = os.path.splitext(os.path.basename(fw_path)) image_file = os.path.join('/tmp/fwupdate', '%s.img' % image_file) if not os.path.exists(image_file): raise OperationFailed('GINFW0003E') else: image_file = fw_path ms.close() command = ['update_flash', '-f', image_file] if pow_ok is not None: command.insert(1, '-n') # update_flash may take some time to restart the system. Inform user. wok_log.info('FW update: System will reboot to flash the firmware.') cmd_params = {'command': command, 'operation': 'update'} taskid = AsyncTask('/plugins/ginger/firmware/upgrade', self._execute_task, cmd_params).id return self.task.lookup(taskid)
def format(self, bus_id, blk_size): tasks = [] dasd_utils.validate_bus_id(bus_id) woklock = threading.Lock() name = self.dev_details['name'] dasd_name_list = dasd_utils._get_dasd_names() if name not in dasd_name_list: raise NotFoundError('GINDASD0007E') task_params = {'blk_size': blk_size, 'name': name} try: woklock.acquire() with self.objstore as session: tasks = session.get_list('task') running_tasks = [] for task in tasks: with self.objstore as session: current_task = session.get('task', str(task)) if (current_task['target_uri'].startswith('/dasddevs') and current_task['status']) == 'running': running_tasks.append(current_task) # Limit the number of concurrent DASD format operations to # MAX_DASD_FMT. if len(running_tasks) > MAX_DASD_FMT: raise InvalidOperation("GINDASD0014E", {'max_dasd_fmt': str(MAX_DASD_FMT)}) taskid = AsyncTask(u'/dasddevs/%s/blksize/%s' % (name, blk_size), self._format_task, task_params).id except OperationFailed: woklock.release() raise OperationFailed("GINDASD0008E", {'name': name}) finally: woklock.release() return self.task.lookup(taskid)
def clone(self, pool, name, new_pool=None, new_name=None): """Clone a storage volume. Arguments: pool -- The name of the original pool. name -- The name of the original volume. new_pool -- The name of the destination pool (optional). If omitted, the new volume will be created on the same pool as the original one. new_name -- The name of the new volume (optional). If omitted, a new value based on the original volume's name will be used. Return: A Task running the clone operation. """ # the same pool will be used if no pool is specified if new_pool is None: new_pool = pool # a default name based on the original name will be used if no name # is specified if new_name is None: base, ext = os.path.splitext(name) new_name = get_next_clone_name( self.storagevolumes.get_list(pool), base, ext ) params = { 'pool': pool, 'name': name, 'new_pool': new_pool, 'new_name': new_name, } target_uri = '/plugins/kimchi/storagepools/%s/storagevolumes/%s/clone' taskid = AsyncTask(target_uri % (pool, new_name), self._clone_task, params).id return self.task.lookup(taskid)
scan_params['scan_path'] = params['path'] params['type'] = 'dir' for pool in self.get_list(): try: res = StoragePoolModel(conn=self.conn, objstore=self.objstore).lookup(pool) if res['state'] == 'active': scan_params['ignore_list'].append(res['path']) except Exception, e: err = "Exception %s occured when get ignore path" wok_log.debug(err % e.message) params['path'] = self.scanner.scan_dir_prepare(params['name']) scan_params['pool_path'] = params['path'] task_id = AsyncTask('/plugins/kimchi/storagepools/%s' % ISO_POOL_NAME, self.scanner.start_scan, scan_params).id # Record scanning-task/storagepool mapping for future querying try: with self.objstore as session: session.store('scanning', params['name'], task_id, get_kimchi_version()) return task_id except Exception as e: raise OperationFailed('KCHPOOL0037E', {'err': e.message}) class StoragePoolModel(object): def __init__(self, **kargs): self.conn = kargs['conn'] self.objstore = kargs['objstore']
def restore(self, archive_id): taskid = AsyncTask(u'/backup/restore/%s' % (archive_id), self._restore_task, archive_id).id return self.task.lookup(taskid)