Example #1
0
 def disconnect_volume(self, connection_properties, device_info):
     client_id = connection_properties.get('volume', None)
     if client_id is None:
         raise exception.BrickException(_LE(
             'Invalid StorPool connection data, no client ID specified'))
     volume_id = connection_properties.get('volume', None)
     if volume_id is None:
         raise exception.BrickException(_LE(
             'Invalid StorPool connection data, no volume ID specified'))
     volume = self._attach.volumeName(volume_id)
     req_id = 'brick-%s-%s' % (client_id, volume_id)
     self._attach.sync(req_id, volume)
     self._attach.remove(req_id)
Example #2
0
    def _get_volume_id(self):
        """
        Return the current volume contexts ScaleIO unique volume identifier
        :return: ScaleIO volume ID
        """

        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(_LE("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(_LE("ScaleIO volume id is %(volume_id)s."),
                 {'volume_id': volume_id})
        return volume_id
Example #3
0
    def _wait_for_volume_path(self, path):
        """
        Wait for mapped volume to appear in path. There is a delay
        between the time the ScaleIO volume is mapped and it appearing
        in the disk device path
        :param path: Path to search for volume in
        :return: Full mapped disk path
        """

        disk_filename = None
        tries = 0

        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)

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

            filenames = os.listdir(path)
            LOG.debug(_LE("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
            if not disk_filename:
                LOG.warn("ScaleIO volume {0} not yet "
                         "found. Try number: {1} ".format(
                             self.volume_id, tries))
                tries = tries + 1
                time.sleep(1)
            else:
                LOG.info(_LE("ScaleIO volume %(volume_id)s "
                             "found!"), {'volume_id': self.volume_id})

        return disk_filename
Example #4
0
 def __init__(self, root_helper, driver=None, execute=putils.execute,
              *args, **kwargs):
     self._execute = execute
     self._root_helper = root_helper
     try:
         from storpool import spopenstack
     except ImportError:
         raise exception.BrickException(_LE(
             'Could not import the StorPool API bindings'))
     try:
         self._attach = spopenstack.AttachDB(log=LOG)
         self._attach.api().attachmentsList()
     except Exception as e:
         raise exception.BrickException(_LE(
             'Could not initialize the StorPool API bindings: %s') % (e))
Example #5
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 #6
0
    def connect_volume(self, connection_properties):
        """Connect to a volume."""
        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(msg=msg)
        out = self._query_attached_volume(connection_properties['volume_id'])
        if not out or int(out['ret_code']) != 0:
            msg = _("query attached volume failed or volume not attached.")
            raise exception.BrickException(msg=msg)

        device_info = {'type': 'block', 'path': out['dev_addr']}
        return device_info
Example #7
0
 def disconnect_volume(self, connection_properties, device_info):
     """Disconnect a volume from the local host."""
     LOG.debug("Disconnect_volume: %s." % connection_properties)
     out = self._detach_volume(connection_properties['volume_id'])
     if not out or int(out['ret_code']) not in (self.attached_success_code,
                                                self.vbs_unnormal_code,
                                                self.not_mount_node_code):
         msg = (_("Disconnect_volume failed, "
                  "error code is %s") % out['ret_code'])
         raise exception.BrickException(msg=msg)
Example #8
0
    def _get_client_id(self):
        """
        Return the local SDC GUID
        :return: Unique ScaleIO SDC ID
        """

        request = ("https://%(server_ip)s:%(server_port)s/"
                   "api/types/Client/instances/getByIp::%(sdc_ip)s/" % {
                       'server_ip': self.server_ip,
                       'server_port': self.server_port,
                       'sdc_ip': self.local_sdc_ip
                   })

        LOG.info(_LE("ScaleIO get client id by ip request: %(request)s"),
                 {'request': request})

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

        r = self._check_response(r, request)
        sdc_id = r.json()
        if not sdc_id:
            msg = (_("Client with ip %(sdc_ip)s was not found.") % {
                'sdc_ip': self.local_sdc_ip
            })
            raise exception.BrickException(message=msg)

        if r.status_code != 200 and "errorCode" in sdc_id:
            msg = (_("Error getting sdc id from ip %(sdc_ip)s: %(err)s") % {
                'sdc_ip': self.local_sdc_ip,
                'err': sdc_id['message']
            })

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

        LOG.info(_LE("ScaleIO sdc id is %(sdc_id)s."), {'sdc_id': sdc_id})
        return sdc_id
Example #9
0
 def connect_volume(self, connection_properties):
     client_id = connection_properties.get('volume', None)
     if client_id is None:
         raise exception.BrickException(_LE(
             'Invalid StorPool connection data, no client ID specified'))
     volume_id = connection_properties.get('volume', None)
     if volume_id is None:
         raise exception.BrickException(_LE(
             'Invalid StorPool connection data, no volume ID specified'))
     volume = self._attach.volumeName(volume_id)
     mode = connection_properties.get('access_mode', None)
     if mode is None or mode not in ('rw', 'ro'):
         raise exception.BrickException(_LE(
             'Invalid access_mode specified in the connection data'))
     req_id = 'brick-%s-%s' % (client_id, volume_id)
     self._attach.add(req_id, {
         'volume': volume,
         'type': 'brick',
         'id': req_id,
         'rights': 1 if mode == 'ro' else 2,
         'volsnap': False
     })
     self._attach.sync(req_id, None)
     return {'type': 'block', 'path': '/dev/storpool/' + volume}
Example #10
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(msg=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 #11
0
 def test_error_msg(self):
     self.assertEqual(six.text_type(exception.BrickException('test')),
                      'test')
Example #12
0
    def disconnect_volume(self, connection_properties, device_info):
        """Disconnect the ScaleIO volume.

        :param connection_properties: The dictionary that describes all
                                      of the target volume attributes.
        :type connection_properties: dict
        :param device_info: historical difference, but same as connection_props
        :type device_info: dict
        """
        self.get_config(connection_properties)
        self.volume_id = self._get_volume_id()
        LOG.info(
            _LE("ScaleIO disconnect volume in ScaleIO brick volume driver."))

        LOG.debug(
            _("ScaleIO Volume name: %(volume_name)s, SDC IP: %(sdc_ip)s, "
              "REST Server IP: %(server_ip)s"), {
                  'volume_name': self.volume_name,
                  'sdc_ip': self.local_sdc_ip,
                  'server_ip': self.server_ip
              })

        LOG.info(_LE("ScaleIO sdc query guid command: %(cmd)s"),
                 {'cmd': self.GET_GUID_CMD})

        try:
            (out, err) = self._execute(*self.GET_GUID_CMD,
                                       run_as_root=True,
                                       root_helper=self._root_helper)
            LOG.info(
                _LE("Unmap volume %(cmd)s: stdout=%(out)s stderr=%(err)s"), {
                    'cmd': self.GET_GUID_CMD,
                    'out': out,
                    'err': err
                })

        except putils.ProcessExecutionError as e:
            msg = _("Error querying sdc guid: %(err)s") % {'err': e.stderr}
            LOG.error(msg)
            raise exception.BrickException(message=msg)

        guid = out
        LOG.info(_LE("Current sdc guid: %(guid)s"), {'guid': guid})

        params = {'guid': guid}
        headers = {'content-type': 'application/json'}
        request = ("https://%(server_ip)s:%(server_port)s/api/instances/"
                   "Volume::%(volume_id)s/action/removeMappedSdc" % {
                       'server_ip': self.server_ip,
                       'server_port': self.server_port,
                       'volume_id': self.volume_id
                   })

        LOG.info(_LE("Unmap volume request: %(request)s"),
                 {'request': request})
        r = requests.post(request,
                          data=json.dumps(params),
                          headers=headers,
                          auth=(self.server_username, self.server_token),
                          verify=False)

        r = self._check_response(r, request, False, params)
        if r.status_code != self.OK_STATUS_CODE:
            response = r.json()
            error_code = response['errorCode']
            if error_code == self.VOLUME_NOT_MAPPED_ERROR:
                LOG.warning(
                    _LW("Ignoring error unmapping volume %(volume_id)s: "
                        "volume not mapped."), {'volume_id': self.volume_name})
            else:
                msg = (_("Error unmapping volume %(volume_id)s: %(err)s") % {
                    'volume_id': self.volume_name,
                    'err': response['message']
                })
                LOG.error(msg)
                raise exception.BrickException(message=msg)
Example #13
0
    def connect_volume(self, connection_properties):
        """Connect the volume.

        :param connection_properties: The dictionary that describes all
                                      of the target volume attributes.
        :type connection_properties: dict
        :returns: dict
        """
        device_info = self.get_config(connection_properties)
        LOG.debug(
            _LE("scaleIO Volume name: %(volume_name)s, SDC IP: %(sdc_ip)s, "
                "REST Server IP: %(server_ip)s, "
                "REST Server username: %(username)s, "
                "iops limit:%(iops_limit)s, "
                "bandwidth limit: %(bandwidth_limit)s."), {
                    'volume_name': self.volume_name,
                    'sdc_ip': self.local_sdc_ip,
                    'server_ip': self.server_ip,
                    'username': self.server_username,
                    'iops_limit': self.iops_limit,
                    'bandwidth_limit': self.bandwidth_limit
                })

        LOG.info(_LE("ScaleIO sdc query guid command: %(cmd)s"),
                 {'cmd': self.GET_GUID_CMD})

        try:
            (out, err) = self._execute(*self.GET_GUID_CMD,
                                       run_as_root=True,
                                       root_helper=self._root_helper)

            LOG.info(
                _LE("Map volume %(cmd)s: stdout=%(out)s "
                    "stderr=%(err)s"), {
                        'cmd': self.GET_GUID_CMD,
                        'out': out,
                        'err': err
                    })

        except putils.ProcessExecutionError as e:
            msg = (_("Error querying sdc guid: %(err)s") % {'err': e.stderr})
            LOG.error(msg)
            raise exception.BrickException(message=msg)

        guid = out
        LOG.info(_LE("Current sdc guid: %(guid)s"), {'guid': guid})
        params = {'guid': guid, 'allowMultipleMappings': 'TRUE'}
        self.volume_id = self._get_volume_id()

        headers = {'content-type': 'application/json'}
        request = ("https://%(server_ip)s:%(server_port)s/api/instances/"
                   "Volume::%(volume_id)s/action/addMappedSdc" % {
                       'server_ip': self.server_ip,
                       'server_port': self.server_port,
                       'volume_id': self.volume_id
                   })

        LOG.info(_LE("map volume request: %(request)s"), {'request': request})
        r = requests.post(request,
                          data=json.dumps(params),
                          headers=headers,
                          auth=(self.server_username, self.server_token),
                          verify=False)

        r = self._check_response(r, request, False, params)
        if r.status_code != self.OK_STATUS_CODE:
            response = r.json()
            error_code = response['errorCode']
            if error_code == self.VOLUME_ALREADY_MAPPED_ERROR:
                LOG.warning(
                    _LW("Ignoring error mapping volume %(volume_name)s: "
                        "volume already mapped."),
                    {'volume_name': self.volume_name})
            else:
                msg = (_("Error mapping volume %(volume_name)s: %(err)s") % {
                    'volume_name': self.volume_name,
                    'err': response['message']
                })

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

        self.volume_path = self._find_volume_path()
        device_info['path'] = self.volume_path

        # Set QoS settings after map was performed
        if self.iops_limit is not None or self.bandwidth_limit is not None:
            params = {'guid': guid}
            if self.bandwidth_limit is not None:
                params['bandwidthLimitInKbps'] = self.bandwidth_limit
            if self.iops_limit is not None:
                params['iopsLimit'] = self.iops_limit

            request = ("https://%(server_ip)s:%(server_port)s/api/instances/"
                       "Volume::%(volume_id)s/action/setMappedSdcLimits" % {
                           'server_ip': self.server_ip,
                           'server_port': self.server_port,
                           'volume_id': self.volume_id
                       })

            LOG.info(_LE("Set client limit request: %(request)s"),
                     {'request': request})

            r = requests.post(request,
                              data=json.dumps(params),
                              headers=headers,
                              auth=(self.server_username, self.server_token),
                              verify=False)
            r = self._check_response(r, request, False, params)
            if r.status_code != self.OK_STATUS_CODE:
                response = r.json()
                LOG.info(_LE("Set client limit response: %(response)s"),
                         {'response': response})
                msg = (_("Error setting client limits for volume "
                         "%(volume_name)s: %(err)s") % {
                             'volume_name': self.volume_name,
                             'err': response['message']
                         })

                LOG.error(msg)

        return device_info
 def test_error_msg(self):
     self.assertEqual(unicode(exception.BrickException('test')), 'test')