예제 #1
0
파일: host.py 프로젝트: shaohef/kimchi
 def __init__(self, **kargs):
     try:
         self.host_swupdate = SoftwareUpdate()
     except:
         self.host_swupdate = None
     self.objstore = kargs['objstore']
     self.task = TaskModel(**kargs)
예제 #2
0
 def __init__(self, **kargs):
     self.conn = kargs['conn']
     self.objstore = kargs['objstore']
     self.caps = CapabilitiesModel(**kargs)
     self.vmscreenshot = VMScreenshotModel(**kargs)
     self.users = import_class('kimchi.model.users.UsersModel')(**kargs)
     self.groups = import_class('kimchi.model.groups.GroupsModel')(**kargs)
     self.vms = VMsModel(**kargs)
     self.task = TaskModel(**kargs)
     self.storagepool = model.storagepools.StoragePoolModel(**kargs)
     self.storagevolume = model.storagevolumes.StorageVolumeModel(**kargs)
     self.storagevolumes = model.storagevolumes.StorageVolumesModel(**kargs)
     cls = import_class('kimchi.model.vmsnapshots.VMSnapshotModel')
     self.vmsnapshot = cls(**kargs)
     cls = import_class('kimchi.model.vmsnapshots.VMSnapshotsModel')
     self.vmsnapshots = cls(**kargs)
예제 #3
0
파일: vms.py 프로젝트: cbosdo/kimchi
 def __init__(self, **kargs):
     self.conn = kargs['conn']
     self.objstore = kargs['objstore']
     self.vmscreenshot = VMScreenshotModel(**kargs)
     self.users = import_class('kimchi.model.host.UsersModel')(**kargs)
     self.groups = import_class('kimchi.model.host.GroupsModel')(**kargs)
     self.vms = VMsModel(**kargs)
     self.task = TaskModel(**kargs)
     self.storagepool = model.storagepools.StoragePoolModel(**kargs)
     self.storagevolume = model.storagevolumes.StorageVolumeModel(**kargs)
     self.storagevolumes = model.storagevolumes.StorageVolumesModel(**kargs)
예제 #4
0
class ProgressSampleModel(object):
    def __init__(self, **kargs):
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)

    def progress(self, *name):
        progress = DummyProgress()

        taskid = add_task('/progresssample/progress', progress.doProgress,
                          self.objstore, None)
        return self.task.lookup(taskid)
예제 #5
0
파일: vms.py 프로젝트: gouzongmei/kimchi
 def __init__(self, **kargs):
     self.conn = kargs['conn']
     self.objstore = kargs['objstore']
     self.caps = CapabilitiesModel(**kargs)
     self.vmscreenshot = VMScreenshotModel(**kargs)
     self.users = import_class('kimchi.model.users.UsersModel')(**kargs)
     self.groups = import_class('kimchi.model.groups.GroupsModel')(**kargs)
     self.vms = VMsModel(**kargs)
     self.task = TaskModel(**kargs)
     self.storagepool = model.storagepools.StoragePoolModel(**kargs)
     self.storagevolume = model.storagevolumes.StorageVolumeModel(**kargs)
     self.storagevolumes = model.storagevolumes.StorageVolumesModel(**kargs)
     cls = import_class('kimchi.model.vmsnapshots.VMSnapshotModel')
     self.vmsnapshot = cls(**kargs)
     cls = import_class('kimchi.model.vmsnapshots.VMSnapshotsModel')
     self.vmsnapshots = cls(**kargs)
예제 #6
0
class StorageVolumesModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)

    def create(self, pool_name, params):
        vol_source = ['url', 'capacity']

        name = params.get('name')

        index_list = list(i for i in range(len(vol_source))
                          if vol_source[i] in params)
        if len(index_list) != 1:
            raise InvalidParameter("KCHVOL0018E",
                                   {'param': ",".join(vol_source)})

        create_param = vol_source[index_list[0]]

        # Verify if the URL is valid
        if create_param == 'url':
            url = params['url']
            try:
                urllib2.urlopen(url).close()
            except:
                raise InvalidParameter('KCHVOL0022E', {'url': url})

        all_vol_names = self.get_list(pool_name)

        if name is None:
            # the methods listed in 'REQUIRE_NAME_PARAMS' cannot have
            # 'name' == None
            if create_param in REQUIRE_NAME_PARAMS:
                raise InvalidParameter('KCHVOL0016E')

            # if 'name' is omitted - except for the methods listed in
            # 'REQUIRE_NAME_PARAMS' - the default volume name will be the
            # file/URL basename.
            if create_param == 'url':
                name = os.path.basename(params['url'])
            else:
                name = 'upload-%s' % int(time.time())

            name = get_unique_file_name(all_vol_names, name)
            params['name'] = name

        try:
            create_func = getattr(self, '_create_volume_with_%s' %
                                        create_param)
        except AttributeError:
            raise InvalidParameter("KCHVOL0019E", {'param': create_param})

        pool_info = StoragePoolModel(conn=self.conn,
                                     objstore=self.objstore).lookup(pool_name)
        if pool_info['type'] in READONLY_POOL_TYPE:
            raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']})
        if pool_info['state'] == 'inactive':
            raise InvalidParameter('KCHVOL0003E', {'pool': pool_name,
                                                   'volume': name})
        if name in all_vol_names:
            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)
        return self.task.lookup(taskid)

    def _create_volume_with_capacity(self, cb, params):
        pool_name = params.pop('pool')
        vol_xml = """
        <volume>
          <name>%(name)s</name>
          <allocation unit='bytes'>%(allocation)s</allocation>
          <capacity unit='bytes'>%(capacity)s</capacity>
          <source>
          </source>
          <target>
            <format type='%(format)s'/>
          </target>
        </volume>
        """
        params.setdefault('allocation', 0)
        params.setdefault('format', 'qcow2')

        name = params['name']
        try:
            pool = StoragePoolModel.get_storagepool(pool_name, self.conn)
            xml = vol_xml % params
        except KeyError, item:
            raise MissingParameter("KCHVOL0004E", {'item': str(item),
                                                   'volume': name})

        try:
            pool.createXML(xml, 0)
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHVOL0007E",
                                  {'name': name, 'pool': pool,
                                   'err': e.get_error_message()})

        vol_info = StorageVolumeModel(conn=self.conn,
                                      objstore=self.objstore).lookup(pool_name,
                                                                     name)

        vol_path = vol_info['path']
        set_disk_used_by(self.objstore, vol_info['path'], [])

        if params.get('upload', False):
            upload_volumes[vol_path] = {'lock': threading.Lock(),
                                        'offset': 0, 'cb': cb}
            cb('ready for upload')
        else:
            cb('OK', True)
예제 #7
0
class StorageVolumeModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)
        self.storagevolumes = StorageVolumesModel(**kargs)
        self.storagepool = StoragePoolModel(**kargs)

    @staticmethod
    def get_storagevolume(poolname, name, conn):
        pool = StoragePoolModel.get_storagepool(poolname, conn)
        if not pool.isActive():
            raise InvalidOperation("KCHVOL0006E", {'name': pool})
        try:
            return pool.storageVolLookupByName(name.encode("utf-8"))
        except libvirt.libvirtError as e:
            if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL:
                raise NotFoundError("KCHVOL0002E", {'name': name,
                                                    'pool': poolname})
            else:
                raise

    def lookup(self, pool, name):
        vol = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
        path = vol.path()
        info = vol.info()
        xml = vol.XMLDesc(0)
        try:
            fmt = xpath_get_text(xml, "/volume/target/format/@type")[0]
        except IndexError:
            # Not all types of libvirt storage can provide volume format
            # infomation. When there is no format information, we assume
            # it's 'raw'.
            fmt = 'raw'

        iso_img = None

        # 'raw' volumes from 'logical' pools may actually be 'iso';
        # libvirt always reports them as 'raw'
        pool_info = self.storagepool.lookup(pool)
        if pool_info['type'] == 'logical' and fmt == 'raw':
            try:
                iso_img = IsoImage(path)
            except IsoFormatError:
                # not 'iso' afterall
                pass
            else:
                fmt = 'iso'

        used_by = get_disk_used_by(self.objstore, self.conn, path)
        res = dict(type=VOLUME_TYPE_MAP[info[0]],
                   capacity=info[1],
                   allocation=info[2],
                   path=path,
                   used_by=used_by,
                   format=fmt)
        if fmt == 'iso':
            if os.path.islink(path):
                path = os.path.join(os.path.dirname(path), os.readlink(path))
            os_distro = os_version = 'unknown'
            try:
                if iso_img is None:
                    iso_img = IsoImage(path)
                os_distro, os_version = iso_img.probe()
                bootable = True
            except IsoFormatError:
                bootable = False
            res.update(
                dict(os_distro=os_distro, os_version=os_version, path=path,
                     bootable=bootable))
        return res

    def wipe(self, pool, name):
        volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
        try:
            volume.wipePattern(libvirt.VIR_STORAGE_VOL_WIPE_ALG_ZERO, 0)
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHVOL0009E",
                                  {'name': name, 'err': e.get_error_message()})

    def delete(self, pool, name):
        pool_info = StoragePoolModel(conn=self.conn,
                                     objstore=self.objstore).lookup(pool)
        if pool_info['type'] in READONLY_POOL_TYPE:
            raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']})

        volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
        try:
            volume.delete(0)
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHVOL0010E",
                                  {'name': name, 'err': e.get_error_message()})

    def resize(self, pool, name, size):
        volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn)

        # When decreasing the storage volume capacity, the flag
        # VIR_STORAGE_VOL_RESIZE_SHRINK must be used
        flags = 0
        if volume.info()[1] > size:
            # FIXME: Even using VIR_STORAGE_VOL_RESIZE_SHRINK flag it is not
            # possible to decrease the volume capacity due a libvirt bug
            # For reference:
            # - https://bugzilla.redhat.com/show_bug.cgi?id=1021802
            flags = libvirt.VIR_STORAGE_VOL_RESIZE_SHRINK

        try:
            volume.resize(size, flags)
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHVOL0011E",
                                  {'name': name, 'err': e.get_error_message()})

    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}
        taskid = add_task(u'/storagepools/%s/storagevolumes/%s' %
                          (pool, new_name), self._clone_task, self.objstore,
                          params)
        return self.task.lookup(taskid)

    def _clone_task(self, cb, params):
        """Asynchronous function which performs the clone operation.

        This function copies all the data inside the original volume into the
        new one.

        Arguments:
        cb -- A callback function to signal the Task's progress.
        params -- A dict with the following values:
            "pool": The name of the original pool.
            "name": The name of the original volume.
            "new_pool": The name of the destination pool.
            "new_name": The name of the new volume.
        """
        orig_pool_name = params['pool']
        orig_vol_name = params['name']
        new_pool_name = params['new_pool']
        new_vol_name = params['new_name']

        try:
            cb('setting up volume cloning')
            orig_vir_vol = StorageVolumeModel.get_storagevolume(orig_pool_name,
                                                                orig_vol_name,
                                                                self.conn)
            orig_vol = self.lookup(orig_pool_name, orig_vol_name)
            new_vir_pool = StoragePoolModel.get_storagepool(new_pool_name,
                                                            self.conn)

            cb('building volume XML')
            root_elem = E.volume()
            root_elem.append(E.name(new_vol_name))
            root_elem.append(E.capacity(unicode(orig_vol['capacity']),
                                        unit='bytes'))
            target_elem = E.target()
            target_elem.append(E.format(type=orig_vol['format']))
            root_elem.append(target_elem)
            new_vol_xml = ET.tostring(root_elem, encoding='utf-8',
                                      pretty_print=True)

            cb('cloning volume')
            new_vir_pool.createXMLFrom(new_vol_xml, orig_vir_vol, 0)
        except (InvalidOperation, NotFoundError, libvirt.libvirtError), e:
            raise OperationFailed('KCHVOL0023E',
                                  {'name': orig_vol_name,
                                   'pool': orig_pool_name,
                                   'err': e.get_error_message()})

        new_vol = self.lookup(new_pool_name, new_vol_name)
        cb('adding volume to the object store')
        set_disk_used_by(self.objstore, new_vol['path'], [])

        cb('OK', True)
예제 #8
0
class VMSnapshotsModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)
        self.vmstorages = VMStoragesModel(**kargs)
        self.vmstorage = VMStorageModel(**kargs)

    def create(self, vm_name, params={}):
        """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.
        """
        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 = add_task(u'/vms/%s/snapshots/%s' % (vm_name, name),
                          self._create_task, self.objstore, task_params)
        return self.task.lookup(taskid)

    def _create_task(self, cb, params):
        """Asynchronous function which actually creates the snapshot.

        Parameters:
        cb -- a callback function to signal the Task's progress.
        params -- a dict with the following values:
            "vm_name": the name of the VM where the snapshot will be created.
            "name": the snapshot name.
        """
        vm_name = params['vm_name']
        name = params['name']

        cb('building snapshot XML')
        root_elem = E.domainsnapshot()
        root_elem.append(E.name(name))
        xml = ET.tostring(root_elem, encoding='utf-8')

        try:
            cb('fetching snapshot domain')
            vir_dom = VMModel.get_vm(vm_name, self.conn)
            cb('creating snapshot')
            vir_dom.snapshotCreateXML(xml, 0)
        except (NotFoundError, OperationFailed, libvirt.libvirtError), e:
            raise OperationFailed('KCHSNAP0002E',
                                  {'name': name, 'vm': vm_name,
                                   'err': e.message})

        cb('OK', True)
예제 #9
0
class HostModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)
        self.host_info = self._get_host_info()

    def _get_ppc_cpu_info(self):
        res = {}
        with open('/proc/cpuinfo') as f:
            for line in f.xreadlines():
                # Parse CPU, CPU's revision and CPU's clock information
                for key in ['cpu', 'revision', 'clock']:
                    if key in line:
                        info = line.split(':')[1].strip()
                        if key == 'clock':
                            value = float(info.split('MHz')[0].strip()) / 1000
                        else:
                            value = info.split('(')[0].strip()
                        res[key] = value

                        # Power machines show, for each cpu/core, a block with
                        # all cpu information. Here we control the scan of the
                        # necessary information (1st block provides
                        # everything), skipping the function when find all
                        # information.
                        if len(res.keys()) == 3:
                            return "%(cpu)s (%(revision)s) @ %(clock)s GHz\
                                    " % res

        return ""

    def _get_host_info(self):
        res = {}
        if platform.machine().startswith('ppc'):
            res['cpu'] = self._get_ppc_cpu_info()
        else:
            with open('/proc/cpuinfo') as f:
                for line in f.xreadlines():
                    if "model name" in line:
                        res['cpu'] = line.split(':')[1].strip()
                        break

        res['memory'] = psutil.TOTAL_PHYMEM

        # Include IBM PowerKVM name to supported distro names
        _sup_distros = platform._supported_dists + ('ibm_powerkvm',)
        # 'fedora' '17' 'Beefy Miracle'
        distro, version, codename = platform.linux_distribution(
            supported_dists=_sup_distros)
        res['os_distro'] = distro
        res['os_version'] = version
        res['os_codename'] = unicode(codename, "utf-8")

        return res

    def lookup(self, *name):
        return self.host_info

    def swupdate(self, *name):
        try:
            swupdate = SoftwareUpdate()
        except:
            raise OperationFailed('KCHPKGUPD0004E')

        pkgs = swupdate.getNumOfUpdates()
        if pkgs == 0:
            raise OperationFailed('KCHPKGUPD0001E')

        kimchi_log.debug('Host is going to be updated.')
        taskid = add_task('', swupdate.doUpdate, self.objstore, None)
        return self.task.lookup(taskid)

    def shutdown(self, args=None):
        # Check for running vms before shutdown
        running_vms = self._get_vms_list_by_state('running')
        if len(running_vms) > 0:
            raise OperationFailed("KCHHOST0001E")

        kimchi_log.info('Host is going to shutdown.')
        os.system('shutdown -h now')

    def reboot(self, args=None):
        # Find running VMs
        running_vms = self._get_vms_list_by_state('running')
        if len(running_vms) > 0:
            raise OperationFailed("KCHHOST0002E")

        kimchi_log.info('Host is going to reboot.')
        os.system('reboot')

    def _get_vms_list_by_state(self, state):
        conn = self.conn.get()
        return [dom.name().decode('utf-8')
                for dom in conn.listAllDomains(0)
                if (DOM_STATE_MAP[dom.info()[0]]) == state]
예제 #10
0
 def __init__(self, **kargs):
     self.conn = kargs['conn']
     self.objstore = kargs['objstore']
     self.task = TaskModel(**kargs)
     self.host_info = self._get_host_info()
예제 #11
0
파일: vms.py 프로젝트: pawangha/kimchi
 def __init__(self, **kargs):
     self.conn = kargs['conn']
     self.objstore = kargs['objstore']
     self.caps = CapabilitiesModel(**kargs)
     self.task = TaskModel(**kargs)
예제 #12
0
파일: vms.py 프로젝트: pawangha/kimchi
class VMsModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.caps = CapabilitiesModel(**kargs)
        self.task = TaskModel(**kargs)

    def create(self, params):
        t_name = template_name_from_uri(params['template'])
        vm_list = self.get_list()
        name = get_vm_name(params.get('name'), t_name, vm_list)
        # incoming text, from js json, is unicode, do not need decode
        if name in vm_list:
            raise InvalidOperation("KCHVM0001E", {'name': name})

        vm_overrides = dict()
        pool_uri = params.get('storagepool')
        if pool_uri:
            vm_overrides['storagepool'] = pool_uri
            vm_overrides['fc_host_support'] = self.caps.fc_host_support
        t = TemplateModel.get_template(t_name, self.objstore, self.conn,
                                       vm_overrides)

        if not self.caps.qemu_stream and t.info.get('iso_stream', False):
            raise InvalidOperation("KCHVM0005E")

        t.validate()
        data = {'name': name, 'template': t,
                'graphics': params.get('graphics', {})}
        taskid = add_task(u'/vms/%s' % name, self._create_task,
                          self.objstore, data)

        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 = str(uuid.uuid4())
        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:
            try:
                with self.objstore as session:
                    session.store('vm', vm_uuid, {'icon': icon})
            except Exception as e:
                # It is possible to continue Kimchi executions without store
                # vm icon info
                kimchi_log.error('Error trying to update database with guest '
                                 'icon information due error: %s', e.message)

        # 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)

        graphics = params.get('graphics', {})
        stream_protocols = self.caps.libvirt_stream_protocols
        xml = t.to_vm_xml(name, vm_uuid,
                          libvirt_stream_protocols=stream_protocols,
                          graphics=graphics,
                          volumes=vol_list)

        cb('Defining new VM')
        try:
            conn.defineXML(xml.encode('utf-8'))
        except libvirt.libvirtError as e:
            if t._get_storage_type() not in READONLY_POOL_TYPE:
                for v in vol_list:
                    vol = conn.storageVolLookupByPath(v['path'])
                    vol.delete(0)
            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)
        cb('OK', True)

    def get_list(self):
        return VMsModel.get_vms(self.conn)

    @staticmethod
    def get_vms(conn):
        conn_ = conn.get()
        names = [dom.name().decode('utf-8') for dom in conn_.listAllDomains(0)]
        names = sorted(names, key=unicode.lower)
        return names
예제 #13
0
class StorageVolumesModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)

    def create(self, pool_name, params):
        vol_source = ['file', 'url', 'capacity']

        name = params.get('name')

        index_list = list(i for i in range(len(vol_source))
                          if vol_source[i] in params)
        if len(index_list) != 1:
            raise InvalidParameter("KCHVOL0018E",
                                   {'param': ",".join(vol_source)})

        create_param = vol_source[index_list[0]]

        # Verify if the URL is valid
        if create_param == 'url':
            url = params['url']
            try:
                urllib2.urlopen(url).close()
            except:
                raise InvalidParameter('KCHVOL0022E', {'url': url})

        if name is None:
            # the methods listed in 'REQUIRE_NAME_PARAMS' cannot have
            # 'name' == None
            if create_param in REQUIRE_NAME_PARAMS:
                raise InvalidParameter('KCHVOL0016E')

            # if 'name' is omitted - except for the methods listed in
            # 'REQUIRE_NAME_PARAMS' - the default volume name will be the
            # file/URL basename.
            if create_param == 'file':
                name = os.path.basename(params['file'].filename)
            elif create_param == 'url':
                name = os.path.basename(params['url'])
            else:
                name = 'upload-%s' % int(time.time())
            params['name'] = name

        try:
            create_func = getattr(self, '_create_volume_with_%s' %
                                        create_param)
        except AttributeError:
            raise InvalidParameter("KCHVOL0019E", {'param': create_param})

        pool_info = StoragePoolModel(conn=self.conn,
                                     objstore=self.objstore).lookup(pool_name)
        if pool_info['type'] in READONLY_POOL_TYPE:
            raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']})
        if pool_info['state'] == 'inactive':
            raise InvalidParameter('KCHVOL0003E', {'pool': pool_name,
                                                   'volume': name})
        if name in self.get_list(pool_name):
            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)
        return self.task.lookup(taskid)

    def _create_volume_with_file(self, cb, params):
        pool_name = params.pop('pool')
        dir_path = StoragePoolModel(
            conn=self.conn, objstore=self.objstore).lookup(pool_name)['path']
        file_path = os.path.join(dir_path, params['name'])
        if os.path.exists(file_path):
            raise InvalidParameter('KCHVOL0001E', {'name': params['name']})

        upload_file = params['file']
        f_len = upload_file.fp.length
        try:
            size = 0
            with open(file_path, 'wb') as f:
                while True:
                    data = upload_file.file.read(READ_CHUNK_SIZE)
                    if not data:
                        break
                    size += len(data)
                    f.write(data)
                    cb('%s/%s' % (size, f_len))
        except Exception as e:
            raise OperationFailed('KCHVOL0007E',
                                  {'name': params['name'],
                                   'pool': pool_name,
                                   'err': e.message})

        # Refresh to make sure volume can be found in following lookup
        StoragePoolModel.get_storagepool(pool_name, self.conn).refresh(0)
        cb('OK', True)

    def _create_volume_with_capacity(self, cb, params):
        pool_name = params.pop('pool')
        vol_xml = """
        <volume>
          <name>%(name)s</name>
          <allocation unit="MiB">%(allocation)s</allocation>
          <capacity unit="MiB">%(capacity)s</capacity>
          <source>
          </source>
          <target>
            <format type='%(format)s'/>
          </target>
        </volume>
        """
        params.setdefault('allocation', 0)
        params.setdefault('format', 'qcow2')

        name = params['name']
        vol_id = '%s:%s' % (pool_name, name)
        try:
            pool = StoragePoolModel.get_storagepool(pool_name, self.conn)
            xml = vol_xml % params
        except KeyError, item:
            raise MissingParameter("KCHVOL0004E", {'item': str(item),
                                                   'volume': name})

        try:
            pool.createXML(xml, 0)
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHVOL0007E",
                                  {'name': name, 'pool': pool,
                                   'err': e.get_error_message()})

        try:
            with self.objstore as session:
                session.store('storagevolume', vol_id, {'ref_cnt': 0})
        except Exception as e:
            # If the storage volume was created flawlessly, then lets hide this
            # error to avoid more error in the VM creation process
            kimchi_log.warning('Unable to store storage volume id in '
                               'objectstore due error: %s', e.message)

        cb('', True)
예제 #14
0
class StorageVolumesModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)

    def create(self, pool_name, params):
        vol_source = ['file', 'url', 'capacity']

        name = params.get('name')

        index_list = list(i for i in range(len(vol_source))
                          if vol_source[i] in params)
        if len(index_list) != 1:
            raise InvalidParameter("KCHVOL0018E",
                                   {'param': ",".join(vol_source)})

        create_param = vol_source[index_list[0]]

        # Verify if the URL is valid
        if create_param == 'url':
            url = params['url']
            try:
                urllib2.urlopen(url).close()
            except:
                raise InvalidParameter('KCHVOL0022E', {'url': url})

        all_vol_names = self.get_list(pool_name)

        if name is None:
            # the methods listed in 'REQUIRE_NAME_PARAMS' cannot have
            # 'name' == None
            if create_param in REQUIRE_NAME_PARAMS:
                raise InvalidParameter('KCHVOL0016E')

            # if 'name' is omitted - except for the methods listed in
            # 'REQUIRE_NAME_PARAMS' - the default volume name will be the
            # file/URL basename.
            if create_param == 'file':
                name = os.path.basename(params['file'].filename)
            elif create_param == 'url':
                name = os.path.basename(params['url'])
            else:
                name = 'upload-%s' % int(time.time())

            name = get_unique_file_name(all_vol_names, name)
            params['name'] = name

        try:
            create_func = getattr(self,
                                  '_create_volume_with_%s' % create_param)
        except AttributeError:
            raise InvalidParameter("KCHVOL0019E", {'param': create_param})

        pool_info = StoragePoolModel(conn=self.conn,
                                     objstore=self.objstore).lookup(pool_name)
        if pool_info['type'] in READONLY_POOL_TYPE:
            raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']})
        if pool_info['state'] == 'inactive':
            raise InvalidParameter('KCHVOL0003E', {
                'pool': pool_name,
                'volume': name
            })
        if name in all_vol_names:
            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)
        return self.task.lookup(taskid)

    def _create_volume_with_file(self, cb, params):
        pool_name = params.pop('pool')
        dir_path = StoragePoolModel(
            conn=self.conn, objstore=self.objstore).lookup(pool_name)['path']
        file_path = os.path.join(dir_path, params['name'])
        if os.path.exists(file_path):
            raise InvalidParameter('KCHVOL0001E', {'name': params['name']})

        upload_file = params['file']
        f_len = upload_file.fp.length
        try:
            size = 0
            with open(file_path, 'wb') as f:
                while True:
                    data = upload_file.file.read(READ_CHUNK_SIZE)
                    if not data:
                        break
                    size += len(data)
                    f.write(data)
                    cb('%s/%s' % (size, f_len))
        except Exception as e:
            raise OperationFailed('KCHVOL0007E', {
                'name': params['name'],
                'pool': pool_name,
                'err': e.message
            })

        # Refresh to make sure volume can be found in following lookup
        StoragePoolModel.get_storagepool(pool_name, self.conn).refresh(0)
        cb('OK', True)

    def _create_volume_with_capacity(self, cb, params):
        pool_name = params.pop('pool')
        vol_xml = """
        <volume>
          <name>%(name)s</name>
          <allocation unit='bytes'>%(allocation)s</allocation>
          <capacity unit='bytes'>%(capacity)s</capacity>
          <source>
          </source>
          <target>
            <format type='%(format)s'/>
          </target>
        </volume>
        """
        params.setdefault('allocation', 0)
        params.setdefault('format', 'qcow2')

        name = params['name']
        try:
            pool = StoragePoolModel.get_storagepool(pool_name, self.conn)
            xml = vol_xml % params
        except KeyError, item:
            raise MissingParameter("KCHVOL0004E", {
                'item': str(item),
                'volume': name
            })

        try:
            pool.createXML(xml, 0)
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHVOL0007E", {
                'name': name,
                'pool': pool,
                'err': e.get_error_message()
            })

        path = StoragePoolModel(
            conn=self.conn, objstore=self.objstore).lookup(pool_name)['path']

        try:
            with self.objstore as session:
                session.store('storagevolume', path, {'ref_cnt': 0})
        except Exception as e:
            # If the storage volume was created flawlessly, then lets hide this
            # error to avoid more error in the VM creation process
            kimchi_log.warning(
                'Unable to store storage volume id in '
                'objectstore due error: %s', e.message)

        cb('', True)
예제 #15
0
 def __init__(self, **kargs):
     self.conn = kargs['conn']
     self.objstore = kargs['objstore']
     self.task = TaskModel(**kargs)
     self.storagevolumes = StorageVolumesModel(**kargs)
예제 #16
0
class StorageVolumeModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)
        self.storagevolumes = StorageVolumesModel(**kargs)

    @staticmethod
    def get_storagevolume(poolname, name, conn):
        pool = StoragePoolModel.get_storagepool(poolname, conn)
        if not pool.isActive():
            raise InvalidOperation("KCHVOL0006E", {'name': pool})
        try:
            return pool.storageVolLookupByName(name.encode("utf-8"))
        except libvirt.libvirtError as e:
            if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL:
                raise NotFoundError("KCHVOL0002E", {
                    'name': name,
                    'pool': poolname
                })
            else:
                raise

    def lookup(self, pool, name):
        vol = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
        path = vol.path()
        info = vol.info()
        xml = vol.XMLDesc(0)
        try:
            fmt = xpath_get_text(xml, "/volume/target/format/@type")[0]
        except IndexError:
            # Not all types of libvirt storage can provide volume format
            # infomation. When there is no format information, we assume
            # it's 'raw'.
            fmt = 'raw'
        ref_cnt = get_disk_ref_cnt(self.objstore, self.conn, path)
        res = dict(type=VOLUME_TYPE_MAP[info[0]],
                   capacity=info[1],
                   allocation=info[2],
                   path=path,
                   ref_cnt=ref_cnt,
                   format=fmt)
        if fmt == 'iso':
            if os.path.islink(path):
                path = os.path.join(os.path.dirname(path), os.readlink(path))
            os_distro = os_version = 'unknown'
            try:
                iso_img = IsoImage(path)
                os_distro, os_version = iso_img.probe()
                bootable = True
            except IsoFormatError:
                bootable = False
            res.update(
                dict(os_distro=os_distro,
                     os_version=os_version,
                     path=path,
                     bootable=bootable))
        return res

    def wipe(self, pool, name):
        volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
        try:
            volume.wipePattern(libvirt.VIR_STORAGE_VOL_WIPE_ALG_ZERO, 0)
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHVOL0009E", {
                'name': name,
                'err': e.get_error_message()
            })

    def delete(self, pool, name):
        pool_info = StoragePoolModel(conn=self.conn,
                                     objstore=self.objstore).lookup(pool)
        if pool_info['type'] in READONLY_POOL_TYPE:
            raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']})

        volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn)
        try:
            volume.delete(0)
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHVOL0010E", {
                'name': name,
                'err': e.get_error_message()
            })

    def resize(self, pool, name, size):
        volume = StorageVolumeModel.get_storagevolume(pool, name, self.conn)

        # When decreasing the storage volume capacity, the flag
        # VIR_STORAGE_VOL_RESIZE_SHRINK must be used
        flags = 0
        if volume.info()[1] > size:
            # FIXME: Even using VIR_STORAGE_VOL_RESIZE_SHRINK flag it is not
            # possible to decrease the volume capacity due a libvirt bug
            # For reference:
            # - https://bugzilla.redhat.com/show_bug.cgi?id=1021802
            flags = libvirt.VIR_STORAGE_VOL_RESIZE_SHRINK

        try:
            volume.resize(size, flags)
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHVOL0011E", {
                'name': name,
                'err': e.get_error_message()
            })

    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
        }
        taskid = add_task(
            u'/storagepools/%s/storagevolumes/%s' % (pool, new_name),
            self._clone_task, self.objstore, params)
        return self.task.lookup(taskid)

    def _clone_task(self, cb, params):
        """Asynchronous function which performs the clone operation.

        This function copies all the data inside the original volume into the
        new one.

        Arguments:
        cb -- A callback function to signal the Task's progress.
        params -- A dict with the following values:
            "pool": The name of the original pool.
            "name": The name of the original volume.
            "new_pool": The name of the destination pool.
            "new_name": The name of the new volume.
        """
        orig_pool_name = params['pool']
        orig_vol_name = params['name']
        new_pool_name = params['new_pool']
        new_vol_name = params['new_name']

        try:
            cb('setting up volume cloning')
            orig_vir_vol = StorageVolumeModel.get_storagevolume(
                orig_pool_name, orig_vol_name, self.conn)
            orig_vol = self.lookup(orig_pool_name, orig_vol_name)
            new_vir_pool = StoragePoolModel.get_storagepool(
                new_pool_name, self.conn)

            cb('building volume XML')
            root_elem = E.volume()
            root_elem.append(E.name(new_vol_name))
            root_elem.append(
                E.capacity(unicode(orig_vol['capacity']), unit='bytes'))
            target_elem = E.target()
            target_elem.append(E.format(type=orig_vol['format']))
            root_elem.append(target_elem)
            new_vol_xml = ET.tostring(root_elem,
                                      encoding='utf-8',
                                      pretty_print=True)

            cb('cloning volume')
            new_vir_pool.createXMLFrom(new_vol_xml, orig_vir_vol, 0)
        except (InvalidOperation, NotFoundError, libvirt.libvirtError), e:
            raise OperationFailed(
                'KCHVOL0023E', {
                    'name': orig_vol_name,
                    'pool': orig_pool_name,
                    'err': e.get_error_message()
                })

        cb('adding volume to the object store')
        new_vol_id = '%s:%s' % (new_pool_name, new_vol_name)
        with self.objstore as session:
            session.store('storagevolume', new_vol_id, {'ref_cnt': 0})

        cb('OK', True)
예제 #17
0
파일: host.py 프로젝트: k0da/kimchi
class HostModel(object):
    def __init__(self, **kargs):
        self.conn = kargs["conn"]
        self.objstore = kargs["objstore"]
        self.task = TaskModel(**kargs)
        self.host_info = self._get_host_info()

    def _get_host_info(self):
        res = {}
        with open("/proc/cpuinfo") as f:
            for line in f.xreadlines():
                if "model name" in line:
                    res["cpu"] = line.split(":")[1].strip()
                    break

        res["memory"] = psutil.TOTAL_PHYMEM
        # 'fedora' '17' 'Beefy Miracle'
        distro, version, codename = platform.linux_distribution()
        res["os_distro"] = distro
        res["os_version"] = version
        res["os_codename"] = unicode(codename, "utf-8")

        return res

    def lookup(self, *name):
        return self.host_info

    def swupdate(self, *name):
        try:
            swupdate = SoftwareUpdate()
        except:
            raise OperationFailed("KCHPKGUPD0004E")

        pkgs = swupdate.getNumOfUpdates()
        if pkgs == 0:
            raise OperationFailed("KCHPKGUPD0001E")

        kimchi_log.debug("Host is going to be updated.")
        taskid = add_task("", swupdate.doUpdate, self.objstore, None)
        return self.task.lookup(taskid)

    def shutdown(self, args=None):
        # Check for running vms before shutdown
        running_vms = self._get_vms_list_by_state("running")
        if len(running_vms) > 0:
            raise OperationFailed("KCHHOST0001E")

        kimchi_log.info("Host is going to shutdown.")
        os.system("shutdown -h now")

    def reboot(self, args=None):
        # Find running VMs
        running_vms = self._get_vms_list_by_state("running")
        if len(running_vms) > 0:
            raise OperationFailed("KCHHOST0002E")

        kimchi_log.info("Host is going to reboot.")
        os.system("reboot")

    def _get_vms_list_by_state(self, state):
        conn = self.conn.get()
        return [dom.name().decode("utf-8") for dom in conn.listAllDomains(0) if (DOM_STATE_MAP[dom.info()[0]]) == state]
예제 #18
0
class HostModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)
        self.host_info = self._get_host_info()

    def _get_ppc_cpu_info(self):
        res = {}
        with open('/proc/cpuinfo') as f:
            for line in f.xreadlines():
                # Parse CPU, CPU's revision and CPU's clock information
                for key in ['cpu', 'revision', 'clock']:
                    if key in line:
                        info = line.split(':')[1].strip()
                        if key == 'clock':
                            value = float(info.split('MHz')[0].strip()) / 1000
                        else:
                            value = info.split('(')[0].strip()
                        res[key] = value

                        # Power machines show, for each cpu/core, a block with
                        # all cpu information. Here we control the scan of the
                        # necessary information (1st block provides
                        # everything), skipping the function when find all
                        # information.
                        if len(res.keys()) == 3:
                            return "%(cpu)s (%(revision)s) @ %(clock)s GHz\
                                    " % res

        return ""

    def _get_host_info(self):
        res = {}
        if platform.machine().startswith('ppc'):
            res['cpu_model'] = self._get_ppc_cpu_info()
        else:
            with open('/proc/cpuinfo') as f:
                for line in f.xreadlines():
                    if "model name" in line:
                        res['cpu_model'] = line.split(':')[1].strip()
                        break

        res['cpus'] = 0
        res['memory'] = 0L

        # Include IBM PowerKVM name to supported distro names
        _sup_distros = platform._supported_dists + ('ibm_powerkvm',)
        # 'fedora' '17' 'Beefy Miracle'
        distro, version, codename = platform.linux_distribution(
            supported_dists=_sup_distros)
        res['os_distro'] = distro
        res['os_version'] = version
        res['os_codename'] = unicode(codename, "utf-8")

        return res

    def lookup(self, *name):
        cpus = psutil.NUM_CPUS

        # psutil is unstable on how to get the number of
        # cpus, different versions call it differently
        if hasattr(psutil, 'cpu_count'):
            cpus = psutil.cpu_count()

        elif hasattr(psutil, '_psplatform'):
            for method_name in ['_get_num_cpus', 'get_num_cpus']:

                method = getattr(psutil._psplatform, method_name, None)
                if method is not None:
                    cpus = method()
                    break

        self.host_info['cpus'] = cpus
        self.host_info['memory'] = psutil.phymem_usage().total
        return self.host_info

    def swupdate(self, *name):
        try:
            swupdate = SoftwareUpdate()
        except:
            raise OperationFailed('KCHPKGUPD0004E')

        pkgs = swupdate.getNumOfUpdates()
        if pkgs == 0:
            raise OperationFailed('KCHPKGUPD0001E')

        kimchi_log.debug('Host is going to be updated.')
        taskid = add_task('/host/swupdate', swupdate.doUpdate, self.objstore,
                          None)
        return self.task.lookup(taskid)

    def shutdown(self, args=None):
        # Check for running vms before shutdown
        running_vms = self._get_vms_list_by_state('running')
        if len(running_vms) > 0:
            raise OperationFailed("KCHHOST0001E")

        kimchi_log.info('Host is going to shutdown.')
        os.system('shutdown -h now')

    def reboot(self, args=None):
        # Find running VMs
        running_vms = self._get_vms_list_by_state('running')
        if len(running_vms) > 0:
            raise OperationFailed("KCHHOST0002E")

        kimchi_log.info('Host is going to reboot.')
        os.system('reboot')

    def _get_vms_list_by_state(self, state):
        conn = self.conn.get()
        return [dom.name().decode('utf-8')
                for dom in conn.listAllDomains(0)
                if (DOM_STATE_MAP[dom.info()[0]]) == state]
예제 #19
0
파일: host.py 프로젝트: shaohef/kimchi
class HostModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)
        self.host_info = self._get_host_info()

    def _get_host_info(self):
        res = {}
        with open('/proc/cpuinfo') as f:
            for line in f.xreadlines():
                if "model name" in line:
                    res['cpu'] = line.split(':')[1].strip()
                    break

        res['memory'] = psutil.TOTAL_PHYMEM
        # 'fedora' '17' 'Beefy Miracle'
        distro, version, codename = platform.linux_distribution()
        res['os_distro'] = distro
        res['os_version'] = version
        res['os_codename'] = unicode(codename, "utf-8")

        return res

    def lookup(self, *name):
        return self.host_info

    def swupdate(self, *name):
        try:
            swupdate = SoftwareUpdate()
        except:
            raise OperationFailed('KCHPKGUPD0004E')

        pkgs = swupdate.getNumOfUpdates()
        if pkgs == 0:
            raise OperationFailed('KCHPKGUPD0001E')

        kimchi_log.debug('Host is going to be updated.')
        taskid = add_task('', swupdate.doUpdate, self.objstore, None)
        return self.task.lookup(taskid)

    def shutdown(self, args=None):
        # Check for running vms before shutdown
        running_vms = self._get_vms_list_by_state('running')
        if len(running_vms) > 0:
            raise OperationFailed("KCHHOST0001E")

        kimchi_log.info('Host is going to shutdown.')
        os.system('shutdown -h now')

    def reboot(self, args=None):
        # Find running VMs
        running_vms = self._get_vms_list_by_state('running')
        if len(running_vms) > 0:
            raise OperationFailed("KCHHOST0002E")

        kimchi_log.info('Host is going to reboot.')
        os.system('reboot')

    def _get_vms_list_by_state(self, state):
        conn = self.conn.get()
        names = [dom.name().decode('utf-8') for dom in conn.listAllDomains(0)]

        ret_list = []
        for name in names:
            dom = conn.lookupByName(name.encode("utf-8"))
            info = dom.info()
            if (DOM_STATE_MAP[info[0]]) == state:
                ret_list.append(name)
        return ret_list
예제 #20
0
파일: vms.py 프로젝트: gouzongmei/kimchi
class VMModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.caps = CapabilitiesModel(**kargs)
        self.vmscreenshot = VMScreenshotModel(**kargs)
        self.users = import_class('kimchi.model.users.UsersModel')(**kargs)
        self.groups = import_class('kimchi.model.groups.GroupsModel')(**kargs)
        self.vms = VMsModel(**kargs)
        self.task = TaskModel(**kargs)
        self.storagepool = model.storagepools.StoragePoolModel(**kargs)
        self.storagevolume = model.storagevolumes.StorageVolumeModel(**kargs)
        self.storagevolumes = model.storagevolumes.StorageVolumesModel(**kargs)
        cls = import_class('kimchi.model.vmsnapshots.VMSnapshotModel')
        self.vmsnapshot = cls(**kargs)
        cls = import_class('kimchi.model.vmsnapshots.VMSnapshotsModel')
        self.vmsnapshots = cls(**kargs)

    def update(self, name, params):
        dom = self.get_vm(name, self.conn)
        dom = self._static_vm_update(dom, params)
        self._live_vm_update(dom, params)
        return dom.name().decode('utf-8')

    def clone(self, name):
        """Clone a virtual machine based on an existing one.

        The new virtual machine will have the exact same configuration as the
        original VM, except for the name, UUID, MAC addresses and disks. The
        name will have the form "<name>-clone-<number>", with <number> starting
        at 1; the UUID will be generated randomly; the MAC addresses will be
        generated randomly with no conflicts within the original and the new
        VM; and the disks will be new volumes [mostly] on the same storage
        pool, with the same content as the original disks. The storage pool
        'default' will always be used when cloning SCSI and iSCSI disks and
        when the original storage pool cannot hold the new volume.

        An exception will be raised if the virtual machine <name> is not
        shutoff, if there is no available space to copy a new volume to the
        storage pool 'default' (when there was also no space to copy it to the
        original storage pool) and if one of the virtual machine's disks belong
        to a storage pool not supported by Kimchi.

        Parameters:
        name -- The name of the existing virtual machine to be cloned.

        Return:
        A Task running the clone operation.
        """
        name = name.decode('utf-8')

        # VM must be shutoff in order to clone it
        info = self.lookup(name)
        if info['state'] != u'shutoff':
            raise InvalidParameter('KCHVM0033E', {'name': name})

        # this name will be used as the Task's 'target_uri' so it needs to be
        # defined now.
        new_name = get_next_clone_name(self.vms.get_list(), 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})

        return self.task.lookup(taskid)

    def _clone_task(self, cb, params):
        """Asynchronous function which performs the clone operation.

        Parameters:
        cb -- A callback function to signal the Task's progress.
        params -- A dict with the following values:
            "name": the name of the original VM.
            "new_name": the name of the new VM.
        """
        name = params['name']
        new_name = params['new_name']
        vir_conn = self.conn.get()

        # fetch base XML
        cb('reading source VM XML')
        try:
            vir_dom = vir_conn.lookupByName(name)
            flags = libvirt.VIR_DOMAIN_XML_SECURE
            xml = vir_dom.XMLDesc(flags).decode('utf-8')
        except libvirt.libvirtError, e:
            raise OperationFailed('KCHVM0035E', {'name': name,
                                                 'err': e.message})

        # update UUID
        cb('updating VM UUID')
        old_uuid = xpath_get_text(xml, XPATH_DOMAIN_UUID)[0]
        new_uuid = unicode(uuid.uuid4())
        xml = xml_item_update(xml, './uuid', new_uuid)

        # update MAC addresses
        cb('updating VM MAC addresses')
        xml = self._clone_update_mac_addresses(xml)

        with RollbackContext() as rollback:
            # copy disks
            cb('copying VM disks')
            xml = self._clone_update_disks(xml, rollback)

            # update objstore entry
            cb('updating object store')
            self._clone_update_objstore(old_uuid, new_uuid, rollback)

            # update name
            cb('updating VM name')
            xml = xml_item_update(xml, './name', new_name)

            # create new guest
            cb('defining new VM')
            try:
                vir_conn.defineXML(xml)
            except libvirt.libvirtError, e:
                raise OperationFailed('KCHVM0035E', {'name': name,
                                                     'err': e.message})

            rollback.commitAll()
예제 #21
0
class DebugReportsModel(object):
    def __init__(self, **kargs):
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)

    def create(self, params):
        ident = params['name']
        taskid = self._gen_debugreport_file(ident)
        return self.task.lookup(taskid)

    def get_list(self):
        path = config.get_debugreports_path()
        file_pattern = os.path.join(path, '*.*')
        file_lists = glob.glob(file_pattern)
        file_lists = [os.path.split(file)[1] for file in file_lists]
        name_lists = [file.split('.', 1)[0] for file in file_lists]

        return name_lists

    def _gen_debugreport_file(self, name):
        gen_cmd = self.get_system_report_tool()

        if gen_cmd is not None:
            return add_task('', gen_cmd, self.objstore, name)

        raise OperationFailed("debugreport tool not found")

    @staticmethod
    def sosreport_generate(cb, name):
        command = 'sosreport --batch --name "%s"' % name
        try:
            retcode = subprocess.call(command, shell=True,
                                      stdout=subprocess.PIPE)
            if retcode < 0:
                raise OperationFailed('Command terminated with signal')
            elif retcode > 0:
                raise OperationFailed('Command failed: rc = %i' % retcode)
            pattern = '/tmp/sosreport-%s-*' % name
            for reportFile in glob.glob(pattern):
                if not fnmatch.fnmatch(reportFile, '*.md5'):
                    output = reportFile
                    break
            else:
                # sosreport tends to change the name mangling rule and
                # compression file format between different releases.
                # It's possible to fail to match a report file even sosreport
                # runs successfully. In future we might have a general name
                # mangling function in kimchi to format the name before passing
                # it to sosreport. Then we can delete this exception.
                raise OperationFailed('Can not find generated debug report '
                                      'named by %s' % pattern)
            ext = output.split('.', 1)[1]
            path = config.get_debugreports_path()
            target = os.path.join(path, name)
            target_file = '%s.%s' % (target, ext)
            shutil.move(output, target_file)
            os.remove('%s.md5' % output)
            cb('OK', True)

            return

        except OSError:
            raise

        except Exception, e:
            # No need to call cb to update the task status here.
            # The task object will catch the exception rasied here
            # and update the task status there
            log = logging.getLogger('Model')
            log.warning('Exception in generating debug file: %s', e)
            raise OperationFailed(e)
예제 #22
0
class DebugReportsModel(object):
    def __init__(self, **kargs):
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)

    def create(self, params):
        ident = params.get('name').strip()
        # Generate a name with time and millisec precision, if necessary
        if ident is None or ident == "":
            ident = 'report-' + str(int(time.time() * 1000))
        taskid = self._gen_debugreport_file(ident)
        return self.task.lookup(taskid)

    def get_list(self):
        path = config.get_debugreports_path()
        file_pattern = os.path.join(path, '*.*')
        file_lists = glob.glob(file_pattern)
        file_lists = [os.path.split(file)[1] for file in file_lists]
        name_lists = [file.split('.', 1)[0] for file in file_lists]

        return name_lists

    def _gen_debugreport_file(self, name):
        gen_cmd = self.get_system_report_tool()

        if gen_cmd is not None:
            return add_task('', gen_cmd, self.objstore, name)

        raise OperationFailed("KCHDR0002E")

    @staticmethod
    def sosreport_generate(cb, name):
        try:
            command = ['sosreport', '--batch', '--name=%s' % name]
            output, error, retcode = run_command(command)

            if retcode < 0:
                raise OperationFailed("KCHDR0003E", {
                    'name': name,
                    'err': retcode
                })
            elif retcode > 0:
                raise OperationFailed("KCHDR0003E", {
                    'name': name,
                    'err': retcode
                })

            # SOSREPORT might create file in /tmp or /var/tmp
            # FIXME: The right way should be passing the tar.xz file directory
            # though the parameter '--tmp-dir', but it is failing in Fedora 20
            patterns = ['/tmp/sosreport-%s-*', '/var/tmp/sosreport-%s-*']
            reports = []
            reportFile = None
            for p in patterns:
                reports = reports + [f for f in glob.glob(p % name)]
            for f in reports:
                if not fnmatch.fnmatch(f, '*.md5'):
                    reportFile = f
                    break
            # Some error in sosreport happened
            if reportFile is None:
                kimchi_log.error(
                    'Debug report file not found. See sosreport '
                    'output for detail:\n%s', output)
                fname = (patterns[0] % name).split('/')[-1]
                raise OperationFailed('KCHDR0004E', {'name': fname})

            md5_report_file = reportFile + '.md5'
            report_file_extension = '.' + reportFile.split('.', 1)[1]
            path = config.get_debugreports_path()
            target = os.path.join(path, name + report_file_extension)
            # Moving report
            msg = 'Moving debug report file "%s" to "%s"' % (reportFile,
                                                             target)
            kimchi_log.info(msg)
            shutil.move(reportFile, target)
            # Deleting md5
            msg = 'Deleting report md5 file: "%s"' % (md5_report_file)
            kimchi_log.info(msg)
            md5 = open(md5_report_file).read().strip()
            kimchi_log.info('Md5 file content: "%s"', md5)
            os.remove(md5_report_file)
            cb('OK', True)
            return

        except OSError:
            raise

        except Exception, e:
            # No need to call cb to update the task status here.
            # The task object will catch the exception rasied here
            # and update the task status there
            log = logging.getLogger('Model')
            log.warning('Exception in generating debug file: %s', e)
            raise OperationFailed("KCHDR0005E", {'name': name, 'err': e})
예제 #23
0
파일: host.py 프로젝트: amoalsale/kimchi
class HostModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)
        self.host_info = self._get_host_info()

    def _get_host_info(self):
        res = {}
        with open('/proc/cpuinfo') as f:
            for line in f.xreadlines():
                if "model name" in line:
                    res['cpu'] = line.split(':')[1].strip()
                    break

        res['memory'] = psutil.TOTAL_PHYMEM
        # 'fedora' '17' 'Beefy Miracle'
        distro, version, codename = platform.linux_distribution()
        res['os_distro'] = distro
        res['os_version'] = version
        res['os_codename'] = unicode(codename, "utf-8")

        return res

    def lookup(self, *name):
        return self.host_info

    def swupdate(self, *name):
        try:
            swupdate = SoftwareUpdate()
        except:
            raise OperationFailed('KCHPKGUPD0004E')

        pkgs = swupdate.getNumOfUpdates()
        if pkgs == 0:
            raise OperationFailed('KCHPKGUPD0001E')

        kimchi_log.debug('Host is going to be updated.')
        taskid = add_task('', swupdate.doUpdate, self.objstore, None)
        return self.task.lookup(taskid)

    def shutdown(self, args=None):
        # Check for running vms before shutdown
        running_vms = self._get_vms_list_by_state('running')
        if len(running_vms) > 0:
            raise OperationFailed("KCHHOST0001E")

        kimchi_log.info('Host is going to shutdown.')
        os.system('shutdown -h now')

    def reboot(self, args=None):
        # Find running VMs
        running_vms = self._get_vms_list_by_state('running')
        if len(running_vms) > 0:
            raise OperationFailed("KCHHOST0002E")

        kimchi_log.info('Host is going to reboot.')
        os.system('reboot')

    def _get_vms_list_by_state(self, state):
        conn = self.conn.get()
        names = [dom.name().decode('utf-8') for dom in conn.listAllDomains(0)]

        ret_list = []
        for name in names:
            dom = conn.lookupByName(name.encode("utf-8"))
            info = dom.info()
            if (DOM_STATE_MAP[info[0]]) == state:
                ret_list.append(name)
        return ret_list
예제 #24
0
 def __init__(self, **kargs):
     self.conn = kargs['conn']
     self.objstore = kargs['objstore']
     self.task = TaskModel(**kargs)
     self.host_info = self._get_host_info()
예제 #25
0
class VMSnapshotsModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)
        self.vmstorages = VMStoragesModel(**kargs)
        self.vmstorage = VMStorageModel(**kargs)

    def create(self, vm_name, params={}):
        """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.
        """
        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 = add_task(u'/vms/%s/snapshots/%s' % (vm_name, name),
                          self._create_task, self.objstore, task_params)
        return self.task.lookup(taskid)

    def _create_task(self, cb, params):
        """Asynchronous function which actually creates the snapshot.

        Parameters:
        cb -- a callback function to signal the Task's progress.
        params -- a dict with the following values:
            "vm_name": the name of the VM where the snapshot will be created.
            "name": the snapshot name.
        """
        vm_name = params['vm_name']
        name = params['name']

        cb('building snapshot XML')
        root_elem = E.domainsnapshot()
        root_elem.append(E.name(name))
        xml = ET.tostring(root_elem, encoding='utf-8')

        try:
            cb('fetching snapshot domain')
            vir_dom = VMModel.get_vm(vm_name, self.conn)
            cb('creating snapshot')
            vir_dom.snapshotCreateXML(xml, 0)
        except (NotFoundError, OperationFailed, libvirt.libvirtError), e:
            raise OperationFailed('KCHSNAP0002E', {
                'name': name,
                'vm': vm_name,
                'err': e.message
            })

        cb('OK', True)
예제 #26
0
 def __init__(self, **kargs):
     self.conn = kargs['conn']
     self.objstore = kargs['objstore']
     self.task = TaskModel(**kargs)
     self.vmstorages = VMStoragesModel(**kargs)
     self.vmstorage = VMStorageModel(**kargs)
예제 #27
0
 def __init__(self, **kargs):
     self.conn = kargs['conn']
     self.objstore = kargs['objstore']
     self.task = TaskModel(**kargs)
     self.vmstorages = VMStoragesModel(**kargs)
     self.vmstorage = VMStorageModel(**kargs)
예제 #28
0
 def __init__(self, **kargs):
     self.conn = kargs['conn']
     self.objstore = kargs['objstore']
     self.task = TaskModel(**kargs)
     self.storagevolumes = StorageVolumesModel(**kargs)
     self.storagepool = StoragePoolModel(**kargs)
예제 #29
0
class DebugReportsModel(object):
    def __init__(self, **kargs):
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)

    def create(self, params):
        ident = params.get('name').strip()
        # Generate a name with time and millisec precision, if necessary
        if ident is None or ident == "":
            ident = 'report-' + str(int(time.time() * 1000))
        taskid = self._gen_debugreport_file(ident)
        return self.task.lookup(taskid)

    def get_list(self):
        path = config.get_debugreports_path()
        file_pattern = os.path.join(path, '*.*')
        file_lists = glob.glob(file_pattern)
        file_lists = [os.path.split(file)[1] for file in file_lists]
        name_lists = [file.split('.', 1)[0] for file in file_lists]

        return name_lists

    def _gen_debugreport_file(self, name):
        gen_cmd = self.get_system_report_tool()

        if gen_cmd is not None:
            return add_task('', gen_cmd, self.objstore, name)

        raise OperationFailed("KCHDR0002E")

    @staticmethod
    def sosreport_generate(cb, name):
        try:
            command = ['sosreport', '--batch', '--name=%s' % name]
            output, error, retcode = run_command(command)

            if retcode < 0:
                raise OperationFailed("KCHDR0003E", {'name': name,
                                                     'err': retcode})
            elif retcode > 0:
                raise OperationFailed("KCHDR0003E", {'name': name,
                                                     'err': retcode})

            # SOSREPORT might create file in /tmp or /var/tmp
            # FIXME: The right way should be passing the tar.xz file directory
            # though the parameter '--tmp-dir', but it is failing in Fedora 20
            patterns = ['/tmp/sosreport-%s-*', '/var/tmp/sosreport-%s-*']
            reports = []
            reportFile = None
            for p in patterns:
                reports = reports + [f for f in glob.glob(p % name)]
            for f in reports:
                if not fnmatch.fnmatch(f, '*.md5'):
                    reportFile = f
                    break
            # Some error in sosreport happened
            if reportFile is None:
                kimchi_log.error('Debug report file not found. See sosreport '
                                 'output for detail:\n%s', output)
                fname = (patterns[0] % name).split('/')[-1]
                raise OperationFailed('KCHDR0004E', {'name': fname})

            md5_report_file = reportFile + '.md5'
            report_file_extension = '.' + reportFile.split('.', 1)[1]
            path = config.get_debugreports_path()
            target = os.path.join(path, name + report_file_extension)
            # Moving report
            msg = 'Moving debug report file "%s" to "%s"' % (reportFile,
                                                             target)
            kimchi_log.info(msg)
            shutil.move(reportFile, target)
            # Deleting md5
            msg = 'Deleting report md5 file: "%s"' % (md5_report_file)
            kimchi_log.info(msg)
            md5 = open(md5_report_file).read().strip()
            kimchi_log.info('Md5 file content: "%s"', md5)
            os.remove(md5_report_file)
            cb('OK', True)
            return

        except OSError:
            raise

        except Exception, e:
            # No need to call cb to update the task status here.
            # The task object will catch the exception rasied here
            # and update the task status there
            log = logging.getLogger('Model')
            log.warning('Exception in generating debug file: %s', e)
            raise OperationFailed("KCHDR0005E", {'name': name, 'err': e})
예제 #30
0
 def __init__(self, **kargs):
     self.conn = kargs['conn']
     self.objstore = kargs['objstore']
     self.task = TaskModel(**kargs)
예제 #31
0
class VMModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.caps = CapabilitiesModel(**kargs)
        self.vmscreenshot = VMScreenshotModel(**kargs)
        self.users = import_class('kimchi.model.users.UsersModel')(**kargs)
        self.groups = import_class('kimchi.model.groups.GroupsModel')(**kargs)
        self.vms = VMsModel(**kargs)
        self.task = TaskModel(**kargs)
        self.storagepool = model.storagepools.StoragePoolModel(**kargs)
        self.storagevolume = model.storagevolumes.StorageVolumeModel(**kargs)
        self.storagevolumes = model.storagevolumes.StorageVolumesModel(**kargs)
        cls = import_class('kimchi.model.vmsnapshots.VMSnapshotModel')
        self.vmsnapshot = cls(**kargs)
        cls = import_class('kimchi.model.vmsnapshots.VMSnapshotsModel')
        self.vmsnapshots = cls(**kargs)

    def update(self, name, params):
        dom = self.get_vm(name, self.conn)
        dom = self._static_vm_update(dom, params)
        self._live_vm_update(dom, params)
        return dom.name().decode('utf-8')

    def clone(self, name):
        """Clone a virtual machine based on an existing one.

        The new virtual machine will have the exact same configuration as the
        original VM, except for the name, UUID, MAC addresses and disks. The
        name will have the form "<name>-clone-<number>", with <number> starting
        at 1; the UUID will be generated randomly; the MAC addresses will be
        generated randomly with no conflicts within the original and the new
        VM; and the disks will be new volumes [mostly] on the same storage
        pool, with the same content as the original disks. The storage pool
        'default' will always be used when cloning SCSI and iSCSI disks and
        when the original storage pool cannot hold the new volume.

        An exception will be raised if the virtual machine <name> is not
        shutoff, if there is no available space to copy a new volume to the
        storage pool 'default' (when there was also no space to copy it to the
        original storage pool) and if one of the virtual machine's disks belong
        to a storage pool not supported by Kimchi.

        Parameters:
        name -- The name of the existing virtual machine to be cloned.

        Return:
        A Task running the clone operation.
        """
        name = name.decode('utf-8')

        # VM must be shutoff in order to clone it
        info = self.lookup(name)
        if info['state'] != u'shutoff':
            raise InvalidParameter('KCHVM0033E', {'name': name})

        # the new VM's name will be used as the Task's 'target_uri' so it needs
        # to be defined now.

        vms_being_created = []

        # lookup names of VMs being created right now
        with self.objstore as session:
            task_names = session.get_list('task')
            for tn in task_names:
                t = session.get('task', tn)
                if t['target_uri'].startswith('/vms/'):
                    uri_name = t['target_uri'][5:]  # 5 = len('/vms/')
                    vms_being_created.append(uri_name)

        current_vm_names = self.vms.get_list() + vms_being_created
        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})

        return self.task.lookup(taskid)

    def _clone_task(self, cb, params):
        """Asynchronous function which performs the clone operation.

        Parameters:
        cb -- A callback function to signal the Task's progress.
        params -- A dict with the following values:
            "name": the name of the original VM.
            "new_name": the name of the new VM.
        """
        name = params['name']
        new_name = params['new_name']
        vir_conn = self.conn.get()

        # fetch base XML
        cb('reading source VM XML')
        try:
            vir_dom = vir_conn.lookupByName(name)
            flags = libvirt.VIR_DOMAIN_XML_SECURE
            xml = vir_dom.XMLDesc(flags).decode('utf-8')
        except libvirt.libvirtError, e:
            raise OperationFailed('KCHVM0035E', {'name': name,
                                                 'err': e.message})

        # update UUID
        cb('updating VM UUID')
        old_uuid = xpath_get_text(xml, XPATH_DOMAIN_UUID)[0]
        new_uuid = unicode(uuid.uuid4())
        xml = xml_item_update(xml, './uuid', new_uuid)

        # update MAC addresses
        cb('updating VM MAC addresses')
        xml = self._clone_update_mac_addresses(xml)

        with RollbackContext() as rollback:
            # copy disks
            cb('copying VM disks')
            xml = self._clone_update_disks(xml, rollback)

            # update objstore entry
            cb('updating object store')
            self._clone_update_objstore(old_uuid, new_uuid, rollback)

            # update name
            cb('updating VM name')
            xml = xml_item_update(xml, './name', new_name)

            # create new guest
            cb('defining new VM')
            try:
                vir_conn.defineXML(xml)
            except libvirt.libvirtError, e:
                raise OperationFailed('KCHVM0035E', {'name': name,
                                                     'err': e.message})

            rollback.commitAll()
예제 #32
0
 def __init__(self, **kargs):
     self.objstore = kargs['objstore']
     self.task = TaskModel(**kargs)
예제 #33
0
class StorageVolumesModel(object):
    def __init__(self, **kargs):
        self.conn = kargs['conn']
        self.objstore = kargs['objstore']
        self.task = TaskModel(**kargs)

    def create(self, pool_name, params):
        vol_source = ['url', 'capacity']

        name = params.get('name')

        index_list = list(i for i in range(len(vol_source))
                          if vol_source[i] in params)
        if len(index_list) != 1:
            raise InvalidParameter("KCHVOL0018E",
                                   {'param': ",".join(vol_source)})

        create_param = vol_source[index_list[0]]

        # Verify if the URL is valid
        if create_param == 'url':
            url = params['url']
            try:
                urllib2.urlopen(url).close()
            except:
                raise InvalidParameter('KCHVOL0022E', {'url': url})

        all_vol_names = self.get_list(pool_name)

        if name is None:
            # the methods listed in 'REQUIRE_NAME_PARAMS' cannot have
            # 'name' == None
            if create_param in REQUIRE_NAME_PARAMS:
                raise InvalidParameter('KCHVOL0016E')

            # if 'name' is omitted - except for the methods listed in
            # 'REQUIRE_NAME_PARAMS' - the default volume name will be the
            # file/URL basename.
            if create_param == 'url':
                name = os.path.basename(params['url'])
            else:
                name = 'upload-%s' % int(time.time())

            name = get_unique_file_name(all_vol_names, name)
            params['name'] = name

        try:
            create_func = getattr(self,
                                  '_create_volume_with_%s' % create_param)
        except AttributeError:
            raise InvalidParameter("KCHVOL0019E", {'param': create_param})

        pool_info = StoragePoolModel(conn=self.conn,
                                     objstore=self.objstore).lookup(pool_name)
        if pool_info['type'] in READONLY_POOL_TYPE:
            raise InvalidParameter("KCHVOL0012E", {'type': pool_info['type']})
        if pool_info['state'] == 'inactive':
            raise InvalidParameter('KCHVOL0003E', {
                'pool': pool_name,
                'volume': name
            })
        if name in all_vol_names:
            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)
        return self.task.lookup(taskid)

    def _create_volume_with_capacity(self, cb, params):
        pool_name = params.pop('pool')
        vol_xml = """
        <volume>
          <name>%(name)s</name>
          <allocation unit='bytes'>%(allocation)s</allocation>
          <capacity unit='bytes'>%(capacity)s</capacity>
          <source>
          </source>
          <target>
            <format type='%(format)s'/>
          </target>
        </volume>
        """
        params.setdefault('allocation', 0)
        params.setdefault('format', 'qcow2')

        name = params['name']
        try:
            pool = StoragePoolModel.get_storagepool(pool_name, self.conn)
            xml = vol_xml % params
        except KeyError, item:
            raise MissingParameter("KCHVOL0004E", {
                'item': str(item),
                'volume': name
            })

        try:
            pool.createXML(xml, 0)
        except libvirt.libvirtError as e:
            raise OperationFailed("KCHVOL0007E", {
                'name': name,
                'pool': pool,
                'err': e.get_error_message()
            })

        vol_info = StorageVolumeModel(conn=self.conn,
                                      objstore=self.objstore).lookup(
                                          pool_name, name)

        vol_path = vol_info['path']
        set_disk_used_by(self.objstore, vol_info['path'], [])

        if params.get('upload', False):
            upload_volumes[vol_path] = {
                'lock': threading.Lock(),
                'offset': 0,
                'cb': cb
            }
            cb('ready for upload')
        else:
            cb('OK', True)