From: Steve Baker Date: Fri, 5 Jul 2013 04:08:13 +0000 (+1200) Subject: Only use a token for openstack client operations. X-Git-Tag: 2014.1~331^2 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=f77195cb6876227b456920cd917a688409c11fdf;p=openstack-build%2Fheat-build.git Only use a token for openstack client operations. This uses the same techniques as horizon for getting client instances with an existing token. This change also fetches a new auth_token if the context has none, as will happen when the context is created from saved user_creds rather than a real request. While it appears that some code paths will result in an extra call to the keystone client, the actual calls to keystone will be less. This is because each client was making its own calls to keystone when authenticating with a username and password. Implements blueprint auth-token-only Change-Id: If6a63a5079464758f42d5d5e83dfffb196f4a7f6 --- diff --git a/heat/common/heat_keystoneclient.py b/heat/common/heat_keystoneclient.py index 737a2529..978b3ce9 100644 --- a/heat/common/heat_keystoneclient.py +++ b/heat/common/heat_keystoneclient.py @@ -154,3 +154,7 @@ class KeystoneClient(object): def url_for(self, **kwargs): return self.client.service_catalog.url_for(**kwargs) + + @property + def auth_token(self): + return self.client.auth_token diff --git a/heat/engine/clients.py b/heat/engine/clients.py index 22301d5a..05cbcaf7 100644 --- a/heat/engine/clients.py +++ b/heat/engine/clients.py @@ -61,6 +61,12 @@ class OpenStackClients(object): self._quantum = None self._cinder = None + @property + def auth_token(self): + # if there is no auth token in the context + # attempt to get one using the context username and password + return self.context.auth_token or self.keystone().auth_token + def keystone(self): if self._keystone: return self._keystone @@ -76,28 +82,23 @@ class OpenStackClients(object): return self._nova[service_type] con = self.context + if self.auth_token is None: + logger.error("Nova connection failed, no auth_token!") + return None + args = { 'project_id': con.tenant, 'auth_url': con.auth_url, 'service_type': service_type, + 'username': None, + 'api_key': None } - if con.password is not None: - args['username'] = con.username - args['api_key'] = con.password - elif con.auth_token is not None: - args['username'] = None - args['api_key'] = None - else: - logger.error("Nova connection failed, no password or auth_token!") - return None - client = novaclient.Client(1.1, **args) - if con.password is None and con.auth_token is not None: - management_url = self.url_for(service_type=service_type) - client.client.auth_token = con.auth_token - client.client.management_url = management_url + management_url = self.url_for(service_type=service_type) + client.client.auth_token = self.auth_token + client.client.management_url = management_url self._nova[service_type] = client return client @@ -109,24 +110,19 @@ class OpenStackClients(object): return self._swift con = self.context + if self.auth_token is None: + logger.error("Swift connection failed, no auth_token!") + return None + args = { 'auth_version': '2.0', 'tenant_name': con.tenant, - 'user': con.username + 'user': con.username, + 'key': None, + 'authurl': None, + 'preauthtoken': self.auth_token, + 'preauthurl': self.url_for(service_type='object-store') } - - if con.password is not None: - args['key'] = con.password - args['authurl'] = con.auth_url - elif con.auth_token is not None: - args['key'] = None - args['authurl'] = None - args['preauthtoken'] = con.auth_token - args['preauthurl'] = self.url_for(service_type='object-store') - else: - logger.error("Swift connection failed, no password or " + - "auth_token!") - return None self._swift = swiftclient.Connection(**args) return self._swift @@ -134,28 +130,20 @@ class OpenStackClients(object): if quantumclient is None: return None if self._quantum: - logger.debug('using existing _quantum') return self._quantum con = self.context + if self.auth_token is None: + logger.error("Quantum connection failed, no auth_token!") + return None + args = { 'auth_url': con.auth_url, 'service_type': 'network', + 'token': self.auth_token, + 'endpoint_url': self.url_for(service_type='network') } - if con.password is not None: - args['username'] = con.username - args['password'] = con.password - args['tenant_name'] = con.tenant - elif con.auth_token is not None: - args['token'] = con.auth_token - args['endpoint_url'] = self.url_for(service_type='network') - else: - logger.error("Quantum connection failed, " - "no password or auth_token!") - return None - logger.debug('quantum args %s', args) - self._quantum = quantumclient.Client(**args) return self._quantum @@ -167,29 +155,22 @@ class OpenStackClients(object): return self._cinder con = self.context + if self.auth_token is None: + logger.error("Cinder connection failed, no auth_token!") + return None + args = { 'service_type': 'volume', 'auth_url': con.auth_url, - 'project_id': con.tenant + 'project_id': con.tenant, + 'username': None, + 'api_key': None } - if con.password is not None: - args['username'] = con.username - args['api_key'] = con.password - elif con.auth_token is not None: - args['username'] = None - args['api_key'] = None - else: - logger.error("Cinder connection failed, " - "no password or auth_token!") - return None - logger.debug('cinder args %s', args) - self._cinder = cinderclient.Client('1', **args) - if con.password is None and con.auth_token is not None: - management_url = self.url_for(service_type='volume') - self._cinder.client.auth_token = con.auth_token - self._cinder.client.management_url = management_url + management_url = self.url_for(service_type='volume') + self._cinder.client.auth_token = self.auth_token + self._cinder.client.management_url = management_url return self._cinder diff --git a/heat/tests/fakes.py b/heat/tests/fakes.py index 0833f2fe..5fb92fb6 100644 --- a/heat/tests/fakes.py +++ b/heat/tests/fakes.py @@ -105,6 +105,7 @@ class FakeKeystoneClient(): self.access = access self.secret = secret self.creds = None + self.auth_token = 'abcd1234' def create_stack_user(self, username, password=''): self.username = username diff --git a/heat/tests/test_parser.py b/heat/tests/test_parser.py index 5316be8d..04958258 100644 --- a/heat/tests/test_parser.py +++ b/heat/tests/test_parser.py @@ -26,6 +26,7 @@ from heat.engine import parameters from heat.engine import scheduler from heat.engine import template +from heat.tests.fakes import FakeKeystoneClient from heat.tests.common import HeatTestCase from heat.tests.utils import dummy_context from heat.tests.utils import setup_dummy_db @@ -532,6 +533,18 @@ class StackTest(HeatTestCase): self.assertEqual(stack.state, (None, None)) self.assertEqual(stack.status_reason, '') + def test_no_auth_token(self): + ctx = dummy_context() + ctx.auth_token = None + self.m.StubOutWithMock(clients.OpenStackClients, 'keystone') + clients.OpenStackClients.keystone().AndReturn(FakeKeystoneClient()) + + self.m.ReplayAll() + stack = parser.Stack(ctx, 'test_stack', parser.Template({})) + self.assertEqual('abcd1234', stack.clients.auth_token) + + self.m.VerifyAll() + def test_state(self): stack = parser.Stack(self.ctx, 'test_stack', parser.Template({}), action=parser.Stack.CREATE, diff --git a/heat/tests/test_quantum.py b/heat/tests/test_quantum.py index ee5a6a3c..de93843e 100644 --- a/heat/tests/test_quantum.py +++ b/heat/tests/test_quantum.py @@ -15,6 +15,7 @@ from testtools import skipIf +from heat.engine import clients from heat.common import exception from heat.common import template_format from heat.engine import properties @@ -26,6 +27,7 @@ from heat.engine.resources.quantum import router from heat.engine.resources.quantum.quantum import QuantumResource as qr from heat.openstack.common.importutils import try_import from heat.tests.common import HeatTestCase +from heat.tests import fakes from heat.tests import utils from heat.tests.utils import setup_dummy_db from heat.tests.utils import parse_stack @@ -211,6 +213,7 @@ class QuantumNetTest(HeatTestCase): self.m.StubOutWithMock(quantumclient.Client, 'create_network') self.m.StubOutWithMock(quantumclient.Client, 'delete_network') self.m.StubOutWithMock(quantumclient.Client, 'show_network') + self.m.StubOutWithMock(clients.OpenStackClients, 'keystone') setup_dummy_db() def create_net(self, t, stack, resource_name): @@ -220,6 +223,8 @@ class QuantumNetTest(HeatTestCase): return rsrc def test_net(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) quantumclient.Client.create_network({ 'network': {'name': u'the_network', 'admin_state_up': True} }).AndReturn({"network": { @@ -342,6 +347,7 @@ class QuantumSubnetTest(HeatTestCase): self.m.StubOutWithMock(quantumclient.Client, 'create_subnet') self.m.StubOutWithMock(quantumclient.Client, 'delete_subnet') self.m.StubOutWithMock(quantumclient.Client, 'show_subnet') + self.m.StubOutWithMock(clients.OpenStackClients, 'keystone') setup_dummy_db() def create_subnet(self, t, stack, resource_name): @@ -353,6 +359,8 @@ class QuantumSubnetTest(HeatTestCase): def test_subnet(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) quantumclient.Client.create_subnet({ 'subnet': { 'name': utils.PhysName('test_stack', 'test_subnet'), @@ -447,6 +455,8 @@ class QuantumSubnetTest(HeatTestCase): def test_subnet_disable_dhcp(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) quantumclient.Client.create_subnet({ 'subnet': { 'name': utils.PhysName('test_stack', 'test_subnet'), @@ -525,6 +535,7 @@ class QuantumRouterTest(HeatTestCase): self.m.StubOutWithMock(quantumclient.Client, 'remove_interface_router') self.m.StubOutWithMock(quantumclient.Client, 'add_gateway_router') self.m.StubOutWithMock(quantumclient.Client, 'remove_gateway_router') + self.m.StubOutWithMock(clients.OpenStackClients, 'keystone') setup_dummy_db() def create_router(self, t, stack, resource_name): @@ -554,6 +565,8 @@ class QuantumRouterTest(HeatTestCase): return rsrc def test_router(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) quantumclient.Client.create_router({ 'router': { 'name': utils.PhysName('test_stack', 'router'), @@ -659,6 +672,8 @@ class QuantumRouterTest(HeatTestCase): self.m.VerifyAll() def test_router_interface(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) quantumclient.Client.add_interface_router( '3e46229d-8fce-4733-819a-b5fe630550f8', {'subnet_id': '91e47a57-7508-46fe-afc9-fc454e8580e1'} @@ -687,6 +702,8 @@ class QuantumRouterTest(HeatTestCase): self.m.VerifyAll() def test_gateway_router(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) quantumclient.Client.add_gateway_router( '3e46229d-8fce-4733-819a-b5fe630550f8', {'network_id': 'fc68ea2c-b60b-4b4f-bd82-94ec81110766'} @@ -725,10 +742,13 @@ class QuantumFloatingIPTest(HeatTestCase): self.m.StubOutWithMock(quantumclient.Client, 'create_port') self.m.StubOutWithMock(quantumclient.Client, 'delete_port') self.m.StubOutWithMock(quantumclient.Client, 'show_port') + self.m.StubOutWithMock(clients.OpenStackClients, 'keystone') setup_dummy_db() def test_floating_ip(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) quantumclient.Client.create_floatingip({ 'floatingip': {'floating_network_id': u'abcd1234'} }).AndReturn({'floatingip': { @@ -789,6 +809,8 @@ class QuantumFloatingIPTest(HeatTestCase): def test_port(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) quantumclient.Client.create_port({'port': { 'network_id': u'xyz1234', 'fixed_ips': [ @@ -853,6 +875,8 @@ class QuantumFloatingIPTest(HeatTestCase): def test_floatip_port(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) quantumclient.Client.create_floatingip({ 'floatingip': {'floating_network_id': u'abcd1234'} }).AndReturn({'floatingip': { diff --git a/heat/tests/test_s3.py b/heat/tests/test_s3.py index 40f5e764..2b93c3e8 100644 --- a/heat/tests/test_s3.py +++ b/heat/tests/test_s3.py @@ -20,9 +20,11 @@ from heat.common import template_format from heat.openstack.common.importutils import try_import from heat.engine.resources import s3 from heat.engine import resource +from heat.engine import clients from heat.engine import scheduler from heat.tests.common import HeatTestCase from heat.tests import utils +from heat.tests import fakes from heat.tests.utils import setup_dummy_db from heat.tests.utils import parse_stack @@ -63,6 +65,7 @@ class s3Test(HeatTestCase): self.m.StubOutWithMock(swiftclient.Connection, 'put_container') self.m.StubOutWithMock(swiftclient.Connection, 'delete_container') self.m.StubOutWithMock(swiftclient.Connection, 'get_auth') + self.m.StubOutWithMock(clients.OpenStackClients, 'keystone') setup_dummy_db() @@ -75,6 +78,8 @@ class s3Test(HeatTestCase): return rsrc def test_attributes(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) container_name = utils.PhysName('test_stack', 'test_resource') swiftclient.Connection.put_container( container_name, @@ -111,6 +116,8 @@ class s3Test(HeatTestCase): self.m.VerifyAll() def test_public_read(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) container_name = utils.PhysName('test_stack', 'test_resource') swiftclient.Connection.put_container( utils.PhysName('test_stack', 'test_resource'), @@ -129,6 +136,8 @@ class s3Test(HeatTestCase): self.m.VerifyAll() def test_public_read_write(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) container_name = utils.PhysName('test_stack', 'test_resource') swiftclient.Connection.put_container( container_name, @@ -147,6 +156,8 @@ class s3Test(HeatTestCase): self.m.VerifyAll() def test_authenticated_read(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) container_name = utils.PhysName('test_stack', 'test_resource') swiftclient.Connection.put_container( container_name, @@ -164,6 +175,8 @@ class s3Test(HeatTestCase): self.m.VerifyAll() def test_website(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) container_name = utils.PhysName('test_stack', 'test_resource') swiftclient.Connection.put_container( container_name, @@ -181,6 +194,8 @@ class s3Test(HeatTestCase): self.m.VerifyAll() def test_delete_exception(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) container_name = utils.PhysName('test_stack', 'test_resource') swiftclient.Connection.put_container( container_name, @@ -199,6 +214,8 @@ class s3Test(HeatTestCase): def test_delete_retain(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) # first run, with retain policy swiftclient.Connection.put_container( utils.PhysName('test_stack', 'test_resource'), diff --git a/heat/tests/test_security_group.py b/heat/tests/test_security_group.py index 3097405b..0d395a0a 100644 --- a/heat/tests/test_security_group.py +++ b/heat/tests/test_security_group.py @@ -19,6 +19,7 @@ from heat.common import template_format from heat.engine import parser from heat.engine import resource from heat.tests.common import HeatTestCase +from heat.tests.fakes import FakeKeystoneClient from heat.tests.utils import dummy_context from heat.tests.utils import setup_dummy_db from heat.tests.v1_1 import fakes @@ -87,6 +88,7 @@ Resources: super(SecurityGroupTest, self).setUp() self.fc = fakes.FakeClient() self.m.StubOutWithMock(clients.OpenStackClients, 'nova') + self.m.StubOutWithMock(clients.OpenStackClients, 'keystone') self.m.StubOutWithMock(nova_sgr.SecurityGroupRuleManager, 'create') self.m.StubOutWithMock(nova_sgr.SecurityGroupRuleManager, 'delete') self.m.StubOutWithMock(nova_sg.SecurityGroupManager, 'create') @@ -275,6 +277,8 @@ Resources: @stack_delete_after def test_security_group_quantum(self): #create script + clients.OpenStackClients.keystone().AndReturn( + FakeKeystoneClient()) sg_name = utils.PhysName('test_stack', 'the_sg') quantumclient.Client.create_security_group({ 'security_group': { @@ -415,6 +419,8 @@ Resources: @stack_delete_after def test_security_group_quantum_exception(self): #create script + clients.OpenStackClients.keystone().AndReturn( + FakeKeystoneClient()) sg_name = utils.PhysName('test_stack', 'the_sg') quantumclient.Client.create_security_group({ 'security_group': { diff --git a/heat/tests/test_swift.py b/heat/tests/test_swift.py index 74ad7db6..7d5b587d 100644 --- a/heat/tests/test_swift.py +++ b/heat/tests/test_swift.py @@ -20,9 +20,11 @@ from testtools import skipIf from heat.common import template_format from heat.openstack.common.importutils import try_import from heat.engine.resources import swift +from heat.engine import clients from heat.engine import resource from heat.engine import scheduler from heat.tests.common import HeatTestCase +from heat.tests import fakes from heat.tests import utils from heat.tests.utils import setup_dummy_db from heat.tests.utils import parse_stack @@ -64,6 +66,7 @@ class swiftTest(HeatTestCase): self.m.StubOutWithMock(swiftclient.Connection, 'delete_container') self.m.StubOutWithMock(swiftclient.Connection, 'head_container') self.m.StubOutWithMock(swiftclient.Connection, 'get_auth') + self.m.StubOutWithMock(clients.OpenStackClients, 'keystone') setup_dummy_db() @@ -114,6 +117,8 @@ class swiftTest(HeatTestCase): "x-container-bytes-used": "17680980", "content-type": "text/plain; charset=utf-8"} + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) container_name = utils.PhysName('test_stack', 'test_resource') swiftclient.Connection.put_container( container_name, @@ -155,6 +160,8 @@ class swiftTest(HeatTestCase): self.m.VerifyAll() def test_public_read(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) container_name = utils.PhysName('test_stack', 'test_resource') swiftclient.Connection.put_container( container_name, @@ -172,6 +179,8 @@ class swiftTest(HeatTestCase): self.m.VerifyAll() def test_public_read_write(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) container_name = utils.PhysName('test_stack', 'test_resource') swiftclient.Connection.put_container( container_name, @@ -190,6 +199,8 @@ class swiftTest(HeatTestCase): self.m.VerifyAll() def test_website(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) container_name = utils.PhysName('test_stack', 'test_resource') swiftclient.Connection.put_container( container_name, @@ -207,6 +218,8 @@ class swiftTest(HeatTestCase): self.m.VerifyAll() def test_delete_exception(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) container_name = utils.PhysName('test_stack', 'test_resource') swiftclient.Connection.put_container( container_name, @@ -225,6 +238,8 @@ class swiftTest(HeatTestCase): def test_delete_retain(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) # first run, with retain policy swiftclient.Connection.put_container( utils.PhysName('test_stack', 'test_resource'), diff --git a/heat/tests/test_vpc.py b/heat/tests/test_vpc.py index 6e863574..641f85cc 100644 --- a/heat/tests/test_vpc.py +++ b/heat/tests/test_vpc.py @@ -17,8 +17,10 @@ from testtools import skipIf from heat.common import exception from heat.common import template_format from heat.engine import parser +from heat.engine import clients from heat.engine import resource from heat.tests.common import HeatTestCase +from heat.tests import fakes from heat.tests import utils from heat.tests.utils import dummy_context from heat.tests.utils import setup_dummy_db @@ -60,6 +62,7 @@ class VPCTestBase(HeatTestCase): quantumclient.Client, 'create_security_group_rule') self.m.StubOutWithMock( quantumclient.Client, 'delete_security_group_rule') + self.m.StubOutWithMock(clients.OpenStackClients, 'keystone') def create_stack(self, template): t = template_format.parse(template) @@ -74,6 +77,10 @@ class VPCTestBase(HeatTestCase): stack.store() return stack + def mock_keystone(self): + clients.OpenStackClients.keystone().AndReturn( + fakes.FakeKeystoneClient()) + def mock_create_network(self): self.vpc_name = utils.PhysName('test_stack', 'the_vpc') quantumclient.Client.create_network( @@ -331,6 +338,7 @@ Resources: ''' def test_vpc(self): + self.mock_keystone() self.mock_create_network() self.mock_delete_network() self.m.ReplayAll() @@ -362,6 +370,7 @@ Resources: ''' def test_subnet(self): + self.mock_keystone() self.mock_create_network() self.mock_create_subnet() self.mock_delete_subnet() @@ -538,6 +547,7 @@ Resources: quantumclient.Client.delete_port('dddd').AndReturn(None) def test_network_interface(self): + self.mock_keystone() self.mock_create_security_group() self.mock_create_network() self.mock_create_subnet() @@ -565,6 +575,7 @@ Resources: self.m.VerifyAll() def test_network_interface_no_groupset(self): + self.mock_keystone() self.mock_create_network() self.mock_create_subnet() self.mock_show_subnet() @@ -592,6 +603,7 @@ Resources: self.assertEquals(str(expected_exception), str(real_exception)) def test_network_interface_error_no_ref(self): + self.mock_keystone() self.mock_create_network() self.mock_create_subnet() self.mock_show_subnet() @@ -667,6 +679,7 @@ Resources: quantumclient.Client.remove_gateway_router('ffff').AndReturn(None) def test_internet_gateway(self): + self.mock_keystone() self.mock_create_internet_gateway() self.mock_create_network() self.mock_create_subnet() @@ -727,6 +740,7 @@ Resources: ''' def test_route_table(self): + self.mock_keystone() self.mock_create_network() self.mock_create_subnet() self.mock_create_route_table() diff --git a/heat/tests/utils.py b/heat/tests/utils.py index 72828c0b..220ade0c 100644 --- a/heat/tests/utils.py +++ b/heat/tests/utils.py @@ -102,7 +102,8 @@ def dummy_context(user='test_username', tenant_id='test_tenant_id', 'username': user, 'password': password, 'roles': roles, - 'auth_url': 'http://localhost:5000/v2.0' + 'auth_url': 'http://localhost:5000/v2.0', + 'auth_token': 'abcd1234' })