Exemple #1
0
    def get_plans(self, reference):
        """Get the plans for a given charm.

        @param the Reference to a charm.
        @return a tuple of plans or an empty tuple if no plans.
        @raise ServerError
        """
        response = make_request(
            '{}charm?charm-url={}'.format(self.url,
                                          'cs:' + reference.path()),
            timeout=self.timeout, client=self._client)
        try:
            return tuple(map(lambda plan: Plan(
                url=plan['url'], plan=plan['plan'],
                created_on=datetime.datetime.strptime(
                    plan['created-on'],
                    "%Y-%m-%dT%H:%M:%SZ"
                ),
                description=plan.get('description'),
                price=plan.get('price')), response))
        except Exception as err:
            log.error(
                'cannot process plans: invalid JSON response: {!r}'.format(
                    response))
            raise ServerError(
                'unable to get list of plans for {}: {}'.format(
                    reference.path(), err))
Exemple #2
0
    def get_wallet(self, wallet_name):
        """Get a single wallet.

        @param the name of the wallet.
        @return the wallet's total.
        @raise ServerError
        """
        response = make_request(
            '{}wallet/{}'.format(self.url, wallet_name),
            timeout=self.timeout,
            client=self._client)
        try:
            total = response['total']
            return {
                'credit': response['credit'],
                'limit': response['limit'],
                'total': WalletTotal(
                    limit=total['limit'],
                    budgeted=total['budgeted'],
                    available=total['available'],
                    unallocated=total['unallocated'],
                    usage=total['usage'],
                    consumed=total['consumed'])
            }
        except Exception as exc:
            log.error(
                'cannot get wallet from server: {!r}'.format(exc))
            raise ServerError(
                'unable to get list of wallets: {!r}'.format(exc))
Exemple #3
0
    def create_case(self, name, email, subject, description, businessImpact,
                    priority, phone):
        """ Send a case creation to SalesForces to create a ticket.

        @param name of the person creating the case.
        @param email of the person creating the case.
        @param subject of the case.
        @param description of the case.
        @param businessImpact of the case.
        @param priority of the case.
        @param phone of the person creating the case.
        @return Nothing if this is ok.
        @raise ServerError when something goes wrong.
        @raise ValueError when data passed in are invalid
        """

        if not ('@' in parseaddr(email)[1]):
            raise ValueError('invalid email: {}'.format(email))
        if '' == name or name is None:
            raise ValueError('empty name')
        if '' == subject or subject is None:
            raise ValueError('empty subject')
        if '' == description or description is None:
            raise ValueError('empty description')
        if '' == businessImpact or businessImpact is None:
            raise ValueError('empty business impact')
        if priority is None:
            raise ValueError('Ensure the priority is from the set of '
                             'known priorities')
        if '' == phone or phone is None:
            raise ValueError('empty phone')

        try:
            r = requests.post(self.url,
                              data={
                                  'orgid': self.orgId,
                                  'recordType': self.recordType,
                                  'name': name,
                                  'email': email,
                                  'subject': subject,
                                  'description': description,
                                  self.BUSINESS_IMPACT: businessImpact,
                                  'priority': priority,
                                  'phone': phone,
                                  'external': 1
                              },
                              timeout=self.timeout)
            r.raise_for_status()
        except Timeout:
            message = 'Request timed out: {url} timeout: {timeout}'
            message = message.format(url=self.url, timeout=self.timeout)
            log.error(message)
            raise ServerError(message)
        except RequestException as err:
            log.info('cannot create case: {}'.format(err))
            raise ServerError('cannot create case: {}'.format(err))
Exemple #4
0
    def list_wallets(self):
        """Get the list of wallets.

        @return an dict containing a list of wallets, a total, and available
            credit.
        @raise ServerError
        """
        response = make_request(
            '{}wallet'.format(self.url),
            timeout=self.timeout,
            client=self._client)
        try:
            total = response['total']
            return {
                'credit': response['credit'],
                'total': WalletTotal(
                    limit=total['limit'],
                    budgeted=total['budgeted'],
                    available=total['available'],
                    unallocated=total['unallocated'],
                    usage=total['usage'],
                    consumed=total['consumed']),
                'wallets': tuple(Wallet(
                    owner=wallet['owner'],
                    wallet=wallet['wallet'],
                    limit=wallet['limit'],
                    budgeted=wallet['budgeted'],
                    unallocated=wallet['unallocated'],
                    available=wallet['available'],
                    consumed=wallet['consumed'],
                    default='default' in wallet)
                    for wallet in response['wallets']),
            }
        except Exception as err:
            log.error(
                'cannot process wallets: invalid JSON response: {!r}'.format(
                    response))
            raise ServerError(
                'unable to get list of wallets: {!r}'.format(err))
Exemple #5
0
    def fetch_macaroon(self):
        """ Fetches the macaroon from the JIMM controller.

        @return The base64 encoded macaroon.
        """
        try:
            # We don't use make_request b/c we don't want the request to be
            # fully handled. This lets us get the macaroon out of the request
            # and keep it.
            url = "{}model".format(self.url)
            response = requests.get(url, timeout=self.timeout)
        except requests.exceptions.Timeout:
            message = 'Request timed out: {url} timeout: {timeout}'
            message = message.format(url=url, timeout=self.timeout)
            log.error(message)
            return None
        except Exception as e:
            log.info('Unable to contact JIMM due to: {}'.format(e))
            return None

        try:
            json_response = response.json()
        except ValueError:
            log.info(
                'cannot process macaroon: '
                'cannot unmarshal response: {!r}'.format(response.content))
            return None

        try:
            raw_macaroon = json_response['Info']['Macaroon']
        except (KeyError, TypeError):
            log.info(
                'cannot process macaroon: invalid JSON response: {!r}'.format(
                    json_response))
            return None

        return json.dumps(raw_macaroon)
Exemple #6
0
def make_request(url,
                 method='GET',
                 query=None,
                 body=None,
                 auth=None,
                 timeout=10,
                 client=None,
                 macaroons=None):
    """Make a request with the provided data.

    @param url The url to make the request to.
    @param method The HTTP request method (defaulting to "GET").
    @param query A dict of the query key and values.
    @param body The optional body as a string or as a JSON decoded dict.
    @param auth The optional username and password as a tuple,
    not used if client is not None
    @param timeout The request timeout in seconds, defaulting to 10 seconds.
    @param client (httpbakery.Client) holds a context for making http
    requests with macaroons.
    @param macaroons Optional JSON serialized, base64 encoded macaroons to be
        included in the request header.

    POST/PUT request bodies are assumed to be in JSON format.
    Return the response content as a JSON decoded object, or an empty dict.
    Raise a ServerError if a problem occurs in the request/response process.
    Raise a ValueError if invalid parameters are provided.
    """
    headers = {}
    kwargs = {'timeout': timeout, 'headers': headers}
    # Handle the request body.
    if body is not None:
        if isinstance(body, collections.Mapping):
            body = json.dumps(body)
        kwargs['data'] = body
    # Handle request methods.
    if method in ('GET', 'HEAD'):
        if query:
            url = '{}?{}'.format(url, urlencode(query, True))
    elif method in ('DELETE', 'PATCH', 'POST', 'PUT'):
        headers['Content-Type'] = 'application/json'
    else:
        raise ValueError('invalid method {}'.format(method))
    if macaroons is not None:
        headers['Macaroons'] = macaroons

    kwargs['auth'] = auth if client is None else client.auth()

    api_method = getattr(requests, method.lower())
    # Perform the request.
    try:
        response = api_method(url, **kwargs)
    except requests.exceptions.Timeout:
        raise timeout_error(url, timeout)
    except Exception as err:
        msg = _server_error_message(url, err)
        raise ServerError(msg)
    # Handle error responses.
    try:
        response.raise_for_status()
    except HTTPError as err:
        msg = _server_error_message(url, err.response.text)
        raise ServerError(err.response.status_code, msg)
    except requests.exceptions.RequestException as err:
        msg = _server_error_message(url, err.message)
        raise ServerError(msg)
    # Some requests just result in a status with no response body.
    if not response.content:
        return {}
    # Assume the response body is a JSON encoded string.
    try:
        return response.json()
    except Exception as err:
        msg = 'Error decoding JSON response: {} message: {}'.format(url, err)
        log.error(msg)
        raise ServerError(msg)
Exemple #7
0
def _server_error_message(url, message):
    """Log and return a server error message."""
    msg = _error_message.format(url=url, message=message)
    log.error(msg)
    return msg
Exemple #8
0
def make_request(
        url, method='GET', query=None, body=None, auth=None, macaroons=None,
        timeout=10):
    """Make a request with the provided data.

    @param url The url to make the request to.
    @param method The HTTP request method (defaulting to "GET").
    @param query A dict of the query key and values.
    @param body The optional body as a string or as a JSON decoded dict.
    @param auth The optional username and password as a tuple.
    @param timeout The request timeout in seconds, defaulting to 10 seconds.

    POST/PUT request bodies are assumed to be in JSON format.
    Return the response content as a JSON decoded object, or an empty dict.
    Raise a ServerError if a problem occurs in the request/response process.
    Raise a ValueError if invalid parameters are provided.
    """
    kwargs = {'auth': auth, 'timeout': timeout, 'headers': {}}
    # Handle the request body.
    if body is not None:
        if isinstance(body, collections.Mapping):
            body = json.dumps(body)
        kwargs['data'] = body
    # Handle request methods.
    if method in ('GET', 'HEAD'):
        if query:
            url = '{}?{}'.format(url, urlencode(query, True))
    elif method in ('POST', 'PUT'):
        kwargs['headers'] = {'Content-Type': 'application/json'}
    else:
        raise ValueError('invalid method {}'.format(method))
    if macaroons is not None:
        kwargs['headers']['Bakery-Protocol-Version'] = 1
        kwargs['headers']['Macaroons'] = macaroons
    api_method = getattr(requests, method.lower())
    # Perform the request.
    try:
        response = api_method(url, **kwargs)
    except requests.exceptions.Timeout:
        raise timeout_error(url, timeout)
    except Exception as err:
        msg = _server_error_message(url, err)
        raise ServerError(msg)
    # Handle error responses.
    try:
        response.raise_for_status()
    except HTTPError as err:
        msg = _server_error_message(url, err.response.text)
        raise ServerError(err.response.status_code, msg)
    except requests.exceptions.RequestException as err:
        msg = _server_error_message(url, err.message)
        raise ServerError(msg)
    # Some requests just result in a status with no response body.
    if not response.content:
        return {}
    # Assume the response body is a JSON encoded string.
    try:
        return response.json()
    except Exception as err:
        msg = 'Error decoding JSON response: {} message: {}'.format(url, err)
        log.error(msg)
        raise ServerError(msg)
Exemple #9
0
def _server_error_message(url, message):
    """Log and return a server error message."""
    msg = _error_message.format(url=url, message=message)
    log.error(msg)
    return msg