Esempio n. 1
0
    def devicename_exists(self, vpool, name=None, names=None):
        """
        Checks whether a given name can be created on the vpool
        :param vpool: vPool object
        :type vpool: VPool
        :param name: Candidate name
        :type name: str
        :param names: Candidate names
        :type names: list
        :return: Whether the devicename exists
        :rtype: bool
        """
        error_message = None
        if not (name is None) ^ (names is None):
            error_message = 'Either the name (string) or the names (list of strings) parameter must be passed'
        if name is not None and not isinstance(name, basestring):
            error_message = 'The name parameter must be a string'
        if names is not None and not isinstance(names, list):
            error_message = 'The names parameter must be a list of strings'
        if error_message is not None:
            raise HttpNotAcceptableException(error_description=error_message,
                                             error='impossible_request')

        if name is not None:
            devicename = VDiskController.clean_devicename(name)
            return VDiskList.get_by_devicename_and_vpool(devicename,
                                                         vpool) is not None
        for name in names:
            devicename = VDiskController.clean_devicename(name)
            if VDiskList.get_by_devicename_and_vpool(devicename,
                                                     vpool) is not None:
                return True
        return False
Esempio n. 2
0
    def devicename_exists(self, vpool, name=None, names=None):
        """
        Checks whether a given name can be created on the vpool
        :param vpool: vPool object
        :type vpool: VPool
        :param name: Candidate name
        :type name: str
        :param names: Candidate names
        :type names: list
        :return: Whether the devicename exists
        :rtype: bool
        """
        error_message = None
        if not (name is None) ^ (names is None):
            error_message = 'Either the name (string) or the names (list of strings) parameter must be passed'
        if name is not None and not isinstance(name, basestring):
            error_message = 'The name parameter must be a string'
        if names is not None and not isinstance(names, list):
            error_message = 'The names parameter must be a list of strings'
        if error_message is not None:
            raise HttpNotAcceptableException(error_description=error_message,
                                             error='impossible_request')

        if name is not None:
            devicename = VDiskController.clean_devicename(name)
            return VDiskList.get_by_devicename_and_vpool(devicename, vpool) is not None
        for name in names:
            devicename = VDiskController.clean_devicename(name)
            if VDiskList.get_by_devicename_and_vpool(devicename, vpool) is not None:
                return True
        return False
Esempio n. 3
0
    def set_as_template(machineguid):
        """
        Set a vmachine as template

        @param machineguid: guid of the machine
        @return: vmachine template conversion successful: True|False
        """
        # Do some magic on the storage layer?
        # This is most likely required as extra security measure
        # Suppose the template is set back to a real machine
        # it can be deleted within vmware which should be blocked.
        # This might also require a storagerouter internal check
        # to be implemented to discourage volumes from being deleted
        # when clones were made from it.

        vmachine = VMachine(machineguid)
        if vmachine.hypervisor_status == 'RUNNING':
            raise RuntimeError(
                'vMachine {0} may not be running to set it as vTemplate'.
                format(vmachine.name))

        for disk in vmachine.vdisks:
            VDiskController.set_as_template(diskguid=disk.guid)

        vmachine.is_vtemplate = True
        vmachine.invalidate_dynamics(['snapshots'])
        vmachine.save()
Esempio n. 4
0
    def create_volume(self, volume):
        """Creates a volume.
        Called on "cinder create ..." or "nova volume-create ..."
        :param volume: volume reference (sqlalchemy Model)
        """
        _debug_vol_info("CREATE", volume)

        hostname = str(volume.host)
        name = volume.display_name
        if not name:
            name = volume.name
        mountpoint = self._get_hostname_mountpoint(hostname)
        location = '{}/{}.raw'.format(mountpoint, name)
        size = volume.size

        LOG.info('DO_CREATE_VOLUME %s %s' % (location, size))
        VDiskController.create_volume(location = location,
                                      size = size)
        volume['provider_location'] = location

        try:
            ovs_disk = self._find_ovs_model_disk_by_location(location,
                                                             hostname)
        except RuntimeError:
            VDiskController.delete_volume(location = location)
            raise

        ovs_disk.cinder_id = volume.id
        ovs_disk.name = name
        ovs_disk.save()
        return {'provider_location': volume['provider_location']}
Esempio n. 5
0
    def _run_and_validate_dtl_checkup(self, vdisk, validations):
        """
        Execute the DTL checkup for a vDisk and validate the settings afterwards
        """
        single_node = len(StorageRouterList.get_storagerouters()) == 1
        VDiskController.dtl_checkup(vdisk_guid=vdisk.guid)
        config = vdisk.storagedriver_client.get_dtl_config(vdisk.volume_id)
        config_mode = vdisk.storagedriver_client.get_dtl_config_mode(vdisk.volume_id)
        msg = '{0} node - {{0}} - Actual: {{1}} - Expected: {{2}}'.format('Single' if single_node is True else 'Multi')

        validations.append({'key': 'config_mode', 'value': DTLConfigMode.MANUAL})
        for validation in validations:
            key = validation['key']
            value = validation['value']
            if key == 'config':
                actual_value = config
            elif key == 'host':
                actual_value = config.host
            elif key == 'port':
                actual_value = config.port
            elif key == 'mode':
                actual_value = config.mode
            else:
                actual_value = config_mode

            if isinstance(value, list):
                self.assertTrue(expr=actual_value in value,
                                msg=msg.format(key.capitalize(), actual_value, ', '.join(value)))
            else:
                self.assertEqual(first=actual_value,
                                 second=value,
                                 msg=msg.format(key.capitalize(), actual_value, value))
        return config
Esempio n. 6
0
    def test_event_migrate_from_volumedriver(self):
        """
        Test migrate from volumedriver event
        """
        _ = self
        structure = DalHelper.build_dal_structure({
            'vpools': [1],
            'storagerouters': [1, 2],
            'storagedrivers':
            [(1, 1, 1), (2, 1, 2)],  # (<id>, <vpool_id>, <storagerouter_id>)
            'mds_services': [(1, 1), (2, 2)]
        }  # (<id>, <storagedriver_id>)
                                                  )
        vpool = structure['vpools'][1]
        storagedrivers = structure['storagedrivers']
        storagerouters = structure['storagerouters']
        self._roll_out_dtl_services(vpool=vpool, storagerouters=storagerouters)

        vdisk = VDisk(
            VDiskController.create_new(
                volume_name='vdisk_1',
                volume_size=1024**4,
                storagedriver_guid=storagedrivers[1].guid))
        vdisk.storagedriver_client.migrate(vdisk.volume_id,
                                           storagedrivers[2].storagedriver_id,
                                           False)
        VDiskController.migrate_from_voldrv(
            volume_id=vdisk.volume_id,
            new_owner_id=storagedrivers[2].storagedriver_id)
        self.assertEqual(vdisk.storagedriver_id,
                         storagedrivers[2].storagedriver_id)
Esempio n. 7
0
def setAsTemplate(templatepath):
    disk = getVDisk(templatepath, timeout=60)
    if not disk:
        raise RuntimeError("Template did not become available on OVS at %s" % templatepath)
    if disk.info['object_type'] != 'TEMPLATE':
        VDiskController.set_as_template(disk.guid)
    return disk.guid
 def snapshot_vdisk(vdisk):
     metadata = {'label': 'snap-' + vdisk.name,
                 'is_consistent': True,
                 'timestamp': time.time(),
                 'is_automatic': False,
                 'is_sticky': False}
     VDiskController.create_snapshot(vdisk.guid, metadata)
Esempio n. 9
0
    def create_volume(self, volume):
        """Creates a volume.
        Called on "cinder create ..." or "nova volume-create ..."
        :param volume: volume reference (sqlalchemy Model)
        """
        _debug_vol_info("CREATE", volume)

        hostname = str(volume.host)
        name = volume.display_name
        if not name:
            name = volume.name
        mountpoint = self._get_hostname_mountpoint(hostname)
        location = '{}/{}.raw'.format(mountpoint, name)
        size = volume.size

        LOG.info('DO_CREATE_VOLUME %s %s' % (location, size))
        VDiskController.create_volume(location=location, size=size)
        volume['provider_location'] = location

        try:
            ovs_disk = self._find_ovs_model_disk_by_location(
                location, hostname)
        except RuntimeError:
            VDiskController.delete_volume(location=location)
            raise

        ovs_disk.cinder_id = volume.id
        ovs_disk.name = name
        ovs_disk.save()
        return {'provider_location': volume['provider_location']}
Esempio n. 10
0
    def _run_and_validate_dtl_checkup(self, vdisk, validations):
        """
        Execute the DTL checkup for a vDisk and validate the settings afterwards
        """
        single_node = len(StorageRouterList.get_storagerouters()) == 1
        VDiskController.dtl_checkup(vdisk_guid=vdisk.guid)
        config = vdisk.storagedriver_client.get_dtl_config(vdisk.volume_id)
        config_mode = vdisk.storagedriver_client.get_dtl_config_mode(vdisk.volume_id)
        msg = '{0} node - {{0}} - Actual: {{1}} - Expected: {{2}}'.format('Single' if single_node is True else 'Multi')

        validations.append({'key': 'config_mode', 'value': DTLConfigMode.MANUAL})
        for validation in validations:
            key = validation['key']
            value = validation['value']
            if key == 'config':
                actual_value = config
            elif key == 'host':
                actual_value = config.host
            elif key == 'port':
                actual_value = config.port
            elif key == 'mode':
                actual_value = config.mode
            else:
                actual_value = config_mode

            if isinstance(value, list):
                self.assertTrue(expr=actual_value in value,
                                msg=msg.format(key.capitalize(), actual_value, ', '.join(value)))
            else:
                self.assertEqual(first=actual_value,
                                 second=value,
                                 msg=msg.format(key.capitalize(), actual_value, value))
        return config
Esempio n. 11
0
    def rollback(machineguid, timestamp):
        """
        Rolls back a VM based on a given disk snapshot timestamp
        :param machineguid: Guid of the machine to rollback
        :param timestamp: Timestamp to rollback to
        """
        vmachine = VMachine(machineguid)
        if vmachine.hypervisor_status == 'RUNNING':
            raise RuntimeError(
                'vMachine {0} may not be running to set it as vTemplate'.
                format(vmachine.name))

        snapshots = [
            snap for snap in vmachine.snapshots
            if snap['timestamp'] == timestamp
        ]
        if not snapshots:
            raise ValueError(
                'No vmachine snapshots found for timestamp {0}'.format(
                    timestamp))

        for disk in vmachine.vdisks:
            VDiskController.rollback(diskguid=disk.guid, timestamp=timestamp)

        vmachine.invalidate_dynamics(['snapshots'])
Esempio n. 12
0
    def create_snapshot(self, snapshot):
        """Creates a snapshot.
        Called on "nova image-create " or "cinder snapshot-create "
        :param snapshot: snapshot reference (sqlalchemy Model)
        """
        _debug_vol_info('CREATE_SNAP', snapshot)
        volume = snapshot.volume
        _debug_vol_info('CREATE_SNAP_VOL', volume)

        hostname = volume.host
        location = volume.provider_location
        ovs_disk = self._find_ovs_model_disk_by_location(location, hostname)
        metadata = {
            'label': "{0} (OpenStack)".format(snapshot.display_name),
            'is_consistent': False,
            'timestamp': time.time(),
            'machineguid': ovs_disk.vmachine_guid,
            'is_automatic': False
        }

        LOG.debug('CREATE_SNAP %s %s' % (snapshot.display_name, str(metadata)))
        VDiskController.create_snapshot(diskguid=ovs_disk.guid,
                                        metadata=metadata,
                                        snapshotid=str(snapshot.id))
        LOG.debug('CREATE_SNAP OK')
    def copy_image_to_volume(self, context, volume, image_service, image_id):
        """Copy image to volume
        Called on "nova volume-create --image-id ..."
        or "cinder create --image-id"
        Downloads image from glance server into local .raw
        :param volume: volume reference (sqlalchemy Model)
        """
        _debug_vol_info("CP_IMG_TO_VOL", volume)
        LOG.info("CP_IMG_TO_VOL %s %s" % (image_service, image_id))

        name = volume.display_name
        if not name:
            name = volume.name
            volume.display_name = volume.name

        # downloading from an existing image
        destination_path = volume.provider_location
        if destination_path:
            try:
                LOG.info("CP_IMG_TO_VOL Deleting existing empty raw file %s " % destination_path)
                VDiskController.delete_volume(location=destination_path)
                LOG.info("CP_IMG_TO_VOL Downloading image to %s" % destination_path)
                image_utils.fetch_to_raw(context, image_service, image_id, destination_path, "1M", size=volume["size"])
                LOG.info("CP_IMG_TO_VOL Resizing volume to size %s" % volume["size"])
                self.extend_volume(volume=volume, size_gb=volume["size"])
            except Exception as ex:
                LOG.error("CP_IMG_TO_VOL Internal error %s " % unicode(ex))
                self.delete_volume(volume)
                raise
            ovs_disk = self._find_ovs_model_disk_by_location(volume.provider_location, str(volume.host))
            ovs_disk.name = name
            ovs_disk.save()
    def download_to_vpool(url, path, overwrite_if_exists=False):
        """
        Special method to download to vpool because voldrv does not support extending file at write
        :param url: URL to download from
        :type url: str

        :param path: Path to download to
        :type path: str

        :param overwrite_if_exists: Overwrite if file already exists
        :type overwrite_if_exists: bool

        :return: None
        """
        print url
        print path
        if os.path.exists(path) and not overwrite_if_exists:
            return
        u = urllib.urlopen(url)
        file_size = u.info()['Content-Length']
        bsize = 4096 * 1024
        VDiskController.create_volume(path, 0)
        with open(path, "wb") as f:
            size_written = 0
            os.ftruncate(f.fileno(), int(file_size))
            while 1:
                s = u.read(bsize)
                size_written += len(s)
                f.write(s)
                if len(s) < bsize:
                    break
        u.close()
Esempio n. 15
0
    def set_as_template(machineguid):
        """
        Set a vmachine as template

        @param machineguid: guid of the machine
        @return: vmachine template conversion successful: True|False
        """
        # Do some magic on the storage layer?
        # This is most likely required as extra security measure
        # Suppose the template is set back to a real machine
        # it can be deleted within vmware which should be blocked.
        # This might also require a storagerouter internal check
        # to be implemented to discourage volumes from being deleted
        # when clones were made from it.

        vmachine = VMachine(machineguid)
        if vmachine.hypervisor_status == 'RUNNING':
            raise RuntimeError('vMachine {0} may not be running to set it as vTemplate'.format(vmachine.name))

        for disk in vmachine.vdisks:
            VDiskController.set_as_template(diskguid=disk.guid)

        vmachine.is_vtemplate = True
        vmachine.invalidate_dynamics(['snapshots'])
        vmachine.save()
Esempio n. 16
0
 def snapshot_all_vdisks():
     """
     Snapshots all vDisks
     """
     GenericController._logger.info('[SSA] started')
     success = []
     fail = []
     for vdisk in VDiskList.get_vdisks():
         if vdisk.is_vtemplate is True:
             continue
         try:
             metadata = {
                 'label': '',
                 'is_consistent': False,
                 'timestamp': str(int(time.time())),
                 'is_automatic': True,
                 'is_sticky': False
             }
             VDiskController.create_snapshot(vdisk_guid=vdisk.guid,
                                             metadata=metadata)
             success.append(vdisk.guid)
         except Exception:
             GenericController._logger.exception(
                 'Error taking snapshot for vDisk {0}'.format(vdisk.guid))
             fail.append(vdisk.guid)
     GenericController._logger.info(
         '[SSA] Snapshot has been taken for {0} vDisks, {1} failed.'.format(
             len(success), len(fail)))
     return success, fail
Esempio n. 17
0
    def validate(self, storagerouter=None, storagedriver=None):
        """
        Perform some validations before creating or extending a vPool
        :param storagerouter: StorageRouter on which the vPool will be created or extended
        :type storagerouter: ovs.dal.hybrids.storagerouter.StorageRouter
        :param storagedriver: When passing a StorageDriver, perform validations when shrinking a vPool
        :type storagedriver: ovs.dal.hybrids.storagedriver.StorageDriver
        :raises ValueError: If extending a vPool which status is not RUNNING
                RuntimeError: If this vPool's configuration does not meet the requirements
                              If the vPool has already been extended on the specified StorageRouter
        :return: None
        :rtype: NoneType
        """
        if self.vpool is not None:
            if self.vpool.status != VPool.STATUSES.RUNNING:
                raise ValueError('vPool should be in {0} status'.format(
                    VPool.STATUSES.RUNNING))

            ExtensionsToolbox.verify_required_params(
                actual_params=self.vpool.configuration,
                required_params={
                    'sco_size':
                    (int, StorageDriverClient.TLOG_MULTIPLIER_MAP.keys()),
                    'dtl_mode':
                    (str, StorageDriverClient.VPOOL_DTL_MODE_MAP.keys()),
                    'write_buffer': (float, None),
                    'dtl_transport':
                    (str, StorageDriverClient.VPOOL_DTL_TRANSPORT_MAP.keys()),
                    'tlog_multiplier':
                    (int, StorageDriverClient.TLOG_MULTIPLIER_MAP.values())
                })

            if storagerouter is not None:
                for vpool_storagedriver in self.vpool.storagedrivers:
                    if vpool_storagedriver.storagerouter_guid == storagerouter.guid:
                        raise RuntimeError(
                            'A StorageDriver is already linked to this StorageRouter for vPool {0}'
                            .format(self.vpool.name))
            if storagedriver is not None:
                VDiskController.sync_with_reality(vpool_guid=self.vpool.guid)
                storagedriver.invalidate_dynamics('vdisks_guids')
                if len(storagedriver.vdisks_guids) > 0:
                    raise RuntimeError(
                        'There are still vDisks served from the given StorageDriver'
                    )

                self.mds_services = [
                    mds_service for mds_service in self.vpool.mds_services
                    if mds_service.service.storagerouter_guid ==
                    storagedriver.storagerouter_guid
                ]
                for mds_service in self.mds_services:
                    if len(mds_service.storagedriver_partitions
                           ) == 0 or mds_service.storagedriver_partitions[
                               0].storagedriver is None:
                        raise RuntimeError(
                            'Failed to retrieve the linked StorageDriver to this MDS Service {0}'
                            .format(mds_service.service.name))
 def extend_volume(self, volume, size_gb):
     """Extend volume to new size size_gb
     """
     _debug_vol_info("EXTEND_VOL", volume)
     LOG.info("EXTEND_VOL Size %s" % size_gb)
     location = volume.provider_location
     if location is not None:
         LOG.info("DO_EXTEND_VOLUME %s" % (location))
         VDiskController.extend_volume(location=location, size=size_gb)
Esempio n. 19
0
 def extend_volume(self, volume, size_gb):
     """Extend volume to new size size_gb
     """
     _debug_vol_info('EXTEND_VOL', volume)
     LOG.info('EXTEND_VOL Size %s' % size_gb)
     location = volume.provider_location
     if location is not None:
         LOG.info('DO_EXTEND_VOLUME %s' % (location))
         VDiskController.extend_volume(location=location, size=size_gb)
Esempio n. 20
0
    def test_sync_vdisk_with_voldrv(self):
        clone_depth = 3

        def _make_clones(vdisks_map, depth=clone_depth):
            for level in range(depth):
                previous_vd = list(vdisks_map.itervalues())[-1]
                new_name = previous_vd.name + '_clone'
                new_guid = VDiskController.clone(previous_vd.guid,
                                                 new_name).get('vdisk_guid')
                vdisks_map[new_name] = VDisk(new_guid)

        structure = DalHelper.build_dal_structure({
            'vpools': [1],
            'storagerouters': [1],
            'storagedrivers':
            [(1, 1, 1)],  # (<id>, <vpool_id>, <storagerouter_id>)
            'mds_services': [(1, 1)]
        }  # (<id>, <storagedriver_id>)
                                                  )
        vdisk_name = 'vdisk_1'
        storagedriver = structure['storagedrivers'][1]
        vdisk_1 = VDisk(
            VDiskController.create_new(volume_name=vdisk_name,
                                       volume_size=1024**4,
                                       storagedriver_guid=storagedriver.guid))
        vdisks = OrderedDict()
        vdisks[vdisk_name] = vdisk_1

        _make_clones(vdisks)
        self.assertEquals(clone_depth + 1, len(list(VDiskList.get_vdisks())))
        delete_list = list(vdisks.itervalues(
        ))[::-1][:-1]  # These vDisks are clones and ought to be deleted
        for vdisk in delete_list:
            for mds_service in vdisk.mds_services:
                mds_service.delete()
            vdisk.delete()
        self.assertEquals(1, len(list(VDiskList.get_vdisks()))
                          )  # Make sure vDisk clones are properly removed
        self.assertEquals(
            VDiskList.get_vdisks()[0].name,
            vdisk_name)  # Make sure only item left is original vDisk

        VDiskController.sync_with_reality()
        self.assertEquals(clone_depth + 1, len(list(
            VDiskList.get_vdisks())))  # The clones should be in place now

        parents = 0
        for vdisk in VDiskList.get_vdisks():
            try:
                if vdisk.parent_vdisk.name:
                    parents += 1
            except AttributeError:
                pass
        self.assertEquals(
            clone_depth, parents
        )  # As much parents should be detected as the depth of the clones
Esempio n. 21
0
    def test_event_resize_from_volumedriver(self):
        """
        Test resize from volumedriver event
            - Create a vDisk using the resize event
            - Resize the created vDisk using the same resize event
        """
        structure = Helper.build_service_structure(
            {'vpools': [1],
             'storagerouters': [1],
             'storagedrivers': [(1, 1, 1)],  # (<id>, <vpool_id>, <storagerouter_id>)
             'mds_services': [(1, 1)]}  # (<id>, <storagedriver_id>)
        )
        vpools = structure['vpools']
        storagedrivers = structure['storagedrivers']
        mds_service = structure['mds_services'][1]

        # Create volume using resize from voldrv
        device_name = '/vdisk.raw'
        srclient = StorageRouterClient(vpools[1].guid, None)
        mds_backend_config = Helper._generate_mdsmetadatabackendconfig([mds_service])
        volume_id = srclient.create_volume(device_name, mds_backend_config, 1024 ** 4, str(storagedrivers[1].storagedriver_id))
        VDiskController.resize_from_voldrv(volume_id=volume_id,
                                           volume_size=1024 ** 4,
                                           volume_path=device_name,
                                           storagedriver_id=storagedrivers[1].storagedriver_id)
        vdisks = VDiskList.get_vdisks()
        self.assertTrue(expr=len(vdisks) == 1,
                        msg='Expected to find 1 vDisk in model')
        self.assertEqual(first=vdisks[0].name,
                         second='vdisk',
                         msg='Volume name should be vdisk')
        self.assertEqual(first=vdisks[0].volume_id,
                         second=volume_id,
                         msg='Volume ID should be {0}'.format(volume_id))
        self.assertEqual(first=vdisks[0].devicename,
                         second=device_name,
                         msg='Device name should be {0}'.format(device_name))
        self.assertEqual(first=vdisks[0].size,
                         second=1024 ** 4,
                         msg='Size should be 1 TiB')

        # Resize volume using resize from voldrv
        VDiskController.resize_from_voldrv(volume_id=volume_id,
                                           volume_size=2 * 1024 ** 4,
                                           volume_path=device_name,
                                           storagedriver_id=storagedrivers[1].storagedriver_id)
        vdisks = VDiskList.get_vdisks()
        self.assertTrue(expr=len(vdisks) == 1,
                        msg='Expected to find 1 vDisk in model')
        self.assertEqual(first=vdisks[0].name,
                         second='vdisk',
                         msg='Volume name should be vdisk')
        self.assertEqual(first=vdisks[0].size,
                         second=2 * 1024 ** 4,
                         msg='Size should be 2 TiB')
Esempio n. 22
0
    def snapshot(machineguid,
                 label=None,
                 is_consistent=False,
                 timestamp=None,
                 is_automatic=False):
        """
        Snapshot VMachine disks

        @param machineguid: guid of the machine
        @param label: label to give the snapshots
        @param is_consistent: flag indicating the snapshot was consistent or not
        @param timestamp: override timestamp, if required. Should be a unix timestamp
        """

        timestamp = timestamp if timestamp is not None else time.time()
        timestamp = str(int(float(timestamp)))

        metadata = {
            'label': label,
            'is_consistent': is_consistent,
            'timestamp': timestamp,
            'machineguid': machineguid,
            'is_automatic': is_automatic
        }
        machine = VMachine(machineguid)

        # @todo: we now skip creating a snapshot when a vmachine's disks
        #        is missing a mandatory property: volume_id
        #        subtask will now raise an exception earlier in the workflow
        for disk in machine.vdisks:
            if not disk.volume_id:
                message = 'Missing volume_id on disk {0} - unable to create snapshot for vm {1}'.format(
                    disk.guid, machine.guid)
                logger.info('Error: {0}'.format(message))
                raise RuntimeError(message)

        snapshots = {}
        success = True
        try:
            for disk in machine.vdisks:
                snapshots[disk.guid] = VDiskController.create_snapshot(
                    diskguid=disk.guid, metadata=metadata)
        except Exception as ex:
            logger.info('Error snapshotting disk {0}: {1}'.format(
                disk.name, str(ex)))
            success = False
            for diskguid, snapshotid in snapshots.iteritems():
                VDiskController.delete_snapshot(diskguid=diskguid,
                                                snapshotid=snapshotid)
        logger.info('Create snapshot for vMachine {0}: {1}'.format(
            machine.name, 'Success' if success else 'Failure'))
        machine.invalidate_dynamics(['snapshots'])
        if not success:
            raise RuntimeError('Failed to snapshot vMachine {0}'.format(
                machine.name))
Esempio n. 23
0
    def delete_volume(self, volume):
        """Deletes a logical volume.
        Called on "cinder delete ... "
        :param volume: volume reference (sqlalchemy Model)
        """
        _debug_vol_info("DELETE", volume)

        location = volume.provider_location
        if location is not None:
            LOG.info('DO_DELETE_VOLUME %s' % (location))
            VDiskController.delete_volume(location = location)
Esempio n. 24
0
    def delete_volume(self, volume):
        """Deletes a logical volume.
        Called on "cinder delete ... "
        :param volume: volume reference (sqlalchemy Model)
        """
        _debug_vol_info("DELETE", volume)

        location = volume.provider_location
        if location is not None:
            LOG.info('DO_DELETE_VOLUME %s' % (location))
            VDiskController.delete_volume(location=location)
Esempio n. 25
0
    def snapshot(machineguid, label=None, is_consistent=False, timestamp=None, is_automatic=False, is_sticky=False):
        """
        Snapshot VMachine disks

        :param machineguid: guid of the machine
        :param label: label to give the snapshots
        :param is_consistent: flag indicating the snapshot was consistent or not
        :param timestamp: override timestamp, if required. Should be a unix timestamp
        :param is_automatic: Flag to determine automated snapshots
        :param is_sticky: Flag indicating the snapshot is not to be deleted automatically
        """

        timestamp = timestamp if timestamp is not None else time.time()
        timestamp = str(int(float(timestamp)))

        if is_automatic is True and is_sticky is True:
            raise ValueError('Snapshot {0} cannot be both automatic and sticky'.format(label))
        metadata = {'label': label,
                    'is_consistent': is_consistent,
                    'timestamp': timestamp,
                    'machineguid': machineguid,
                    'is_automatic': is_automatic,
                    'is_sticky': is_sticky}
        machine = VMachine(machineguid)

        # @todo: we now skip creating a snapshot when a vmachine's disks
        #        is missing a mandatory property: volume_id
        #        sub-task will now raise an exception earlier in the workflow
        for disk in machine.vdisks:
            if not disk.volume_id:
                message = 'Missing volume_id on disk {0} - unable to create snapshot for vm {1}'.format(
                    disk.guid, machine.guid
                )
                VMachineController._logger.info('Error: {0}'.format(message))
                raise RuntimeError(message)

        snapshots = {}
        success = True
        for disk in machine.vdisks:
            try:
                snapshots[disk.guid] = VDiskController.create_snapshot(diskguid=disk.guid,
                                                                       metadata=metadata)
            except Exception as ex:
                VMachineController._logger.info('Error taking snapshot of disk {0}: {1}'.format(disk.name, str(ex)))
                success = False
                for diskguid, snapshotid in snapshots.iteritems():
                    VDiskController.delete_snapshot(diskguid=diskguid,
                                                    snapshotid=snapshotid)
        VMachineController._logger.info('Create snapshot for vMachine {0}: {1}'.format(
            machine.name, 'Success' if success else 'Failure'
        ))
        machine.invalidate_dynamics(['snapshots'])
        if not success:
            raise RuntimeError('Failed to snapshot vMachine {0}'.format(machine.name))
    def delete_snapshot(self, snapshot):
        """Deletes a snapshot.
        :param snapshot: snapshot reference (sqlalchemy Model)
        """
        _debug_vol_info("DELETE_SNAP", snapshot)
        volume = snapshot.volume
        hostname = volume.host
        location = volume.provider_location

        ovs_disk = self._find_ovs_model_disk_by_location(location, hostname)
        LOG.debug("DELETE_SNAP %s" % snapshot.id)
        VDiskController.delete_snapshot(diskguid=ovs_disk.guid, snapshotid=str(snapshot.id))
        LOG.debug("DELETE_SNAP OK")
Esempio n. 27
0
    def test_clone_from_template_happypath(self):
        """
        Test clone from template - happy path
        """
        StorageDriverModule.use_good_client()
        vdisk_1_1, pmachine = self._prepare()

        VDiskController.create_from_template(vdisk_1_1.guid, 'vmachine_2', 'vdisk_1_1-clone', pmachine.guid)

        vdisks = VDiskList.get_vdisk_by_name('vdisk_1_1')
        self.assertEqual(len(vdisks), 1, 'Vdisk not modeled')
        clones = VDiskList.get_vdisk_by_name('vdisk_1_1-clone')
        self.assertEqual(len(clones), 1, 'Clone not modeled')
Esempio n. 28
0
    def test_clone_from_template_happypath(self):
        """
        Test clone from template - happy path
        """
        StorageDriverModule.use_good_client()
        vdisk_1_1, pmachine = self._prepare()

        VDiskController.create_from_template(vdisk_1_1.guid, 'vmachine_2',
                                             'vdisk_1_1-clone', pmachine.guid)

        vdisks = VDiskList.get_vdisk_by_name('vdisk_1_1')
        self.assertEqual(len(vdisks), 1, 'Vdisk not modeled')
        clones = VDiskList.get_vdisk_by_name('vdisk_1_1-clone')
        self.assertEqual(len(clones), 1, 'Clone not modeled')
Esempio n. 29
0
    def test_folder_renames(self):
        """
        Validates whether folder renames are correctly processed
        """
        structure = DalHelper.build_dal_structure({
            'vpools': [1],
            'storagerouters': [1],
            'storagedrivers':
            [(1, 1, 1)],  # (<id>, <vpool_id>, <storagerouter_id>)
            'mds_services': [(1, 1)]
        }  # (<id>, <storagedriver_id>)
                                                  )
        storagedriver = structure['storagedrivers'][1]
        vdisk1 = VDisk(
            VDiskController.create_new('foo/one.raw', 1024**3,
                                       storagedriver.guid))
        vdisk2 = VDisk(
            VDiskController.create_new('bar/two.raw', 1024**3,
                                       storagedriver.guid))
        vdisk3 = VDisk(
            VDiskController.create_new('three.raw', 1024**3,
                                       storagedriver.guid))

        VDiskController.rename_from_voldrv(
            old_path='/thr',
            new_path='/test',
            storagedriver_id=storagedriver.storagedriver_id)
        vdisk1.discard()
        vdisk2.discard()
        vdisk3.discard()
        self.assertEqual(vdisk1.devicename, '/foo/one.raw')
        self.assertEqual(vdisk2.devicename, '/bar/two.raw')
        self.assertEqual(vdisk3.devicename, '/three.raw')

        VDiskController.rename_from_voldrv(
            old_path='/foo',
            new_path='/bar',
            storagedriver_id=storagedriver.storagedriver_id)
        vdisk1.discard()
        vdisk2.discard()
        vdisk3.discard()
        self.assertEqual(vdisk1.devicename, '/bar/one.raw')
        self.assertEqual(vdisk2.devicename, '/bar/two.raw')
        self.assertEqual(vdisk3.devicename, '/three.raw')

        VDiskController.rename_from_voldrv(
            old_path='/bar',
            new_path='/foo',
            storagedriver_id=storagedriver.storagedriver_id)
        vdisk1.discard()
        vdisk2.discard()
        vdisk3.discard()
        self.assertEqual(vdisk1.devicename, '/foo/one.raw')
        self.assertEqual(vdisk2.devicename, '/foo/two.raw')
        self.assertEqual(vdisk3.devicename, '/three.raw')
Esempio n. 30
0
    def delete_snapshot(self, snapshot):
        """Deletes a snapshot.
        :param snapshot: snapshot reference (sqlalchemy Model)
        """
        _debug_vol_info('DELETE_SNAP', snapshot)
        volume = snapshot.volume
        hostname = volume.host
        location = volume.provider_location

        ovs_disk = self._find_ovs_model_disk_by_location(location, hostname)
        LOG.debug('DELETE_SNAP %s' % snapshot.id)
        VDiskController.delete_snapshot(diskguid=ovs_disk.guid,
                                        snapshotid=str(snapshot.id))
        LOG.debug('DELETE_SNAP OK')
Esempio n. 31
0
 def test_clean_devicename(self):
     """
     Validates whether a devicename is properly cleaned
     * Test several names and validate the returned devicename
     """
     test = {
         'Foo Bar':
         '/Foo_Bar.raw',
         '/Foo Bar .raw':
         '/Foo_Bar_.raw',
         'foo-bar.rawtest':
         '/foo-bar.rawtest.raw',
         'test///folder':
         '/test/folder.raw',
         'foobar-flat.vmdk':
         '/foobar-flat.vmdk.raw',
         '//test.raw':
         '/test.raw',
         'test/.raw':
         '/test/.raw.raw',
         '//d\'!@#%xfoo Bar/te_b --asdfS SA AS lolz///f.wrv.':
         '/dxfoo_Bar/te_b_--asdfS_SA_AS_lolz/f.wrv..raw'
     }
     for raw, expected in test.iteritems():
         result = VDiskController.clean_devicename(raw)
         self.assertEqual(result, expected)
Esempio n. 32
0
 def delete_snapshot(vmachineguid, timestamp):
     """
     Remove a snapshot from the vmachine
     @param vmachineguid: Guid of the virtual machine
     @param timestamp: timestamp of the snapshot
     """
     vmachine = VMachine(vmachineguid)
     vmachine_snapshots = [snap for snap in vmachine.snapshots if snap['timestamp'] == str(timestamp)]
     if len(vmachine_snapshots) != 1:
         raise RuntimeError('Snapshot {0} does not belong to vmachine {1}'.format(timestamp, vmachine.name))
     vmachine_snapshot = vmachine_snapshots[0]
     VMachineController._logger.info('Deleting snapshot {0} from vmachine {1}'.format(timestamp, vmachine.name))
     for diskguid, snapshotid in vmachine_snapshot['snapshots'].items():
         VDiskController.delete_snapshot(diskguid, snapshotid)
     VMachineController._logger.info('Deleted snapshot {0}'.format(timestamp))
     vmachine.invalidate_dynamics(['snapshots'])
Esempio n. 33
0
 def _make_clones(vdisks_map, depth=clone_depth):
     for level in range(depth):
         previous_vd = list(vdisks_map.itervalues())[-1]
         new_name = previous_vd.name + '_clone'
         new_guid = VDiskController.clone(previous_vd.guid,
                                          new_name).get('vdisk_guid')
         vdisks_map[new_name] = VDisk(new_guid)
Esempio n. 34
0
 def delete_snapshot(vmachineguid, timestamp):
     """
     Remove a snapshot from the vmachine
     @param vmachineguid: Guid of the virtual machine
     @param timestamp: timestamp of the snapshot
     """
     vmachine = VMachine(vmachineguid)
     vmachine_snapshots = [snap for snap in vmachine.snapshots if snap['timestamp'] == str(timestamp)]
     if len(vmachine_snapshots) != 1:
         raise RuntimeError('Snapshot {0} does not belong to vmachine {1}'.format(timestamp, vmachine.name))
     vmachine_snapshot = vmachine_snapshots[0]
     VMachineController._logger.info('Deleting snapshot {0} from vmachine {1}'.format(timestamp, vmachine.name))
     for diskguid, snapshotid in vmachine_snapshot['snapshots'].items():
         VDiskController.delete_snapshot(diskguid, snapshotid)
     VMachineController._logger.info('Deleted snapshot {0}'.format(timestamp))
     vmachine.invalidate_dynamics(['snapshots'])
Esempio n. 35
0
    def test_delete(self):
        """
        Test the delete of a vDisk
            - Create 2 vDisks with identical names on 2 different vPools
            - Delete 1st vDisk and verify other still remains on correct vPool
            - Delete 2nd vDisk and verify no more volumes left
        """
        structure = DalHelper.build_dal_structure({
            'vpools': [1, 2],
            'domains': [1],
            'storagerouters': [1],
            'storagedrivers':
            [(1, 1, 1), (2, 2, 1)],  # (<id>, <vpool_id>, <storagerouter_id>)
            'mds_services': [(1, 1), (2, 2)]
        }  # (<id>, <storagedriver_id>)
                                                  )
        domains = structure['domains']
        storagedrivers = structure['storagedrivers']

        vdisk1 = VDisk(
            VDiskController.create_new(
                volume_name='vdisk_1',
                volume_size=1024**3,
                storagedriver_guid=storagedrivers[1].guid))
        vdisk2 = VDisk(
            VDiskController.create_new(
                volume_name='vdisk_1',
                volume_size=1024**3,
                storagedriver_guid=storagedrivers[2].guid))

        vdisk_domain = VDiskDomain()
        vdisk_domain.domain = domains[1]
        vdisk_domain.vdisk = vdisk1
        vdisk_domain.save()

        # Delete vDisk1 and make some assertions
        VDiskController.delete(vdisk_guid=vdisk1.guid)
        with self.assertRaises(ObjectNotFoundException):
            VDisk(vdisk1.guid)
        self.assertEqual(
            first=len(VDiskController.list_volumes()),
            second=1,
            msg='Expected to find only 1 volume in Storage Driver list_volumes'
        )
        self.assertIn(member=vdisk2,
                      container=VDiskList.get_vdisks(),
                      msg='vDisk2 should still be modeled')

        # Delete vDisk2 and make some assertions
        VDiskController.delete(vdisk_guid=vdisk2.guid)
        with self.assertRaises(ObjectNotFoundException):
            VDisk(vdisk2.guid)
        self.assertEqual(
            first=len(VDiskController.list_volumes()),
            second=0,
            msg=
            'Expected to find no more volumes in Storage Driver list_volumes')
Esempio n. 36
0
    def test_create_snapshot(self):
        """
        Test the create snapshot functionality
            - Create a vDisk
            - Attempt to create a snapshot providing incorrect parameters
            - Create a snapshot and make some assertions
        """
        structure = DalHelper.build_dal_structure(
            {'vpools': [1],
             'storagerouters': [1],
             'storagedrivers': [(1, 1, 1)],  # (<id>, <vpool_id>, <storagerouter_id>)
             'mds_services': [(1, 1)]}  # (<id>, <storagedriver_id>)
        )
        storagedrivers = structure['storagedrivers']

        vdisk1 = VDisk(VDiskController.create_new(volume_name='vdisk_1', volume_size=1024 ** 3, storagedriver_guid=storagedrivers[1].guid))
        with self.assertRaises(ValueError):
            # noinspection PyTypeChecker
            VDiskController.create_snapshot(vdisk_guid=vdisk1.guid,
                                            metadata='')

        now = int(time.time())
        snapshot_id = VDiskController.create_snapshot(vdisk_guid=vdisk1.guid, metadata={'timestamp': now,
                                                                                        'label': 'label1',
                                                                                        'is_consistent': True,
                                                                                        'is_automatic': True,
                                                                                        'is_sticky': False})
        self.assertTrue(expr=len(vdisk1.snapshots) == 1, msg='Expected to find 1 snapshot')
        self.assertTrue(expr=len(vdisk1.snapshot_ids) == 1, msg='Expected to find 1 snapshot ID')
        snapshot = vdisk1.snapshots[0]
        expected_keys = {'guid', 'timestamp', 'label', 'is_consistent', 'is_automatic', 'is_sticky', 'in_backend', 'stored'}
        self.assertEqual(first=expected_keys,
                         second=set(snapshot.keys()),
                         msg='Set of expected keys differs from reality. Expected: {0}  -  Reality: {1}'.format(expected_keys, set(snapshot.keys())))

        for key, value in {'guid': snapshot_id,
                           'label': 'label1',
                           'stored': 0,
                           'is_sticky': False,
                           'timestamp': now,
                           'in_backend': True,
                           'is_automatic': True,
                           'is_consistent': True}.iteritems():
            self.assertEqual(first=value,
                             second=snapshot[key],
                             msg='Value for key "{0}" does not match reality. Expected: {1}  -  Reality: {2}'.format(key, value, snapshot[key]))
Esempio n. 37
0
    def test_create_snapshot(self):
        """
        Test the create snapshot functionality
            - Create a vDisk
            - Attempt to create a snapshot providing incorrect parameters
            - Create a snapshot and make some assertions
        """
        structure = Helper.build_service_structure(
            {'vpools': [1],
             'storagerouters': [1],
             'storagedrivers': [(1, 1, 1)],  # (<id>, <vpool_id>, <storagerouter_id>)
             'mds_services': [(1, 1)]}  # (<id>, <storagedriver_id>)
        )
        storagedrivers = structure['storagedrivers']

        vdisk1 = VDisk(VDiskController.create_new(volume_name='vdisk_1', volume_size=1024 ** 3, storagedriver_guid=storagedrivers[1].guid))
        with self.assertRaises(ValueError):
            # noinspection PyTypeChecker
            VDiskController.create_snapshot(vdisk_guid=vdisk1.guid,
                                            metadata='')

        now = int(time.time())
        snapshot_id = VDiskController.create_snapshot(vdisk_guid=vdisk1.guid, metadata={'timestamp': now,
                                                                                        'label': 'label1',
                                                                                        'is_consistent': True,
                                                                                        'is_automatic': True,
                                                                                        'is_sticky': False})
        self.assertTrue(expr=len(vdisk1.snapshots) == 1,
                        msg='Expected to find 1 snapshot')
        snapshot = vdisk1.snapshots[0]
        expected_keys = {'guid', 'timestamp', 'label', 'is_consistent', 'is_automatic', 'is_sticky', 'in_backend', 'stored'}
        self.assertEqual(first=expected_keys,
                         second=set(snapshot.keys()),
                         msg='Set of expected keys differs from reality. Expected: {0}  -  Reality: {1}'.format(expected_keys, set(snapshot.keys())))

        for key, value in {'guid': snapshot_id,
                           'label': 'label1',
                           'stored': 0,
                           'is_sticky': False,
                           'timestamp': now,
                           'in_backend': True,
                           'is_automatic': True,
                           'is_consistent': True}.iteritems():
            self.assertEqual(first=value,
                             second=snapshot[key],
                             msg='Value for key "{0}" does not match reality. Expected: {1}  -  Reality: {2}'.format(key, value, snapshot[key]))
Esempio n. 38
0
    def test_delete_snapshot(self):
        """
        Test the delete snapshot functionality
            - Create a vDisk and take a snapshot
            - Attempt to delete a non-existing snapshot
        """
        structure = Helper.build_service_structure(
            {'vpools': [1],
             'storagerouters': [1],
             'storagedrivers': [(1, 1, 1)],  # (<id>, <vpool_id>, <storagerouter_id>)
             'mds_services': [(1, 1)]}  # (<id>, <storagedriver_id>)
        )
        storagedrivers = structure['storagedrivers']

        vdisk1 = VDisk(VDiskController.create_new(volume_name='vdisk_1', volume_size=1024 ** 3, storagedriver_guid=storagedrivers[1].guid))
        VDiskController.create_snapshot(vdisk_guid=vdisk1.guid, metadata={'timestamp': int(time.time()),
                                                                          'label': 'label1',
                                                                          'is_consistent': True,
                                                                          'is_automatic': True,
                                                                          'is_sticky': False})
        snapshot = vdisk1.snapshots[0]
        self.assertTrue(expr=len(vdisk1.snapshots) == 1,
                        msg='Expected to find 1 snapshot')
        with self.assertRaises(RuntimeError):
            VDiskController.delete_snapshot(vdisk_guid=vdisk1.guid,
                                            snapshot_id='non-existing')

        VDiskController.delete_snapshot(vdisk_guid=vdisk1.guid,
                                        snapshot_id=snapshot['guid'])
        self.assertTrue(expr=len(vdisk1.snapshots) == 0,
                        msg='Expected to find no more snapshots')
Esempio n. 39
0
    def test_delete_snapshot(self):
        """
        Test the delete snapshot functionality
            - Create a vDisk and take a snapshot
            - Attempt to delete a non-existing snapshot
        """
        structure = DalHelper.build_dal_structure(
            {'vpools': [1],
             'storagerouters': [1],
             'storagedrivers': [(1, 1, 1)],  # (<id>, <vpool_id>, <storagerouter_id>)
             'mds_services': [(1, 1)]}  # (<id>, <storagedriver_id>)
        )
        storagedrivers = structure['storagedrivers']

        vdisk1 = VDisk(VDiskController.create_new(volume_name='vdisk_1', volume_size=1024 ** 3, storagedriver_guid=storagedrivers[1].guid))
        VDiskController.create_snapshot(vdisk_guid=vdisk1.guid, metadata={'timestamp': int(time.time()),
                                                                          'label': 'label1',
                                                                          'is_consistent': True,
                                                                          'is_automatic': True,
                                                                          'is_sticky': False})
        self.assertTrue(expr=len(vdisk1.snapshots) == 1, msg='Expected to find 1 snapshot')
        self.assertTrue(expr=len(vdisk1.snapshot_ids) == 1, msg='Expected to find 1 snapshot ID')
        with self.assertRaises(RuntimeError):
            VDiskController.delete_snapshot(vdisk_guid=vdisk1.guid,
                                            snapshot_id='non-existing')

        VDiskController.delete_snapshot(vdisk_guid=vdisk1.guid,
                                        snapshot_id=vdisk1.snapshot_ids[0])
        self.assertTrue(expr=len(vdisk1.snapshots) == 0, msg='Expected to find no more snapshots')
        self.assertTrue(expr=len(vdisk1.snapshot_ids) == 0, msg='Expected to find no more snapshot IDs')
Esempio n. 40
0
    def test_set_as_template(self):
        """
        Test the set as template functionality
            - Create a vDisk
            - Set it as template and make some assertions
        """
        structure = Helper.build_service_structure(
            {'vpools': [1],
             'storagerouters': [1],
             'storagedrivers': [(1, 1, 1)],  # (<id>, <vpool_id>, <storagerouter_id>)
             'mds_services': [(1, 1)]}  # (<id>, <storagedriver_id>)
        )
        storagedrivers = structure['storagedrivers']

        vdisk = VDisk(VDiskController.create_new(volume_name='vdisk_1', volume_size=1024 ** 4, storagedriver_guid=storagedrivers[1].guid))
        metadata = {'is_consistent': True,
                    'is_automatic': True,
                    'is_sticky': False}
        for x in range(5):
            metadata['label'] = 'label{0}'.format(x)
            metadata['timestamp'] = int(time.time())
            VDiskController.create_snapshot(vdisk_guid=vdisk.guid, metadata=metadata)
        self.assertTrue(expr=len(vdisk.snapshots) == 5, msg='Expected to find 5 snapshots')

        # Set as template and validate the model
        self.assertFalse(expr=vdisk.is_vtemplate, msg='Dynamic property "is_vtemplate" should be False')
        VDiskController.set_as_template(vdisk.guid)
        vdisk.invalidate_dynamics('snapshots')
        self.assertTrue(expr=vdisk.is_vtemplate, msg='Dynamic property "is_vtemplate" should be True')
        self.assertTrue(expr=len(vdisk.snapshots) == 1, msg='Expected to find only 1 snapshot after converting to template')

        # Try again and verify job succeeds, previously we raised error when setting as template an additional time
        VDiskController.set_as_template(vdisk.guid)
        self.assertTrue(expr=vdisk.is_vtemplate, msg='Dynamic property "is_vtemplate" should still be True')
Esempio n. 41
0
    def rollback(machineguid, timestamp):
        """
        Rolls back a VM based on a given disk snapshot timestamp
        """
        vmachine = VMachine(machineguid)
        if vmachine.hypervisor_status == 'RUNNING':
            raise RuntimeError('vMachine {0} may not be running to set it as vTemplate'.format(
                vmachine.name
            ))

        snapshots = [snap for snap in vmachine.snapshots if snap['timestamp'] == timestamp]
        if not snapshots:
            raise ValueError('No vmachine snapshots found for timestamp {0}'.format(timestamp))

        for disk in vmachine.vdisks:
            VDiskController.rollback(diskguid=disk.guid,
                                     timestamp=timestamp)

        vmachine.invalidate_dynamics(['snapshots'])
Esempio n. 42
0
    def test_event_migrate_from_volumedriver(self):
        """
        Test migrate from volumedriver event
        """
        _ = self
        structure = Helper.build_service_structure(
            {'vpools': [1],
             'storagerouters': [1, 2],
             'storagedrivers': [(1, 1, 1), (2, 1, 2)],  # (<id>, <vpool_id>, <storagerouter_id>)
             'mds_services': [(1, 1), (2, 2)]}  # (<id>, <storagedriver_id>)
        )
        vpool = structure['vpools'][1]
        storagedrivers = structure['storagedrivers']
        storagerouters = structure['storagerouters']
        self._roll_out_dtl_services(vpool=vpool, storagerouters=storagerouters)

        vdisk = VDisk(VDiskController.create_new(volume_name='vdisk_1', volume_size=1024 ** 4, storagedriver_guid=storagedrivers[1].guid))
        vdisk.storagedriver_client.migrate(vdisk.volume_id, storagedrivers[2].storagedriver_id, False)
        VDiskController.migrate_from_voldrv(volume_id=vdisk.volume_id, new_owner_id=storagedrivers[2].storagedriver_id)
        self.assertEqual(vdisk.storagedriver_id, storagedrivers[2].storagedriver_id)
Esempio n. 43
0
    def create_volume_from_snapshot(self, volume, snapshot):
        """Creates a volume from a snapshot.
        Called on "cinder create --snapshot-id ..."
        :param snapshot: snapshot reference (sqlalchemy Model)
        :param volume: volume reference (sqlalchemy Model)

        Volume here is just a ModelObject, it doesn't exist physically,
            it will be created by OVS.
        Diskguid to be passed to the clone method is the ovs diskguid of the
            parent of the snapshot with snapshot.id

        OVS: Clone from arbitrary volume,
        requires volumedriver 3.6 release > 15.08.2014
        """
        _debug_vol_info('CLONE_VOL', volume)
        _debug_vol_info('CLONE_SNAP', snapshot)

        mountpoint = self._get_hostname_mountpoint(str(volume.host))
        ovs_snap_disk = self._find_ovs_model_disk_by_snapshot_id(snapshot.id)
        devicename = volume.display_name
        if not devicename:
            devicename = volume.name
        pmachineguid = self._find_ovs_model_pmachine_guid_by_hostname(
            str(volume.host))

        LOG.info('[CLONE FROM SNAP] %s %s %s %s' %
                 (ovs_snap_disk.guid, snapshot.id, devicename, pmachineguid))
        try:
            disk_meta = VDiskController.clone(diskguid=ovs_snap_disk.guid,
                                              snapshotid=snapshot.id,
                                              devicename=devicename,
                                              pmachineguid=pmachineguid,
                                              machinename="",
                                              machineguid=None)
            volume['provider_location'] = '{}{}'.format(
                mountpoint, disk_meta['backingdevice'])

            LOG.debug('[CLONE FROM SNAP] Meta: %s' % str(disk_meta))
            LOG.debug('[CLONE FROM SNAP] New volume %s' %
                      volume['provider_location'])
            vdisk = VDisk(disk_meta['diskguid'])
            vdisk.cinder_id = volume.id
            vdisk.name = devicename
            vdisk.save()
        except Exception as ex:
            LOG.error('CLONE FROM SNAP: Internal error %s ' % str(ex))
            self.delete_volume(volume)
            self.delete_snapshot(snapshot)
            raise

        return {
            'provider_location': volume['provider_location'],
            'display_name': volume['display_name']
        }
Esempio n. 44
0
    def test_exception_handling(self):
        """
        Test if the scheduled job can handle exceptions
        """
        def raise_an_exception(*args, **kwargs):
            raise RuntimeError('Emulated snapshot delete error')

        structure = DalHelper.build_dal_structure({
            'vpools': [1],
            'vdisks': [
                (1, 1, 1, 1), (2, 1, 1, 1)
            ],  # (<id>, <storagedriver_id>, <vpool_id>, <mds_service_id>)
            'mds_services': [(1, 1)],
            'storagerouters': [1],
            'storagedrivers': [(1, 1, 1)]
        }  # (<id>, <vpool_id>, <storagerouter_id>)
                                                  )

        vdisk_1, vdisk_2 = structure['vdisks'].values()
        storagedriver_1 = structure['storagedrivers'][1]

        vdisks = [vdisk_1, vdisk_2]

        for vdisk in vdisks:
            [
                dynamic for dynamic in vdisk._dynamics
                if dynamic.name == 'snapshots'
            ][0].timeout = 0
            for i in xrange(0, 2):
                metadata = {
                    'label':
                    str(i),
                    'is_consistent':
                    False,
                    'is_sticky':
                    False,
                    'timestamp':
                    str((int(time.time() -
                             datetime.timedelta(2).total_seconds() - i)))
                }
                snapshot_id = VDiskController.create_snapshot(
                    vdisk.guid, metadata)
                if vdisk == vdisk_1:
                    StorageRouterClient.delete_snapshot_callbacks[
                        vdisk.volume_id] = {
                            snapshot_id: raise_an_exception
                        }
        with self.assertRaises(RuntimeError):
            GenericController.delete_snapshots_storagedriver(
                storagedriver_guid=storagedriver_1.guid)
        self.assertEqual(1, len(vdisk_2.snapshot_ids),
                         'One snapshot should be removed for vdisk 2')
        self.assertEqual(2, len(vdisk_1.snapshot_ids),
                         'No snapshots should be removed for vdisk 1')
Esempio n. 45
0
    def copy_image_to_volume(self, context, volume, image_service, image_id):
        """Copy image to volume
        Called on "nova volume-create --image-id ..."
        or "cinder create --image-id"
        Downloads image from glance server into local .raw
        :param volume: volume reference (sqlalchemy Model)
        """
        _debug_vol_info("CP_IMG_TO_VOL", volume)
        LOG.info("CP_IMG_TO_VOL %s %s" % (image_service, image_id))

        name = volume.display_name
        if not name:
            name = volume.name
            volume.display_name = volume.name

        # downloading from an existing image
        destination_path = volume.provider_location
        if destination_path:
            try:
                LOG.info('CP_IMG_TO_VOL Deleting existing empty raw file %s ' %
                         destination_path)
                VDiskController.delete_volume(location=destination_path)
                LOG.info('CP_IMG_TO_VOL Downloading image to %s' %
                         destination_path)
                image_utils.fetch_to_raw(context,
                                         image_service,
                                         image_id,
                                         destination_path,
                                         '1M',
                                         size=volume['size'])
                LOG.info('CP_IMG_TO_VOL Resizing volume to size %s' %
                         volume['size'])
                self.extend_volume(volume=volume, size_gb=volume['size'])
            except Exception as ex:
                LOG.error('CP_IMG_TO_VOL Internal error %s ' % unicode(ex))
                self.delete_volume(volume)
                raise
            ovs_disk = self._find_ovs_model_disk_by_location(
                volume.provider_location, str(volume.host))
            ovs_disk.name = name
            ovs_disk.save()
Esempio n. 46
0
 def test_extract_volumename(self):
     """
     Validates whether a correct volumename is yielded from a given devicename
     * Test several devicenames and validate the returned name
     """
     test = {'/foo/Bar/something.raw': 'something',
             '/Some.long.dotted.name.raw': 'Some.long.dotted.name',
             '': '',
             'f4qav@#$%sd.raw': 'f4qav@#$%sd'}
     for devicename, expected in test.iteritems():
         result = VDiskController.extract_volumename(devicename)
         self.assertEqual(result, expected)
Esempio n. 47
0
 def snapshot_all_vdisks():
     """
     Snapshots all vDisks
     """
     ScheduledTaskController._logger.info('[SSA] started')
     success = []
     fail = []
     for vdisk in VDiskList.get_vdisks():
         try:
             metadata = {'label': '',
                         'is_consistent': False,
                         'timestamp': str(int(time.time())),
                         'is_automatic': True,
                         'is_sticky': False}
             VDiskController.create_snapshot(vdisk_guid=vdisk.guid,
                                             metadata=metadata)
             success.append(vdisk.guid)
         except Exception:
             ScheduledTaskController._logger.exception('Error taking snapshot for vDisk {0}'.format(vdisk.guid))
             fail.append(vdisk.guid)
     ScheduledTaskController._logger.info('[SSA] Snapshot has been taken for {0} vDisks, {1} failed.'.format(len(success), len(fail)))
Esempio n. 48
0
    def _snapshot_ids(self):
        """
        Fetches the snapshot IDs for this vDisk
        """
        if not self.volume_id or not self.vpool:
            return []

        from ovs.lib.vdisk import VDiskController
        try:
            return VDiskController.list_snapshot_ids(vdisk=self)
        except:
            return []
Esempio n. 49
0
    def clone(machineguid, timestamp, name):
        """
        Clone a vmachine using the disk snapshot based on a snapshot timestamp

        @param machineguid: guid of the machine to clone
        @param timestamp: timestamp of the disk snapshots to use for the clone
        @param name: name for the new machine
        """
        machine = VMachine(machineguid)

        disks = {}
        for snapshot in machine.snapshots:
            if snapshot['timestamp'] == timestamp:
                for diskguid, snapshotguid in snapshot['snapshots'].iteritems(
                ):
                    disks[diskguid] = snapshotguid

        new_machine = VMachine()
        new_machine.copy(machine)
        new_machine.name = name
        new_machine.pmachine = machine.pmachine
        new_machine.save()

        new_disk_guids = []
        disks_by_order = sorted(machine.vdisks, key=lambda x: x.order)
        for currentDisk in disks_by_order:
            if machine.is_vtemplate and currentDisk.templatesnapshot:
                snapshotid = currentDisk.templatesnapshot
            else:
                snapshotid = disks[currentDisk.guid]
            prefix = '%s-clone' % currentDisk.name

            result = VDiskController.clone(
                diskguid=currentDisk.guid,
                snapshotid=snapshotid,
                devicename=prefix,
                pmachineguid=new_machine.pmachine_guid,
                machinename=new_machine.name,
                machineguid=new_machine.guid)
            new_disk_guids.append(result['diskguid'])

        hv = Factory.get(machine.pmachine)
        try:
            result = hv.clone_vm(machine.hypervisor_id, name, disks, None,
                                 True)
        except:
            VMachineController.delete(machineguid=new_machine.guid)
            raise

        new_machine.hypervisor_id = result
        new_machine.save()
        return new_machine.guid
Esempio n. 50
0
    def create_volume_from_snapshot(self, volume, snapshot):
        """Creates a volume from a snapshot.
        Called on "cinder create --snapshot-id ..."
        :param snapshot: snapshot reference (sqlalchemy Model)
        :param volume: volume reference (sqlalchemy Model)

        Volume here is just a ModelObject, it doesn't exist physically,
            it will be created by OVS.
        Diskguid to be passed to the clone method is the ovs diskguid of the
            parent of the snapshot with snapshot.id

        OVS: Clone from arbitrary volume,
        requires volumedriver 3.6 release > 15.08.2014
        """
        _debug_vol_info('CLONE_VOL', volume)
        _debug_vol_info('CLONE_SNAP', snapshot)

        mountpoint = self._get_hostname_mountpoint(str(volume.host))
        ovs_snap_disk = self._find_ovs_model_disk_by_snapshot_id(snapshot.id)
        devicename = volume.display_name
        if not devicename:
            devicename = volume.name
        pmachineguid = self._find_ovs_model_pmachine_guid_by_hostname(
            str(volume.host))

        LOG.info('[CLONE FROM SNAP] %s %s %s %s'
                 % (ovs_snap_disk.guid, snapshot.id, devicename, pmachineguid))
        try:
            disk_meta = VDiskController.clone(diskguid = ovs_snap_disk.guid,
                                              snapshotid = snapshot.id,
                                              devicename = devicename,
                                              pmachineguid = pmachineguid,
                                              machinename = "",
                                              machineguid=None)
            volume['provider_location'] = '{}{}'.format(
                mountpoint, disk_meta['backingdevice'])

            LOG.debug('[CLONE FROM SNAP] Meta: %s' % str(disk_meta))
            LOG.debug('[CLONE FROM SNAP] New volume %s'
                      % volume['provider_location'])
            vdisk = VDisk(disk_meta['diskguid'])
            vdisk.cinder_id = volume.id
            vdisk.name = devicename
            vdisk.save()
        except Exception as ex:
            LOG.error('CLONE FROM SNAP: Internal error %s ' % str(ex))
            self.delete_volume(volume)
            self.delete_snapshot(snapshot)
            raise

        return {'provider_location': volume['provider_location'],
                'display_name': volume['display_name']}
 def _check_volumedriver_remove(vpool_name, vdisk_name, present=True):
     """
     Remove a vdisk from a vpool
     :param vdisk_name: name of a vdisk (e.g. test.raw)
     :type vdisk_name: str
     :param vpool_name: name of a vpool
     :type vpool_name: str
     :param present: should the disk be present?
     :type present: bool
     :return: True if disk is not present anymore
     :rtype: bool
     """
     try:
         vdisk = VDiskHelper.get_vdisk_by_name(vdisk_name=vdisk_name, vpool_name=vpool_name)
         VDiskController.delete(vdisk.guid)
         return True
     except VDiskNotFoundError:
         # not found, if it should be present, re-raise the exception
         if present:
             raise
         else:
             return True
Esempio n. 52
0
 def test_extract_volumename(self):
     """
     Validates whether a correct volumename is yielded from a given devicename
     * Test several devicenames and validate the returned name
     """
     test = {
         '/foo/Bar/something.raw': 'something',
         '/Some.long.dotted.name.raw': 'Some.long.dotted.name',
         '': '',
         'f4qav@#$%sd.raw': 'f4qav@#$%sd'
     }
     for devicename, expected in test.iteritems():
         result = VDiskController.extract_volumename(devicename)
         self.assertEqual(result, expected)
Esempio n. 53
0
    def create_snapshot(self, snapshot):
        """Creates a snapshot.
        Called on "nova image-create " or "cinder snapshot-create "
        :param snapshot: snapshot reference (sqlalchemy Model)
        """
        _debug_vol_info('CREATE_SNAP', snapshot)
        volume = snapshot.volume
        _debug_vol_info('CREATE_SNAP_VOL', volume)

        hostname = volume.host
        location = volume.provider_location
        ovs_disk = self._find_ovs_model_disk_by_location(location, hostname)
        metadata = {'label': "{0} (OpenStack)".format(snapshot.display_name),
                    'is_consistent': False,
                    'timestamp': time.time(),
                    'machineguid': ovs_disk.vmachine_guid,
                    'is_automatic': False}

        LOG.debug('CREATE_SNAP %s %s' % (snapshot.display_name, str(metadata)))
        VDiskController.create_snapshot(diskguid = ovs_disk.guid,
                                        metadata = metadata,
                                        snapshotid = str(snapshot.id))
        LOG.debug('CREATE_SNAP OK')
Esempio n. 54
0
    def clone(machineguid, timestamp, name):
        """
        Clone a vmachine using the disk snapshot based on a snapshot timestamp

        @param machineguid: guid of the machine to clone
        @param timestamp: timestamp of the disk snapshots to use for the clone
        @param name: name for the new machine
        """
        machine = VMachine(machineguid)

        disks = {}
        for snapshot in machine.snapshots:
            if snapshot['timestamp'] == timestamp:
                for diskguid, snapshotguid in snapshot['snapshots'].iteritems():
                    disks[diskguid] = snapshotguid

        new_machine = VMachine()
        new_machine.copy(machine)
        new_machine.name = name
        new_machine.pmachine = machine.pmachine
        new_machine.save()

        new_disk_guids = []
        disks_by_order = sorted(machine.vdisks, key=lambda x: x.order)
        for currentDisk in disks_by_order:
            if machine.is_vtemplate and currentDisk.templatesnapshot:
                snapshotid = currentDisk.templatesnapshot
            else:
                snapshotid = disks[currentDisk.guid]
            prefix = '%s-clone' % currentDisk.name

            result = VDiskController.clone(diskguid=currentDisk.guid,
                                           snapshotid=snapshotid,
                                           devicename=prefix,
                                           pmachineguid=new_machine.pmachine_guid,
                                           machinename=new_machine.name,
                                           machineguid=new_machine.guid)
            new_disk_guids.append(result['diskguid'])

        hv = Factory.get(machine.pmachine)
        try:
            result = hv.clone_vm(machine.hypervisor_id, name, disks, None, True)
        except:
            VMachineController.delete(machineguid=new_machine.guid)
            raise

        new_machine.hypervisor_id = result
        new_machine.save()
        return new_machine.guid
 def _check_volumedriver(vdisk_name, storagedriver_guid, logger, vdisk_size=VDISK_CHECK_SIZE):
     """
     Checks if the volumedriver can create a new vdisk
     :param vdisk_name: name of a vdisk (e.g. test.raw)
     :type vdisk_name: str
     :param storagedriver_guid: guid of a storagedriver
     :type storagedriver_guid: str
     :param vdisk_size: size of the volume in bytes (e.g. 10737418240 is 10GB in bytes)
     :type vdisk_size: int
     :param logger: logger instance
     :type logger: ovs.extensions.healthcheck.result.HCResults
     :return: True if succeeds
     :rtype: bool
     """
     try:
         VDiskController.create_new(vdisk_name, vdisk_size, storagedriver_guid)
     except FileExistsException:
         # can be ignored until fixed in framework
         # https://github.com/openvstorage/framework/issues/1247
         return True
     except Exception as ex:
         logger.failure('Creation of the vdisk failed. Got {0}'.format(str(ex)))
         return False
     return True
Esempio n. 56
0
 def test_clean_devicename(self):
     """
     Validates whether a devicename is properly cleaned
     * Test several names and validate the returned devicename
     """
     test = {'Foo Bar': '/Foo_Bar.raw',
             '/Foo Bar .raw': '/Foo_Bar_.raw',
             'foo-bar.rawtest': '/foo-bar.rawtest.raw',
             'test///folder': '/test/folder.raw',
             'foobar-flat.vmdk': '/foobar-flat.vmdk.raw',
             '//test.raw': '/test.raw',
             'test/.raw': '/test/.raw.raw',
             '//d\'!@#%xfoo Bar/te_b --asdfS SA AS lolz///f.wrv.': '/dxfoo_Bar/te_b_--asdfS_SA_AS_lolz/f.wrv..raw'}
     for raw, expected in test.iteritems():
         result = VDiskController.clean_devicename(raw)
         self.assertEqual(result, expected)
Esempio n. 57
0
    def test_delete(self):
        """
        Test the delete of a vDisk
            - Create 2 vDisks with identical names on 2 different vPools
            - Delete 1st vDisk and verify other still remains on correct vPool
            - Delete 2nd vDisk and verify no more volumes left
        """
        structure = Helper.build_service_structure(
            {'vpools': [1, 2],
             'domains': [1],
             'storagerouters': [1],
             'storagedrivers': [(1, 1, 1), (2, 2, 1)],  # (<id>, <vpool_id>, <storagerouter_id>)
             'mds_services': [(1, 1), (2, 2)]}  # (<id>, <storagedriver_id>)
        )
        domains = structure['domains']
        storagedrivers = structure['storagedrivers']

        vdisk1 = VDisk(VDiskController.create_new(volume_name='vdisk_1', volume_size=1024 ** 3, storagedriver_guid=storagedrivers[1].guid))
        vdisk2 = VDisk(VDiskController.create_new(volume_name='vdisk_1', volume_size=1024 ** 3, storagedriver_guid=storagedrivers[2].guid))

        vdisk_domain = VDiskDomain()
        vdisk_domain.domain = domains[1]
        vdisk_domain.vdisk = vdisk1
        vdisk_domain.save()

        # Delete vDisk1 and make some assertions
        VDiskController.delete(vdisk_guid=vdisk1.guid)
        with self.assertRaises(ObjectNotFoundException):
            VDisk(vdisk1.guid)
        self.assertEqual(first=len(VDiskController.list_volumes()),
                         second=1,
                         msg='Expected to find only 1 volume in Storage Driver list_volumes')
        self.assertIn(member=vdisk2,
                      container=VDiskList.get_vdisks(),
                      msg='vDisk2 should still be modeled')

        # Delete vDisk2 and make some assertions
        VDiskController.delete(vdisk_guid=vdisk2.guid)
        with self.assertRaises(ObjectNotFoundException):
            VDisk(vdisk2.guid)
        self.assertEqual(first=len(VDiskController.list_volumes()),
                         second=0,
                         msg='Expected to find no more volumes in Storage Driver list_volumes')
Esempio n. 58
0
    def test_happypath(self):
        """
        Validates the happy path; Hourly snapshots are taken with a few manual consistents
        every now an then. The delelete policy is exectued every day
        """
        # Setup
        # There are 2 machines; one with two disks, one with one disk and an additional disk
        backend_type = BackendType()
        backend_type.name = 'BackendType'
        backend_type.code = 'BT'
        backend_type.save()
        vpool = VPool()
        vpool.name = 'vpool'
        vpool.backend_type = backend_type
        vpool.save()
        pmachine = PMachine()
        pmachine.name = 'PMachine'
        pmachine.username = '******'
        pmachine.ip = '127.0.0.1'
        pmachine.hvtype = 'VMWARE'
        pmachine.save()
        vmachine_1 = VMachine()
        vmachine_1.name = 'vmachine_1'
        vmachine_1.devicename = 'dummy'
        vmachine_1.pmachine = pmachine
        vmachine_1.save()
        vdisk_1_1 = VDisk()
        vdisk_1_1.name = 'vdisk_1_1'
        vdisk_1_1.volume_id = 'vdisk_1_1'
        vdisk_1_1.vmachine = vmachine_1
        vdisk_1_1.vpool = vpool
        vdisk_1_1.devicename = 'dummy'
        vdisk_1_1.size = 0
        vdisk_1_1.save()
        vdisk_1_1.reload_client()
        vdisk_1_2 = VDisk()
        vdisk_1_2.name = 'vdisk_1_2'
        vdisk_1_2.volume_id = 'vdisk_1_2'
        vdisk_1_2.vmachine = vmachine_1
        vdisk_1_2.vpool = vpool
        vdisk_1_2.devicename = 'dummy'
        vdisk_1_2.size = 0
        vdisk_1_2.save()
        vdisk_1_2.reload_client()
        vmachine_2 = VMachine()
        vmachine_2.name = 'vmachine_2'
        vmachine_2.devicename = 'dummy'
        vmachine_2.pmachine = pmachine
        vmachine_2.save()
        vdisk_2_1 = VDisk()
        vdisk_2_1.name = 'vdisk_2_1'
        vdisk_2_1.volume_id = 'vdisk_2_1'
        vdisk_2_1.vmachine = vmachine_2
        vdisk_2_1.vpool = vpool
        vdisk_2_1.devicename = 'dummy'
        vdisk_2_1.size = 0
        vdisk_2_1.save()
        vdisk_2_1.reload_client()
        vdisk_3 = VDisk()
        vdisk_3.name = 'vdisk_3'
        vdisk_3.volume_id = 'vdisk_3'
        vdisk_3.vpool = vpool
        vdisk_3.devicename = 'dummy'
        vdisk_3.size = 0
        vdisk_3.save()
        vdisk_3.reload_client()

        for disk in [vdisk_1_1, vdisk_1_2, vdisk_2_1, vdisk_3]:
            [dynamic for dynamic in disk._dynamics if dynamic.name == 'snapshots'][0].timeout = 0

        # Run the testing scenario
        debug = True
        amount_of_days = 50
        base = datetime.now().date()
        day = timedelta(1)
        minute = 60
        hour = minute * 60

        for d in xrange(0, amount_of_days):
            base_timestamp = DeleteSnapshots._make_timestamp(base, day * d)
            print ''
            print 'Day cycle: {}: {}'.format(
                d, datetime.fromtimestamp(base_timestamp).strftime('%Y-%m-%d')
            )

            # At the start of the day, delete snapshot policy runs at 00:30
            print '- Deleting snapshots'
            ScheduledTaskController.deletescrubsnapshots(timestamp=base_timestamp + (minute * 30))

            # Validate snapshots
            print '- Validating snapshots'
            for vdisk in [vdisk_1_1, vdisk_1_2, vdisk_2_1, vdisk_3]:
                self._validate(vdisk, d, base, amount_of_days, debug)

            # During the day, snapshots are taken
            # - Create non consistent snapshot every hour, between 2:00 and 22:00
            # - Create consistent snapshot at 6:30, 12:30, 18:30
            print '- Creating snapshots'
            for h in xrange(2, 23):
                timestamp = base_timestamp + (hour * h)
                for vm in [vmachine_1, vmachine_2]:
                    VMachineController.snapshot(machineguid=vm.guid,
                                                label='ss_i_{0}:00'.format(str(h)),
                                                is_consistent=False,
                                                timestamp=timestamp)
                    if h in [6, 12, 18]:
                        ts = (timestamp + (minute * 30))
                        VMachineController.snapshot(machineguid=vm.guid,
                                                    label='ss_c_{0}:30'.format(str(h)),
                                                    is_consistent=True,
                                                    timestamp=ts)

                VDiskController.create_snapshot(diskguid=vdisk_3.guid,
                                                metadata={'label': 'ss_i_{0}:00'.format(str(h)),
                                                          'is_consistent': False,
                                                          'timestamp': str(timestamp),
                                                          'machineguid': None})
                if h in [6, 12, 18]:
                    ts = (timestamp + (minute * 30))
                    VDiskController.create_snapshot(diskguid=vdisk_3.guid,
                                                    metadata={'label': 'ss_c_{0}:30'.format(str(h)),
                                                              'is_consistent': True,
                                                              'timestamp': str(ts),
                                                              'machineguid': None})
Esempio n. 59
0
    def create_cloned_volume(self, volume, src_vref):
        """Create a cloned volume from another volume.
        Called on "cinder create --source-volid ... "

        :param volume: volume reference - target volume (sqlalchemy Model)
        :param src_vref: volume reference - source volume (sqlalchemy Model)

        OVS: Create clone from template if the source is a template
             Create volume from snapshot if the source is a volume
             - create snapshot of source volume if it doesn't have snapshots
        """
        _debug_vol_info('CREATE_CLONED_VOL', volume)
        _debug_vol_info('CREATE_CLONED_VOL Source', src_vref)

        mountpoint = self._get_hostname_mountpoint(str(volume.host))
        name = volume.display_name
        if not name:
            name = volume.name
            volume.display_name = volume.name

        pmachineguid = self._find_ovs_model_pmachine_guid_by_hostname(
            str(volume.host))

        #source
        source_ovs_disk = self._find_ovs_model_disk_by_location(
            str(src_vref.provider_location), src_vref.host)
        if source_ovs_disk.info['object_type'] == 'TEMPLATE':
            LOG.info('[CREATE_FROM_TEMPLATE] VDisk %s is a template'
                     % source_ovs_disk.devicename)

            # cloning from a template
            LOG.debug('[CREATE FROM TEMPLATE] ovs_disk %s '
                      % (source_ovs_disk.devicename))

            disk_meta = VDiskController.create_from_template(
                diskguid = source_ovs_disk.guid,
                machinename = "",
                devicename = str(name),
                pmachineguid = pmachineguid,
                machineguid = None,
                storagedriver_guid = None)
            volume['provider_location'] = '{}{}'.format(
                mountpoint, disk_meta['backingdevice'])
            LOG.debug('[CREATE FROM TEMPLATE] New volume %s'
                      % volume['provider_location'])
            vdisk = VDisk(disk_meta['diskguid'])
            vdisk.cinder_id = volume.id
            vdisk.name = name
            LOG.debug('[CREATE FROM TEMPLATE] Updating meta %s %s'
                      % (volume.id, name))
            vdisk.save()
        else:
            LOG.info('[THIN CLONE] VDisk %s is not a template'
                     % source_ovs_disk.devicename)
            # We do not support yet full volume clone
            # - requires "emancipate" functionality
            # So for now we'll take a snapshot
            # (or the latest snapshot existing) and clone from that snapshot
            available_snapshots = [snapshot for snapshot in source_ovs_disk.snapshots
                                   if 'in_backend' not in snapshot or snapshot['in_backend'] is True]
            if len(available_snapshots) == 0:
                metadata = {'label': "Cinder clone snapshot {0}".format(name),
                            'is_consistent': False,
                            'timestamp': time.time(),
                            'machineguid': source_ovs_disk.vmachine_guid,
                            'is_automatic': False}

                LOG.debug('CREATE_SNAP %s %s' % (name, str(metadata)))
                snapshotid = VDiskController.create_snapshot(
                    diskguid = source_ovs_disk.guid,
                    metadata = metadata,
                    snapshotid = None)
                LOG.debug('CREATE_SNAP OK')

                OVSVolumeDriver._wait_for_snapshot(source_ovs_disk, snapshotid)
            else:
                snapshotid = available_snapshots[-1]['guid']
            LOG.debug('[CREATE CLONE FROM SNAP] %s ' % snapshotid)

            disk_meta = VDiskController.clone(diskguid = source_ovs_disk.guid,
                                              snapshotid = snapshotid,
                                              devicename = str(name),
                                              pmachineguid = pmachineguid,
                                              machinename = "",
                                              machineguid=None)
            volume['provider_location'] = '{}{}'.format(
                mountpoint, disk_meta['backingdevice'])

            LOG.debug('[CLONE FROM SNAP] Meta: %s' % str(disk_meta))
            LOG.debug('[CLONE FROM SNAP] New volume %s'
                      % volume['provider_location'])
            vdisk = VDisk(disk_meta['diskguid'])
            vdisk.cinder_id = volume.id
            vdisk.name = name
            vdisk.save()
        return {'provider_location': volume['provider_location'],
                'display_name': volume['display_name']}