예제 #1
0
파일: cinder.py 프로젝트: neujie/fuxi
    def create(self, docker_volume_name, volume_opts):
        if not volume_opts:
            volume_opts = {}

        connector = self._get_connector()
        cinder_volume, state = self._get_docker_volume(docker_volume_name)
        LOG.info(
            _LI("Get docker volume {0} {1} with state "
                "{2}").format(docker_volume_name, cinder_volume, state))

        device_info = {}
        if state == ATTACH_TO_THIS:
            LOG.warn(
                _LW("The volume {0} {1} already exists and attached to "
                    "this server").format(docker_volume_name, cinder_volume))
            device_info = {'path': connector.get_device_path(cinder_volume)}
        elif state == NOT_ATTACH:
            LOG.warn(
                _LW("The volume {0} {1} is already exists but not "
                    "attached").format(docker_volume_name, cinder_volume))
            device_info = connector.connect_volume(cinder_volume)
        elif state == ATTACH_TO_OTHER:
            if cinder_volume.multiattach:
                fstype = volume_opts.get('fstype', cinder_conf.fstype)
                vol_fstype = cinder_volume.metadata.get(
                    'fstype', cinder_conf.fstype)
                if fstype != vol_fstype:
                    msg = _LE("Volume already exists with fstype: {0}, but "
                              "currently provided fstype is {1}, not "
                              "match").format(vol_fstype, fstype)
                    LOG.error(msg)
                    raise exceptions.FuxiException('FSType Not Match')
                device_info = connector.connect_volume(cinder_volume)
            else:
                msg = _LE("The volume {0} {1} is already attached to another "
                          "server").format(docker_volume_name, cinder_volume)
                LOG.error(msg)
                raise exceptions.FuxiException(msg)
        elif state == UNKNOWN:
            if 'volume_id' in volume_opts:
                cinder_volume = self._create_from_existing_volume(
                    docker_volume_name, volume_opts.pop('volume_id'),
                    volume_opts)
                if self._check_attached_to_this(cinder_volume):
                    device_info = {
                        'path': connector.get_device_path(cinder_volume)
                    }
                else:
                    device_info = connector.connect_volume(cinder_volume)
            else:
                cinder_volume = self._create_volume(docker_volume_name,
                                                    volume_opts)
                device_info = connector.connect_volume(cinder_volume)

        return device_info
예제 #2
0
파일: cinder.py 프로젝트: drngsl/fuxi
    def mount(self, docker_volume_name):
        cinder_volume, state = self._get_docker_volume(docker_volume_name)
        LOG.info(_LI("Get docker volume %(d_v)s %(vol)s with state %(st)s"), {
            'd_v': docker_volume_name,
            'vol': cinder_volume,
            'st': state
        })

        connector = self._get_connector()
        if state == NOT_ATTACH:
            connector.connect_volume(cinder_volume)
        elif state == ATTACH_TO_OTHER:
            if cinder_volume.multiattach:
                connector.connect_volume(cinder_volume)
            else:
                msg = _("Volume {0} {1} is not shareable").format(
                    docker_volume_name, cinder_volume)
                raise exceptions.FuxiException(msg)
        elif state != ATTACH_TO_THIS:
            msg = _("Volume %(vol_name)s %(c_vol)s is not in correct state, "
                    "current state is %(state)s")
            LOG.error(
                msg, {
                    'vol_name': docker_volume_name,
                    'c_vol': cinder_volume,
                    'state': state
                })
            raise exceptions.NotMatchedState()

        link_path = connector.get_device_path(cinder_volume)
        if not os.path.exists(link_path):
            LOG.warning(
                _LW("Could not find device link file, "
                    "so rebuild it"))
            connector.disconnect_volume(cinder_volume)
            connector.connect_volume(cinder_volume)

        devpath = os.path.realpath(link_path)
        if not devpath or not os.path.exists(devpath):
            msg = _("Can't find volume device path")
            LOG.error(msg)
            raise exceptions.FuxiException(msg)

        mountpoint = self._get_mountpoint(docker_volume_name)
        self._create_mountpoint(mountpoint)

        fstype = cinder_volume.metadata.get('fstype', cinder_conf.fstype)

        mount.do_mount(devpath, mountpoint, fstype)

        return mountpoint
예제 #3
0
 def _get_connector(self):
     connector = cinder_conf.volume_connector
     if not connector or connector not in volume_connector_conf:
         msg = _LE("Must provide an valid volume connector")
         LOG.error(msg)
         raise exceptions.FuxiException(msg)
     return importutils.import_class(volume_connector_conf[connector])()
예제 #4
0
파일: blockdevice.py 프로젝트: neujie/fuxi
 def get_device_size(self, device):
     try:
         nr_sectors = open(device + '/size').read().rstrip('\n')
         sect_size = open(device + '/queue/hw_sector_size')\
             .read().rstrip('\n')
         return (float(nr_sectors) * float(sect_size)) / units.Gi
     except IOError as e:
         LOG.error(_LE("Failed to read device size. {0}").format(e))
         raise exceptions.FuxiException(e.message)
예제 #5
0
def get_instance_uuid():
    try:
        inst_uuid = ''
        inst_uuid_count = 0
        dirs = os.listdir(cloud_init_conf)
        for uuid_dir in dirs:
            if uuidutils.is_uuid_like(uuid_dir):
                inst_uuid = uuid_dir
                inst_uuid_count += 1

        # If not or not only get on instance_uuid, then search
        # it from metadata server.
        if inst_uuid_count == 1:
            return inst_uuid
    except Exception:
        LOG.warning("Get instance_uuid from cloud-init failed")

    try:
        resp = requests.get('http://169.254.169.254/openstack',
                            timeout=constants.CURL_MD_TIMEOUT)
        metadata_api_versions = resp.text.split()
        metadata_api_versions.sort(reverse=True)
    except Exception as e:
        LOG.error("Get metadata apis failed. Error: %s", e)
        raise exceptions.FuxiException("Metadata API Not Found")

    for api_version in metadata_api_versions:
        metadata_url = ''.join(['http://169.254.169.254/openstack/',
                                api_version,
                                '/meta_data.json'])
        try:
            resp = requests.get(metadata_url,
                                timeout=constants.CURL_MD_TIMEOUT)
            metadata = resp.json()
            if metadata.get('uuid', None):
                return metadata['uuid']
        except Exception as e:
            LOG.warning("Get instance_uuid from metadata server"
                        " %(md_url)s failed. Error: %(err)s",
                        {'md_url': metadata_url, 'err': e})
            continue

    raise exceptions.FuxiException("Instance UUID Not Found")
예제 #6
0
파일: provider.py 프로젝트: neujie/fuxi
    def _get_mountpoint(self, docker_volume_name):
        """Generate a mount point for volume.

        :param docker_volume_name:
        :rtype: str
        """
        if not docker_volume_name:
            LOG.error(_LE("Volume name could not be None"))
            raise exceptions.FuxiException("Volume name could not be None")
        if self.volume_provider_type:
            return os.path.join(CONF.volume_dir,
                                self.volume_provider_type,
                                docker_volume_name)
        else:
            return os.path.join(CONF.volume_dir,
                                docker_volume_name)
예제 #7
0
    def delete(self, docker_volume_name):
        cinder_volume, state = self._get_docker_volume(docker_volume_name)
        LOG.info(_LI("Get docker volume {0} {1} with state "
                     "{2}").format(docker_volume_name, cinder_volume, state))

        if state == ATTACH_TO_THIS:
            link_path = self._get_connector().get_device_path(cinder_volume)
            if not link_path or not os.path.exists(link_path):
                msg = _LE(
                    "Could not find device link path for volume {0} {1} "
                    "in host").format(docker_volume_name, cinder_volume)
                LOG.error(msg)
                raise exceptions.FuxiException(msg)

            devpath = os.path.realpath(link_path)
            if not os.path.exists(devpath):
                msg = _LE("Could not find device path for volume {0} {1} in "
                          "host").format(docker_volume_name, cinder_volume)
                LOG.error(msg)
                raise exceptions.FuxiException(msg)

            mounter = mount.Mounter()
            mps = mounter.get_mps_by_device(devpath)
            ref_count = len(mps)
            if ref_count > 0:
                mountpoint = self._get_mountpoint(docker_volume_name)
                if mountpoint in mps:
                    mounter.unmount(mountpoint)

                    self._clear_mountpoint(mountpoint)

                    # If this volume is still mounted on other mount point,
                    # then return.
                    if ref_count > 1:
                        return True
                else:
                    return True

            # Detach device from this server.
            self._get_connector().disconnect_volume(cinder_volume)

            available_volume = self.opensdsclient.get(cinder_volume.id)
            # If this volume is not used by other server any more,
            # than delete it from Cinder.
	    available_volume = APIDictWrapper(available_volume)
            if not available_volume.attachments:
                msg = _LW("No other servers still use this volume {0} "
                          "{1} any more, so delete it from OpenSDS"
                          "").format(docker_volume_name, cinder_volume)
                LOG.warning(msg)
                self._delete_volume(available_volume)
            return True
        elif state == NOT_ATTACH:
            self._delete_volume(cinder_volume)
            return True
        elif state == ATTACH_TO_OTHER:
            msg = _LW("Volume %s is still in use, could not delete it")
            LOG.warning(msg, cinder_volume)
            return True
        elif state == UNKNOWN:
            return False
        else:
            msg = _LE("Volume %(vol_name)s %(c_vol)s "
                      "state %(state)s is invalid")
            LOG.error(msg, {'vol_name': docker_volume_name,
                            'c_vol': cinder_volume,
                            'state': state})
            raise exceptions.NotMatchedState()
예제 #8
0
    def connect_volume(self, volume, **connect_opts):
        bdm = blockdevice.BlockerDeviceManager()
        ori_devices = bdm.device_scan()

        # Do volume-attach
        try:
            server_id = connect_opts.get('server_id', None)
            if not server_id:
                server_id = utils.get_instance_uuid()

            LOG.info("Start to connect to volume %s", volume)
            nova_volume = self.novaclient.volumes.create_server_volume(
                server_id=server_id, volume_id=volume.id, device=None)

            volume_monitor = state_monitor.StateMonitor(
                self.cinderclient, nova_volume, 'in-use', (
                    'available',
                    'attaching',
                ))
            attached_volume = volume_monitor.monitor_cinder_volume()
        except nova_exception.ClientException as ex:
            LOG.error(
                "Attaching volume %(vol)s to server %(s)s "
                "failed. Error: %(err)s", {
                    'vol': volume.id,
                    's': server_id,
                    'err': ex
                })
            raise

        # Get all devices on host after do volume-attach,
        # and then find attached device.
        LOG.info("After connected to volume, scan the added "
                 "block device on host")
        curr_devices = bdm.device_scan()
        start_time = time.time()
        delta_devices = list(set(curr_devices) - set(ori_devices))
        while not delta_devices:
            time.sleep(consts.DEVICE_SCAN_TIME_DELAY)
            curr_devices = bdm.device_scan()
            delta_devices = list(set(curr_devices) - set(ori_devices))
            if time.time() - start_time > consts.DEVICE_SCAN_TIMEOUT:
                msg = _("Could not detect added device with " "limited time")
                raise exceptions.FuxiException(msg)
        LOG.info("Get extra added block device %s", delta_devices)

        for device in delta_devices:
            if bdm.get_device_size(device) == volume.size:
                device = device.replace('/sys/block', '/dev')
                LOG.info(
                    "Find attached device %(dev)s"
                    " for volume %(at)s %(vol)s", {
                        'dev': device,
                        'at': attached_volume.name,
                        'vol': volume
                    })

                link_path = os.path.join(consts.VOLUME_LINK_DIR, volume.id)
                try:
                    utils.execute('ln',
                                  '-s',
                                  device,
                                  link_path,
                                  run_as_root=True)
                except processutils.ProcessExecutionError as e:
                    LOG.error(
                        "Error happened when create link file for"
                        " block device attached by Nova."
                        " Error: %s", e)
                    raise
                return {'path': link_path}

        LOG.warning("Could not find matched device")
        raise exceptions.NotFound("Not Found Matched Device")
예제 #9
0
    def create(self, docker_volume_name, volume_opts):
        if not volume_opts:
            volume_opts = {}

        connector = self._get_connector()
        cinder_volume, state = self._get_docker_volume(docker_volume_name)
        LOG.info("Get docker volume %(d_v)s %(vol)s with state %(st)s", {
            'd_v': docker_volume_name,
            'vol': cinder_volume,
            'st': state
        })

        device_info = {}
        if state == ATTACH_TO_THIS:
            LOG.warning(
                "The volume %(d_v)s %(vol)s already exists "
                "and attached to this server", {
                    'd_v': docker_volume_name,
                    'vol': cinder_volume
                })
            device_info = {'path': connector.get_device_path(cinder_volume)}
        elif state == NOT_ATTACH:
            LOG.warning(
                "The volume %(d_v)s %(vol)s is already exists "
                "but not attached", {
                    'd_v': docker_volume_name,
                    'vol': cinder_volume
                })
            device_info = connector.connect_volume(cinder_volume)
        elif state == ATTACH_TO_OTHER:
            if cinder_volume.multiattach:
                fstype = volume_opts.get('fstype', cinder_conf.fstype)
                vol_fstype = cinder_volume.metadata.get(
                    'fstype', cinder_conf.fstype)
                if fstype != vol_fstype:
                    LOG.error(
                        ("Volume already exists with fstype: %{v_fs}s, but "
                         "currently provided fstype is %{fs}s, not "
                         "match"), {
                             'v_fs': vol_fstype,
                             'fs': fstype
                         })
                    raise exceptions.FuxiException('FSType Not Match')
                device_info = connector.connect_volume(cinder_volume)
            else:
                msg = _("The volume {0} {1} is already attached to another "
                        "server").format(docker_volume_name, cinder_volume)
                LOG.error(msg)
                raise exceptions.FuxiException(msg)
        elif state == UNKNOWN:
            if 'volume_id' in volume_opts:
                cinder_volume = self._create_from_existing_volume(
                    docker_volume_name, volume_opts.pop('volume_id'),
                    volume_opts)
                if self._check_attached_to_this(cinder_volume):
                    device_info = {
                        'path': connector.get_device_path(cinder_volume)
                    }
                else:
                    device_info = connector.connect_volume(cinder_volume)
            else:
                cinder_volume = self._create_volume(docker_volume_name,
                                                    volume_opts)
                device_info = connector.connect_volume(cinder_volume)

        return device_info