From b53a77d9aa37a8a41afdc16b1b9b595a2c7f503d Mon Sep 17 00:00:00 2001 From: greemo Date: Fri, 23 Oct 2020 20:19:23 +1100 Subject: [PATCH] Optionally use "name" for auth body attributes intead of "id" This seems to be more compatible with providers, and is in the example provided on the openstack website: https://docs.openstack.org/api-ref/identity/v3/?expanded=password-authentication-with-unscoped-authorization-detail#password-authentication-with-unscoped-authorization Co-authored-by: Daniel Jagszent Co-authored-by: Les Green --- .gitignore | 1 + Changes.txt | 2 ++ rst/backends.rst | 20 ++++++++++++++++++++ src/s3ql/backends/swift.py | 3 +-- src/s3ql/backends/swiftks.py | 18 ++++++++++++++---- 5 files changed, 38 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 1c88d3e67..e65e81c4b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ __pycache__/ /tests/.pytest_cache/ /tests/test.log /tests/test_crit.log +/.history diff --git a/Changes.txt b/Changes.txt index 0f476b031..b87b0b205 100644 --- a/Changes.txt +++ b/Changes.txt @@ -1,4 +1,6 @@ UNRELEASED CHANGES + * Added ability to specify domain-name, project-domain-name and tenant-name as options + for the OpenStack Swift (Keystone v3) backend for providers that prefer name to id. * The open() syscall supports the O_TRUNC flag now. diff --git a/rst/backends.rst b/rst/backends.rst index e06531006..d38db5375 100644 --- a/rst/backends.rst +++ b/rst/backends.rst @@ -269,6 +269,12 @@ The OpenStack backend accepts the following backend options: If your provider did not give you a domain ID, then it is most likely :var:`default`. +.. option:: domain-is-name + + If your provider only supplies you with the name of your domain and not the uuid, + you need to set this :var:`domain-is-name` option, whereby the :var:`domain` is used as the domain name, + not the domain id. + .. option:: project-domain In simple cases, the project domain will be the same as the auth @@ -278,6 +284,20 @@ The OpenStack backend accepts the following backend options: If your provider did not give you a domain ID, then it is most likely :var:`default`. +.. option:: project-domain-is-name + + If your provider only supplies you with the name of your project domain and not the uuid, + you need to set this :var:`project-domain-name` option, whereby the :var:`project-domain` is used + as the name of the project domain, not the id of the project domain. + If project-domain-is-name is not set, it is assumed the same as domain-is-name. + +.. option:: tenant-is-name + + Some providers use the tenant name to specify the storage location, and others use the tenant id. + If your provider uses the tenant name and not the id, you need to set this :var:`tenant-is-name` option. + If :var:`tenant-is-name` is provided, the :var:`` component of the login is used as the tenant + name, not the tenant id. + .. __: http://tools.ietf.org/html/rfc2616#section-8.2.3 .. _OpenStack: http://www.openstack.org/ .. _Swift: http://openstack.org/projects/storage/ diff --git a/src/s3ql/backends/swift.py b/src/s3ql/backends/swift.py index 489f0a999..334989f4d 100644 --- a/src/s3ql/backends/swift.py +++ b/src/s3ql/backends/swift.py @@ -39,8 +39,7 @@ class Backend(AbstractBackend, metaclass=ABCDocstMeta): hdr_prefix = 'X-Object-' known_options = {'no-ssl', 'ssl-ca-path', 'tcp-timeout', - 'disable-expect100', 'no-feature-detection', - 'domain', 'project_domain'} + 'disable-expect100', 'no-feature-detection'} _add_meta_headers = s3c.Backend._add_meta_headers _extractmeta = s3c.Backend._extractmeta diff --git a/src/s3ql/backends/swiftks.py b/src/s3ql/backends/swiftks.py index c43dd1d62..04d7412a6 100644 --- a/src/s3ql/backends/swiftks.py +++ b/src/s3ql/backends/swiftks.py @@ -21,6 +21,9 @@ class Backend(swift.Backend): + # Add the options for the v3 keystore swift. + known_options = swift.Backend.known_options | {'domain', 'project-domain', 'project-domain-is-name', 'domain-is-name', 'tenant-is-name'} + def __init__(self, options): self.region = None super().__init__(options) @@ -76,7 +79,12 @@ def _get_conn(self): tenant = None user = self.login + # We can optionally configure with tenant name instead of id. + tenant_is_name = 'tenant-is-name' in self.options + + # We can configure with domain as id or name. domain = self.options.get('domain', None) + domain_is_name = 'domain-is-name' in self.options if domain: if not tenant: raise ValueError("Tenant is required when Keystone v3 is used") @@ -84,7 +92,9 @@ def _get_conn(self): # In simple cases where there's only one domain, the project domain # will be the same as the authentication domain, but this option # allows for them to be different + # We can configure with project-domain as id or name project_domain = self.options.get('project-domain', domain) + project_domain_is_name = ('project-domain-is-name' in self.options) or domain_is_name auth_body = { 'auth': { @@ -94,7 +104,7 @@ def _get_conn(self): 'user': { 'name': user, 'domain': { - 'id': domain + ('name' if domain_is_name else 'id'): domain }, 'password': self.password } @@ -102,9 +112,9 @@ def _get_conn(self): }, 'scope': { 'project': { - 'id': tenant, + ('name' if tenant_is_name else 'id'): tenant, 'domain': { - 'id': project_domain + ('name' if project_domain_is_name else 'id'): project_domain } } } @@ -141,7 +151,7 @@ def _get_conn(self): cat = json.loads(conn.read().decode('utf-8')) - if self.options.get('domain', None): + if self.options.get('domain', None) or self.options.get('domain-name', None): self.auth_token = resp.headers['X-Subject-Token'] service_catalog = cat['token']['catalog'] else: