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:
@@ -21,6 +21,7 @@ mccabe==0.2.1
|
|||||||
mock==1.2.0
|
mock==1.2.0
|
||||||
netaddr==0.7.10
|
netaddr==0.7.10
|
||||||
openstackdocstheme==1.20.0
|
openstackdocstheme==1.20.0
|
||||||
|
openstacksdk==0.11.0
|
||||||
oslo.config==1.2.0
|
oslo.config==1.2.0
|
||||||
pbr==2.0.0
|
pbr==2.0.0
|
||||||
pep8==1.5.7
|
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
|
# 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
|
# requirements.txt -- this entire module only makes sense (and should only be
|
||||||
# loaded) if keystoneauth is already installed.
|
# loaded) if keystoneauth is already installed.
|
||||||
|
from keystoneauth1 import discover
|
||||||
from keystoneauth1 import plugin
|
from keystoneauth1 import plugin
|
||||||
from keystoneauth1 import exceptions
|
from keystoneauth1 import exceptions
|
||||||
from keystoneauth1 import loading
|
from keystoneauth1 import loading
|
||||||
@@ -110,11 +111,20 @@ class ServiceCatalogV1(object):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def url_for(self, **kwargs):
|
def url_for(self, **kwargs):
|
||||||
|
return self.endpoint_data_for(**kwargs).url
|
||||||
|
|
||||||
|
def endpoint_data_for(self, **kwargs):
|
||||||
kwargs.setdefault('interface', 'public')
|
kwargs.setdefault('interface', 'public')
|
||||||
kwargs.setdefault('service_type', None)
|
kwargs.setdefault('service_type', None)
|
||||||
|
|
||||||
if kwargs['service_type'] == 'object-store':
|
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
|
# Although our "catalog" includes an identity entry, nothing that uses
|
||||||
# url_for() (including `openstack endpoint list`) will know what to do
|
# 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
|
keystoneauth1>=3.4.0 # Apache-2.0
|
||||||
mock>=1.2.0 # BSD
|
mock>=1.2.0 # BSD
|
||||||
stestr>=2.0.0 # Apache-2.0
|
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
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import os
|
|
||||||
import unittest
|
import unittest
|
||||||
import time
|
import time
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import six
|
import six
|
||||||
from six.moves import configparser
|
|
||||||
|
|
||||||
import swiftclient
|
import swiftclient
|
||||||
|
from . import TEST_CONFIG
|
||||||
|
|
||||||
|
|
||||||
class TestFunctional(unittest.TestCase):
|
class TestFunctional(unittest.TestCase):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(TestFunctional, self).__init__(*args, **kwargs)
|
super(TestFunctional, self).__init__(*args, **kwargs)
|
||||||
self.skip_tests = False
|
self.skip_tests = (TEST_CONFIG is None)
|
||||||
self._get_config()
|
if not self.skip_tests:
|
||||||
|
self._get_config()
|
||||||
|
|
||||||
self.test_data = b'42' * 10
|
self.test_data = b'42' * 10
|
||||||
self.etag = '2704306ec982238d85d4b235c925d58e'
|
self.etag = '2704306ec982238d85d4b235c925d58e'
|
||||||
@@ -41,50 +41,10 @@ class TestFunctional(unittest.TestCase):
|
|||||||
self.objectname_2 = self.objectname + '_second'
|
self.objectname_2 = self.objectname + '_second'
|
||||||
|
|
||||||
def _get_config(self):
|
def _get_config(self):
|
||||||
config_file = os.environ.get('SWIFT_TEST_CONFIG_FILE',
|
self.auth_url = TEST_CONFIG['auth_url']
|
||||||
'/etc/swift/test.conf')
|
self.auth_version = TEST_CONFIG['auth_version']
|
||||||
config = configparser.ConfigParser({'auth_version': '1'})
|
self.account_username = TEST_CONFIG['account_username']
|
||||||
config.read(config_file)
|
self.password = TEST_CONFIG['password']
|
||||||
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
|
|
||||||
|
|
||||||
def _get_connection(self):
|
def _get_connection(self):
|
||||||
"""
|
"""
|
||||||
@@ -514,20 +474,20 @@ class TestUsingKeystone(TestFunctional):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def _get_connection(self):
|
def _get_connection(self):
|
||||||
account = username = password = None
|
account = username = None
|
||||||
if self.auth_version not in ('2', '3'):
|
if self.auth_version not in ('2', '3'):
|
||||||
self.skipTest('SKIPPING KEYSTONE-SPECIFIC FUNCTIONAL TESTS')
|
self.skipTest('SKIPPING KEYSTONE-SPECIFIC FUNCTIONAL TESTS')
|
||||||
try:
|
try:
|
||||||
account = self.config.get('func_test', 'account')
|
account = TEST_CONFIG['account']
|
||||||
username = self.config.get('func_test', 'username')
|
username = TEST_CONFIG['username']
|
||||||
password = self.config.get('func_test', 'password')
|
except KeyError:
|
||||||
except Exception:
|
|
||||||
self.skipTest('SKIPPING KEYSTONE-SPECIFIC FUNCTIONAL TESTS' +
|
self.skipTest('SKIPPING KEYSTONE-SPECIFIC FUNCTIONAL TESTS' +
|
||||||
' - NO CONFIG')
|
' - NO CONFIG')
|
||||||
os_options = {'tenant_name': account}
|
|
||||||
return swiftclient.Connection(
|
return swiftclient.Connection(
|
||||||
self.auth_url, username, password, auth_version=self.auth_version,
|
self.auth_url, username, self.password,
|
||||||
os_options=os_options)
|
auth_version=self.auth_version,
|
||||||
|
os_options={'tenant_name': account})
|
||||||
|
|
||||||
|
|
||||||
class TestUsingKeystoneV3(TestFunctional):
|
class TestUsingKeystoneV3(TestFunctional):
|
||||||
@@ -539,13 +499,14 @@ class TestUsingKeystoneV3(TestFunctional):
|
|||||||
account = username = password = project_domain = user_domain = None
|
account = username = password = project_domain = user_domain = None
|
||||||
if self.auth_version != '3':
|
if self.auth_version != '3':
|
||||||
self.skipTest('SKIPPING KEYSTONE-V3-SPECIFIC FUNCTIONAL TESTS')
|
self.skipTest('SKIPPING KEYSTONE-V3-SPECIFIC FUNCTIONAL TESTS')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
account = self.config.get('func_test', 'account4')
|
account = TEST_CONFIG['account4']
|
||||||
username = self.config.get('func_test', 'username4')
|
username = TEST_CONFIG['username4']
|
||||||
user_domain = self.config.get('func_test', 'domain4')
|
user_domain = TEST_CONFIG['domain4']
|
||||||
project_domain = self.config.get('func_test', 'domain4')
|
project_domain = TEST_CONFIG['domain4']
|
||||||
password = self.config.get('func_test', 'password4')
|
password = TEST_CONFIG['password4']
|
||||||
except Exception:
|
except KeyError:
|
||||||
self.skipTest('SKIPPING KEYSTONE-V3-SPECIFIC FUNCTIONAL TESTS' +
|
self.skipTest('SKIPPING KEYSTONE-V3-SPECIFIC FUNCTIONAL TESTS' +
|
||||||
' - NO CONFIG')
|
' - NO CONFIG')
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user