Merge "Stop using NoAuthMiddleware in tests"
This commit is contained in:
commit
efdc734832
|
@ -81,6 +81,14 @@ class InjectContext(wsgi.Middleware):
|
||||||
class NovaKeystoneContext(wsgi.Middleware):
|
class NovaKeystoneContext(wsgi.Middleware):
|
||||||
"""Make a request context from keystone headers."""
|
"""Make a request context from keystone headers."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _create_context(env, **kwargs):
|
||||||
|
"""Create a context from a request environ.
|
||||||
|
|
||||||
|
This exists to make test stubbing easier.
|
||||||
|
"""
|
||||||
|
return context.RequestContext.from_environ(env, **kwargs)
|
||||||
|
|
||||||
@webob.dec.wsgify(RequestClass=wsgi.Request)
|
@webob.dec.wsgify(RequestClass=wsgi.Request)
|
||||||
def __call__(self, req):
|
def __call__(self, req):
|
||||||
# Build a context, including the auth_token...
|
# Build a context, including the auth_token...
|
||||||
|
@ -101,7 +109,7 @@ class NovaKeystoneContext(wsgi.Middleware):
|
||||||
# middleware in newer versions.
|
# middleware in newer versions.
|
||||||
user_auth_plugin = req.environ.get('keystone.token_auth')
|
user_auth_plugin = req.environ.get('keystone.token_auth')
|
||||||
|
|
||||||
ctx = context.RequestContext.from_environ(
|
ctx = self._create_context(
|
||||||
req.environ,
|
req.environ,
|
||||||
user_auth_plugin=user_auth_plugin,
|
user_auth_plugin=user_auth_plugin,
|
||||||
remote_address=remote_address,
|
remote_address=remote_address,
|
||||||
|
|
|
@ -955,18 +955,21 @@ class OSAPIFixture(fixtures.Fixture):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, api_version='v2',
|
def __init__(self, api_version='v2',
|
||||||
project_id='6f70656e737461636b20342065766572'):
|
project_id='6f70656e737461636b20342065766572',
|
||||||
|
use_project_id_in_urls=False):
|
||||||
"""Constructor
|
"""Constructor
|
||||||
|
|
||||||
:param api_version: the API version that we're interested in
|
:param api_version: the API version that we're interested in
|
||||||
using. Currently this expects 'v2' or 'v2.1' as possible
|
using. Currently this expects 'v2' or 'v2.1' as possible
|
||||||
options.
|
options.
|
||||||
:param project_id: the project id to use on the API.
|
:param project_id: the project id to use on the API.
|
||||||
|
:param use_project_id_in_urls: If True, act like the "endpoint" in the
|
||||||
|
"service catalog" has the legacy format including the project_id.
|
||||||
"""
|
"""
|
||||||
super(OSAPIFixture, self).__init__()
|
super(OSAPIFixture, self).__init__()
|
||||||
self.api_version = api_version
|
self.api_version = api_version
|
||||||
self.project_id = project_id
|
self.project_id = project_id
|
||||||
|
self.use_project_id_in_urls = use_project_id_in_urls
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(OSAPIFixture, self).setUp()
|
super(OSAPIFixture, self).setUp()
|
||||||
|
@ -982,6 +985,23 @@ class OSAPIFixture(fixtures.Fixture):
|
||||||
}
|
}
|
||||||
self.useFixture(ConfPatcher(**conf_overrides))
|
self.useFixture(ConfPatcher(**conf_overrides))
|
||||||
|
|
||||||
|
# Stub out authentication middleware
|
||||||
|
# TODO(efried): Use keystonemiddleware.fixtures.AuthTokenFixture
|
||||||
|
self.useFixture(fixtures.MockPatch(
|
||||||
|
'keystonemiddleware.auth_token.filter_factory',
|
||||||
|
return_value=lambda _app: _app))
|
||||||
|
|
||||||
|
# Stub out context middleware
|
||||||
|
def fake_ctx(env, **kwargs):
|
||||||
|
user_id = env['HTTP_X_AUTH_USER']
|
||||||
|
project_id = env['HTTP_X_AUTH_PROJECT_ID']
|
||||||
|
is_admin = user_id == 'admin'
|
||||||
|
return context.RequestContext(
|
||||||
|
user_id, project_id, is_admin=is_admin, **kwargs)
|
||||||
|
|
||||||
|
self.useFixture(fixtures.MonkeyPatch(
|
||||||
|
'nova.api.auth.NovaKeystoneContext._create_context', fake_ctx))
|
||||||
|
|
||||||
# Turn off manipulation of socket_options in TCPKeepAliveAdapter
|
# Turn off manipulation of socket_options in TCPKeepAliveAdapter
|
||||||
# to keep wsgi-intercept happy. Replace it with the method
|
# to keep wsgi-intercept happy. Replace it with the method
|
||||||
# from its superclass.
|
# from its superclass.
|
||||||
|
@ -999,12 +1019,15 @@ class OSAPIFixture(fixtures.Fixture):
|
||||||
intercept.install_intercept()
|
intercept.install_intercept()
|
||||||
self.addCleanup(intercept.uninstall_intercept)
|
self.addCleanup(intercept.uninstall_intercept)
|
||||||
|
|
||||||
self.auth_url = 'http://%(host)s:%(port)s/%(api_version)s' % ({
|
base_url = 'http://%(host)s:%(port)s/%(api_version)s' % ({
|
||||||
'host': hostname, 'port': port, 'api_version': self.api_version})
|
'host': hostname, 'port': port, 'api_version': self.api_version})
|
||||||
self.api = client.TestOpenStackClient('fake', 'fake', self.auth_url,
|
if self.use_project_id_in_urls:
|
||||||
self.project_id)
|
base_url += '/' + self.project_id
|
||||||
|
|
||||||
|
self.api = client.TestOpenStackClient(
|
||||||
|
'fake', base_url, project_id=self.project_id)
|
||||||
self.admin_api = client.TestOpenStackClient(
|
self.admin_api = client.TestOpenStackClient(
|
||||||
'admin', 'admin', self.auth_url, self.project_id)
|
'admin', base_url, project_id=self.project_id)
|
||||||
# Provide a way to access the wsgi application to tests using
|
# Provide a way to access the wsgi application to tests using
|
||||||
# the fixture.
|
# the fixture.
|
||||||
self.app = app
|
self.app = app
|
||||||
|
|
|
@ -124,13 +124,10 @@ class TestOpenStackClient(object):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, auth_user, auth_key, auth_url,
|
def __init__(self, auth_user, base_url, project_id=None):
|
||||||
project_id=None):
|
|
||||||
super(TestOpenStackClient, self).__init__()
|
super(TestOpenStackClient, self).__init__()
|
||||||
self.auth_result = None
|
|
||||||
self.auth_user = auth_user
|
self.auth_user = auth_user
|
||||||
self.auth_key = auth_key
|
self.base_url = base_url
|
||||||
self.auth_url = auth_url
|
|
||||||
if project_id is None:
|
if project_id is None:
|
||||||
self.project_id = "6f70656e737461636b20342065766572"
|
self.project_id = "6f70656e737461636b20342065766572"
|
||||||
else:
|
else:
|
||||||
|
@ -144,49 +141,22 @@ class TestOpenStackClient(object):
|
||||||
response = requests.request(method, url, data=body, headers=_headers)
|
response = requests.request(method, url, data=body, headers=_headers)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def _authenticate(self, retry_count=0):
|
|
||||||
if self.auth_result:
|
|
||||||
return self.auth_result
|
|
||||||
|
|
||||||
auth_url = self.auth_url
|
|
||||||
headers = {'X-Auth-User': self.auth_user,
|
|
||||||
'X-Auth-Key': self.auth_key,
|
|
||||||
'X-Auth-Project-Id': self.project_id}
|
|
||||||
response = self.request(auth_url,
|
|
||||||
headers=headers)
|
|
||||||
|
|
||||||
http_status = response.status_code
|
|
||||||
LOG.debug("%(auth_url)s => code %(http_status)s",
|
|
||||||
{'auth_url': auth_url,
|
|
||||||
'http_status': http_status})
|
|
||||||
|
|
||||||
# NOTE(cdent): This is a workaround for an issue where the placement
|
|
||||||
# API fixture may respond when a request was supposed to go to the
|
|
||||||
# compute API fixture. Retry a few times, hoping to hit the right
|
|
||||||
# fixture.
|
|
||||||
if http_status == 401:
|
|
||||||
if retry_count <= 3:
|
|
||||||
return self._authenticate(retry_count=retry_count + 1)
|
|
||||||
else:
|
|
||||||
raise OpenStackApiAuthenticationException(response=response)
|
|
||||||
|
|
||||||
self.auth_result = response.headers
|
|
||||||
return self.auth_result
|
|
||||||
|
|
||||||
def api_request(self, relative_uri, check_response_status=None,
|
def api_request(self, relative_uri, check_response_status=None,
|
||||||
strip_version=False, **kwargs):
|
strip_version=False, **kwargs):
|
||||||
auth_result = self._authenticate()
|
base_uri = self.base_url
|
||||||
|
|
||||||
# NOTE(justinsb): httplib 'helpfully' converts headers to lower case
|
|
||||||
base_uri = auth_result['x-server-management-url']
|
|
||||||
if strip_version:
|
if strip_version:
|
||||||
# NOTE(vish): cut out version number and tenant_id
|
# The base_uri is either http://%(host)s:%(port)s/%(api_version)s
|
||||||
base_uri = '/'.join(base_uri.split('/', 3)[:-1])
|
# or http://%(host)s:%(port)s/%(api_version)s/%(project_id)s
|
||||||
|
# NOTE(efried): Using urlparse was not easier :)
|
||||||
|
chunked = base_uri.split('/')
|
||||||
|
base_uri = '/'.join(chunked[:3])
|
||||||
|
# Restore the project ID if present
|
||||||
|
if len(chunked) == 5:
|
||||||
|
base_uri += '/' + chunked[-1]
|
||||||
|
|
||||||
full_uri = '%s/%s' % (base_uri, relative_uri)
|
full_uri = '%s/%s' % (base_uri, relative_uri)
|
||||||
|
|
||||||
headers = kwargs.setdefault('headers', {})
|
headers = kwargs.setdefault('headers', {})
|
||||||
headers['X-Auth-Token'] = auth_result['x-auth-token']
|
|
||||||
if ('X-OpenStack-Nova-API-Version' in headers or
|
if ('X-OpenStack-Nova-API-Version' in headers or
|
||||||
'OpenStack-API-Version' in headers):
|
'OpenStack-API-Version' in headers):
|
||||||
raise Exception('Microversion should be set via '
|
raise Exception('Microversion should be set via '
|
||||||
|
@ -195,6 +165,10 @@ class TestOpenStackClient(object):
|
||||||
headers['X-OpenStack-Nova-API-Version'] = self.microversion
|
headers['X-OpenStack-Nova-API-Version'] = self.microversion
|
||||||
headers['OpenStack-API-Version'] = 'compute %s' % self.microversion
|
headers['OpenStack-API-Version'] = 'compute %s' % self.microversion
|
||||||
|
|
||||||
|
headers.setdefault('X-Auth-User', self.auth_user)
|
||||||
|
headers.setdefault('X-User-Id', self.auth_user)
|
||||||
|
headers.setdefault('X-Auth-Project-Id', self.project_id)
|
||||||
|
|
||||||
response = self.request(full_uri, **kwargs)
|
response = self.request(full_uri, **kwargs)
|
||||||
|
|
||||||
http_status = response.status_code
|
http_status = response.status_code
|
||||||
|
|
|
@ -62,6 +62,11 @@ class ApiSampleTestBaseV21(testscenarios.WithScenarios,
|
||||||
# any additional fixtures needed for this scenario
|
# any additional fixtures needed for this scenario
|
||||||
_additional_fixtures = []
|
_additional_fixtures = []
|
||||||
sample_dir = None
|
sample_dir = None
|
||||||
|
# Include the project ID in request URLs by default. This is overridden
|
||||||
|
# for certain `scenarios` and by certain subclasses.
|
||||||
|
# Note that API sample tests also use this in substitutions to validate
|
||||||
|
# that URLs in responses (e.g. location of a server just created) are
|
||||||
|
# correctly constructed.
|
||||||
_use_project_id = True
|
_use_project_id = True
|
||||||
# Availability zones for the API samples tests. Can be overridden by
|
# Availability zones for the API samples tests. Can be overridden by
|
||||||
# sub-classes. If set, the AvailabilityZoneFilter is not used.
|
# sub-classes. If set, the AvailabilityZoneFilter is not used.
|
||||||
|
|
|
@ -74,6 +74,7 @@ class SimpleTenantUsageV240Test(test_servers.ServersSampleBase):
|
||||||
sample_dir = 'os-simple-tenant-usage'
|
sample_dir = 'os-simple-tenant-usage'
|
||||||
microversion = '2.40'
|
microversion = '2.40'
|
||||||
scenarios = [('v2_40', {'api_major_version': 'v2.1'})]
|
scenarios = [('v2_40', {'api_major_version': 'v2.1'})]
|
||||||
|
_use_project_id = False
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(SimpleTenantUsageV240Test, self).setUp()
|
super(SimpleTenantUsageV240Test, self).setUp()
|
||||||
|
|
|
@ -19,6 +19,7 @@ from nova.tests.functional.api_sample_tests import api_sample_base
|
||||||
|
|
||||||
class VersionsSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
class VersionsSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
||||||
sample_dir = 'versions'
|
sample_dir = 'versions'
|
||||||
|
_use_project_id = False
|
||||||
# NOTE(gmann): Setting empty scenario for 'version' API testing
|
# NOTE(gmann): Setting empty scenario for 'version' API testing
|
||||||
# as those does not send request on particular endpoint and running
|
# as those does not send request on particular endpoint and running
|
||||||
# its tests alone is enough.
|
# its tests alone is enough.
|
||||||
|
|
|
@ -80,6 +80,9 @@ class _IntegratedTestBase(test.TestCase):
|
||||||
# New tests should rely on Neutron and old ones migrated to use this since
|
# New tests should rely on Neutron and old ones migrated to use this since
|
||||||
# nova-network is deprecated.
|
# nova-network is deprecated.
|
||||||
USE_NEUTRON = True
|
USE_NEUTRON = True
|
||||||
|
# This indicates whether to include the project ID in the URL for API
|
||||||
|
# requests through OSAPIFixture. Overridden by subclasses.
|
||||||
|
_use_project_id = False
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(_IntegratedTestBase, self).setUp()
|
super(_IntegratedTestBase, self).setUp()
|
||||||
|
@ -125,8 +128,11 @@ class _IntegratedTestBase(test.TestCase):
|
||||||
self.scheduler = self._setup_scheduler_service()
|
self.scheduler = self._setup_scheduler_service()
|
||||||
|
|
||||||
self.compute = self._setup_compute_service()
|
self.compute = self._setup_compute_service()
|
||||||
|
|
||||||
self.api_fixture = self.useFixture(
|
self.api_fixture = self.useFixture(
|
||||||
nova_fixtures.OSAPIFixture(self.api_major_version))
|
nova_fixtures.OSAPIFixture(
|
||||||
|
api_version=self.api_major_version,
|
||||||
|
use_project_id_in_urls=self._use_project_id))
|
||||||
|
|
||||||
# if the class needs to run as admin, make the api endpoint
|
# if the class needs to run as admin, make the api endpoint
|
||||||
# the admin, otherwise it's safer to run as non admin user.
|
# the admin, otherwise it's safer to run as non admin user.
|
||||||
|
|
|
@ -41,6 +41,10 @@ class TestCORSMiddleware(api_sample_base.ApiSampleTestBaseV21):
|
||||||
self._original_call_method = cfg.ConfigOpts.GroupAttr.__getattr__
|
self._original_call_method = cfg.ConfigOpts.GroupAttr.__getattr__
|
||||||
cfg.ConfigOpts.GroupAttr.__getattr__ = _mock_getattr
|
cfg.ConfigOpts.GroupAttr.__getattr__ = _mock_getattr
|
||||||
|
|
||||||
|
# With the project_id in the URL, we get the 300 'multiple choices'
|
||||||
|
# response from nova.api.openstack.compute.versions.Versions.
|
||||||
|
self.exp_version_status = 300 if self._use_project_id else 200
|
||||||
|
|
||||||
# Initialize the application after all the config overrides are in
|
# Initialize the application after all the config overrides are in
|
||||||
# place.
|
# place.
|
||||||
super(TestCORSMiddleware, self).setUp()
|
super(TestCORSMiddleware, self).setUp()
|
||||||
|
@ -103,7 +107,7 @@ class TestCORSMiddleware(api_sample_base.ApiSampleTestBaseV21):
|
||||||
'Access-Control-Request-Method': 'GET'
|
'Access-Control-Request-Method': 'GET'
|
||||||
})
|
})
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, self.exp_version_status)
|
||||||
self.assertIn('Access-Control-Allow-Origin', response.headers)
|
self.assertIn('Access-Control-Allow-Origin', response.headers)
|
||||||
self.assertEqual('http://valid.example.com',
|
self.assertEqual('http://valid.example.com',
|
||||||
response.headers['Access-Control-Allow-Origin'])
|
response.headers['Access-Control-Allow-Origin'])
|
||||||
|
@ -116,5 +120,5 @@ class TestCORSMiddleware(api_sample_base.ApiSampleTestBaseV21):
|
||||||
'Access-Control-Request-Method': 'GET'
|
'Access-Control-Request-Method': 'GET'
|
||||||
})
|
})
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, self.exp_version_status)
|
||||||
self.assertNotIn('Access-Control-Allow-Origin', response.headers)
|
self.assertNotIn('Access-Control-Allow-Origin', response.headers)
|
||||||
|
|
|
@ -63,18 +63,15 @@ class TestRequestLogMiddleware(testtools.TestCase):
|
||||||
api = self.useFixture(fixtures.OSAPIFixture()).api
|
api = self.useFixture(fixtures.OSAPIFixture()).api
|
||||||
|
|
||||||
resp = api.api_request('/', strip_version=True)
|
resp = api.api_request('/', strip_version=True)
|
||||||
log1 = ('INFO [nova.api.openstack.requestlog] 127.0.0.1 '
|
|
||||||
'"GET /v2" status: 204 len: 0 microversion: - time:')
|
|
||||||
self.assertIn(log1, self.stdlog.logger.output)
|
|
||||||
|
|
||||||
# the content length might vary, but the important part is
|
# the content length might vary, but the important part is
|
||||||
# what we log is what we return to the user (which turns out
|
# what we log is what we return to the user (which turns out
|
||||||
# to excitingly not be the case with eventlet!)
|
# to excitingly not be the case with eventlet!)
|
||||||
content_length = resp.headers['content-length']
|
content_length = resp.headers['content-length']
|
||||||
|
|
||||||
log2 = ('INFO [nova.api.openstack.requestlog] 127.0.0.1 '
|
log1 = ('INFO [nova.api.openstack.requestlog] 127.0.0.1 '
|
||||||
'"GET /" status: 200 len: %s' % content_length)
|
'"GET /" status: 200 len: %s' % content_length)
|
||||||
self.assertIn(log2, self.stdlog.logger.output)
|
self.assertIn(log1, self.stdlog.logger.output)
|
||||||
|
|
||||||
@mock.patch('nova.api.openstack.requestlog.RequestLog._should_emit')
|
@mock.patch('nova.api.openstack.requestlog.RequestLog._should_emit')
|
||||||
def test_logs_mv(self, emit):
|
def test_logs_mv(self, emit):
|
||||||
|
|
|
@ -45,9 +45,6 @@ class ConfFixture(config_fixture.Config):
|
||||||
self.conf.set_default('use_ipv6', True)
|
self.conf.set_default('use_ipv6', True)
|
||||||
self.conf.set_default('vlan_interface', 'eth0')
|
self.conf.set_default('vlan_interface', 'eth0')
|
||||||
|
|
||||||
# api group
|
|
||||||
self.conf.set_default('auth_strategy', 'noauth2', group='api')
|
|
||||||
|
|
||||||
# api_database group
|
# api_database group
|
||||||
self.conf.set_default('connection', "sqlite://", group='api_database')
|
self.conf.set_default('connection', "sqlite://", group='api_database')
|
||||||
self.conf.set_default('sqlite_synchronous', False,
|
self.conf.set_default('sqlite_synchronous', False,
|
||||||
|
|
Loading…
Reference in New Issue