Example #1
0
    def _wait_for_volume_path(self, path):
        if not os.path.isdir(path):
            msg = (
                _("ScaleIO volume %(volume_id)s not found at "
                  "expected path.") % {'volume_id': self.volume_id}
                )

            LOG.debug(msg)
            raise exception.BrickException(message=msg)

        disk_filename = None
        filenames = os.listdir(path)
        LOG.info(_LI(
            "Files found in %(path)s path: %(files)s "),
            {'path': path, 'files': filenames}
        )

        for filename in filenames:
            if (filename.startswith("emc-vol") and
                    filename.endswith(self.volume_id)):
                disk_filename = filename
                break

        if not disk_filename:
            msg = (_("ScaleIO volume %(volume_id)s not found.") %
                   {'volume_id': self.volume_id})
            LOG.debug(msg)
            raise exception.BrickException(message=msg)

        return disk_filename
Example #2
0
 def _find_vgc_host(self):
     """Finds vgc-cluster hostname for this box."""
     params = [self.VGCCLUSTER, "domain-list", "-1"]
     try:
         out, unused = self._execute(*params, run_as_root=True,
                                     root_helper=self._root_helper)
     except putils.ProcessExecutionError as err:
         self._log_cli_err(err)
         msg = _("Unable to get list of domain members, check that "
                 "the cluster is running.")
         raise exception.BrickException(message=msg)
     domain = out.splitlines()
     params = ["ip", "addr", "list"]
     try:
         out, unused = self._execute(*params, run_as_root=False)
     except putils.ProcessExecutionError as err:
         self._log_cli_err(err)
         msg = _("Unable to get list of IP addresses on this host, "
                 "check permissions and networking.")
         raise exception.BrickException(message=msg)
     nets = out.splitlines()
     for host in domain:
         try:
             ip = socket.gethostbyname(host)
             for l in nets:
                 x = l.strip()
                 if x.startswith("inet %s/" % ip):
                     return host
         except socket.error:
             pass
     msg = _("Current host isn't part of HGST domain.")
     raise exception.BrickException(message=msg)
Example #3
0
    def disconnect_volume(self, connection_properties, device_info,
                          force=False, ignore_errors=False):
        """Detach and flush the volume.

        :param connection_properties: The dictionary that describes all
               of the target volume attributes.
               For HGST must include:
               name - Name of space to detach
               noremovehost - Host which should never be removed
        :type connection_properties: dict
        :param device_info: historical difference, but same as connection_props
        :type device_info: dict
        """
        if connection_properties is None:
            msg = _("Connection properties passed in as None.")
            raise exception.BrickException(message=msg)
        if 'name' not in connection_properties:
            msg = _("Connection properties missing 'name' field.")
            raise exception.BrickException(message=msg)
        if 'noremovehost' not in connection_properties:
            msg = _("Connection properties missing 'noremovehost' field.")
            raise exception.BrickException(message=msg)
        if connection_properties['noremovehost'] != self._hostname():
            params = [self.VGCCLUSTER, 'space-set-apphosts']
            params += ['-n', connection_properties['name']]
            params += ['-A', self._hostname()]
            params += ['--action', 'DELETE']
            try:
                self._execute(*params, run_as_root=True,
                              root_helper=self._root_helper)
            except putils.ProcessExecutionError as err:
                self._log_cli_err(err)
                msg = (_("Unable to set apphost for space %s") %
                       connection_properties['name'])
                raise exception.BrickException(message=msg)
Example #4
0
    def disconnect_volume(self, connection_properties, device_info,
                          force=False, ignore_errors=False):
        """Disconnect a volume from an instance."""
        volume_name = None

        if 'name' in connection_properties.keys():
            volume_name = connection_properties['name']

        if volume_name is None:
            msg = _("Failed to disconnect volume: invalid volume name")
            raise exception.BrickException(message=msg)

        cmd_arg = {'operation': 'disconnect_volume'}
        cmd_arg['volume_guid'] = volume_name
        cmdarg_json = json.dumps(cmd_arg)

        LOG.debug("HyperScale command hscli: %(cmd_arg)s",
                  {'cmd_arg': cmdarg_json})
        try:
            (out, err) = self._execute('hscli', cmdarg_json,
                                       run_as_root=True,
                                       root_helper=self._root_helper)

        except putils.ProcessExecutionError as e:
            msg = (_("Error executing hscli: %(err)s") % {'err': e.stderr})
            raise exception.BrickException(message=msg)

        if err:
            msg = (_("Failed to connect volume: stdout=%(out)s "
                     "stderr=%(err)s") % {'out': out, 'err': err})
            raise exception.BrickException(message=msg)
    def __init__(self, mount_type, root_helper,
                 execute=putils.execute, *args, **kwargs):

        self._mount_type = mount_type
        if mount_type == "nfs":
            self._mount_base = kwargs.get('nfs_mount_point_base', None)
            if not self._mount_base:
                raise exception.InvalidParameterValue(
                    err=_('nfs_mount_point_base required'))
            self._mount_options = kwargs.get('nfs_mount_options', None)
            self._check_nfs_options()
        elif mount_type == "cifs":
            self._mount_base = kwargs.get('smbfs_mount_point_base', None)
            if not self._mount_base:
                raise exception.InvalidParameterValue(
                    err=_('smbfs_mount_point_base required'))
            self._mount_options = kwargs.get('smbfs_mount_options', None)
        elif mount_type == "glusterfs":
            self._mount_base = kwargs.get('glusterfs_mount_point_base', None)
            if not self._mount_base:
                raise exception.InvalidParameterValue(
                    err=_('glusterfs_mount_point_base required'))
            self._mount_options = None
        else:
            raise exception.ProtocolNotSupported(protocol=mount_type)
        self.root_helper = root_helper
        self.set_execute(execute)
Example #6
0
    def connect_volume(self, connection_properties):
        """Attach a Space volume to running host.

        :param connection_properties: The dictionary that describes all
                                      of the target volume attributes.
            connection_properties for HGST must include:
            name - Name of space to attach
        :type connection_properties: dict
        :returns: dict
        """
        if connection_properties is None:
            msg = _("Connection properties passed in as None.")
            raise exception.BrickException(message=msg)
        if 'name' not in connection_properties:
            msg = _("Connection properties missing 'name' field.")
            raise exception.BrickException(message=msg)
        device_info = {
            'type': 'block',
            'device': connection_properties['name'],
            'path': '/dev/' + connection_properties['name']
        }
        volname = device_info['device']
        params = [self.VGCCLUSTER, 'space-set-apphosts']
        params += ['-n', volname]
        params += ['-A', self._hostname()]
        params += ['--action', 'ADD']
        try:
            self._execute(*params, run_as_root=True,
                          root_helper=self._root_helper)
        except putils.ProcessExecutionError as err:
            self._log_cli_err(err)
            msg = (_("Unable to set apphost for space %s") % volname)
            raise exception.BrickException(message=msg)

        return device_info
Example #7
0
    def disconnect_volume(self, connection_properties, device_info,
                          force=False, ignore_errors=False):
        tmp_file_path = device_info['path']
        if not os.path.exists(tmp_file_path):
            msg = _("Vmdk: %s not found.") % tmp_file_path
            raise exception.NotFound(message=msg)

        session = None
        try:
            # We upload the temporary file to vCenter server only if it is
            # modified after connect_volume.
            if os.path.getmtime(tmp_file_path) > device_info['last_modified']:
                self._load_config(connection_properties)
                session = self._create_session()
                backing = vim_util.get_moref(connection_properties['volume'],
                                             "VirtualMachine")
                # Currently there is no way we can restore the volume if it
                # contains redo-log based snapshots (bug 1599026).
                if self._snapshot_exists(session, backing):
                    msg = (_("Backing of volume: %s contains one or more "
                             "snapshots; cannot disconnect.") %
                           connection_properties['volume_id'])
                    raise exception.BrickException(message=msg)

                ds_ref = vim_util.get_moref(
                    connection_properties['datastore'], "Datastore")
                dc_ref = vim_util.get_moref(
                    connection_properties['datacenter'], "Datacenter")
                vmdk_path = connection_properties['vmdk_path']
                self._disconnect(
                    tmp_file_path, session, ds_ref, dc_ref, vmdk_path)
        finally:
            os.remove(tmp_file_path)
            if session:
                session.logout()
Example #8
0
    def connect_volume(self, connection_properties):
        """Connect to a volume.

        :param connection_properties: The dictionary that describes all
                                      of the target volume attributes.
        :type connection_properties: dict
        :returns: dict
        """
        LOG.debug("Connect_volume connection properties: %s.",
                  connection_properties)
        out = self._attach_volume(connection_properties['volume_id'])
        if not out or int(out['ret_code']) not in (self.attached_success_code,
                                                   self.has_been_attached_code,
                                                   self.attach_mnid_done_code):
            msg = (_("Attach volume failed, "
                   "error code is %s") % out['ret_code'])
            raise exception.BrickException(message=msg)

        try:
            volume_path = self._get_volume_path(connection_properties)
        except Exception:
            msg = _("query attached volume failed or volume not attached.")
            LOG.error(msg)
            raise exception.BrickException(message=msg)

        device_info = {'type': 'block',
                       'path': volume_path}
        return device_info
Example #9
0
    def __init__(self, user, pool, *args, **kwargs):

        self.rbd_user = user
        self.rbd_pool = pool

        for attr in ['rbd_user', 'rbd_pool']:
            val = getattr(self, attr)
            if val is not None:
                setattr(self, attr, utils.convert_str(val))

        # allow these to be overridden for testing
        self.rados = kwargs.get('rados', rados)
        self.rbd = kwargs.get('rbd', rbd)

        if self.rados is None:
            raise exception.InvalidParameterValue(
                err=_('rados module required'))
        if self.rbd is None:
            raise exception.InvalidParameterValue(
                err=_('rbd module required'))

        self.rbd_conf = kwargs.get('conffile', '/etc/ceph/ceph.conf')
        self.rbd_cluster_name = kwargs.get('rbd_cluster_name', 'ceph')
        self.rados_connect_timeout = kwargs.get('rados_connect_timeout', -1)

        self.client, self.ioctx = self.connect()
Example #10
0
    def _get_volume_id(self):
        volname_encoded = urllib.parse.quote(self.volume_name, '')
        volname_double_encoded = urllib.parse.quote(volname_encoded, '')
        LOG.debug(_(
            "Volume name after double encoding is %(volume_name)s."),
            {'volume_name': volname_double_encoded}
        )

        request = (
            "https://%(server_ip)s:%(server_port)s/api/types/Volume/instances"
            "/getByName::%(encoded_volume_name)s" %
            {
                'server_ip': self.server_ip,
                'server_port': self.server_port,
                'encoded_volume_name': volname_double_encoded
            }
        )

        LOG.info(
            _LI("ScaleIO get volume id by name request: %(request)s"),
            {'request': request}
        )

        r = requests.get(request,
                         auth=(self.server_username, self.server_token),
                         verify=False)

        r = self._check_response(r, request)

        volume_id = r.json()
        if not volume_id:
            msg = (_("Volume with name %(volume_name)s wasn't found.") %
                   {'volume_name': self.volume_name})

            LOG.error(msg)
            raise exception.BrickException(message=msg)

        if r.status_code != self.OK_STATUS_CODE and "errorCode" in volume_id:
            msg = (
                _("Error getting volume id from name %(volume_name)s: "
                  "%(err)s") %
                {'volume_name': self.volume_name, 'err': volume_id['message']}
            )

            LOG.error(msg)
            raise exception.BrickException(message=msg)

        LOG.info(_LI("ScaleIO volume id is %(volume_id)s."),
                 {'volume_id': volume_id})
        return volume_id
Example #11
0
    def _mount_vzstorage(self, vz_share, mount_path, flags=None):
        m = re.search("(?:(\S+):\/)?([a-zA-Z0-9_-]+)(?::(\S+))?", vz_share)
        if not m:
            msg = (_("Invalid Virtuozzo Storage share specification: %r."
                     "Must be: [MDS1[,MDS2],...:/]<CLUSTER NAME>[:PASSWORD].")
                   % vz_share)
            raise exception.BrickException(msg)

        mdss = m.group(1)
        cluster_name = m.group(2)
        passwd = m.group(3)

        if mdss:
            mdss = mdss.split(',')
            self._vzstorage_write_mds_list(cluster_name, mdss)

        if passwd:
            self._execute('pstorage', '-c', cluster_name, 'auth-node', '-P',
                          process_input=passwd,
                          root_helper=self.root_helper, run_as_root=True)

        mnt_cmd = ['pstorage-mount', '-c', cluster_name]
        if flags:
            mnt_cmd.extend(flags)
        mnt_cmd.extend([mount_path])

        self._execute(*mnt_cmd, root_helper=self.root_helper,
                      run_as_root=True, check_exit_code=0)
Example #12
0
def retry(exceptions, interval=1, retries=3, backoff_rate=2):

    def _retry_on_exception(e):
        return isinstance(e, exceptions)

    def _backoff_sleep(previous_attempt_number, delay_since_first_attempt_ms):
        exp = backoff_rate ** previous_attempt_number
        wait_for = max(0, interval * exp)
        LOG.debug("Sleeping for %s seconds", wait_for)
        return wait_for * 1000.0

    def _print_stop(previous_attempt_number, delay_since_first_attempt_ms):
        delay_since_first_attempt = delay_since_first_attempt_ms / 1000.0
        LOG.debug("Failed attempt %s", previous_attempt_number)
        LOG.debug("Have been at this for %s seconds",
                  delay_since_first_attempt)
        return previous_attempt_number == retries

    if retries < 1:
        raise ValueError(_('Retries must be greater than or '
                         'equal to 1 (received: %s). ') % retries)

    def _decorator(f):

        @six.wraps(f)
        def _wrapper(*args, **kwargs):
            r = retrying.Retrying(retry_on_exception=_retry_on_exception,
                                  wait_func=_backoff_sleep,
                                  stop_func=_print_stop)
            return r.call(f, *args, **kwargs)

        return _wrapper

    return _decorator
Example #13
0
File: rbd.py Project: e0ne/os-brick
    def connect_volume(self, connection_properties):
        """Connect to a volume.

        :param connection_properties: The dictionary that describes all
                                      of the target volume attributes.
        :type connection_properties: dict
        :returns: dict
        """
        do_local_attach = connection_properties.get('do_local_attach',
                                                    self.do_local_attach)

        if do_local_attach:
            # NOTE(e0ne): sanity check if ceph-common is installed.
            cmd = ['which', 'rbd']
            try:
                self._execute(*cmd)
            except putils.ProcessExecutionError:
                msg = _("ceph-common package is not installed.")
                LOG.error(msg)
                raise exception.BrickException(message=msg)

            # NOTE(e0ne): map volume to a block device
            # via the rbd kernel module.
            pool, volume = connection_properties['name'].split('/')
            cmd = ['rbd', 'map', volume, '--pool', pool]
            self._execute(*cmd, root_helper=self._root_helper,
                          run_as_root=True)

            return {'path': RBDConnector.get_rbd_device_name(pool, volume),
                    'type': 'block'}

        rbd_handle = self._get_rbd_handle(connection_properties)
        return {'path': rbd_handle}
Example #14
0
    def _get_rbd_handle(self, connection_properties):
        try:
            user = connection_properties['auth_username']
            pool, volume = connection_properties['name'].split('/')
            cluster_name = connection_properties.get('cluster_name')
            monitor_ips = connection_properties.get('hosts')
            monitor_ports = connection_properties.get('ports')
            keyring = connection_properties.get('keyring')
        except IndexError:
            msg = _("Connect volume failed, malformed connection properties")
            raise exception.BrickException(msg=msg)

        conf = self._create_ceph_conf(monitor_ips, monitor_ports,
                                      str(cluster_name), user,
                                      keyring)
        try:
            rbd_client = linuxrbd.RBDClient(user, pool, conffile=conf,
                                            rbd_cluster_name=str(cluster_name))
            rbd_volume = linuxrbd.RBDVolume(rbd_client, volume)
            rbd_handle = linuxrbd.RBDVolumeIOWrapper(
                linuxrbd.RBDImageMetadata(rbd_volume, pool, user, conf))
        except Exception:
            fileutils.delete_if_exists(conf)
            raise

        return rbd_handle
Example #15
0
    def fileno(self):
        """Sheepdog does not have support for fileno so we raise IOError.

        Raising IOError is recommended way to notify caller that interface is
        not supported - see http://docs.python.org/2/library/io.html#io.IOBase
        """
        raise IOError(_("fileno is not supported by SheepdogVolumeIOWrapper"))
Example #16
0
    def fileno(self):
        """RBD does not have support for fileno() so we raise IOError.

        Raising IOError is recommended way to notify caller that interface is
        not supported - see http://docs.python.org/2/library/io.html#io.IOBase
        """
        raise IOError(_("fileno() not supported by RBD()"))
Example #17
0
    def seek(self, offset, whence=0):
        if whence == 0:
            new_offset = offset
        elif whence == 1:
            new_offset = self._offset + offset
        elif whence == 2:
            new_offset = self._rbd_volume.image.size()
            new_offset += offset
        else:
            raise IOError(_("Invalid argument - whence=%s not supported") %
                          (whence))

        if (new_offset < 0):
            raise IOError(_("Invalid argument"))

        self._offset = new_offset
Example #18
0
    def __init__(self, mount_type, root_helper,
                 execute=putils.execute, *args, **kwargs):

        mount_type_to_option_prefix = {
            'nfs': 'nfs',
            'cifs': 'smbfs',
            'glusterfs': 'glusterfs',
            'vzstorage': 'vzstorage',
            'quobyte': 'quobyte'
        }

        if mount_type not in mount_type_to_option_prefix:
            raise exception.ProtocolNotSupported(protocol=mount_type)

        self._mount_type = mount_type
        option_prefix = mount_type_to_option_prefix[mount_type]

        self._mount_base = kwargs.get(option_prefix + '_mount_point_base')
        if not self._mount_base:
            raise exception.InvalidParameterValue(
                err=_('%s_mount_point_base required') % option_prefix)

        self._mount_options = kwargs.get(option_prefix + '_mount_options')

        if mount_type == "nfs":
            self._check_nfs_options()

        self.root_helper = root_helper
        self.set_execute(execute)
Example #19
0
 def _get_volume_path(self, connection_properties):
     out = self._query_attached_volume(
         connection_properties['volume_id'])
     if not out or int(out['ret_code']) != 0:
         msg = _("Couldn't find attached volume.")
         LOG.error(msg)
         raise exception.BrickException(message=msg)
     return out['dev_addr']
Example #20
0
    def get_local_share_path(self, share, expect_existing=True):
        local_share_path = self._smbutils.get_smb_share_path(share)
        if not local_share_path and expect_existing:
            err_msg = _("Could not find the local "
                        "share path for %(share)s.")
            raise exception.VolumePathsNotFound(err_msg % dict(share=share))

        return local_share_path
Example #21
0
 def _check_device_paths(self, device_paths):
     if len(device_paths) > 1:
         err_msg = _("Multiple volume paths were found: %s. This can "
                     "occur if multipath is used and MPIO is not "
                     "properly configured, thus not claiming the device "
                     "paths. This issue must be addressed urgently as "
                     "it can lead to data corruption.")
         raise exception.BrickException(err_msg % device_paths)
Example #22
0
 def get_volume_paths(self, connection_properties):
     volume_path = None
     try:
         volume_path = self._get_volume_path(connection_properties)
     except Exception:
         msg = _("Couldn't find a volume.")
         LOG.warning(msg)
         raise exception.BrickException(message=msg)
     return [volume_path]
Example #23
0
    def extend_volume(self, connection_properties):
        volume_paths = self.get_volume_paths(connection_properties)
        if not volume_paths:
            err_msg = _("Could not find the disk. Extend failed.")
            raise exception.NotFound(err_msg)

        device_path = volume_paths[0]
        device_number = self._diskutils.get_device_number_from_device_name(
            device_path)
        self._diskutils.refresh_disk(device_number)
Example #24
0
 def _check_or_get_keyring_contents(self, keyring, cluster_name, user):
     try:
         if keyring is None:
             keyring_path = ("/etc/ceph/%s.client.%s.keyring" %
                             (cluster_name, user))
             with open(keyring_path, 'r') as keyring_file:
                 keyring = keyring_file.read()
         return keyring
     except IOError:
         msg = (_("Keyring path %s is not readable.") % (keyring_path))
         raise exception.BrickException(msg=msg)
Example #25
0
 def __init__(self, mount_type, root_helper,
              execute=None, *args, **kwargs):
     self._mount_type = mount_type
     self._mount_base = kwargs.get(
         'scality_mount_point_base', "").rstrip('/')
     if not self._mount_base:
         raise exception.InvalidParameterValue(
             err=_('scality_mount_point_base required'))
     self.root_helper = root_helper
     self.set_execute(execute or putils.execute)
     self._mount_options = None
Example #26
0
 def __init__(self, mount_type, root_helper,
              execute=None, *args, **kwargs):
     super(ScalityRemoteFsClient, self).__init__(mount_type, root_helper,
                                                 execute=execute,
                                                 *args, **kwargs)
     self._mount_type = mount_type
     self._mount_base = kwargs.get(
         'scality_mount_point_base', "").rstrip('/')
     if not self._mount_base:
         raise exception.InvalidParameterValue(
             err=_('scality_mount_point_base required'))
     self._mount_options = None
Example #27
0
    def _create_mount_point(self, share):
        mnt_point = self.get_mount_point(share)

        if not os.path.isdir(self._mount_base):
            os.makedirs(self._mount_base)

        if os.path.exists(mnt_point):
            if not self._pathutils.is_symlink(mnt_point):
                raise exception.BrickException(_("Link path already exists "
                                                 "and it's not a symlink"))
        else:
            self._pathutils.create_sym_link(mnt_point, share)
Example #28
0
    def connect_volume(self, connection_properties):
        volume_connected = False
        for (initiator_name,
             target_portal,
             target_iqn,
             target_lun) in self._get_all_paths(connection_properties):
            try:
                LOG.info("Attempting to establish an iSCSI session to "
                         "target %(target_iqn)s on portal %(target_portal)s "
                         "accessing LUN %(target_lun)s using initiator "
                         "%(initiator_name)s.",
                         dict(target_portal=target_portal,
                              target_iqn=target_iqn,
                              target_lun=target_lun,
                              initiator_name=initiator_name))
                self._iscsi_utils.login_storage_target(
                    target_lun=target_lun,
                    target_iqn=target_iqn,
                    target_portal=target_portal,
                    auth_username=connection_properties.get('auth_username'),
                    auth_password=connection_properties.get('auth_password'),
                    mpio_enabled=self.use_multipath,
                    initiator_name=initiator_name,
                    ensure_lun_available=False)
                self._iscsi_utils.ensure_lun_available(
                    target_iqn=target_iqn,
                    target_lun=target_lun,
                    rescan_attempts=self.device_scan_attempts,
                    retry_interval=self.device_scan_interval)

                if not volume_connected:
                    (device_number,
                     device_path) = (
                        self._iscsi_utils.get_device_number_and_path(
                            target_iqn, target_lun))
                    volume_connected = True

                if not self.use_multipath:
                    break
            except os_win_exc.OSWinException:
                LOG.exception("Could not establish the iSCSI session.")

        if not volume_connected:
            raise exception.BrickException(
                _("Could not connect volume %s.") % connection_properties)

        scsi_wwn = self._get_scsi_wwn(device_number)

        device_info = {'type': 'block',
                       'path': device_path,
                       'number': device_number,
                       'scsi_wwn': scsi_wwn}
        return device_info
Example #29
0
    def _get_sheepdog_handle(self, connection_properties):
        try:
            host = connection_properties['hosts'][0]
            name = connection_properties['name']
            port = connection_properties['ports'][0]
        except IndexError:
            msg = _("Connect volume failed, malformed connection properties")
            raise exception.BrickException(msg=msg)

        sheepdog_handle = linuxsheepdog.SheepdogVolumeIOWrapper(
            host, port, name)
        return sheepdog_handle
Example #30
0
    def seek(self, offset, whence=0):
        if not self._valid:
            raise exception.VolumeDriverException(name=self._vdiname)

        if whence == 0:
            # SEEK_SET or 0 - start of the stream (the default);
            # offset should be zero or positive
            new_offset = offset
        elif whence == 1:
            # SEEK_CUR or 1 - current stream position; offset may be negative
            new_offset = self._offset + offset
        else:
            # SEEK_END or 2 - end of the stream; offset is usually negative
            # TODO(yamada-h): Support SEEK_END
            raise IOError(_("Invalid argument - whence=%s not supported.") %
                          whence)

        if new_offset < 0:
            raise IOError(_("Invalid argument - negative seek offset."))

        self._offset = new_offset
Example #31
0
    def _create_mount_point(self, share, use_local_path):
        # The mount point will contain a hash of the share so we're
        # intentionally preserving the original share path as this is
        # what the caller will expect.
        mnt_point = self.get_mount_point(share)
        share_norm_path = self._get_share_norm_path(share)
        symlink_dest = (share_norm_path if not use_local_path else
                        self.get_local_share_path(share))

        if not os.path.isdir(self._mount_base):
            os.makedirs(self._mount_base)

        if os.path.exists(mnt_point):
            if not self._pathutils.is_symlink(mnt_point):
                raise exception.BrickException(
                    _("Link path already exists "
                      "and it's not a symlink"))
        else:
            self._pathutils.create_sym_link(mnt_point, symlink_dest)
Example #32
0
    def __init__(self, *args, **kwargs):
        # Check if oslo.vmware library is available.
        if vim_util is None:
            message = _("Missing oslo_vmware python module, ensure oslo.vmware"
                        " library is installed and available.")
            raise exception.BrickException(message=message)

        super(VmdkConnector, self).__init__(*args, **kwargs)

        self._ip = None
        self._port = None
        self._username = None
        self._password = None
        self._api_retry_count = None
        self._task_poll_interval = None
        self._ca_file = None
        self._insecure = None
        self._tmp_dir = None
        self._timeout = None
Example #33
0
    def _create_ceph_conf(self, monitor_ips, monitor_ports, cluster_name, user,
                          keyring):
        monitors = [
            "%s:%s" % (ip, port) for ip, port in zip(
                self._sanitize_mon_hosts(monitor_ips), monitor_ports)
        ]
        mon_hosts = "mon_host = %s" % (','.join(monitors))

        keyring = self._check_or_get_keyring_contents(keyring, cluster_name,
                                                      user)

        try:
            fd, ceph_conf_path = tempfile.mkstemp(prefix="brickrbd_")
            with os.fdopen(fd, 'w') as conf_file:
                conf_file.writelines([mon_hosts, "\n", keyring, "\n"])
            return ceph_conf_path
        except IOError:
            msg = (_("Failed to write data to %s.") % (ceph_conf_path))
            raise exception.BrickException(msg=msg)
Example #34
0
    def connect_volume(self, connection_properties):
        """Connect to a volume.

        :param connection_properties: The dictionary that describes all
                                      of the target volume attributes.
        :type connection_properties: dict
        :returns: dict
        """
        do_local_attach = connection_properties.get('do_local_attach',
                                                    self.do_local_attach)

        if do_local_attach:
            # NOTE(e0ne): sanity check if ceph-common is installed.
            cmd = ['which', 'rbd']
            try:
                self._execute(*cmd)
            except putils.ProcessExecutionError:
                msg = _("ceph-common package is not installed.")
                LOG.error(msg)
                raise exception.BrickException(message=msg)

            # NOTE(e0ne): map volume to a block device
            # via the rbd kernel module.
            pool, volume = connection_properties['name'].split('/')
            rbd_dev_path = RBDConnector.get_rbd_device_name(pool, volume)
            if (not os.path.islink(rbd_dev_path) or
                    not os.path.exists(os.path.realpath(rbd_dev_path))):
                cmd = ['rbd', 'map', volume, '--pool', pool]
                cmd += self._get_rbd_args(connection_properties)
                self._execute(*cmd, root_helper=self._root_helper,
                              run_as_root=True)
            else:
                LOG.debug('volume %(vol)s is already mapped to local'
                          ' device %(dev)s',
                          {'vol': volume,
                           'dev': os.path.realpath(rbd_dev_path)})

            return {'path': rbd_dev_path,
                    'type': 'block'}

        rbd_handle = self._get_rbd_handle(connection_properties)
        return {'path': rbd_handle}
Example #35
0
    def _check_response(self,
                        response,
                        request,
                        is_get_request=True,
                        params=None):
        if response.status_code == 401 or response.status_code == 403:
            LOG.info(
                _LI("Token is invalid, "
                    "going to re-login to get a new one"))

            login_request = (
                "https://%(server_ip)s:%(server_port)s/api/login" % {
                    'server_ip': self.server_ip,
                    'server_port': self.server_port
                })

            r = requests.get(login_request,
                             auth=(self.server_username, self.server_password),
                             verify=False)

            token = r.json()
            # repeat request with valid token
            LOG.debug(
                _("Going to perform request %(request)s again "
                  "with valid token"), {'request': request})

            if is_get_request:
                res = requests.get(request,
                                   auth=(self.server_username, token),
                                   verify=False)
            else:
                headers = {'content-type': 'application/json'}
                res = requests.post(request,
                                    data=json.dumps(params),
                                    headers=headers,
                                    auth=(self.server_username, token),
                                    verify=False)

            self.server_token = token
            return res

        return response
Example #36
0
    def connect_volume(self, connection_properties):
        """Connect to a volume.

        :param connection_properties: The dictionary that describes all
                                      of the target volume attributes.
               connection_properties must include:
               device_path - path to the volume to be connected
        :type connection_properties: dict
        :returns: dict
        """
        if 'device_path' not in connection_properties:
            msg = (_("Invalid connection_properties specified "
                     "no device_path attribute."))
            raise ValueError(msg)

        device_info = {
            'type': 'gpfs',
            'path': connection_properties['device_path']
        }
        return device_info
Example #37
0
    def connect(self):
        LOG.debug("opening connection to ceph cluster (timeout=%s).",
                  self.rados_connect_timeout)
        client = self.rados.Rados(rados_id=self.rbd_user,
                                  clustername=self.rbd_cluster_name,
                                  conffile=self.rbd_conf)

        try:
            if self.rados_connect_timeout >= 0:
                client.connect(timeout=self.rados_connect_timeout)
            else:
                client.connect()
            ioctx = client.open_ioctx(self.rbd_pool)
            return client, ioctx
        except self.rados.Error:
            msg = _("Error connecting to ceph cluster.")
            LOG.exception(msg)
            # shutdown cannot raise an exception
            client.shutdown()
            raise exception.BrickException(message=msg)
Example #38
0
    def _create_ceph_conf(self, monitor_ips, monitor_ports, cluster_name,
                          user):
        monitors = [
            "%s:%s" % (ip, port) for ip, port in zip(
                self._sanitize_mon_hosts(monitor_ips), monitor_ports)
        ]
        mon_hosts = "mon_host = %s" % (','.join(monitors))

        client_section = "[client.%s]" % user
        keyring = ("keyring = /etc/ceph/%s.client.%s.keyring" %
                   (cluster_name, user))
        try:
            fd, ceph_conf_path = tempfile.mkstemp(prefix="brickrbd_")
            with os.fdopen(fd, 'w') as conf_file:
                conf_file.writelines(
                    [mon_hosts, "\n", client_section, "\n", keyring])
            return ceph_conf_path
        except IOError:
            msg = (_("Failed to write data to %s.") % (ceph_conf_path))
            raise exception.BrickException(msg=msg)
Example #39
0
 def _show_rbd_mapping(self, connection_properties):
     # TODO(lpetrut): consider using "rbd device show" if/when
     # it becomes available.
     cmd = [
         'rbd-wnbd', 'show', connection_properties['name'], '--format',
         'json'
     ]
     try:
         out, err = self._execute(*cmd)
         return json.loads(out)
     except processutils.ProcessExecutionError as ex:
         if abs(ctypes.c_int32(ex.exit_code).value) == errno.ENOENT:
             LOG.debug("Couldn't find RBD mapping: %s",
                       connection_properties['name'])
             return
         raise
     except json.decoder.JSONDecodeError:
         msg = _("Could not get rbd mappping.")
         LOG.exception(msg)
         raise exception.BrickException(msg)
Example #40
0
 def _cli_cmd(self, method, volume_name):
     LOG.debug("Enter into _cli_cmd.")
     if not self.iscliexist:
         msg = _("SDS command line doesn't exist, "
                 "can't execute SDS command.")
         raise exception.BrickException(message=msg)
     if not method or volume_name is None:
         return
     cmd = [self.cli_path, '-c', method, '-v', volume_name]
     out, clilog = self._execute(*cmd,
                                 run_as_root=False,
                                 root_helper=self._root_helper)
     analyse_result = self._analyze_output(out)
     LOG.debug('%(method)s volume returns %(analyse_result)s.', {
         'method': method,
         'analyse_result': analyse_result
     })
     if clilog:
         LOG.error(_LE("SDS CLI output some log: %s."), clilog)
     return analyse_result
Example #41
0
    def factory(protocol,
                root_helper,
                driver=None,
                use_multipath=False,
                device_scan_attempts=initiator.DEVICE_SCAN_ATTEMPTS_DEFAULT,
                arch=None,
                *args,
                **kwargs):
        """Build a Connector object based upon protocol and architecture."""

        _mapping = get_connector_mapping(arch)

        LOG.debug("Factory for %(protocol)s on %(arch)s", {
            'protocol': protocol,
            'arch': arch
        })
        protocol = protocol.upper()

        # set any special kwargs needed by connectors
        if protocol in (initiator.NFS, initiator.GLUSTERFS, initiator.SCALITY,
                        initiator.QUOBYTE, initiator.VZSTORAGE):
            kwargs.update({'mount_type': protocol.lower()})
        elif protocol == initiator.ISER:
            kwargs.update({'transport': 'iser'})

        # now set all the default kwargs
        kwargs.update({
            'root_helper': root_helper,
            'driver': driver,
            'use_multipath': use_multipath,
            'device_scan_attempts': device_scan_attempts,
        })

        connector = _mapping.get(protocol)
        if not connector:
            msg = (_("Invalid InitiatorConnector protocol "
                     "specified %(protocol)s") % dict(protocol=protocol))
            raise exception.InvalidConnectorProtocol(msg)

        conn_cls = importutils.import_class(connector)
        return conn_cls(*args, **kwargs)
Example #42
0
    def _do_mount(self,
                  mount_type,
                  vz_share,
                  mount_path,
                  mount_options=None,
                  flags=None):
        m = re.search(r"(?:(\S+):\/)?([a-zA-Z0-9_-]+)(?::(\S+))?", vz_share)
        if not m:
            msg = (
                _("Invalid Virtuozzo Storage share specification: %r."
                  "Must be: [MDS1[,MDS2],...:/]<CLUSTER NAME>[:PASSWORD].") %
                vz_share)
            raise exception.BrickException(msg)

        mdss = m.group(1)
        cluster_name = m.group(2)
        passwd = m.group(3)

        if mdss:
            mdss = mdss.split(',')
            self._vzstorage_write_mds_list(cluster_name, mdss)

        if passwd:
            self._execute('pstorage',
                          '-c',
                          cluster_name,
                          'auth-node',
                          '-P',
                          process_input=passwd,
                          root_helper=self._root_helper,
                          run_as_root=True)

        mnt_cmd = ['pstorage-mount', '-c', cluster_name]
        if flags:
            mnt_cmd.extend(flags)
        mnt_cmd.extend([mount_path])

        self._execute(*mnt_cmd,
                      root_helper=self._root_helper,
                      run_as_root=True,
                      check_exit_code=0)
Example #43
0
    def get_local_share_path(self, share, expect_existing=True):
        share = self._get_share_norm_path(share)
        share_name = self.get_share_name(share)
        share_subdir = self.get_share_subdir(share)
        is_local_share = self._smbutils.is_local_share(share)

        if not is_local_share:
            LOG.debug("Share '%s' is not exposed by the current host.", share)
            local_share_path = None
        else:
            local_share_path = self._smbutils.get_smb_share_path(share_name)

        if not local_share_path and expect_existing:
            err_msg = _("Could not find the local "
                        "share path for %(share)s.")
            raise exception.VolumePathsNotFound(err_msg % dict(share=share))

        if local_share_path and share_subdir:
            local_share_path = os.path.join(local_share_path, share_subdir)

        return local_share_path
Example #44
0
    def _mount_nfs(self, nfs_share, mount_path, flags=None):
        """Mount nfs share using present mount types."""
        mnt_errors = {}

        # This loop allows us to first try to mount with NFS 4.1 for pNFS
        # support but falls back to mount NFS 4 or NFS 3 if either the client
        # or server do not support it.
        for mnt_type in sorted(self._nfs_mount_type_opts.keys(), reverse=True):
            options = self._nfs_mount_type_opts[mnt_type]
            try:
                self._do_mount('nfs', nfs_share, mount_path, options, flags)
                LOG.debug('Mounted %(sh)s using %(mnt_type)s.',
                          {'sh': nfs_share, 'mnt_type': mnt_type})
                return
            except Exception as e:
                mnt_errors[mnt_type] = six.text_type(e)
                LOG.debug('Failed to do %s mount.', mnt_type)
        raise exception.BrickException(_("NFS mount failed for share %(sh)s. "
                                         "Error - %(error)s")
                                       % {'sh': nfs_share,
                                          'error': mnt_errors})
Example #45
0
    def create_non_openstack_config(cls, connection_properties):
        """Get root owned Ceph's .conf file for non OpenStack usage."""
        # If keyring info is missing then we are in OpenStack, nothing to do
        keyring = connection_properties.get('keyring')
        if not keyring:
            return None

        try:
            user = connection_properties['auth_username']
            pool, volume = connection_properties['name'].split('/')
            cluster_name = connection_properties['cluster_name']
            monitor_ips = connection_properties['hosts']
            monitor_ports = connection_properties['ports']
            keyring = connection_properties.get('keyring')
        except (KeyError, ValueError):
            msg = _("Connect volume failed, malformed connection properties.")
            raise exception.BrickException(msg=msg)

        conf = rbd_privsep.root_create_ceph_conf(monitor_ips, monitor_ports,
                                                 str(cluster_name), user,
                                                 keyring)
        return conf
Example #46
0
    def _get_rbd_args(cls, connection_properties, conf=None):
        try:
            user = connection_properties['auth_username']
            monitor_ips = connection_properties.get('hosts')
            monitor_ports = connection_properties.get('ports')
        except KeyError:
            msg = _("Connect volume failed, malformed connection properties")
            raise exception.BrickException(msg=msg)

        args = ['--id', user]
        if monitor_ips and monitor_ports:
            monitors = ["%s:%s" % (ip, port) for ip, port in
                        zip(
                            cls._sanitize_mon_hosts(monitor_ips),
                            monitor_ports)]
            for monitor in monitors:
                args += ['--mon_host', monitor]

        if conf:
            args += ['--conf', conf]

        return args
Example #47
0
    def _create_ceph_conf(cls, monitor_ips, monitor_ports,
                          cluster_name, user, keyring):
        monitors = ["%s:%s" % (ip, port) for ip, port in
                    zip(cls._sanitize_mon_hosts(monitor_ips), monitor_ports)]
        mon_hosts = "mon_host = %s" % (','.join(monitors))

        keyring = cls._check_or_get_keyring_contents(keyring, cluster_name,
                                                     user)

        try:
            fd, ceph_conf_path = tempfile.mkstemp(prefix="brickrbd_")
            with os.fdopen(fd, 'w') as conf_file:
                # Bug #1865754 - '[global]' has been the appropriate
                # place for this stuff since at least Hammer, but in
                # Octopus (15.2.0+), Ceph began enforcing this.
                conf_file.writelines(["[global]", "\n",
                                      mon_hosts, "\n",
                                      keyring, "\n"])
            return ceph_conf_path
        except IOError:
            msg = (_("Failed to write data to %s.") % (ceph_conf_path))
            raise exception.BrickException(msg=msg)
Example #48
0
    def __init__(self, mount_type, root_helper,
                 execute=None, *args, **kwargs):
        # For backwards compatibility, `putils.execute` is interpreted
        # as a sentinel to mean "I want the os-brick default" :-/
        # This can be burnt as soon as we update all the callsites (in
        # nova+cinder) to the new default - and then we shall never
        # speak of it again.
        # TODO(gus): RemoteFsClient should probably inherit from Executor
        if execute is None or execute == putils.execute:
            execute = priv_rootwrap.execute

        mount_type_to_option_prefix = {
            'nfs': 'nfs',
            'cifs': 'smbfs',
            'glusterfs': 'glusterfs',
            'vzstorage': 'vzstorage',
            'quobyte': 'quobyte'
        }

        if mount_type not in mount_type_to_option_prefix:
            raise exception.ProtocolNotSupported(protocol=mount_type)

        self._mount_type = mount_type
        option_prefix = mount_type_to_option_prefix[mount_type]

        self._mount_base = kwargs.get(option_prefix + '_mount_point_base')
        if not self._mount_base:
            raise exception.InvalidParameterValue(
                err=_('%s_mount_point_base required') % option_prefix)

        self._mount_options = kwargs.get(option_prefix + '_mount_options')

        if mount_type == "nfs":
            self._check_nfs_options()

        self.root_helper = root_helper
        self.set_execute(execute)
Example #49
0
    def connect_volume(self, connection_properties):
        """Connect to a volume.

        :param connection_properties: The dictionary that describes all
                                      of the target volume attributes.
        :type connection_properties: dict
        :returns: dict
        """
        do_local_attach = connection_properties.get('do_local_attach',
                                                    self.do_local_attach)

        if do_local_attach:
            # NOTE(e0ne): sanity check if ceph-common is installed.
            cmd = ['which', 'rbd']
            try:
                self._execute(*cmd)
            except putils.ProcessExecutionError:
                msg = _("ceph-common package is not installed.")
                LOG.error(msg)
                raise exception.BrickException(message=msg)

            # NOTE(e0ne): map volume to a block device
            # via the rbd kernel module.
            pool, volume = connection_properties['name'].split('/')
            cmd = ['rbd', 'map', volume, '--pool', pool]
            self._execute(*cmd,
                          root_helper=self._root_helper,
                          run_as_root=True)

            return {
                'path': RBDConnector.get_rbd_device_name(pool, volume),
                'type': 'block'
            }

        rbd_handle = self._get_rbd_handle(connection_properties)
        return {'path': rbd_handle}
Example #50
0
def retry(exceptions, interval=1, retries=3, backoff_rate=2):

    if retries < 1:
        raise ValueError(
            _('Retries must be greater than or '
              'equal to 1 (received: %s). ') % retries)

    def _decorator(f):
        @functools.wraps(f)
        def _wrapper(*args, **kwargs):
            r = tenacity.Retrying(
                before_sleep=tenacity.before_sleep_log(LOG, logging.DEBUG),
                after=tenacity.after_log(LOG, logging.DEBUG),
                stop=tenacity.stop_after_attempt(retries),
                reraise=True,
                retry=tenacity.retry_if_exception_type(exceptions),
                wait=tenacity.wait_exponential(multiplier=interval,
                                               min=0,
                                               exp_base=backoff_rate))
            return r.call(f, *args, **kwargs)

        return _wrapper

    return _decorator
Example #51
0
class VolumeNotDeactivated(BrickException):
    message = _('Volume %(name)s was not deactivated in time.')
Example #52
0
class NoFibreChannelVolumeDeviceFound(BrickException):
    message = _("Unable to find a Fibre Channel volume device.")
Example #53
0
class NoFibreChannelHostsFound(BrickException):
    message = _("We are unable to locate any Fibre Channel devices.")
Example #54
0
class InvalidParameterValue(Invalid):
    message = _("%(err)s")
Example #55
0
class Invalid(BrickException):
    message = _("Unacceptable parameters.")
    code = 400
Example #56
0
class NotFound(BrickException):
    message = _("Resource could not be found.")
    code = 404
    safe = True
Example #57
0
class VolumeEncryptionNotSupported(Invalid):
    message = _("Volume encryption is not supported for %(volume_type)s "
                "volume %(volume_id)s.")
Example #58
0
class InvalidIOHandleObject(BrickException):
    message = _('IO handle of %(protocol)s has wrong object '
                'type %(actual_type)s.')
Example #59
0
class VolumeDriverException(BrickException):
    message = _('An error occurred while IO to volume %(name)s.')
Example #60
0
class CommandExecutionFailed(BrickException):
    message = _("Failed to execute command %(cmd)s")