summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/service-api.rst2
-rw-r--r--examples/upload.py3
-rw-r--r--swiftclient/client.py8
-rw-r--r--swiftclient/service.py11
-rw-r--r--tests/unit/test_service.py2
-rw-r--r--tests/unit/test_swiftclient.py355
6 files changed, 236 insertions, 145 deletions
diff --git a/doc/source/service-api.rst b/doc/source/service-api.rst
index ea530b0..02b12d0 100644
--- a/doc/source/service-api.rst
+++ b/doc/source/service-api.rst
@@ -833,6 +833,8 @@ the method docstring.
For each successful call to list capabilities, a result dictionary will be
returned with the contents described below:
+.. code-block:: python
+
{
'action': 'capabilities',
'timestamp': <time of the call>,
diff --git a/examples/upload.py b/examples/upload.py
index 1b1e349..0715b19 100644
--- a/examples/upload.py
+++ b/examples/upload.py
@@ -1,6 +1,7 @@
import logging
-from os.path import join, walk
+from os import walk
+from os.path import join
from swiftclient.multithreading import OutputManager
from swiftclient.service import SwiftError, SwiftService, SwiftUploadObject
from sys import argv
diff --git a/swiftclient/client.py b/swiftclient/client.py
index 602489d..988c7d9 100644
--- a/swiftclient/client.py
+++ b/swiftclient/client.py
@@ -1619,7 +1619,7 @@ class Connection(object):
backoff = self.starting_backoff
caller_response_dict = kwargs.pop('response_dict', None)
self.attempts = kwargs.pop('attempts', 0)
- while self.attempts <= self.retries:
+ while self.attempts <= self.retries or retried_auth:
self.attempts += 1
try:
if not self.url or not self.token:
@@ -1648,9 +1648,6 @@ class Connection(object):
self.http_conn = None
except ClientException as err:
self._add_response_dict(caller_response_dict, kwargs)
- if self.attempts > self.retries or err.http_status is None:
- logger.exception(err)
- raise
if err.http_status == 401:
self.url = self.token = self.service_token = None
if retried_auth or not all((self.authurl,
@@ -1659,6 +1656,9 @@ class Connection(object):
logger.exception(err)
raise
retried_auth = True
+ elif self.attempts > self.retries or err.http_status is None:
+ logger.exception(err)
+ raise
elif err.http_status == 408:
self.http_conn = None
elif 500 <= err.http_status <= 599:
diff --git a/swiftclient/service.py b/swiftclient/service.py
index af412d1..f204895 100644
--- a/swiftclient/service.py
+++ b/swiftclient/service.py
@@ -282,7 +282,7 @@ def split_headers(options, prefix=''):
for item in options:
split_item = item.split(':', 1)
if len(split_item) == 2:
- headers[(prefix + split_item[0]).title()] = split_item[1]
+ headers[(prefix + split_item[0]).title()] = split_item[1].strip()
else:
raise SwiftError(
"Metadata parameter %s must contain a ':'.\n%s"
@@ -323,13 +323,12 @@ class SwiftPostObject(object):
specified separately for each individual object.
"""
def __init__(self, object_name, options=None):
- if not isinstance(object_name, string_types) or not object_name:
+ if not (isinstance(object_name, string_types) and object_name):
raise SwiftError(
"Object names must be specified as non-empty strings"
)
- else:
- self.object_name = object_name
- self.options = options
+ self.object_name = object_name
+ self.options = options
class SwiftCopyObject(object):
@@ -340,7 +339,7 @@ class SwiftCopyObject(object):
destination and fresh_metadata should be set in options
"""
def __init__(self, object_name, options=None):
- if not isinstance(object_name, string_types) or not object_name:
+ if not (isinstance(object_name, string_types) and object_name):
raise SwiftError(
"Object names must be specified as non-empty strings"
)
diff --git a/tests/unit/test_service.py b/tests/unit/test_service.py
index d306fdb..546e495 100644
--- a/tests/unit/test_service.py
+++ b/tests/unit/test_service.py
@@ -532,7 +532,7 @@ class TestServiceUtils(unittest.TestCase):
self.assertEqual(opt_c['key'], 'key')
def test_split_headers(self):
- mock_headers = ['color:blue', 'size:large']
+ mock_headers = ['color:blue', 'SIZE: large']
expected = {'Color': 'blue', 'Size': 'large'}
actual = swiftclient.service.split_headers(mock_headers)
diff --git a/tests/unit/test_swiftclient.py b/tests/unit/test_swiftclient.py
index 4e4c9f4..0095447 100644
--- a/tests/unit/test_swiftclient.py
+++ b/tests/unit/test_swiftclient.py
@@ -335,79 +335,84 @@ class TestGetAuth(MockHttpTest):
def test_auth_v2_with_tenant_name(self):
os_options = {'tenant_name': 'asdf'}
req_args = {'auth_version': '2.0'}
- c.get_auth_keystone = fake_get_auth_keystone(os_options,
- required_kwargs=req_args)
- url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
- os_options=os_options,
- auth_version="2.0")
+ ks = fake_get_auth_keystone(os_options, required_kwargs=req_args)
+ with mock.patch('swiftclient.client.get_auth_keystone', ks):
+ url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
+ os_options=os_options,
+ auth_version="2.0")
self.assertTrue(url.startswith("http"))
self.assertTrue(token)
def test_auth_v2_with_tenant_id(self):
os_options = {'tenant_id': 'asdf'}
req_args = {'auth_version': '2.0'}
- c.get_auth_keystone = fake_get_auth_keystone(os_options,
- required_kwargs=req_args)
- url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
- os_options=os_options,
- auth_version="2.0")
+ ks = fake_get_auth_keystone(os_options, required_kwargs=req_args)
+ with mock.patch('swiftclient.client.get_auth_keystone', ks):
+ url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
+ os_options=os_options,
+ auth_version="2.0")
self.assertTrue(url.startswith("http"))
self.assertTrue(token)
def test_auth_v2_with_project_name(self):
os_options = {'project_name': 'asdf'}
req_args = {'auth_version': '2.0'}
- c.get_auth_keystone = fake_get_auth_keystone(os_options,
- required_kwargs=req_args)
- url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
- os_options=os_options,
- auth_version="2.0")
+ ks = fake_get_auth_keystone(os_options, required_kwargs=req_args)
+ with mock.patch('swiftclient.client.get_auth_keystone', ks):
+ url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
+ os_options=os_options,
+ auth_version="2.0")
self.assertTrue(url.startswith("http"))
self.assertTrue(token)
def test_auth_v2_with_project_id(self):
os_options = {'project_id': 'asdf'}
req_args = {'auth_version': '2.0'}
- c.get_auth_keystone = fake_get_auth_keystone(os_options,
- required_kwargs=req_args)
- url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
- os_options=os_options,
- auth_version="2.0")
+
+ ks = fake_get_auth_keystone(os_options, required_kwargs=req_args)
+ with mock.patch('swiftclient.client.get_auth_keystone', ks):
+ url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
+ os_options=os_options,
+ auth_version="2.0")
self.assertTrue(url.startswith("http"))
self.assertTrue(token)
def test_auth_v2_no_tenant_name_or_tenant_id(self):
- c.get_auth_keystone = fake_get_auth_keystone({})
- self.assertRaises(c.ClientException, c.get_auth,
- 'http://www.tests.com', 'asdf', 'asdf',
- os_options={},
- auth_version='2.0')
+ with mock.patch('swiftclient.client.get_auth_keystone',
+ fake_get_auth_keystone({})):
+ self.assertRaises(c.ClientException, c.get_auth,
+ 'http://www.tests.com', 'asdf', 'asdf',
+ os_options={},
+ auth_version='2.0')
def test_auth_v2_with_tenant_name_none_and_tenant_id_none(self):
os_options = {'tenant_name': None,
'tenant_id': None}
- c.get_auth_keystone = fake_get_auth_keystone(os_options)
- self.assertRaises(c.ClientException, c.get_auth,
- 'http://www.tests.com', 'asdf', 'asdf',
- os_options=os_options,
- auth_version='2.0')
+ with mock.patch('swiftclient.client.get_auth_keystone',
+ fake_get_auth_keystone(os_options)):
+ self.assertRaises(c.ClientException, c.get_auth,
+ 'http://www.tests.com', 'asdf', 'asdf',
+ os_options=os_options,
+ auth_version='2.0')
def test_auth_v2_with_tenant_user_in_user(self):
tenant_option = {'tenant_name': 'foo'}
- c.get_auth_keystone = fake_get_auth_keystone(tenant_option)
- url, token = c.get_auth('http://www.test.com', 'foo:bar', 'asdf',
- os_options={},
- auth_version="2.0")
+ with mock.patch('swiftclient.client.get_auth_keystone',
+ fake_get_auth_keystone(tenant_option)):
+ url, token = c.get_auth('http://www.test.com', 'foo:bar', 'asdf',
+ os_options={},
+ auth_version="2.0")
self.assertTrue(url.startswith("http"))
self.assertTrue(token)
def test_auth_v2_tenant_name_no_os_options(self):
tenant_option = {'tenant_name': 'asdf'}
- c.get_auth_keystone = fake_get_auth_keystone(tenant_option)
- url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
- tenant_name='asdf',
- os_options={},
- auth_version="2.0")
+ with mock.patch('swiftclient.client.get_auth_keystone',
+ fake_get_auth_keystone(tenant_option)):
+ url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
+ tenant_name='asdf',
+ os_options={},
+ auth_version="2.0")
self.assertTrue(url.startswith("http"))
self.assertTrue(token)
@@ -415,138 +420,141 @@ class TestGetAuth(MockHttpTest):
os_options = {'service_type': 'object-store',
'endpoint_type': 'internalURL',
'tenant_name': 'asdf'}
- c.get_auth_keystone = fake_get_auth_keystone(os_options)
- url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
- os_options=os_options,
- auth_version="2.0")
+ with mock.patch('swiftclient.client.get_auth_keystone',
+ fake_get_auth_keystone(os_options)):
+ url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
+ os_options=os_options,
+ auth_version="2.0")
self.assertTrue(url.startswith("http"))
self.assertTrue(token)
def test_auth_v2_with_tenant_user_in_user_no_os_options(self):
tenant_option = {'tenant_name': 'foo'}
- c.get_auth_keystone = fake_get_auth_keystone(tenant_option)
- url, token = c.get_auth('http://www.test.com', 'foo:bar', 'asdf',
- auth_version="2.0")
+ with mock.patch('swiftclient.client.get_auth_keystone',
+ fake_get_auth_keystone(tenant_option)):
+ url, token = c.get_auth('http://www.test.com', 'foo:bar', 'asdf',
+ auth_version="2.0")
self.assertTrue(url.startswith("http"))
self.assertTrue(token)
def test_auth_v2_with_os_region_name(self):
os_options = {'region_name': 'good-region',
'tenant_name': 'asdf'}
- c.get_auth_keystone = fake_get_auth_keystone(os_options)
- url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
- os_options=os_options,
- auth_version="2.0")
+ with mock.patch('swiftclient.client.get_auth_keystone',
+ fake_get_auth_keystone(os_options)):
+ url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
+ os_options=os_options,
+ auth_version="2.0")
self.assertTrue(url.startswith("http"))
self.assertTrue(token)
def test_auth_v2_no_endpoint(self):
os_options = {'region_name': 'unknown_region',
'tenant_name': 'asdf'}
- c.get_auth_keystone = fake_get_auth_keystone(
- os_options, c.ClientException)
- self.assertRaises(c.ClientException, c.get_auth,
- 'http://www.tests.com', 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0')
+ with mock.patch('swiftclient.client.get_auth_keystone',
+ fake_get_auth_keystone(os_options, c.ClientException)):
+ self.assertRaises(c.ClientException, c.get_auth,
+ 'http://www.tests.com', 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0')
def test_auth_v2_ks_exception(self):
- c.get_auth_keystone = fake_get_auth_keystone(
- {}, c.ClientException)
- self.assertRaises(c.ClientException, c.get_auth,
- 'http://www.tests.com', 'asdf', 'asdf',
- os_options={},
- auth_version='2.0')
+ with mock.patch('swiftclient.client.get_auth_keystone',
+ fake_get_auth_keystone({}, c.ClientException)):
+ self.assertRaises(c.ClientException, c.get_auth,
+ 'http://www.tests.com', 'asdf', 'asdf',
+ os_options={},
+ auth_version='2.0')
def test_auth_v2_cacert(self):
os_options = {'tenant_name': 'foo'}
- c.get_auth_keystone = fake_get_auth_keystone(
- os_options, None)
-
auth_url_secure = 'https://www.tests.com'
auth_url_insecure = 'https://www.tests.com/self-signed-certificate'
- url, token = c.get_auth(auth_url_secure, 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0',
- insecure=False)
- self.assertTrue(url.startswith("http"))
- self.assertTrue(token)
-
- url, token = c.get_auth(auth_url_insecure, 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0',
- cacert='ca.pem', insecure=False)
- self.assertTrue(url.startswith("http"))
- self.assertTrue(token)
-
- self.assertRaises(c.ClientException, c.get_auth,
- auth_url_insecure, 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0')
- self.assertRaises(c.ClientException, c.get_auth,
- auth_url_insecure, 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0',
- insecure=False)
+ with mock.patch('swiftclient.client.get_auth_keystone',
+ fake_get_auth_keystone(os_options, None)):
+ url, token = c.get_auth(auth_url_secure, 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0',
+ insecure=False)
+ self.assertTrue(url.startswith("http"))
+ self.assertTrue(token)
+
+ url, token = c.get_auth(auth_url_insecure, 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0',
+ cacert='ca.pem', insecure=False)
+ self.assertTrue(url.startswith("http"))
+ self.assertTrue(token)
+
+ self.assertRaises(c.ClientException, c.get_auth,
+ auth_url_insecure, 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0')
+ self.assertRaises(c.ClientException, c.get_auth,
+ auth_url_insecure, 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0',
+ insecure=False)
def test_auth_v2_insecure(self):
os_options = {'tenant_name': 'foo'}
- c.get_auth_keystone = fake_get_auth_keystone(
- os_options, None)
-
auth_url_secure = 'https://www.tests.com'
auth_url_insecure = 'https://www.tests.com/invalid-certificate'
- url, token = c.get_auth(auth_url_secure, 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0')
- self.assertTrue(url.startswith("http"))
- self.assertTrue(token)
-
- url, token = c.get_auth(auth_url_insecure, 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0',
- insecure=True)
- self.assertTrue(url.startswith("http"))
- self.assertTrue(token)
-
- self.assertRaises(c.ClientException, c.get_auth,
- auth_url_insecure, 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0')
- self.assertRaises(c.ClientException, c.get_auth,
- auth_url_insecure, 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0',
- insecure=False)
+ with mock.patch('swiftclient.client.get_auth_keystone',
+ fake_get_auth_keystone(os_options, None)):
+ url, token = c.get_auth(auth_url_secure, 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0')
+ self.assertTrue(url.startswith("http"))
+ self.assertTrue(token)
+
+ url, token = c.get_auth(auth_url_insecure, 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0',
+ insecure=True)
+ self.assertTrue(url.startswith("http"))
+ self.assertTrue(token)
+
+ self.assertRaises(c.ClientException, c.get_auth,
+ auth_url_insecure, 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0')
+ self.assertRaises(c.ClientException, c.get_auth,
+ auth_url_insecure, 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0',
+ insecure=False)
def test_auth_v2_cert(self):
os_options = {'tenant_name': 'foo'}
- c.get_auth_keystone = fake_get_auth_keystone(os_options, None)
-
auth_url_no_sslauth = 'https://www.tests.com'
auth_url_sslauth = 'https://www.tests.com/client-certificate'
- url, token = c.get_auth(auth_url_no_sslauth, 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0')
- self.assertTrue(url.startswith("http"))
- self.assertTrue(token)
-
- url, token = c.get_auth(auth_url_sslauth, 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0',
- cert='minnie', cert_key='mickey')
- self.assertTrue(url.startswith("http"))
- self.assertTrue(token)
-
- self.assertRaises(c.ClientException, c.get_auth,
- auth_url_sslauth, 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0')
- self.assertRaises(c.ClientException, c.get_auth,
- auth_url_sslauth, 'asdf', 'asdf',
- os_options=os_options, auth_version='2.0',
- cert='minnie')
+ with mock.patch('swiftclient.client.get_auth_keystone',
+ fake_get_auth_keystone(os_options, None)):
+ url, token = c.get_auth(auth_url_no_sslauth, 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0')
+ self.assertTrue(url.startswith("http"))
+ self.assertTrue(token)
+
+ url, token = c.get_auth(auth_url_sslauth, 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0',
+ cert='minnie', cert_key='mickey')
+ self.assertTrue(url.startswith("http"))
+ self.assertTrue(token)
+
+ self.assertRaises(c.ClientException, c.get_auth,
+ auth_url_sslauth, 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0')
+ self.assertRaises(c.ClientException, c.get_auth,
+ auth_url_sslauth, 'asdf', 'asdf',
+ os_options=os_options, auth_version='2.0',
+ cert='minnie')
def test_auth_v3_with_tenant_name(self):
# check the correct auth version is passed to get_auth_keystone
os_options = {'tenant_name': 'asdf'}
req_args = {'auth_version': '3'}
- c.get_auth_keystone = fake_get_auth_keystone(os_options,
- required_kwargs=req_args)
- url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
- os_options=os_options,
- auth_version="3")
+
+ ks = fake_get_auth_keystone(os_options, required_kwargs=req_args)
+ with mock.patch('swiftclient.client.get_auth_keystone', ks):
+ url, token = c.get_auth('http://www.test.com', 'asdf', 'asdf',
+ os_options=os_options,
+ auth_version="3")
+
self.assertTrue(url.startswith("http"))
self.assertTrue(token)
@@ -554,10 +562,13 @@ class TestGetAuth(MockHttpTest):
# check the correct auth version is passed to get_auth_keystone
os_options = {'tenant_name': 'asdf'}
req_args = {'auth_version': '2.0'}
- c.get_auth_keystone = fake_get_auth_keystone(os_options,
- required_kwargs=req_args)
- url, token = c.get_keystoneclient_2_0('http://www.test.com', 'asdf',
- 'asdf', os_options=os_options)
+
+ ks = fake_get_auth_keystone(os_options, required_kwargs=req_args)
+ with mock.patch('swiftclient.client.get_auth_keystone', ks):
+ url, token = c.get_keystoneclient_2_0('http://www.test.com',
+ 'asdf', 'asdf',
+ os_options=os_options)
+
self.assertTrue(url.startswith("http"))
self.assertTrue(token)
@@ -2691,6 +2702,84 @@ class TestServiceToken(MockHttpTest):
self.assertEqual('service_project_name',
auth_kwargs['os_options']['tenant_name'])
+ def test_service_token_reauth_retries_0(self):
+ get_auth_call_list = []
+
+ def get_auth(url, user, key, **kwargs):
+ # The real get_auth function will always return the os_option
+ # dict's object_storage_url which will be overridden by the
+ # preauthurl parameter to Connection if it is provided.
+ args = {'url': url, 'user': user, 'key': key, 'kwargs': kwargs}
+ get_auth_call_list.append(args)
+ return_dict = {'asdf': 'new', 'service_username': 'newserv'}
+ storage_url = kwargs['os_options'].get('object_storage_url')
+ return storage_url, return_dict[user]
+
+ def swap_sleep(*args):
+ self.swap_sleep_called = True
+ c.get_auth = get_auth
+
+ with mock.patch('swiftclient.client.http_connection',
+ self.fake_http_connection(401, 200)):
+ with mock.patch('swiftclient.client.sleep', swap_sleep):
+ self.swap_sleep_called = False
+
+ conn = c.Connection('http://www.test.com', 'asdf', 'asdf',
+ preauthurl='http://www.old.com',
+ preauthtoken='old',
+ os_options=self.os_options,
+ retries=0)
+
+ self.assertEqual(conn.attempts, 0)
+ self.assertEqual(conn.url, 'http://www.old.com')
+ self.assertEqual(conn.token, 'old')
+
+ conn.head_account()
+
+ self.assertTrue(self.swap_sleep_called)
+ self.assertEqual(conn.attempts, 2)
+ # The original 'preauth' storage URL *must* be preserved
+ self.assertEqual(conn.url, 'http://www.old.com')
+ self.assertEqual(conn.token, 'new')
+ self.assertEqual(conn.service_token, 'newserv')
+
+ # Check get_auth was called with expected args
+ auth_args = get_auth_call_list[0]
+ auth_kwargs = get_auth_call_list[0]['kwargs']
+ self.assertEqual('asdf', auth_args['user'])
+ self.assertEqual('asdf', auth_args['key'])
+ self.assertEqual('service_key',
+ auth_kwargs['os_options']['service_key'])
+ self.assertEqual('service_username',
+ auth_kwargs['os_options']['service_username'])
+ self.assertEqual('service_project_name',
+ auth_kwargs['os_options']['service_project_name'])
+
+ auth_args = get_auth_call_list[1]
+ auth_kwargs = get_auth_call_list[1]['kwargs']
+ self.assertEqual('service_username', auth_args['user'])
+ self.assertEqual('service_key', auth_args['key'])
+ self.assertEqual('service_project_name',
+ auth_kwargs['os_options']['tenant_name'])
+
+ # Ensure this is not an endless loop - it fails after the second 401
+ with mock.patch('swiftclient.client.http_connection',
+ self.fake_http_connection(401, 401, 401, 401)):
+ with mock.patch('swiftclient.client.sleep', swap_sleep):
+ self.swap_sleep_called = False
+
+ conn = c.Connection('http://www.test.com', 'asdf', 'asdf',
+ preauthurl='http://www.old.com',
+ preauthtoken='old',
+ os_options=self.os_options,
+ retries=0)
+
+ self.assertEqual(conn.attempts, 0)
+ self.assertRaises(c.ClientException, conn.head_account)
+ self.assertEqual(conn.attempts, 2)
+ unused_responses = list(self.fake_connect.code_iter)
+ self.assertEqual(unused_responses, [401, 401])
+
def test_service_token_get_account(self):
with mock.patch('swiftclient.client.http_connection',
self.fake_http_connection(200)):