Fix authentication and service endpoint fetching

Make the client library take environment variables by default
This commit is contained in:
Arash Ghoreyshi
2013-06-20 16:47:38 -05:00
parent 02b130c822
commit 99f6d9f367
3 changed files with 80 additions and 43 deletions

View File

@@ -2,6 +2,7 @@ import eventlet
eventlet.monkey_patch(socket=True, select=True)
import json
import os
import requests
from barbicanclient.secrets import Secret
@@ -22,24 +23,36 @@ class Connection(object):
SECRETS_PATH = 'secrets'
ORDERS_PATH = 'orders'
def __init__(self, auth_endpoint, user, key, tenant,
token=None, authenticate=None, request=None, **kwargs):
def __init__(self, auth_endpoint=None, user=None, key=None, tenant=None,
token=None, authenticate=None, request=None, fake_env=None,
**kwargs):
"""
Authenticate and connect to the endpoint
:param auth_endpoint: The auth URL to authenticate against
default: env('OS_AUTH_URL')
:param user: The user to authenticate as
default: env('OS_USERNAME')
:param key: The API key or password to auth with
default: env('OS_PASSWORD')
:param tenant: The tenant ID
default: env('OS_TENANT_NAME')
"""
LOG.debug(_("Creating Connection object"))
self._auth_endpoint = auth_endpoint
self.env = fake_env or env
self._auth_endpoint = auth_endpoint or self.env('OS_AUTH_URL')
self._user = user or self.env('OS_USERNAME')
self._key = key or self.env('OS_PASSWORD')
self._tenant = tenant or self.env('OS_TENANT_NAME')
if not all([self._auth_endpoint, self._user, self._key, self._tenant]):
raise ClientException("The authorization endpoint, username, key,"
" and tenant name should either be passed i"
"n or defined as environment variables.")
self.authenticate = authenticate or auth.authenticate
self.request = request or requests.request
self._user = user
self._key = key
self._tenant = tenant
self._endpoint = (kwargs.get('endpoint')
or 'https://barbican.api.rackspacecloud.com/v1/')
self._endpoint = kwargs.get('endpoint')
self._cacert = kwargs.get('cacert')
self.connect(token=token)
@@ -47,8 +60,7 @@ class Connection(object):
@property
def _conn(self):
"""
Property to enable decorators to work
properly
Property to enable decorators to work properly
"""
return self
@@ -62,6 +74,10 @@ class Connection(object):
"""The fully-qualified URI of the endpoint"""
return self._endpoint
@endpoint.setter
def endpoint(self, value):
self._endpoint = value
def connect(self, token=None):
"""
Establishes a connection. If token is not None the
@@ -81,11 +97,12 @@ class Connection(object):
self.auth_token = token
else:
LOG.debug(_("Authenticating token"))
self._endpoint, self.auth_token = self.authenticate(
self.endpoint, self.auth_token = self.authenticate(
self._auth_endpoint,
self._user,
self._key,
self._tenant,
service_type='key-store',
endpoint=self._endpoint,
cacert=self._cacert
)
@@ -149,7 +166,7 @@ class Connection(object):
cypher_type=None,
expiration=None):
"""
Creates and returns a Secret object with all of its metadata filled in.
Creates and returns an Order object with all of its metadata filled in.
arguments:
mime_type - The MIME type of the secret
@@ -356,11 +373,15 @@ class Connection(object):
if not isinstance(request_body, str):
request_body = json.dumps(request_body)
url = urljoin(self._endpoint, href)
if not self.endpoint.endswith('/'):
self.endpoint += '/'
url = urljoin(self.endpoint, href)
headers['X-Auth-Token'] = self.auth_token
response = self.request(method=method, url=url, data=request_body,
headers=headers)
# Check if the status code is 2xx class
if not response.ok:
LOG.error('Bad response: {0}'.format(response.status_code))
@@ -376,3 +397,18 @@ class Connection(object):
resp_body = ''
return response.headers, resp_body
def env(*vars, **kwargs):
"""Search for the first defined of possibly many env vars
Returns the first environment variable defined in vars, or
returns the default defined in kwargs.
Source: Keystone's shell.py
"""
for v in vars:
value = os.environ.get(v, None)
if value:
return value
return kwargs.get('default', '')

41
keep
View File

@@ -1,7 +1,6 @@
#!/usr/bin/env python
import argparse
import os
from barbicanclient import client
@@ -24,23 +23,26 @@ class Keep:
choices=["order", "secret"],
help="type to operate on")
parser.add_argument('--auth_endpoint', '-A',
default=env('OS_AUTH_URL'),
default=client.env('OS_AUTH_URL'),
help='the URL to authenticate against (default: '
'%(default)s)')
parser.add_argument('--user', '-U', default=env('OS_USERNAME'),
parser.add_argument('--user', '-U', default=client.env('OS_USERNAME'),
help='the user to authenticate as (default: %(de'
'fault)s)')
parser.add_argument('--password', '-P', default=env('OS_PASSWORD'),
parser.add_argument('--password', '-P',
default=client.env('OS_PASSWORD'),
help='the API key or password to authenticate with'
' (default: %(default)s)')
parser.add_argument('--tenant', '-T', default=env('OS_TENANT_NAME'),
parser.add_argument('--tenant', '-T',
default=client.env('OS_TENANT_NAME'),
help='the tenant ID (default: %(default)s)')
parser.add_argument('--endpoint', '-E', default=env('SERVICE_ENDPOINT')
, help='the URL of the barbican server (default: %'
parser.add_argument('--endpoint', '-E',
default=client.env('SERVICE_ENDPOINT'),
help='the URL of the barbican server (default: %'
'(default)s)')
parser.add_argument('--token', '-K', default=env('SERVICE_TOKEN'),
help='the authentication token (default: %(default'
')s)')
parser.add_argument('--token', '-K',
default=client.env('SERVICE_TOKEN'), help='the au'
'thentication token (default: %(default)s)')
return parser
def add_create_args(self):
@@ -149,8 +151,8 @@ class Keep:
l = self.conn.list_orders(args.limit, args.offset)
for i in l[0]:
print i
print 'Displayed {0} {1}s - offset: {2}'.format(len(l[0]), args.type,
args.offset)
print '{0}s displayed: {1} - offset: {2}'.format(args.type, len(l[0]),
args.offset)
def execute(self):
args = self.parser.parse_args()
@@ -161,21 +163,6 @@ class Keep:
args.func(args)
def env(*vars, **kwargs):
"""Search for the first defined of possibly many env vars
Returns the first environment variable defined in vars, or
returns the default defined in kwargs.
Source: Keystone's shell.py
"""
for v in vars:
value = os.environ.get(v, None)
if value:
return value
return kwargs.get('default', '')
def main():
k = Keep()
k.execute()

View File

@@ -40,6 +40,8 @@ class WhenTestingConnection(unittest.TestCase):
self.auth_token = 'token'
self.href = 'http://localhost:9311/v1/12345/orders'
self.fake_env = MagicMock()
self.fake_env.return_value = None
self.authenticate = MagicMock()
self.authenticate.return_value = (self.endpoint, self.auth_token)
self.request = MagicMock()
@@ -62,7 +64,8 @@ class WhenTestingConnection(unittest.TestCase):
self.key, self.tenant,
token=self.auth_token,
authenticate=self.authenticate,
request=self.request)
request=self.request,
endpoint=self.endpoint)
def test_should_connect_with_token(self):
self.assertFalse(self.authenticate.called)
@@ -79,6 +82,7 @@ class WhenTestingConnection(unittest.TestCase):
self.user,
self.key,
self.tenant,
service_type='key-store',
endpoint=self.endpoint,
cacert=None
)
@@ -89,6 +93,16 @@ class WhenTestingConnection(unittest.TestCase):
self.assertEqual(self.tenant, self.connection._tenant)
self.assertEqual(self.endpoint, self.connection._endpoint)
def test_should_raise_for_bad_args(self):
with self.assertRaises(ClientException):
self.connection = client.Connection(None, self.user,
self.key, self.tenant,
fake_env=self.fake_env,
token=self.auth_token,
authenticate=self.authenticate,
request=self.request,
endpoint=self.endpoint)
def test_should_create_secret(self):
body = {'status': 'ACTIVE',
'content_types': {'default': 'text/plain'},
@@ -318,7 +332,7 @@ class WhenTestingConnection(unittest.TestCase):
parse_json=False)
self.assertEqual(self.request.return_value.content, body)
def test_should_raise_exception(self):
def test_should_raise_for_bad_response(self):
self._setup_request()
self.request.return_value.ok = False
self.request.return_value.status_code = 404