Пример #1
0
    def _issue_api_request(self, method_name, params):
        """All API requests to SolidFire device go through this method

        Simple json-rpc web based API calls.
        each call takes a set of paramaters (dict)
        and returns results in a dict as well.
        """

        host = FLAGS.san_ip
        # For now 443 is the only port our server accepts requests on
        port = 443

        # NOTE(john-griffith): Probably don't need this, but the idea is
        # we provide a request_id so we can correlate
        # responses with requests
        request_id = int(uuid.uuid4())  # just generate a random number

        cluster_admin = FLAGS.san_login
        cluster_password = FLAGS.san_password

        command = {'method': method_name, 'id': request_id}

        if params is not None:
            command['params'] = params

        payload = json.dumps(command, ensure_ascii=False)
        payload.encode('utf-8')
        # we use json-rpc, webserver needs to see json-rpc in header
        header = {'Content-Type': 'application/json-rpc; charset=utf-8'}

        if cluster_password is not None:
            # base64.encodestring includes a newline character
            # in the result, make sure we strip it off
            auth_key = base64.encodestring(
                '%s:%s' % (cluster_admin, cluster_password))[:-1]
            header['Authorization'] = 'Basic %s' % auth_key

        LOG.debug(_("Payload for SolidFire API call: %s"), payload)
        connection = httplib.HTTPSConnection(host, port)
        connection.request('POST', '/json-rpc/1.0', payload, header)
        response = connection.getresponse()
        data = {}

        if response.status != 200:
            connection.close()
            raise exception.SolidFireAPIException(status=response.status)

        else:
            data = response.read()
            try:
                data = json.loads(data)

            except (TypeError, ValueError), exc:
                connection.close()
                msg = _("Call to json.loads() raised an exception: %s") % exc
                raise exception.SfJsonEncodeFailure(msg)

            connection.close()
Пример #2
0
    def _issue_api_request(self, method_name, params, version='1.0'):
        """All API requests to SolidFire device go through this method.

        Simple json-rpc web based API calls.
        each call takes a set of paramaters (dict)
        and returns results in a dict as well.

        """
        max_simultaneous_clones = ['xMaxSnapshotsPerVolumeExceeded',
                                   'xMaxClonesPerVolumeExceeded',
                                   'xMaxSnapshotsPerNodeExceeded',
                                   'xMaxClonesPerNodeExceeded']
        host = self.configuration.san_ip
        port = self.configuration.sf_api_port

        cluster_admin = self.configuration.san_login
        cluster_password = self.configuration.san_password

        # NOTE(jdg): We're wrapping a retry loop for a know XDB issue
        # Shows up in very high request rates (ie create 1000 volumes)
        # we have to wrap the whole sequence because the request_id
        # can't be re-used
        retry_count = 5
        while retry_count > 0:
            request_id = hash(uuid.uuid4())  # just generate a random number
            command = {'method': method_name,
                       'id': request_id}

            if params is not None:
                command['params'] = params

            payload = json.dumps(command, ensure_ascii=False)
            payload.encode('utf-8')
            header = {'Content-Type': 'application/json-rpc; charset=utf-8'}

            if cluster_password is not None:
                # base64.encodestring includes a newline character
                # in the result, make sure we strip it off
                auth_key = base64.encodestring('%s:%s' % (cluster_admin,
                                               cluster_password))[:-1]
                header['Authorization'] = 'Basic %s' % auth_key

            LOG.debug(_("Payload for SolidFire API call: %s"), payload)

            api_endpoint = '/json-rpc/%s' % version
            connection = httplib.HTTPSConnection(host, port)
            try:
                connection.request('POST', api_endpoint, payload, header)
            except Exception as ex:
                LOG.error(_('Failed to make httplib connection '
                            'SolidFire Cluster: %s (verify san_ip '
                            'settings)') % ex.message)
                msg = _("Failed to make httplib connection: %s") % ex.message
                raise exception.SolidFireAPIException(msg)
            response = connection.getresponse()

            data = {}
            if response.status != 200:
                connection.close()
                LOG.error(_('Request to SolidFire cluster returned '
                            'bad status: %(status)s / %(reason)s (check '
                            'san_login/san_password settings)') %
                          {'status': response.status,
                           'reason': response.reason})
                msg = (_("HTTP request failed, with status: %(status)s "
                         "and reason: %(reason)s") %
                       {'status': response.status, 'reason': response.reason})
                raise exception.SolidFireAPIException(msg)

            else:
                data = response.read()
                try:
                    data = json.loads(data)
                except (TypeError, ValueError) as exc:
                    connection.close()
                    msg = _("Call to json.loads() raised "
                            "an exception: %s") % exc
                    raise exception.SfJsonEncodeFailure(msg)

                connection.close()

            LOG.debug(_("Results of SolidFire API call: %s"), data)

            if 'error' in data:
                if data['error']['name'] in max_simultaneous_clones:
                    LOG.warning(_('Clone operation '
                                  'encountered: %s') % data['error']['name'])
                    LOG.warning(_(
                        'Waiting for outstanding operation '
                        'before retrying snapshot: %s') % params['name'])
                    time.sleep(5)
                    # Don't decrement the retry count for this one
                elif 'xDBVersionMismatch' in data['error']['name']:
                    LOG.warning(_('Detected xDBVersionMismatch, '
                                'retry %s of 5') % (5 - retry_count))
                    time.sleep(1)
                    retry_count -= 1
                elif 'xUnknownAccount' in data['error']['name']:
                    retry_count = 0
                else:
                    msg = _("API response: %s") % data
                    raise exception.SolidFireAPIException(msg)
            else:
                retry_count = 0

        return data