summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/using-api-v3.rst1
-rw-r--r--keystoneclient/tests/functional/v3/client_fixtures.py17
-rw-r--r--keystoneclient/tests/functional/v3/test_domain_configs.py101
-rw-r--r--keystoneclient/tests/unit/v3/test_domain_configs.py96
-rw-r--r--keystoneclient/v3/client.py6
-rw-r--r--keystoneclient/v3/domain_configs.py130
-rw-r--r--releasenotes/notes/bp-domain-config-9566e672a98f4e7f.yaml7
7 files changed, 358 insertions, 0 deletions
diff --git a/doc/source/using-api-v3.rst b/doc/source/using-api-v3.rst
index 8e2093d..f0c82c5 100644
--- a/doc/source/using-api-v3.rst
+++ b/doc/source/using-api-v3.rst
@@ -8,6 +8,7 @@ Introduction
The main concepts in the Identity v3 API are:
* :py:mod:`~keystoneclient.v3.credentials`
+ * :py:mod:`~keystoneclient.v3.domain_configs`
* :py:mod:`~keystoneclient.v3.domains`
* :py:mod:`~keystoneclient.v3.endpoints`
* :py:mod:`~keystoneclient.v3.groups`
diff --git a/keystoneclient/tests/functional/v3/client_fixtures.py b/keystoneclient/tests/functional/v3/client_fixtures.py
index 4b54b88..37da4a4 100644
--- a/keystoneclient/tests/functional/v3/client_fixtures.py
+++ b/keystoneclient/tests/functional/v3/client_fixtures.py
@@ -219,3 +219,20 @@ class EC2(Base):
self.addCleanup(self.client.ec2.delete,
self.user_id,
self.entity.access)
+
+
+class DomainConfig(Base):
+
+ def __init__(self, client, domain_id):
+ super(DomainConfig, self).__init__(client, domain_id=domain_id)
+ self.domain_id = domain_id
+
+ def setUp(self):
+ super(DomainConfig, self).setUp()
+
+ self.ref = {'identity': {'driver': uuid.uuid4().hex},
+ 'ldap': {'url': uuid.uuid4().hex}}
+ self.entity = self.client.domain_configs.create(
+ self.domain_id, self.ref)
+ self.addCleanup(self.client.domain_configs.delete,
+ self.domain_id)
diff --git a/keystoneclient/tests/functional/v3/test_domain_configs.py b/keystoneclient/tests/functional/v3/test_domain_configs.py
new file mode 100644
index 0000000..91112be
--- /dev/null
+++ b/keystoneclient/tests/functional/v3/test_domain_configs.py
@@ -0,0 +1,101 @@
+# 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 uuid
+
+from keystoneauth1.exceptions import http
+from keystoneclient.tests.functional import base
+from keystoneclient.tests.functional.v3 import client_fixtures as fixtures
+
+
+class DomainConfigsTestCase(base.V3ClientTestCase):
+
+ def check_domain_config(self, config, config_ref):
+ for attr in config_ref:
+ self.assertEqual(
+ getattr(config, attr),
+ config_ref[attr],
+ 'Expected different %s' % attr)
+
+ def _new_ref(self):
+ return {'identity': {'driver': uuid.uuid4().hex},
+ 'ldap': {'url': uuid.uuid4().hex}}
+
+ def test_create_domain_config(self):
+ config_ref = self._new_ref()
+ config = self.client.domain_configs.create(
+ self.project_domain_id, config_ref)
+ self.addCleanup(
+ self.client.domain_configs.delete, self.project_domain_id)
+ self.check_domain_config(config, config_ref)
+
+ def test_create_invalid_domain_config(self):
+ invalid_groups_ref = {
+ uuid.uuid4().hex: {uuid.uuid4().hex: uuid.uuid4().hex},
+ uuid.uuid4().hex: {uuid.uuid4().hex: uuid.uuid4().hex}}
+ self.assertRaises(http.Forbidden,
+ self.client.domain_configs.create,
+ self.project_domain_id,
+ invalid_groups_ref)
+
+ invalid_options_ref = {
+ 'identity': {uuid.uuid4().hex: uuid.uuid4().hex},
+ 'ldap': {uuid.uuid4().hex: uuid.uuid4().hex}}
+ self.assertRaises(http.Forbidden,
+ self.client.domain_configs.create,
+ self.project_domain_id,
+ invalid_options_ref)
+
+ def test_get_domain_config(self):
+ config = fixtures.DomainConfig(self.client, self.project_domain_id)
+ self.useFixture(config)
+
+ config_ret = self.client.domain_configs.get(self.project_domain_id)
+ self.check_domain_config(config_ret, config.ref)
+
+ def test_update_domain_config(self):
+ config = fixtures.DomainConfig(self.client, self.project_domain_id)
+ self.useFixture(config)
+
+ update_config_ref = self._new_ref()
+ config_ret = self.client.domain_configs.update(
+ self.project_domain_id, update_config_ref)
+ self.check_domain_config(config_ret, update_config_ref)
+
+ def test_update_invalid_domain_config(self):
+ config = fixtures.DomainConfig(self.client, self.project_domain_id)
+ self.useFixture(config)
+
+ invalid_groups_ref = {
+ uuid.uuid4().hex: {uuid.uuid4().hex: uuid.uuid4().hex},
+ uuid.uuid4().hex: {uuid.uuid4().hex: uuid.uuid4().hex}}
+ self.assertRaises(http.Forbidden,
+ self.client.domain_configs.update,
+ self.project_domain_id,
+ invalid_groups_ref)
+
+ invalid_options_ref = {
+ 'identity': {uuid.uuid4().hex: uuid.uuid4().hex},
+ 'ldap': {uuid.uuid4().hex: uuid.uuid4().hex}}
+ self.assertRaises(http.Forbidden,
+ self.client.domain_configs.update,
+ self.project_domain_id,
+ invalid_options_ref)
+
+ def test_domain_config_delete(self):
+ config_ref = self._new_ref()
+ self.client.domain_configs.create(self.project_domain_id, config_ref)
+
+ self.client.domain_configs.delete(self.project_domain_id)
+ self.assertRaises(http.NotFound,
+ self.client.domain_configs.get,
+ self.project_domain_id)
diff --git a/keystoneclient/tests/unit/v3/test_domain_configs.py b/keystoneclient/tests/unit/v3/test_domain_configs.py
new file mode 100644
index 0000000..2a7df09
--- /dev/null
+++ b/keystoneclient/tests/unit/v3/test_domain_configs.py
@@ -0,0 +1,96 @@
+# 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 uuid
+
+from keystoneclient import exceptions
+from keystoneclient.tests.unit.v3 import utils
+from keystoneclient.v3 import domain_configs
+
+
+class DomainConfigsTests(utils.ClientTestCase, utils.CrudTests):
+ """Test domain config database management."""
+
+ def setUp(self):
+ super(DomainConfigsTests, self).setUp()
+ self.key = 'config'
+ self.model = domain_configs.DomainConfig
+ self.manager = self.client.domain_configs
+
+ def new_ref(self, **kwargs):
+ config_groups = {'identity': {uuid.uuid4().hex: uuid.uuid4().hex},
+ 'ldap': {uuid.uuid4().hex: uuid.uuid4().hex}}
+ kwargs.setdefault('config', config_groups)
+ return kwargs
+
+ def _assert_resource_attributes(self, resource, req_ref):
+ for attr in req_ref:
+ self.assertEqual(
+ getattr(resource, attr),
+ req_ref[attr],
+ 'Expected different %s' % attr)
+
+ def test_create(self):
+ domain_id = uuid.uuid4().hex
+ config = self.new_ref()
+
+ self.stub_url('PUT',
+ parts=['domains', domain_id, 'config'],
+ json=config, status_code=201)
+ res = self.manager.create(domain_id, config)
+ self._assert_resource_attributes(res, config['config'])
+ self.assertEntityRequestBodyIs(config)
+
+ def test_update(self):
+ domain_id = uuid.uuid4().hex
+ config = self.new_ref()
+
+ self.stub_url('PATCH',
+ parts=['domains', domain_id, 'config'],
+ json=config, status_code=200)
+ res = self.manager.update(domain_id, config)
+ self._assert_resource_attributes(res, config['config'])
+ self.assertEntityRequestBodyIs(config)
+
+ def test_get(self):
+ domain_id = uuid.uuid4().hex
+ config = self.new_ref()
+ config = config['config']
+
+ self.stub_entity('GET',
+ parts=['domains', domain_id, 'config'],
+ entity=config)
+ res = self.manager.get(domain_id)
+ self._assert_resource_attributes(res, config)
+
+ def test_delete(self):
+ domain_id = uuid.uuid4().hex
+ self.stub_url('DELETE',
+ parts=['domains', domain_id, 'config'],
+ status_code=204)
+ self.manager.delete(domain_id)
+
+ def test_list(self):
+ # List not supported for domain config
+ self.assertRaises(exceptions.MethodNotImplemented, self.manager.list)
+
+ def test_list_by_id(self):
+ # List not supported for domain config
+ self.assertRaises(exceptions.MethodNotImplemented, self.manager.list)
+
+ def test_list_params(self):
+ # List not supported for domain config
+ self.assertRaises(exceptions.MethodNotImplemented, self.manager.list)
+
+ def test_find(self):
+ # Find not supported for domain config
+ self.assertRaises(exceptions.MethodNotImplemented, self.manager.find)
diff --git a/keystoneclient/v3/client.py b/keystoneclient/v3/client.py
index 619de60..62c0c8d 100644
--- a/keystoneclient/v3/client.py
+++ b/keystoneclient/v3/client.py
@@ -30,6 +30,7 @@ from keystoneclient.v3.contrib import oauth1
from keystoneclient.v3.contrib import simple_cert
from keystoneclient.v3.contrib import trusts
from keystoneclient.v3 import credentials
+from keystoneclient.v3 import domain_configs
from keystoneclient.v3 import domains
from keystoneclient.v3 import ec2
from keystoneclient.v3 import endpoints
@@ -116,6 +117,10 @@ class Client(httpclient.HTTPClient):
:py:class:`keystoneclient.v3.credentials.CredentialManager`
+ .. py:attribute:: domain_configs
+
+ :py:class:`keystoneclient.v3.domain_configs.DomainConfigManager`
+
.. py:attribute:: ec2
:py:class:`keystoneclient.v3.ec2.EC2Manager`
@@ -209,6 +214,7 @@ class Client(httpclient.HTTPClient):
self.endpoint_policy = endpoint_policy.EndpointPolicyManager(
self._adapter)
self.endpoints = endpoints.EndpointManager(self._adapter)
+ self.domain_configs = domain_configs.DomainConfigManager(self._adapter)
self.domains = domains.DomainManager(self._adapter)
self.federation = federation.FederationManager(self._adapter)
self.groups = groups.GroupManager(self._adapter)
diff --git a/keystoneclient/v3/domain_configs.py b/keystoneclient/v3/domain_configs.py
new file mode 100644
index 0000000..4c011bc
--- /dev/null
+++ b/keystoneclient/v3/domain_configs.py
@@ -0,0 +1,130 @@
+# 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.
+
+from keystoneclient import base
+from keystoneclient import exceptions
+from keystoneclient.i18n import _
+
+
+class DomainConfig(base.Resource):
+ """An object representing a domain config association.
+
+ This resource object does not necessarily contain fixed attributes, as new
+ attributes are added in the server, they are supported here directly.
+ The currently supported configs are `identity` and `ldap`.
+
+ """
+
+ pass
+
+
+class DomainConfigManager(base.Manager):
+ """Manager class for manipulating domain config associations."""
+
+ resource_class = DomainConfig
+ key = 'config'
+
+ def build_url(self, domain):
+ return '/domains/%s/config' % base.getid(domain)
+
+ def create(self, domain, config):
+ """Create a config for a domain.
+
+ :param domain: the domain where the config is going to be applied.
+ :type domain: str or :py:class:`keystoneclient.v3.domains.Domain`
+
+ :param dict config: a dictionary of domain configurations.
+
+ Example of the ``config`` parameter::
+
+ {
+ "identity": {
+ "driver": "ldap"
+ },
+ "ldap": {
+ "url": "ldap://myldap.com:389/",
+ "user_tree_dn": "ou=Users,dc=my_new_root,dc=org"
+ }
+ }
+
+ :returns: the created domain config returned from server.
+ :rtype: :class:`keystoneclient.v3.domain_configs.DomainConfig`
+
+ """
+ base_url = self.build_url(domain)
+ body = {self.key: config}
+ return super(DomainConfigManager, self)._put(
+ base_url, body=body, response_key=self.key)
+
+ def get(self, domain):
+ """Get a config for a domain.
+
+ :param domain: the domain for which the config is defined.
+ :type domain: str or :py:class:`keystoneclient.v3.domains.Domain`
+
+ :returns: the domain config returned from server.
+ :rtype: :class:`keystoneclient.v3.domain_configs.DomainConfig`
+
+ """
+ base_url = self.build_url(domain)
+ return super(DomainConfigManager, self)._get(base_url, self.key)
+
+ def update(self, domain, config):
+ """Update a config for a domain.
+
+ :param domain: the domain where the config is going to be updated.
+ :type domain: str or :py:class:`keystoneclient.v3.domains.Domain`
+
+ :param dict config: a dictionary of domain configurations.
+
+ Example of the ``config`` parameter::
+
+ {
+ "identity": {
+ "driver": "ldap"
+ },
+ "ldap": {
+ "url": "ldap://myldap.com:389/",
+ "user_tree_dn": "ou=Users,dc=my_new_root,dc=org"
+ }
+ }
+
+ :returns: the updated domain config returned from server.
+ :rtype: :class:`keystoneclient.v3.domain_configs.DomainConfig`
+
+ """
+ base_url = self.build_url(domain)
+ body = {self.key: config}
+ return super(DomainConfigManager, self)._patch(
+ base_url, body=body, response_key=self.key)
+
+ def delete(self, domain):
+ """Delete a config for a domain.
+
+ :param domain: the domain which the config will be deleted on
+ the server.
+ :type domain: str or :class:`keystoneclient.v3.domains.Domain`
+
+ :returns: Response object with 204 status.
+ :rtype: :class:`requests.models.Response`
+
+ """
+ base_url = self.build_url(domain)
+ return super(DomainConfigManager, self)._delete(url=base_url)
+
+ def find(self, **kwargs):
+ raise exceptions.MethodNotImplemented(
+ _('Find not supported for domain configs'))
+
+ def list(self, **kwargs):
+ raise exceptions.MethodNotImplemented(
+ _('List not supported for domain configs'))
diff --git a/releasenotes/notes/bp-domain-config-9566e672a98f4e7f.yaml b/releasenotes/notes/bp-domain-config-9566e672a98f4e7f.yaml
new file mode 100644
index 0000000..e6ae2b0
--- /dev/null
+++ b/releasenotes/notes/bp-domain-config-9566e672a98f4e7f.yaml
@@ -0,0 +1,7 @@
+---
+features:
+ - Added support for ``domain configs``. A user can now
+ upload domain specific configurations to keytone
+ using the client. See ``client.domain_configs.create``,
+ ``client.domain_configs.delete``, ``client.domain_configs.get``
+ and ``client.domain_configs.update``.