summaryrefslogtreecommitdiff
path: root/quantumclient/client.py
diff options
context:
space:
mode:
Diffstat (limited to 'quantumclient/client.py')
-rw-r--r--quantumclient/client.py250
1 files changed, 2 insertions, 248 deletions
diff --git a/quantumclient/client.py b/quantumclient/client.py
index a4669c4..b816bee 100644
--- a/quantumclient/client.py
+++ b/quantumclient/client.py
@@ -1,249 +1,3 @@
-# Copyright 2012 OpenStack LLC.
-# All Rights Reserved
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
+from neutronclient import client
-try:
- import json
-except ImportError:
- import simplejson as json
-import logging
-import os
-import urlparse
-# Python 2.5 compat fix
-if not hasattr(urlparse, 'parse_qsl'):
- import cgi
- urlparse.parse_qsl = cgi.parse_qsl
-
-import httplib2
-
-from quantumclient.common import exceptions
-from quantumclient.common import utils
-
-_logger = logging.getLogger(__name__)
-
-if 'QUANTUMCLIENT_DEBUG' in os.environ and os.environ['QUANTUMCLIENT_DEBUG']:
- ch = logging.StreamHandler()
- _logger.setLevel(logging.DEBUG)
- _logger.addHandler(ch)
-
-
-class ServiceCatalog(object):
- """Helper methods for dealing with a Keystone Service Catalog."""
-
- def __init__(self, resource_dict):
- self.catalog = resource_dict
-
- def get_token(self):
- """Fetch token details fron service catalog."""
- token = {'id': self.catalog['access']['token']['id'],
- 'expires': self.catalog['access']['token']['expires'], }
- try:
- token['user_id'] = self.catalog['access']['user']['id']
- token['tenant_id'] = (
- self.catalog['access']['token']['tenant']['id'])
- except Exception:
- # just leave the tenant and user out if it doesn't exist
- pass
- return token
-
- def url_for(self, attr=None, filter_value=None,
- service_type='network', endpoint_type='publicURL'):
- """Fetch the URL from the Quantum service for
- a particular endpoint type. If none given, return
- publicURL.
- """
-
- catalog = self.catalog['access'].get('serviceCatalog', [])
- matching_endpoints = []
- for service in catalog:
- if service['type'] != service_type:
- continue
-
- endpoints = service['endpoints']
- for endpoint in endpoints:
- if not filter_value or endpoint.get(attr) == filter_value:
- matching_endpoints.append(endpoint)
-
- if not matching_endpoints:
- raise exceptions.EndpointNotFound()
- elif len(matching_endpoints) > 1:
- raise exceptions.AmbiguousEndpoints(message=matching_endpoints)
- else:
- if endpoint_type not in matching_endpoints[0]:
- raise exceptions.EndpointTypeNotFound(message=endpoint_type)
-
- return matching_endpoints[0][endpoint_type]
-
-
-class HTTPClient(httplib2.Http):
- """Handles the REST calls and responses, include authn."""
-
- USER_AGENT = 'python-quantumclient'
-
- def __init__(self, username=None, tenant_name=None,
- password=None, auth_url=None,
- token=None, region_name=None, timeout=None,
- endpoint_url=None, insecure=False,
- endpoint_type='publicURL',
- auth_strategy='keystone', **kwargs):
- super(HTTPClient, self).__init__(timeout=timeout)
- self.username = username
- self.tenant_name = tenant_name
- self.password = password
- self.auth_url = auth_url.rstrip('/') if auth_url else None
- self.endpoint_type = endpoint_type
- self.region_name = region_name
- self.auth_token = token
- self.content_type = 'application/json'
- self.endpoint_url = endpoint_url
- self.auth_strategy = auth_strategy
- # httplib2 overrides
- self.force_exception_to_status_code = True
- self.disable_ssl_certificate_validation = insecure
-
- def _cs_request(self, *args, **kwargs):
- kargs = {}
- kargs.setdefault('headers', kwargs.get('headers', {}))
- kargs['headers']['User-Agent'] = self.USER_AGENT
-
- if 'content_type' in kwargs:
- kargs['headers']['Content-Type'] = kwargs['content_type']
- kargs['headers']['Accept'] = kwargs['content_type']
- else:
- kargs['headers']['Content-Type'] = self.content_type
- kargs['headers']['Accept'] = self.content_type
-
- if 'body' in kwargs:
- kargs['body'] = kwargs['body']
- args = utils.safe_encode_list(args)
- kargs = utils.safe_encode_dict(kargs)
- utils.http_log_req(_logger, args, kargs)
- resp, body = self.request(*args, **kargs)
- utils.http_log_resp(_logger, resp, body)
- status_code = self.get_status_code(resp)
- if status_code == 401:
- raise exceptions.Unauthorized(message=body)
- elif status_code == 403:
- raise exceptions.Forbidden(message=body)
- return resp, body
-
- def authenticate_and_fetch_endpoint_url(self):
- if not self.auth_token:
- self.authenticate()
- elif not self.endpoint_url:
- self.endpoint_url = self._get_endpoint_url()
-
- def do_request(self, url, method, **kwargs):
- self.authenticate_and_fetch_endpoint_url()
- # Perform the request once. If we get a 401 back then it
- # might be because the auth token expired, so try to
- # re-authenticate and try again. If it still fails, bail.
- try:
- kwargs.setdefault('headers', {})
- kwargs['headers']['X-Auth-Token'] = self.auth_token
- resp, body = self._cs_request(self.endpoint_url + url, method,
- **kwargs)
- return resp, body
- except exceptions.Unauthorized:
- self.authenticate()
- kwargs.setdefault('headers', {})
- kwargs['headers']['X-Auth-Token'] = self.auth_token
- resp, body = self._cs_request(
- self.endpoint_url + url, method, **kwargs)
- return resp, body
-
- def _extract_service_catalog(self, body):
- """Set the client's service catalog from the response data."""
- self.service_catalog = ServiceCatalog(body)
- try:
- sc = self.service_catalog.get_token()
- self.auth_token = sc['id']
- self.auth_tenant_id = sc.get('tenant_id')
- self.auth_user_id = sc.get('user_id')
- except KeyError:
- raise exceptions.Unauthorized()
- self.endpoint_url = self.service_catalog.url_for(
- attr='region', filter_value=self.region_name,
- endpoint_type=self.endpoint_type)
-
- def authenticate(self):
- if self.auth_strategy != 'keystone':
- raise exceptions.Unauthorized(message='unknown auth strategy')
- body = {'auth': {'passwordCredentials':
- {'username': self.username,
- 'password': self.password, },
- 'tenantName': self.tenant_name, }, }
-
- token_url = self.auth_url + "/tokens"
-
- # Make sure we follow redirects when trying to reach Keystone
- tmp_follow_all_redirects = self.follow_all_redirects
- self.follow_all_redirects = True
- try:
- resp, body = self._cs_request(token_url, "POST",
- body=json.dumps(body),
- content_type="application/json")
- finally:
- self.follow_all_redirects = tmp_follow_all_redirects
- status_code = self.get_status_code(resp)
- if status_code != 200:
- raise exceptions.Unauthorized(message=body)
- if body:
- try:
- body = json.loads(body)
- except ValueError:
- pass
- else:
- body = None
- self._extract_service_catalog(body)
-
- def _get_endpoint_url(self):
- url = self.auth_url + '/tokens/%s/endpoints' % self.auth_token
- try:
- resp, body = self._cs_request(url, "GET")
- except exceptions.Unauthorized:
- # rollback to authenticate() to handle case when quantum client
- # is initialized just before the token is expired
- self.authenticate()
- return self.endpoint_url
-
- body = json.loads(body)
- for endpoint in body.get('endpoints', []):
- if (endpoint['type'] == 'network' and
- endpoint.get('region') == self.region_name):
- if self.endpoint_type not in endpoint:
- raise exceptions.EndpointTypeNotFound(
- message=self.endpoint_type)
- return endpoint[self.endpoint_type]
-
- raise exceptions.EndpointNotFound()
-
- def get_auth_info(self):
- return {'auth_token': self.auth_token,
- 'auth_tenant_id': self.auth_tenant_id,
- 'auth_user_id': self.auth_user_id,
- 'endpoint_url': self.endpoint_url}
-
- def get_status_code(self, response):
- """Returns the integer status code from the response.
-
- Either a Webob.Response (used in testing) or httplib.Response
- is returned.
- """
- if hasattr(response, 'status_int'):
- return response.status_int
- else:
- return response.status
+HTTPClient = client.HTTPClient