diff options
author | Steven Hardy <shardy@redhat.com> | 2013-11-19 16:42:49 +0000 |
---|---|---|
committer | Steven Hardy <shardy@redhat.com> | 2013-11-27 19:13:06 +0000 |
commit | fe3629f1bab78664498192efcc9d782d061459f1 (patch) | |
tree | 6436cf3356ea54b971b7263b5b4b7dbcf81e8765 | |
parent | a7ba3c323b16227e0ba2527f21bc89625f125234 (diff) | |
download | python-heatclient-fe3629f1bab78664498192efcc9d782d061459f1.tar.gz |
Fix shell operation with --os-auth-token
Currently the --os-auth-token/env[OS_AUTH_TOKEN] case doesn't
work, as we always expect a username/password to create the
connection to keystone. This enables the client to be used
with only a token and tenant (which is required for keystoneclient
to retrieve the catalog) specified, e.g:
heat --os-auth-url http://127.0.0.1:35357/v2.0/ \
--os-auth-token <a keystone token> \
--os-tenant-id <tenant ID> stack-list
Change-Id: I478ce178f44e42c68153f1b347c6144f0a133f5b
Partial-Bug: #1252248
-rw-r--r-- | heatclient/shell.py | 30 | ||||
-rw-r--r-- | heatclient/tests/fakes.py | 19 | ||||
-rw-r--r-- | heatclient/tests/test_shell.py | 108 |
3 files changed, 118 insertions, 39 deletions
diff --git a/heatclient/shell.py b/heatclient/shell.py index 56ce087..b254964 100644 --- a/heatclient/shell.py +++ b/heatclient/shell.py @@ -219,15 +219,22 @@ class HeatShell(object): :param tenant_id: unique identifier of tenant :param tenant_name: name of tenant :param auth_url: endpoint to authenticate against + :param token: token to use instead of username/password """ kc_args = {'auth_url': kwargs.get('auth_url'), - 'insecure': kwargs.get('insecure'), - 'username': kwargs.get('username'), - 'password': kwargs.get('password')} + 'insecure': kwargs.get('insecure')} + if kwargs.get('tenant_id'): kc_args['tenant_id'] = kwargs.get('tenant_id') else: kc_args['tenant_name'] = kwargs.get('tenant_name') + + if kwargs.get('token'): + kc_args['token'] = kwargs.get('token') + else: + kc_args['username'] = kwargs.get('username') + kc_args['password'] = kwargs.get('password') + return ksclient.Client(**kc_args) def _get_endpoint(self, client, **kwargs): @@ -280,18 +287,22 @@ class HeatShell(object): self.do_help(args) return 0 - if not args.os_username: + if not args.os_username and not args.os_auth_token: raise exc.CommandError("You must provide a username via" - " either --os-username or env[OS_USERNAME]") + " either --os-username or env[OS_USERNAME]" + " or a token via --os-auth-token or" + " env[OS_AUTH_TOKEN]") - if not args.os_password: + if not args.os_password and not args.os_auth_token: raise exc.CommandError("You must provide a password via" - " either --os-password or env[OS_PASSWORD]") + " either --os-password or env[OS_PASSWORD]" + " or a token via --os-auth-token or" + " env[OS_AUTH_TOKEN]") if not (args.os_tenant_id or args.os_tenant_name): raise exc.CommandError("You must provide a tenant_id via" - " either --os-tenant-id or via " - "env[OS_TENANT_ID]") + " either --os-tenant-id or via" + " env[OS_TENANT_ID]") if not args.os_auth_url: raise exc.CommandError("You must provide an auth url via" @@ -305,6 +316,7 @@ class HeatShell(object): kwargs = { 'username': args.os_username, 'password': args.os_password, + 'token': args.os_auth_token, 'tenant_id': args.os_tenant_id, 'tenant_name': args.os_tenant_name, 'auth_url': args.os_auth_url, diff --git a/heatclient/tests/fakes.py b/heatclient/tests/fakes.py index 51ef8fa..c6c3db3 100644 --- a/heatclient/tests/fakes.py +++ b/heatclient/tests/fakes.py @@ -18,12 +18,19 @@ from heatclient.v1 import client as v1client from keystoneclient.v2_0 import client as ksclient -def script_keystone_client(): - ksclient.Client(auth_url='http://no.where', - insecure=False, - password='password', - tenant_name='tenant_name', - username='username').AndReturn(FakeKeystone('abcd1234')) +def script_keystone_client(token=None): + if token: + ksclient.Client(auth_url='http://no.where', + insecure=False, + tenant_id='tenant_id', + token=token).AndReturn(FakeKeystone(token)) + else: + ksclient.Client(auth_url='http://no.where', + insecure=False, + password='password', + tenant_name='tenant_name', + username='username').AndReturn(FakeKeystone( + 'abcd1234')) def script_heat_list(): diff --git a/heatclient/tests/test_shell.py b/heatclient/tests/test_shell.py index 26805b1..c902011 100644 --- a/heatclient/tests/test_shell.py +++ b/heatclient/tests/test_shell.py @@ -114,6 +114,29 @@ class EnvVarTest(TestCase): self.shell_error('list', self.err) +class EnvVarTestToken(TestCase): + + scenarios = [ + ('tenant_id', dict( + remove='OS_TENANT_ID', + err='You must provide a tenant_id')), + ('auth_url', dict( + remove='OS_AUTH_URL', + err='You must provide an auth url')), + ] + + def test_missing_auth(self): + + fake_env = { + 'OS_AUTH_TOKEN': 'atoken', + 'OS_TENANT_ID': 'tenant_id', + 'OS_AUTH_URL': 'http://no.where', + } + fake_env[self.remove] = None + self.set_fake_env(fake_env) + self.shell_error('list', self.err) + + class ShellParamValidationTest(TestCase): scenarios = [ @@ -208,24 +231,16 @@ class ShellValidationTest(TestCase): 'Need to specify exactly one of') -class ShellTest(TestCase): +class ShellBase(TestCase): - # Patch os.environ to avoid required auth info. def setUp(self): - super(ShellTest, self).setUp() + super(ShellBase, self).setUp() self.m = mox.Mox() self.m.StubOutWithMock(ksclient, 'Client') self.m.StubOutWithMock(v1client.Client, 'json_request') self.m.StubOutWithMock(v1client.Client, 'raw_request') self.addCleanup(self.m.VerifyAll) self.addCleanup(self.m.UnsetStubs) - fake_env = { - 'OS_USERNAME': 'username', - 'OS_PASSWORD': 'password', - 'OS_TENANT_NAME': 'tenant_name', - 'OS_AUTH_URL': 'http://no.where', - } - self.set_fake_env(fake_env) # Some tests set exc.verbose = 1, so reset on cleanup def unset_exc_verbose(): @@ -249,6 +264,12 @@ class ShellTest(TestCase): return out + +class ShellTestCommon(ShellBase): + + def setUp(self): + super(ShellTestCommon, self).setUp() + def test_help_unknown_command(self): self.assertRaises(exc.CommandError, self.shell, 'help foofoo') @@ -280,8 +301,28 @@ class ShellTest(TestCase): for r in required: self.assertRegexpMatches(help_text, r) - def test_list(self): + +class ShellTestUserPass(ShellBase): + + def setUp(self): + super(ShellTestUserPass, self).setUp() + self._set_fake_env() + + # Patch os.environ to avoid required auth info. + def _set_fake_env(self): + fake_env = { + 'OS_USERNAME': 'username', + 'OS_PASSWORD': 'password', + 'OS_TENANT_NAME': 'tenant_name', + 'OS_AUTH_URL': 'http://no.where', + } + self.set_fake_env(fake_env) + + def _script_keystone_client(self): fakes.script_keystone_client() + + def test_list(self): + self._script_keystone_client() fakes.script_heat_list() self.m.ReplayAll() @@ -313,7 +354,7 @@ class ShellTest(TestCase): "title": "Not Found" } - fakes.script_keystone_client() + self._script_keystone_client() fakes.script_heat_error(json.dumps(resp_dict)) self.m.ReplayAll() @@ -336,7 +377,7 @@ class ShellTest(TestCase): "title": "Not Found" } - fakes.script_keystone_client() + self._script_keystone_client() fakes.script_heat_error(json.dumps(resp_dict)) self.m.ReplayAll() @@ -351,7 +392,7 @@ class ShellTest(TestCase): def test_parsable_malformed_error(self): invalid_json = "ERROR: {Invalid JSON Error." - fakes.script_keystone_client() + self._script_keystone_client() fakes.script_heat_error(invalid_json) self.m.ReplayAll() @@ -371,7 +412,7 @@ class ShellTest(TestCase): "title": "Not Found" } - fakes.script_keystone_client() + self._script_keystone_client() fakes.script_heat_error(json.dumps(missing_message)) self.m.ReplayAll() @@ -392,7 +433,7 @@ class ShellTest(TestCase): "title": "Not Found" } - fakes.script_keystone_client() + self._script_keystone_client() fakes.script_heat_error(json.dumps(resp_dict)) self.m.ReplayAll() @@ -405,7 +446,7 @@ class ShellTest(TestCase): "ERROR: The Stack (bad) could not be found.\n") def test_describe(self): - fakes.script_keystone_client() + self._script_keystone_client() resp_dict = {"stack": { "id": "1", "stack_name": "teststack", @@ -437,7 +478,7 @@ class ShellTest(TestCase): self.assertRegexpMatches(list_text, r) def test_template_show_cfn(self): - fakes.script_keystone_client() + self._script_keystone_client() template_data = open(os.path.join(TEST_VAR_DIR, 'minimal.template')).read() resp = fakes.FakeHTTPResponse( @@ -464,7 +505,7 @@ class ShellTest(TestCase): self.assertRegexpMatches(show_text, r) def test_template_show_hot(self): - fakes.script_keystone_client() + self._script_keystone_client() resp_dict = {"heat_template_version": "2013-05-23", "parameters": {}, "resources": {}, @@ -490,7 +531,7 @@ class ShellTest(TestCase): self.assertRegexpMatches(show_text, r) def test_create(self): - fakes.script_keystone_client() + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 201, 'Created', @@ -523,7 +564,7 @@ class ShellTest(TestCase): def test_create_url(self): - fakes.script_keystone_client() + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 201, 'Created', @@ -554,7 +595,7 @@ class ShellTest(TestCase): def test_create_object(self): - fakes.script_keystone_client() + self._script_keystone_client() template_file = os.path.join(TEST_VAR_DIR, 'minimal.template') template_data = open(template_file).read() v1client.Client.raw_request( @@ -592,7 +633,7 @@ class ShellTest(TestCase): self.assertRegexpMatches(create_text, r) def test_update(self): - fakes.script_keystone_client() + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 202, 'Accepted', @@ -624,7 +665,7 @@ class ShellTest(TestCase): self.assertRegexpMatches(create_text, r) def test_delete(self): - fakes.script_keystone_client() + self._script_keystone_client() resp = fakes.FakeHTTPResponse( 204, 'No Content', @@ -649,6 +690,25 @@ class ShellTest(TestCase): self.assertRegexpMatches(create_text, r) +class ShellTestToken(ShellTestUserPass): + + # Rerun all ShellTestUserPass test with token auth + def setUp(self): + self.token = 'a_token' + super(ShellTestToken, self).setUp() + + def _set_fake_env(self): + fake_env = { + 'OS_AUTH_TOKEN': self.token, + 'OS_TENANT_ID': 'tenant_id', + 'OS_AUTH_URL': 'http://no.where', + } + self.set_fake_env(fake_env) + + def _script_keystone_client(self): + fakes.script_keystone_client(token=self.token) + + class ShellEnvironmentTest(TestCase): def setUp(self): |