Пример #1
0
 def _throw_on_http_error(self, response):
     if response.status == 401:
         raise exception.QBException(
             _("JSON RPC failed: unauthorized user %(status)s %(reason)s"
               " Please check the Quobyte API service log for "
               "more details.")
             % {'status': six.text_type(response.status),
                'reason': response.reason})
     elif response.status >= 300:
         raise exception.QBException(
             _("JSON RPC failed:  %(status)s %(reason)s"
               " Please check the Quobyte API service log for "
               "more details.")
             % {'status': six.text_type(response.status),
                'reason': response.reason})
Пример #2
0
 def _fetch_existing_access(self, context, share):
     volume_uuid = self._resolve_volume_name(
         share['name'], self._get_project_name(context,
                                               share['project_id']))
     result = self.rpc.call('getConfiguration', {})
     if result is None:
         raise exception.QBException(
             "Could not retrieve Quobyte configuration data!")
     tenant_configs = result['tenant_configuration']
     qb_access_list = []
     for tc in tenant_configs:
         for va in tc['volume_access']:
             if va['volume_uuid'] == volume_uuid:
                 a_level = constants.ACCESS_LEVEL_RW
                 if va['read_only']:
                     a_level = constants.ACCESS_LEVEL_RO
                 qb_access_list.append({
                     'access_to':
                     va['restrict_to_network'],
                     'access_level':
                     a_level,
                     'access_type':
                     'ip'
                 })
     return qb_access_list
Пример #3
0
    def create_share(self, context, share, share_server=None):
        """Create or export a volume that is usable as a Manila share."""
        if share['share_proto'] != 'NFS':
            raise exception.QBException(
                _('Quobyte driver only supports NFS shares'))

        volume_uuid = self._resolve_volume_name(
            share['name'], self._get_project_name(context,
                                                  share['project_id']))

        if not volume_uuid:
            # create tenant, expect ERROR_GARBAGE_ARGS if it already exists
            self.rpc.call('setTenant',
                          dict(tenant=dict(tenant_id=share['project_id'])),
                          expected_errors=[jsonrpc.ERROR_GARBAGE_ARGS])
            result = self.rpc.call(
                'createVolume',
                dict(name=share['name'],
                     tenant_domain=share['project_id'],
                     root_user_id=self.configuration.
                     quobyte_default_volume_user,
                     root_group_id=self.configuration.
                     quobyte_default_volume_group,
                     configuration_name=(
                         self.configuration.quobyte_volume_configuration)))
            volume_uuid = result['volume_uuid']

        result = self.rpc.call('exportVolume',
                               dict(volume_uuid=volume_uuid, protocol='NFS'))

        return '%(nfs_server_ip)s:%(nfs_export_path)s' % result
Пример #4
0
 def _checked_for_application_error(self, result):
     if 'error' in result and result['error']:
         if 'message' in result['error'] and 'code' in result['error']:
             if result["error"]["code"] == ERROR_ENOENT:
                 return None  # No Entry
             else:
                 raise exception.QBRpcException(
                     result=result["error"]["message"],
                     qbcode=result["error"]["code"])
         else:
             raise exception.QBException(six.text_type(result["error"]))
     return result["result"]
Пример #5
0
 def _checked_for_application_error(self, result, expected_errors=[]):
     if 'error' in result and result['error']:
         if 'message' in result['error'] and 'code' in result['error']:
             if result["error"]["code"] in expected_errors:
                 # hit an expected error, return empty result
                 return None
             else:
                 raise exception.QBRpcException(
                     result=result["error"]["message"],
                     qbcode=result["error"]["code"])
         else:
             raise exception.QBException(six.text_type(result["error"]))
     return result["result"]
Пример #6
0
    def do_setup(self, context):
        """Prepares the backend."""
        self.rpc = jsonrpc.JsonRpc(
            url=self.configuration.quobyte_api_url,
            ca_file=self.configuration.quobyte_api_ca,
            user_credentials=(self.configuration.quobyte_api_username,
                              self.configuration.quobyte_api_password))

        try:
            self.rpc.call('getInformation', {})
        except Exception as exc:
            LOG.error("Could not connect to API: %s", exc)
            raise exception.QBException(
                _('Could not connect to API: %s') % exc)
Пример #7
0
    def call(self, method_name, user_parameters):

        parameters = {'retry': 'INFINITELY'}  # Backend specific setting
        if user_parameters:
            parameters.update(user_parameters)
        call_body = {
            'jsonrpc': '2.0',
            'method': method_name,
            'params': parameters,
            'id': six.text_type(self._id)
        }
        self.call_counter = 0
        self._connection.connect()  # prevents http_client timing issue

        while self.call_counter < CONNECTION_RETRIES:
            self.call_counter += 1
            try:
                self._id += 1
                call_body['id'] = six.text_type(self._id)
                LOG.debug("Posting to Quobyte backend: %s",
                          jsonutils.dumps(call_body))
                self._connection.request(
                    "POST", self._url + '/', jsonutils.dumps(call_body),
                    dict(Authorization=(
                        self._credentials.get_authorization_header())))

                response = self._connection.getresponse()
                self._throw_on_http_error(response)
                result = jsonutils.loads(response.read())
                LOG.debug("Retrieved data from Quobyte backend: %s", result)
                return self._checked_for_application_error(result)
            except ssl.SSLError as e:
                # Generic catch because OpenSSL does not return
                # meaningful errors.
                if (not self._disabled_cert_verification
                        and not self._require_cert_verify):
                    LOG.warning(
                        _LW("Could not verify server certificate of "
                            "API service against CA."))
                    self._connection.close()
                    # Core HTTPSConnection does no certificate verification.
                    self._connection = http_client.HTTPSConnection(
                        self._netloc)
                    self._disabled_cert_verification = True
                else:
                    raise exception.QBException(
                        _("Client SSL subsystem returned error: %s") % e)
            except http_client.BadStatusLine as e:
                raise exception.QBException(
                    _("If SSL is enabled for the API service, the URL must"
                      " start with 'https://' for the URL. Failed to parse"
                      " status code from server response. Error was %s") % e)
            except socket.error as se:
                error_code = se.errno
                error_msg = se.strerror
                composite_msg = _("Socket error No. %(code)s (%(msg)s) "
                                  "connecting to API with") % {
                                      'code': (six.text_type(error_code)),
                                      'msg': error_msg
                                  }
                if self._fail_fast:
                    raise exception.QBException(composite_msg)
                else:
                    LOG.warning(composite_msg)
            except http_client.HTTPException as e:
                with excutils.save_and_reraise_exception() as ctxt:
                    if self._fail_fast:
                        ctxt.reraise = True
                    else:
                        LOG.warning(_LW("Encountered error, retrying: %s"),
                                    six.text_type(e))
                        ctxt.reraise = False

        raise exception.QBException("Unable to connect to backend after "
                                    "%s retries" %
                                    six.text_type(CONNECTION_RETRIES))