Exemplo n.º 1
0
class VolumeOperations(object):

    def __init__(self):
        self.MetadataHandler = MetadataHandler()

    def create(self, dbg, uri, size):
        raise NotImplementedError('Override in VolumeOperations specifc class')

    def destroy(self, dbg, uri):
        raise NotImplementedError('Override in VolumeOperations specifc class')

    def resize(self, dbg, uri, size):
        raise NotImplementedError('Override in VolumeOperations specifc class')

    def swap(self, dbg, uri1, uri2):
        log.debug("%s: xcpng.volume.VolumeOperations.swap: uri1: %s uri2: %s" % (dbg, uri1, uri2))
        volume1_meta = self.MetadataHandler.get_vdi_meta(dbg, uri1)
        volume2_meta = self.MetadataHandler.get_vdi_meta(dbg, uri2)
        log.debug("%s: xcpng.volume.VolumeOperations.swap: before image_uuid1: %s image_uudi2: %s" %
                  (dbg, volume1_meta[IMAGE_UUID_TAG], volume2_meta[IMAGE_UUID_TAG]))
        image1_uuid = volume1_meta[IMAGE_UUID_TAG]
        image2_uuid = volume2_meta[IMAGE_UUID_TAG]
        volume1_meta = {IMAGE_UUID_TAG: image2_uuid}
        volume2_meta = {IMAGE_UUID_TAG: image1_uuid}
        log.debug("%s: xcpng.volume.VolumeOperations.swap: after image_uuid1: %s image_uudi2: %s" %
                  (dbg, volume1_meta[IMAGE_UUID_TAG], volume2_meta[IMAGE_UUID_TAG]))
        self.MetadataHandler.update_vdi_meta(dbg, uri1, volume1_meta)
        self.MetadataHandler.update_vdi_meta(dbg, uri2, volume2_meta)

    def get_phisical_utilization(self, dbg, uri):
        raise NotImplementedError('Override in VolumeOperations specifc class')

    def roundup_size(self, dbg, size):
        raise NotImplementedError('Override in VolumeOperations specifc class')
Exemplo n.º 2
0
class Volume(object):

    def __init__(self):
        self.MetadataHandler = MetadataHandler()
        self.VolOpsHendler = _VolumeOperations_()
        self.Datapathes = DATAPATHES

        for k, v in DATAPATHES.iteritems():
            self.Datapathes[k] = v()

    def _create(self, dbg, sr, name, description, size, sharable, volume_meta):
        raise NotImplementedError('Override in Volume specifc class')

    def create(self, dbg, sr, name, description, size, sharable):
        log.debug("%s: xcpng.volume.Volume.create: SR: %s Name: %s Description: %s Size: %s, Sharable: %s"
                  % (dbg, sr, name, description, size, sharable))

        vdi_uuid = str(uuid.uuid4())
        image_uuid = str(uuid.uuid4())
        vdi_uri = "%s/%s" % (sr, vdi_uuid)

        volume_meta = {
            KEY_TAG: vdi_uuid,
            VDI_UUID_TAG: vdi_uuid,
            IMAGE_UUID_TAG: image_uuid,
            TYPE_TAG: get_vdi_type_by_uri(dbg, vdi_uri),
            NAME_TAG: name,
            DESCRIPTION_TAG: description,
            READ_WRITE_TAG: True,
            VIRTUAL_SIZE_TAG: size,
            PHYSICAL_UTILISATION_TAG: 0,
            URI_TAG: [vdi_uri],
            SHARABLE_TAG: sharable,
            CUSTOM_KEYS_TAG: {}
        }

        try:
            self.MetadataHandler.update_vdi_meta(dbg, vdi_uri, volume_meta)
            volume_meta = self._create(dbg, sr, name, description, size, sharable, volume_meta)
        except Exception as e:
            log.error("%s: xcpng.volume.Volume.create: Failed to create volume: key %s: SR: %s" % (dbg, vdi_uuid, sr))
            try:
                self.destroy(dbg, sr, vdi_uuid)
                self.MetadataHandler.remove_vdi_meta(dbg, vdi_uri)
            except:
                pass
            raise Exception(e)

        return volume_meta

    def set(self, dbg, sr, key, k, v):
        log.debug("%s: xcpng.volume.Volume.set: SR: %s Key: %s Custom_key: %s Value: %s"
                  % (dbg, sr, key, k, v))

        uri = "%s/%s" % (sr, key)

        volume_meta = {CUSTOM_KEYS_TAG: {}}

        try:
            volume_meta[CUSTOM_KEYS_TAG][k] = v
            self.MetadataHandler.update_vdi_meta(dbg, uri, volume_meta)
        except Exception as e:
            log.error("%s: xcpng.volume.Volume.set: Failed to set volume param: key %s: SR: %s" % (dbg, key, sr))
            raise Exception(e)

    def unset(self, dbg, sr, key, k):
        log.debug("%s: xcpng.volume.Volume.unset: SR: %s Key: %s Custom_key: %s"
                  % (dbg, sr, key, k))

        uri = "%s/%s" % (sr, key)

        volume_meta = {CUSTOM_KEYS_TAG: {}}

        try:
            volume_meta[CUSTOM_KEYS_TAG][k] = None
            self.MetadataHandler.update_vdi_meta(dbg, uri, volume_meta)
        except Exception as e:
            log.error("%s: xcpng.volume.Volume.set: Failed to unset volume param: key %s: SR: %s" % (dbg, key, sr))
            raise Exception(e)

    def _stat(self, dbg, sr, key, volume_meta):
        # Override in Volume specific class
        return volume_meta

    def stat(self, dbg, sr, key):
        log.debug("%s: xcpng.volume.Volume.stat: SR: %s Key: %s"
                  % (dbg, sr, key))

        uri = "%s/%s" % (sr, key)

        try:
            volume_meta = self.MetadataHandler.get_vdi_meta(dbg, uri)
            volume_meta[PHYSICAL_UTILISATION_TAG] = self.VolOpsHendler.get_phisical_utilization(dbg, uri)
            log.debug("%s: xcpng.volume.Volume.stat: SR: %s Key: %s Metadata: %s"
                      % (dbg, sr, key, volume_meta))
            return self._stat(dbg, sr, key, volume_meta)
        except Exception as e:
            log.error("%s: xcpng.volume.Volume.stat: Failed to get volume stat: key %s: SR: %s" % (dbg, key, sr))
            raise Exception(e)

    def _destroy(self, dbg, sr, key):
        # Override in Volume specifc class
        pass

    def destroy(self, dbg, sr, key):
        log.debug("%s: xcpng.volume.Volume.destroy: SR: %s Key: %s"
                  % (dbg, sr, key))

        uri = "%s/%s" % (sr, key)

        try:
            self._destroy(dbg, sr, key)
            self.VolOpsHendler.destroy(dbg, uri)
            self.MetadataHandler.remove_vdi_meta(dbg, uri)
        except Exception as e:
            log.error("%s: xcpng.volume.Volume.destroy: Failed to destroy volume: key %s: SR: %s" % (dbg, key, sr))
            raise Exception(e)

    def set_description(self, dbg, sr, key, new_description):
        log.debug("%s: xcpng.volume.Volume.set_description: SR: %s Key: %s New_description: %s"
                  % (dbg, sr, key, new_description))

        uri = "%s/%s" % (sr, key)

        volume_meta = {
            'description': new_description,
        }

        try:
            self.MetadataHandler.update_vdi_meta(dbg, uri, volume_meta)
        except Exception as e:
            log.error("%s: xcpng.volume.Volume.set: Failed to set volume description: key %s: SR: %s" % (dbg, key, sr))
            raise Exception(e)

    def set_name(self, dbg, sr, key, new_name):
        log.debug("%s: xcpng.volume.Volume.set_name: SR: %s Key: %s New_name: %s"
                  % (dbg, sr, key, new_name))

        uri = "%s/%s" % (sr, key)

        volume_meta = {
            'name': new_name,
        }

        try:
            self.MetadataHandler.update_vdi_meta(dbg, uri, volume_meta)
        except Exception as e:
            log.error("%s: xcpng.volume.Volume.set: Failed to set volume name: key %s: SR: %s" % (dbg, key, sr))
            raise Exception(e)

    def _resize(self, dbg, sr, key, new_size):
        raise NotImplementedError('Override in Volume specifc class')

    def resize(self, dbg, sr, key, new_size):
        log.debug("%s: xcpng.volume.Volume.resize: SR: %s Key: %s New_size: %s"
                  % (dbg, sr, key, new_size))

        uri = "%s/%s" % (sr, key)

        volume_meta = {
            'virtual_size': new_size,
        }

        try:
            self._resize(dbg, sr, key, new_size)
            self.MetadataHandler.update_vdi_meta(dbg, uri, volume_meta)
        except Exception as e:
            log.error("%s: xcpng.volume.Volume.set: Failed to resize volume: key %s: SR: %s" % (dbg, key, sr))
            raise Exception(e)

    def _clone(self, dbg, sr, key, mode, volume_meta):
        raise NotImplementedError('Override in Volume specifc class')

    def clone(self, dbg, sr, key, mode):
        log.debug("%s: xcpng.volume.Volume.clone: SR: %s Key: %s Mode: %s"
                  % (dbg, sr, key, mode))

        orig_uri = "%s/%s" % (sr, key)

        try:
            orig_meta = self.MetadataHandler.get_vdi_meta(dbg, orig_uri)

            if SNAPSHOT_OF_TAG in orig_meta[CUSTOM_KEYS_TAG]:
                base_uri = orig_meta[PARENT_URI_TAG][0]
                base_meta = self.MetadataHandler.get_vdi_meta(dbg, base_uri)
            else:
                base_meta = deepcopy(orig_meta)

            if ACTIVE_ON_TAG in base_meta:
                current_host = get_current_host_uuid()
                if base_meta[ACTIVE_ON_TAG] != current_host:
                    log.debug("%s: librbd.Volume.clone: SR: %s Key: %s Can not snapshot on %s as VDI already active on %s"
                              % (dbg, sr, base_meta[VDI_UUID_TAG],
                                 current_host, base_meta[ACTIVE_ON_TAG]))
                    raise Activated_on_another_host(base_meta[ACTIVE_ON_TAG])

            return self._clone(dbg, sr, key, mode, base_meta)
        except Exception as e:
            log.error("%s: xcpng.volume.Volume.set: Failed to clone volume: key %s: SR: %s" % (dbg, key, sr))
            raise Exception(e)

    def _commit(self, dbg, sr, child, parent):
        raise NotImplementedError('Coalesce is not supported')

    def _set_parent(self, dbg, sr, child, parent):
        raise NotImplementedError('Coalesce is not supported')

    def commit(self, dbg, sr, child, parent):
        self._commit(dbg, sr, child, parent)

    def set_parent(self, dbg, sr, child, parent):
        self._set_parent(dbg, sr, child, parent)

    def coalesce(self, dbg, sr, key):

        uri = "%s/%s" % (sr, key)

        try:
            volume_meta = self.MetadataHandler.get_vdi_meta(dbg, uri)
            children = self.MetadataHandler.find_vdi_children(dbg, uri)

            self._commit(dbg, sr, uri, volume_meta[PARENT_URI_TAG])

            for child in children:
                self._set_parent(dbg, sr, child[URI_TAG], volume_meta[PARENT_URI_TAG])
                meta = {PARENT_URI_TAG: volume_meta[PARENT_URI_TAG]}
                self.MetadataHandler.update_vdi_meta(dbg, child[URI_TAG], meta)

            self.destroy(dbg, sr, key)
            self.MetadataHandler.remove_vdi_meta(dbg, uri)
        except Exception as e:
            log.error("%s: xcpng.volume.Volume.set: Failed to coalesce volume with parent: key %s: SR: %s"
                      % (dbg, key, sr))
            raise Exception(e)
class DatapathOperations(object):
    def __init__(self):
        self.MetadataHandler = MetadataHandler()
        self.blkdev = None

    def gen_vol_path(self, dbg, uri):
        volume_meta = self.MetadataHandler.get_vdi_meta(dbg, uri)
        return "%s/%s/%s" % (SR_PATH_PREFIX, get_sr_uuid_by_uri(
            dbg, uri), volume_meta[IMAGE_UUID_TAG])

    def gen_vol_uri(self, dbg, uri):
        return "file:%s" % self.gen_vol_path(dbg, uri)

    def map_vol(self, dbg, uri, chained=False):
        if self.blkdev:
            log.debug(
                "%s: xcpng.datapath.DatapathOperations.map_vol: uri: %s" %
                (dbg, uri))
            _blkdev_ = self.blkdev

            try:
                volume_meta = self.MetadataHandler.get_vdi_meta(dbg, uri)

                if chained is True:
                    if PARENT_URI_TAG in volume_meta:
                        self.map_vol(dbg, volume_meta[PARENT_URI_TAG][0],
                                     chained)

                if REF_COUNT_TAG in volume_meta:
                    new_meta = {}
                    new_meta[REF_COUNT_TAG] = volume_meta[REF_COUNT_TAG] + 1
                    self.MetadataHandler.update_vdi_meta(dbg, uri, new_meta)
                else:
                    new_meta = {}
                    new_meta[REF_COUNT_TAG] = 1
                    call(dbg,
                         ['ln', '-s', _blkdev_,
                          self.gen_vol_path(dbg, uri)])
                    self.MetadataHandler.update_vdi_meta(dbg, uri, new_meta)
            except Exception as e:
                log.error(
                    "%s: xcpng.datapath.DatapathOperations.map_vol: Failed to map volume: uri: %s device: %s"
                    % (dbg, uri, _blkdev_))
                raise Exception(e)

    def unmap_vol(self, dbg, uri, chained=False):
        path = self.gen_vol_path(dbg, uri)

        if exists(path):
            log.debug(
                "%s: xcpng.datapath.DatapathOperations.unmap_vol: uri: %s" %
                (dbg, uri))
            try:
                volume_meta = self.MetadataHandler.get_vdi_meta(dbg, uri)
                if REF_COUNT_TAG in volume_meta:
                    new_meta = {}
                    if volume_meta[REF_COUNT_TAG] == 1:
                        new_meta[REF_COUNT_TAG] = None
                        call(dbg, ['unlink', path])
                    else:
                        new_meta[
                            REF_COUNT_TAG] = volume_meta[REF_COUNT_TAG] - 1
                    self.MetadataHandler.update_vdi_meta(dbg, uri, new_meta)

                if chained:
                    if PARENT_URI_TAG in volume_meta:
                        self.unmap_vol(dbg, volume_meta[PARENT_URI_TAG][0],
                                       chained)
            except Exception as e:
                log.error(
                    "%s: xcpng.datapath.DatapathOperations.unmap_vol: Failed to unmap volume: uri: %s"
                    % (dbg, uri))
                raise Exception(e)
class Datapath(object):
    def __init__(self):
        self.MetadataHandler = MetadataHandler()
        self.DatapathOpsHandler = _DatapathOperations_()

    def _relink(self, dbg, uri, child, parent, domain):
        raise NotImplementedError('Override in Datapath specifc class')

    def relink(self, dbg, uri, child, parent, domain):
        log.debug(
            "%s: xcpng.datapath.Datapath.relink: uri: %s child: %s parent: %s domain: %s"
            % (dbg, uri, child, parent, domain))

        try:
            self._relink(dbg, uri, child, parent, domain)
        except Exception as e:
            log.error(
                "%s: xcpng.datapath.Datapath.relink: Failed to relink: uri: %s"
                % (dbg, uri))
            raise Exception(e)

    def _commit(self, dbg, uri, child, parent, domain):
        raise NotImplementedError('Override in Datapath specifc class')

    def commit(self, dbg, uri, child, parent, domain):
        log.debug(
            "%s: xcpng.datapath.Datapath.commit: uri: %s child: %s parent: %s domain: %s"
            % (dbg, uri, child, parent, domain))

        try:
            self._commit(dbg, uri, child, parent, domain)
        except Exception as e:
            log.error(
                "%s: xcpng.datapath.Datapath.commit: Failed to commit: uri: %s"
                % (dbg, uri))
            raise Exception(e)

    def _open(self, dbg, uri, persistent):
        raise NotImplementedError('Override in Datapath specifc class')

    def open(self, dbg, uri, persistent):
        log.debug("%s: xcpng.datapath.Datapath.open: uri: %s persistent: %s" %
                  (dbg, uri, persistent))

        try:
            image_meta = self.MetadataHandler.get_vdi_meta(dbg, uri)

            if NON_PERSISTENT_TAG in image_meta:
                vdi_non_persistent = image_meta[NON_PERSISTENT_TAG]
            else:
                vdi_non_persistent = False

            if persistent:
                log.debug(
                    "%s: xcpng.Datapath.open: uri: %s will be marked as persistent"
                    % (dbg, uri))
                if vdi_non_persistent:
                    # unmark as non-peristent
                    image_meta = {
                        NON_PERSISTENT_TAG: None,
                    }
                    self.MetadataHandler.update_vdi_meta(dbg, uri, image_meta)
                    # on detach remove special snapshot to rollback to
            elif vdi_non_persistent:
                log.debug(
                    "%s: xcpng.Datapath.open: uri: %s already marked as non-persistent"
                    % (dbg, uri))
            else:
                log.debug(
                    "%s: xcpng.Datapath.open: uri: %s will be marked as non-persistent"
                    % (dbg, uri))
                # mark as non-peristent
                image_meta = {
                    NON_PERSISTENT_TAG: True,
                }
                self.MetadataHandler.update_vdi_meta(dbg, uri, image_meta)
                # on attach create special snapshot to rollback to on detach

            self._open(dbg, uri, persistent)
        except Exception as e:
            log.error(
                "%s: xcpng.datapath.Datapath.open: Failed to open datapath for volume: uri: %s"
                % (dbg, uri))
            raise Exception(e)

    def _close(self, dbg, uri):
        raise NotImplementedError('Override in Datapath specifc class')

    def close(self, dbg, uri):
        log.debug("%s: xcpng.datapath.Datapath.close: uri: %s" % (dbg, uri))

        try:
            image_meta = self.MetadataHandler.get_vdi_meta(dbg, uri)

            if NON_PERSISTENT_TAG in image_meta:
                vdi_non_persistent = image_meta[NON_PERSISTENT_TAG]
            else:
                vdi_non_persistent = False

            log.debug(
                "%s: xcpng.Datapath.close: uri: %s will be marked as persistent"
                % (dbg, uri))
            if vdi_non_persistent:
                # unmark as non-peristent
                image_meta = {
                    NON_PERSISTENT_TAG: None,
                }
                self.MetadataHandler.update_vdi_meta(dbg, uri, image_meta)

            self._close(dbg, uri)
        except Exception as e:
            log.error(
                "%s: xcpng.datapath.Datapath.close: Failed to close datapath for volume: uri: %s"
                % (dbg, uri))
            raise Exception(e)

    def _attach(self, dbg, uri, domain):
        raise NotImplementedError('Override in Datapath specifc class')

    def attach(self, dbg, uri, domain):
        log.debug("%s: xcpng.datapath.Datapath.attach: uri: %s domain: %s" %
                  (dbg, uri, domain))

        try:
            self.DatapathOpsHandler.map_vol(dbg, uri, chained=True)

            if platform.linux_distribution()[1] == '7.5.0':
                protocol, params = self._attach(dbg, uri, domain)
                return {
                    'domain_uuid': '0',
                    'implementation': [protocol, params]
                }
            elif platform.linux_distribution(
            )[1] == '7.6.0' or platform.linux_distribution()[1] == '8.0.0':
                return {'implementations': self._attach(dbg, uri, domain)}
        except Exception as e:
            log.error(
                "%s: xcpng.datapath.Datapath.attach: Failed to attach datapath for volume: uri: %s"
                % (dbg, uri))
            try:
                self.DatapathOpsHandler.unmap_vol(dbg, uri, chained=True)
            except:
                pass
            raise Exception(e)

    def _detach(self, dbg, uri, domain):
        raise NotImplementedError('Override in Datapath specifc class')

    def detach(self, dbg, uri, domain):
        log.debug("%s: xcpng.datapath.Datapath.detach: uri: %s domain: %s" %
                  (dbg, uri, domain))

        try:
            self.DatapathOpsHandler.unmap_vol(dbg, uri, chained=True)
            self._detach(dbg, uri, domain)
        except Exception as e:
            log.error(
                "%s: xcpng.datapath.Datapath.detach: Failed to detach datapath for volume: uri: %s"
                % (dbg, uri))
            raise Exception(e)

    def _activate(self, dbg, uri, domain):
        raise NotImplementedError('Override in Datapath specifc class')

    def activate(self, dbg, uri, domain):
        log.debug("%s: xcpng.datapath.Datapath.activate: uri: %s domain: %s" %
                  (dbg, uri, domain))

        # TODO: Check that VDI is not active on other host

        try:
            self._activate(dbg, uri, domain)

            image_meta = {ACTIVE_ON_TAG: get_current_host_uuid()}

            self.MetadataHandler.update_vdi_meta(dbg, uri, image_meta)
        except Exception as e:
            log.error(
                "%s: xcpng.datapath.Datapath.activate: Failed to activate datapath for volume: uri: %s"
                % (dbg, uri))
            try:
                self._deactivate(dbg, uri, domain)
            except:
                pass
            raise Exception(e)

    def _deactivate(self, dbg, uri, domain):
        raise NotImplementedError('Override in Datapath specifc class')

    def deactivate(self, dbg, uri, domain):
        log.debug(
            "%s: xcpng.datapath.Datapath.deactivate: uri: %s domain: %s" %
            (dbg, uri, domain))

        try:
            self._deactivate(dbg, uri, domain)

            image_meta = {ACTIVE_ON_TAG: None}

            self.MetadataHandler.update_vdi_meta(dbg, uri, image_meta)
        except Exception as e:
            log.error(
                "%s: xcpng.datapath.Datapath.deactivate: Failed to deactivate datapath for volume: uri: %s"
                % (dbg, uri))
            raise Exception(e)

    def _suspend(self, dbg, uri, domain):
        raise NotImplementedError('Override in Datapath specifc class')

    def suspend(self, dbg, uri, domain):
        log.debug("%s: xcpng.datapath.Datapath.suspend: uri: %s domain: %s" %
                  (dbg, uri, domain))
        try:
            self._suspend(dbg, uri, domain)
        except Exception as e:
            log.error(
                "%s: xcpng.datapath.Datapath.suspend: Failed to suspend datapath for volume: uri: %s"
                % (dbg, uri))
            raise Exception(e)

    def _resume(self, dbg, uri, domain):
        raise NotImplementedError('Override in Datapath specifc class')

    def resume(self, dbg, uri, domain):
        log.debug("%s: xcpng.datapath.Datapath.resume: uri: %s domain: %s" %
                  (dbg, uri, domain))
        try:
            self._resume(dbg, uri, domain)
        except Exception as e:
            log.error(
                "%s: xcpng.datapath.Datapath.resume: Failed to resume datapath for volume: uri: %s"
                % (dbg, uri))
            raise Exception(e)

    def _snapshot(self, dbg, base_uri, snap_uri, domain):
        raise NotImplementedError('Override in Datapath specifc class')

    def snapshot(self, dbg, base_uri, snap_uri, domain):
        log.debug(
            "%s: xcpng.Datapath.snapshot: base_uri: %s snap_uri: %s domain: %s"
            % (dbg, base_uri, snap_uri, domain))
        try:
            self._snapshot(dbg, base_uri, snap_uri, domain)
        except Exception as e:
            log.error(
                "%s: xcpng.datapath.Datapath.snapshot: Failed to set backing file for live volume: uri: %s"
                % (dbg, snap_uri))
            raise Exception(e)