v1auth: support endpoint_data_for() api
...so we can be used with openstacksdk. Also, add a few functests that use openstacksdk. Change-Id: Ie6987f5de48914ec8932254cde79a973a0264877
This commit is contained in:
parent
1eda8f9f3e
commit
c4bef14fc1
@ -21,6 +21,7 @@ mccabe==0.2.1
|
||||
mock==1.2.0
|
||||
netaddr==0.7.10
|
||||
openstackdocstheme==1.20.0
|
||||
openstacksdk==0.11.0
|
||||
oslo.config==1.2.0
|
||||
pbr==2.0.0
|
||||
pep8==1.5.7
|
||||
|
@ -45,6 +45,7 @@ from six.moves.urllib.parse import urljoin
|
||||
# Note that while we import keystoneauth1 here, we *don't* need to add it to
|
||||
# requirements.txt -- this entire module only makes sense (and should only be
|
||||
# loaded) if keystoneauth is already installed.
|
||||
from keystoneauth1 import discover
|
||||
from keystoneauth1 import plugin
|
||||
from keystoneauth1 import exceptions
|
||||
from keystoneauth1 import loading
|
||||
@ -110,11 +111,20 @@ class ServiceCatalogV1(object):
|
||||
]
|
||||
|
||||
def url_for(self, **kwargs):
|
||||
return self.endpoint_data_for(**kwargs).url
|
||||
|
||||
def endpoint_data_for(self, **kwargs):
|
||||
kwargs.setdefault('interface', 'public')
|
||||
kwargs.setdefault('service_type', None)
|
||||
|
||||
if kwargs['service_type'] == 'object-store':
|
||||
return self.storage_url
|
||||
return discover.EndpointData(
|
||||
service_type='object-store',
|
||||
service_name='swift',
|
||||
interface=kwargs['interface'],
|
||||
region_name='default',
|
||||
catalog_url=self.storage_url,
|
||||
)
|
||||
|
||||
# Although our "catalog" includes an identity entry, nothing that uses
|
||||
# url_for() (including `openstack endpoint list`) will know what to do
|
||||
|
@ -4,3 +4,4 @@ coverage!=4.4,>=4.0 # Apache-2.0
|
||||
keystoneauth1>=3.4.0 # Apache-2.0
|
||||
mock>=1.2.0 # BSD
|
||||
stestr>=2.0.0 # Apache-2.0
|
||||
openstacksdk>=0.11.0 # Apache-2.0
|
||||
|
@ -0,0 +1,93 @@
|
||||
# Copyright (c) 2014 Christian Schwede <christian.schwede@enovance.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
import os
|
||||
from six.moves import configparser
|
||||
|
||||
TEST_CONFIG = None
|
||||
|
||||
|
||||
def _load_config(force_reload=False):
|
||||
global TEST_CONFIG
|
||||
if not force_reload and TEST_CONFIG is not None:
|
||||
return TEST_CONFIG
|
||||
|
||||
config_file = os.environ.get('SWIFT_TEST_CONFIG_FILE',
|
||||
'/etc/swift/test.conf')
|
||||
parser = configparser.ConfigParser({'auth_version': '1'})
|
||||
parser.read(config_file)
|
||||
conf = {}
|
||||
if parser.has_section('func_test'):
|
||||
if parser.has_option('func_test', 'auth_uri'):
|
||||
conf['auth_url'] = parser.get('func_test', 'auth_uri')
|
||||
try:
|
||||
conf['auth_version'] = parser.get('func_test', 'auth_version')
|
||||
except configparser.NoOptionError:
|
||||
last_piece = conf['auth_url'].rstrip('/').rsplit('/', 1)[1]
|
||||
if last_piece.endswith('.0'):
|
||||
last_piece = last_piece[:-2]
|
||||
if last_piece in ('1', '2', '3'):
|
||||
conf['auth_version'] = last_piece
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
auth_host = parser.get('func_test', 'auth_host')
|
||||
auth_port = parser.getint('func_test', 'auth_port')
|
||||
auth_ssl = parser.getboolean('func_test', 'auth_ssl')
|
||||
auth_prefix = parser.get('func_test', 'auth_prefix')
|
||||
conf['auth_version'] = parser.get('func_test', 'auth_version')
|
||||
if auth_ssl:
|
||||
auth_url = "https://"
|
||||
else:
|
||||
auth_url = "http://"
|
||||
auth_url += "%s:%s%s" % (auth_host, auth_port, auth_prefix)
|
||||
if conf['auth_version'] == "1":
|
||||
auth_url += 'v1.0'
|
||||
conf['auth_url'] = auth_url
|
||||
|
||||
try:
|
||||
conf['account_username'] = parser.get('func_test',
|
||||
'account_username')
|
||||
except configparser.NoOptionError:
|
||||
conf['account'] = parser.get('func_test', 'account')
|
||||
conf['username'] = parser.get('func_test', 'username')
|
||||
conf['account_username'] = "%s:%s" % (conf['account'],
|
||||
conf['username'])
|
||||
else:
|
||||
# Still try to get separate account/usernames for keystone tests
|
||||
try:
|
||||
conf['account'] = parser.get('func_test', 'account')
|
||||
conf['username'] = parser.get('func_test', 'username')
|
||||
except configparser.NoOptionError:
|
||||
pass
|
||||
|
||||
conf['password'] = parser.get('func_test', 'password')
|
||||
|
||||
# For keystone v3
|
||||
try:
|
||||
conf['account4'] = parser.get('func_test', 'account4')
|
||||
conf['username4'] = parser.get('func_test', 'username4')
|
||||
conf['domain4'] = parser.get('func_test', 'domain4')
|
||||
conf['password4'] = parser.get('func_test', 'password4')
|
||||
except configparser.NoOptionError:
|
||||
pass
|
||||
|
||||
TEST_CONFIG = conf
|
||||
|
||||
|
||||
try:
|
||||
_load_config()
|
||||
except configparser.NoOptionError:
|
||||
TEST_CONFIG = None # sentinel used in test setup
|
92
test/functional/test_openstacksdk.py
Normal file
92
test/functional/test_openstacksdk.py
Normal file
@ -0,0 +1,92 @@
|
||||
# Copyright (c) 2019 Tim Burke <tim@swiftstack.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
import unittest
|
||||
import uuid
|
||||
|
||||
import openstack
|
||||
|
||||
from . import TEST_CONFIG
|
||||
|
||||
PREFIX = 'test-swiftclient-'
|
||||
|
||||
|
||||
class TestOpenStackSDK(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
# NB: Only runs for v1 auth, to exercise our keystoneauth plugin
|
||||
cls.skip_tests = (TEST_CONFIG is None or
|
||||
TEST_CONFIG['auth_version'] != '1')
|
||||
if not cls.skip_tests:
|
||||
cls.conn = openstack.connect(
|
||||
auth_type='v1password',
|
||||
auth_url=TEST_CONFIG['auth_url'],
|
||||
username=TEST_CONFIG['account_username'],
|
||||
password=TEST_CONFIG['password'],
|
||||
)
|
||||
cls.object_store = cls.conn.object_store
|
||||
|
||||
def setUp(self):
|
||||
if self.skip_tests:
|
||||
raise unittest.SkipTest('SKIPPING V1-AUTH TESTS')
|
||||
|
||||
def tearDown(self):
|
||||
if self.skip_tests:
|
||||
return
|
||||
for c in self.object_store.containers():
|
||||
if c.name.startswith(PREFIX):
|
||||
for o in self.object_store.objects(c.name):
|
||||
self.object_store.delete_object(
|
||||
o.name, container=c.name)
|
||||
self.object_store.delete_container(c.name)
|
||||
|
||||
def test_containers(self):
|
||||
meta = self.object_store.get_account_metadata()
|
||||
count_before = meta.account_container_count
|
||||
containers = sorted(PREFIX + str(uuid.uuid4())
|
||||
for _ in range(10))
|
||||
for c in containers:
|
||||
self.object_store.create_container(c)
|
||||
self.assertEqual([
|
||||
c.name for c in self.object_store.containers()
|
||||
if c.name.startswith(PREFIX)
|
||||
], containers)
|
||||
meta = self.object_store.get_account_metadata()
|
||||
self.assertEqual(count_before + len(containers),
|
||||
meta.account_container_count)
|
||||
|
||||
def test_objects(self):
|
||||
container = PREFIX + str(uuid.uuid4())
|
||||
self.object_store.create_container(container)
|
||||
objects = sorted(str(uuid.uuid4()) for _ in range(10))
|
||||
for o in objects:
|
||||
self.object_store.create_object(container, o, data=b'x')
|
||||
self.assertEqual([
|
||||
o.name for o in self.object_store.objects(container)
|
||||
], objects)
|
||||
meta = self.object_store.get_container_metadata(container)
|
||||
self.assertEqual(len(objects), meta.object_count)
|
||||
|
||||
def test_object_metadata(self):
|
||||
container = PREFIX + str(uuid.uuid4())
|
||||
self.object_store.create_container(container)
|
||||
obj = str(uuid.uuid4())
|
||||
obj_meta = {str(uuid.uuid4()): str(uuid.uuid4()) for _ in range(10)}
|
||||
# NB: as of 0.36.0, create_object() doesn't play well with passing
|
||||
# both data and metadata, so we do a PUT then POST
|
||||
self.object_store.create_object(container, obj, data=b'x')
|
||||
self.object_store.set_object_metadata(obj, container, **obj_meta)
|
||||
meta = self.object_store.get_object_metadata(obj, container)
|
||||
self.assertEqual(obj_meta, meta.metadata)
|
@ -13,23 +13,23 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import time
|
||||
from io import BytesIO
|
||||
|
||||
import six
|
||||
from six.moves import configparser
|
||||
|
||||
import swiftclient
|
||||
from . import TEST_CONFIG
|
||||
|
||||
|
||||
class TestFunctional(unittest.TestCase):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TestFunctional, self).__init__(*args, **kwargs)
|
||||
self.skip_tests = False
|
||||
self._get_config()
|
||||
self.skip_tests = (TEST_CONFIG is None)
|
||||
if not self.skip_tests:
|
||||
self._get_config()
|
||||
|
||||
self.test_data = b'42' * 10
|
||||
self.etag = '2704306ec982238d85d4b235c925d58e'
|
||||
@ -41,50 +41,10 @@ class TestFunctional(unittest.TestCase):
|
||||
self.objectname_2 = self.objectname + '_second'
|
||||
|
||||
def _get_config(self):
|
||||
config_file = os.environ.get('SWIFT_TEST_CONFIG_FILE',
|
||||
'/etc/swift/test.conf')
|
||||
config = configparser.ConfigParser({'auth_version': '1'})
|
||||
config.read(config_file)
|
||||
self.config = config
|
||||
if config.has_section('func_test'):
|
||||
if config.has_option('func_test', 'auth_uri'):
|
||||
self.auth_url = config.get('func_test', 'auth_uri')
|
||||
try:
|
||||
self.auth_version = config.get('func_test', 'auth_version')
|
||||
except configparser.NoOptionError:
|
||||
last_piece = self.auth_url.rstrip('/').rsplit('/', 1)[1]
|
||||
if last_piece.endswith('.0'):
|
||||
last_piece = last_piece[:-2]
|
||||
if last_piece in ('1', '2', '3'):
|
||||
self.auth_version = last_piece
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
auth_host = config.get('func_test', 'auth_host')
|
||||
auth_port = config.getint('func_test', 'auth_port')
|
||||
auth_ssl = config.getboolean('func_test', 'auth_ssl')
|
||||
auth_prefix = config.get('func_test', 'auth_prefix')
|
||||
self.auth_version = config.get('func_test', 'auth_version')
|
||||
self.auth_url = ""
|
||||
if auth_ssl:
|
||||
self.auth_url += "https://"
|
||||
else:
|
||||
self.auth_url += "http://"
|
||||
self.auth_url += "%s:%s%s" % (
|
||||
auth_host, auth_port, auth_prefix)
|
||||
if self.auth_version == "1":
|
||||
self.auth_url += 'v1.0'
|
||||
|
||||
try:
|
||||
self.account_username = config.get('func_test',
|
||||
'account_username')
|
||||
except configparser.NoOptionError:
|
||||
account = config.get('func_test', 'account')
|
||||
username = config.get('func_test', 'username')
|
||||
self.account_username = "%s:%s" % (account, username)
|
||||
self.password = config.get('func_test', 'password')
|
||||
else:
|
||||
self.skip_tests = True
|
||||
self.auth_url = TEST_CONFIG['auth_url']
|
||||
self.auth_version = TEST_CONFIG['auth_version']
|
||||
self.account_username = TEST_CONFIG['account_username']
|
||||
self.password = TEST_CONFIG['password']
|
||||
|
||||
def _get_connection(self):
|
||||
"""
|
||||
@ -514,20 +474,20 @@ class TestUsingKeystone(TestFunctional):
|
||||
"""
|
||||
|
||||
def _get_connection(self):
|
||||
account = username = password = None
|
||||
account = username = None
|
||||
if self.auth_version not in ('2', '3'):
|
||||
self.skipTest('SKIPPING KEYSTONE-SPECIFIC FUNCTIONAL TESTS')
|
||||
try:
|
||||
account = self.config.get('func_test', 'account')
|
||||
username = self.config.get('func_test', 'username')
|
||||
password = self.config.get('func_test', 'password')
|
||||
except Exception:
|
||||
account = TEST_CONFIG['account']
|
||||
username = TEST_CONFIG['username']
|
||||
except KeyError:
|
||||
self.skipTest('SKIPPING KEYSTONE-SPECIFIC FUNCTIONAL TESTS' +
|
||||
' - NO CONFIG')
|
||||
os_options = {'tenant_name': account}
|
||||
|
||||
return swiftclient.Connection(
|
||||
self.auth_url, username, password, auth_version=self.auth_version,
|
||||
os_options=os_options)
|
||||
self.auth_url, username, self.password,
|
||||
auth_version=self.auth_version,
|
||||
os_options={'tenant_name': account})
|
||||
|
||||
|
||||
class TestUsingKeystoneV3(TestFunctional):
|
||||
@ -539,13 +499,14 @@ class TestUsingKeystoneV3(TestFunctional):
|
||||
account = username = password = project_domain = user_domain = None
|
||||
if self.auth_version != '3':
|
||||
self.skipTest('SKIPPING KEYSTONE-V3-SPECIFIC FUNCTIONAL TESTS')
|
||||
|
||||
try:
|
||||
account = self.config.get('func_test', 'account4')
|
||||
username = self.config.get('func_test', 'username4')
|
||||
user_domain = self.config.get('func_test', 'domain4')
|
||||
project_domain = self.config.get('func_test', 'domain4')
|
||||
password = self.config.get('func_test', 'password4')
|
||||
except Exception:
|
||||
account = TEST_CONFIG['account4']
|
||||
username = TEST_CONFIG['username4']
|
||||
user_domain = TEST_CONFIG['domain4']
|
||||
project_domain = TEST_CONFIG['domain4']
|
||||
password = TEST_CONFIG['password4']
|
||||
except KeyError:
|
||||
self.skipTest('SKIPPING KEYSTONE-V3-SPECIFIC FUNCTIONAL TESTS' +
|
||||
' - NO CONFIG')
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user