identity: Add support for domain config
https://docs.openstack.org/api-ref/identity/v3/index.html#create-domain-configuration Change-Id: I25e5e4266bfa1bf470fa2dcd38e9002950ecebef
This commit is contained in:
parent
d7993d779d
commit
60be29a596
@ -28,6 +28,14 @@ Domain Operations
|
||||
:members: create_domain, update_domain, delete_domain, get_domain,
|
||||
find_domain, domains
|
||||
|
||||
Domain Config Operations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. autoclass:: openstack.identity.v3._proxy.Proxy
|
||||
:noindex:
|
||||
:members: create_domain_config, delete_domain_config, get_domain_config,
|
||||
update_domain_config
|
||||
|
||||
Endpoint Operations
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -5,24 +5,15 @@ Identity v2 Resources
|
||||
---------------------
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:glob:
|
||||
|
||||
v2/extension
|
||||
v2/role
|
||||
v2/tenant
|
||||
v2/user
|
||||
v2/*
|
||||
|
||||
Identity v3 Resources
|
||||
---------------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:glob:
|
||||
|
||||
v3/credential
|
||||
v3/domain
|
||||
v3/endpoint
|
||||
v3/group
|
||||
v3/policy
|
||||
v3/project
|
||||
v3/service
|
||||
v3/trust
|
||||
v3/user
|
||||
v3/*
|
||||
|
12
doc/source/user/resources/identity/v3/domain_config.rst
Normal file
12
doc/source/user/resources/identity/v3/domain_config.rst
Normal file
@ -0,0 +1,12 @@
|
||||
openstack.identity.v3.domain_config
|
||||
===================================
|
||||
|
||||
.. automodule:: openstack.identity.v3.domain_config
|
||||
|
||||
The Domain Class
|
||||
----------------
|
||||
|
||||
The ``DomainConfig`` class inherits from :class:`~openstack.resource.Resource`.
|
||||
|
||||
.. autoclass:: openstack.identity.v3.domain_config.DomainConfig
|
||||
:members:
|
@ -16,6 +16,7 @@ from openstack.identity.v3 import (
|
||||
)
|
||||
from openstack.identity.v3 import credential as _credential
|
||||
from openstack.identity.v3 import domain as _domain
|
||||
from openstack.identity.v3 import domain_config as _domain_config
|
||||
from openstack.identity.v3 import endpoint as _endpoint
|
||||
from openstack.identity.v3 import federation_protocol as _federation_protocol
|
||||
from openstack.identity.v3 import group as _group
|
||||
@ -51,6 +52,7 @@ from openstack.identity.v3 import system as _system
|
||||
from openstack.identity.v3 import trust as _trust
|
||||
from openstack.identity.v3 import user as _user
|
||||
from openstack import proxy
|
||||
from openstack import resource
|
||||
from openstack import utils
|
||||
|
||||
|
||||
@ -83,6 +85,8 @@ class Proxy(proxy.Proxy):
|
||||
"user": _user.User,
|
||||
}
|
||||
|
||||
# ========== Credentials ==========
|
||||
|
||||
def create_credential(self, **attrs):
|
||||
"""Create a new credential from attributes
|
||||
|
||||
@ -165,6 +169,8 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._update(_credential.Credential, credential, **attrs)
|
||||
|
||||
# ========== Domains ==========
|
||||
|
||||
def create_domain(self, **attrs):
|
||||
"""Create a new domain from attributes
|
||||
|
||||
@ -244,6 +250,85 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._update(_domain.Domain, domain, **attrs)
|
||||
|
||||
# ========== Domain configs ==========
|
||||
|
||||
def create_domain_config(self, domain, **attrs):
|
||||
"""Create a new config for a domain from attributes.
|
||||
|
||||
:param domain: The value can be the ID of a domain or
|
||||
a :class:`~openstack.identity.v3.domain.Domain` instance.
|
||||
:param dict attrs: Keyword arguments which will be used to create a
|
||||
:class:`~openstack.identity.v3.domain_config.DomainConfig`
|
||||
comprised of the properties on the DomainConfig class.
|
||||
|
||||
:returns: The results of domain config creation
|
||||
:rtype: :class:`~openstack.identity.v3.domain_config.DomainConfig`
|
||||
"""
|
||||
domain_id = resource.Resource._get_id(domain)
|
||||
return self._create(
|
||||
_domain_config.DomainConfig,
|
||||
domain_id=domain_id,
|
||||
**attrs,
|
||||
)
|
||||
|
||||
def delete_domain_config(self, domain, ignore_missing=True):
|
||||
"""Delete a config for a domain
|
||||
|
||||
:param domain: The value can be the ID of a domain or a
|
||||
a :class:`~openstack.identity.v3.domain.Domain` instance.
|
||||
:param bool ignore_missing: When set to ``False``
|
||||
:class:`~openstack.exceptions.ResourceNotFound` will be
|
||||
raised when the identity provider does not exist.
|
||||
When set to ``True``, no exception will be set when
|
||||
attempting to delete a nonexistent config for a domain.
|
||||
|
||||
:returns: ``None``
|
||||
"""
|
||||
domain_id = resource.Resource._get_id(domain)
|
||||
self._delete(
|
||||
_domain_config.DomainConfig,
|
||||
domain_id=domain_id,
|
||||
ignore_missing=ignore_missing,
|
||||
)
|
||||
|
||||
def get_domain_config(self, domain):
|
||||
"""Get a single config for a domain
|
||||
|
||||
:param domain_id: The value can be the ID of a domain or a
|
||||
:class:`~openstack.identity.v3.domain.Domain` instance.
|
||||
|
||||
:returns: One
|
||||
:class:`~openstack.identity.v3.domain_config.DomainConfig`
|
||||
:raises: :class:`~openstack.exceptions.ResourceNotFound` when no
|
||||
resource can be found.
|
||||
"""
|
||||
domain_id = resource.Resource._get_id(domain)
|
||||
return self._get(
|
||||
_domain_config.DomainConfig,
|
||||
domain_id=domain_id,
|
||||
requires_id=False,
|
||||
)
|
||||
|
||||
def update_domain_config(self, domain, **attrs):
|
||||
"""Update a config for a domain
|
||||
|
||||
:param domain_id: The value can be the ID of a domain or a
|
||||
:class:`~openstack.identity.v3.domain.Domain` instance.
|
||||
:attrs kwargs: The attributes to update on the config for a domain
|
||||
represented by ``domain_id``.
|
||||
|
||||
:returns: The updated config for a domain
|
||||
:rtype: :class:`~openstack.identity.v3.domain_config.DomainConfig`
|
||||
"""
|
||||
domain_id = resource.Resource._get_id(domain)
|
||||
return self._update(
|
||||
_domain_config.DomainConfig,
|
||||
domain_id=domain_id,
|
||||
**attrs,
|
||||
)
|
||||
|
||||
# ========== Endpoints ==========
|
||||
|
||||
def create_endpoint(self, **attrs):
|
||||
"""Create a new endpoint from attributes
|
||||
|
||||
@ -326,6 +411,8 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._update(_endpoint.Endpoint, endpoint, **attrs)
|
||||
|
||||
# ========== Groups ==========
|
||||
|
||||
def create_group(self, **attrs):
|
||||
"""Create a new group from attributes
|
||||
|
||||
@ -462,6 +549,8 @@ class Proxy(proxy.Proxy):
|
||||
users = self._list(_user.User, base_path=base_path, **attrs)
|
||||
return users
|
||||
|
||||
# ========== Policies ==========
|
||||
|
||||
def create_policy(self, **attrs):
|
||||
"""Create a new policy from attributes
|
||||
|
||||
@ -541,6 +630,8 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._update(_policy.Policy, policy, **attrs)
|
||||
|
||||
# ========== Project ==========
|
||||
|
||||
def create_project(self, **attrs):
|
||||
"""Create a new project from attributes
|
||||
|
||||
@ -638,6 +729,8 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._update(_project.Project, project, **attrs)
|
||||
|
||||
# ========== Services ==========
|
||||
|
||||
def create_service(self, **attrs):
|
||||
"""Create a new service from attributes
|
||||
|
||||
@ -717,6 +810,8 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._update(_service.Service, service, **attrs)
|
||||
|
||||
# ========== Users ==========
|
||||
|
||||
def create_user(self, **attrs):
|
||||
"""Create a new user from attributes
|
||||
|
||||
@ -799,6 +894,8 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._update(_user.User, user, **attrs)
|
||||
|
||||
# ========== Trusts ==========
|
||||
|
||||
def create_trust(self, **attrs):
|
||||
"""Create a new trust from attributes
|
||||
|
||||
@ -865,6 +962,8 @@ class Proxy(proxy.Proxy):
|
||||
# TODO(briancurtin): This is paginated but requires base list changes.
|
||||
return self._list(_trust.Trust, **query)
|
||||
|
||||
# ========== Regions ==========
|
||||
|
||||
def create_region(self, **attrs):
|
||||
"""Create a new region from attributes
|
||||
|
||||
@ -944,6 +1043,8 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._update(_region.Region, region, **attrs)
|
||||
|
||||
# ========== Roles ==========
|
||||
|
||||
def create_role(self, **attrs):
|
||||
"""Create a new role from attributes
|
||||
|
||||
@ -1025,6 +1126,8 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._update(_role.Role, role, **attrs)
|
||||
|
||||
# ========== Role assignments ==========
|
||||
|
||||
def role_assignments_filter(
|
||||
self, domain=None, project=None, system=None, group=None, user=None
|
||||
):
|
||||
@ -1127,6 +1230,8 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._list(_role_assignment.RoleAssignment, **query)
|
||||
|
||||
# ========== Registered limits ==========
|
||||
|
||||
def registered_limits(self, **query):
|
||||
"""Retrieve a generator of registered_limits
|
||||
|
||||
@ -1204,6 +1309,8 @@ class Proxy(proxy.Proxy):
|
||||
ignore_missing=ignore_missing,
|
||||
)
|
||||
|
||||
# ========== Limits ==========
|
||||
|
||||
def limits(self, **query):
|
||||
"""Retrieve a generator of limits
|
||||
|
||||
@ -1267,6 +1374,8 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
self._delete(limit.Limit, limit, ignore_missing=ignore_missing)
|
||||
|
||||
# ========== Roles ==========
|
||||
|
||||
def assign_domain_role_to_user(self, domain, user, role):
|
||||
"""Assign role to user on a domain
|
||||
|
||||
@ -1555,6 +1664,8 @@ class Proxy(proxy.Proxy):
|
||||
system = self._get_resource(_system.System, system)
|
||||
return system.validate_group_has_role(self, group, role)
|
||||
|
||||
# ========== Application credentials ==========
|
||||
|
||||
def application_credentials(self, user, **query):
|
||||
"""Retrieve a generator of application credentials
|
||||
|
||||
@ -1681,6 +1792,8 @@ class Proxy(proxy.Proxy):
|
||||
ignore_missing=ignore_missing,
|
||||
)
|
||||
|
||||
# ========== Federation protocols ==========
|
||||
|
||||
def create_federation_protocol(self, idp_id, **attrs):
|
||||
"""Create a new federation protocol from attributes
|
||||
|
||||
@ -1834,6 +1947,8 @@ class Proxy(proxy.Proxy):
|
||||
idp_id = idp_id.id
|
||||
return self._update(cls, protocol, idp_id=idp_id, **attrs)
|
||||
|
||||
# ========== Mappings ==========
|
||||
|
||||
def create_mapping(self, **attrs):
|
||||
"""Create a new mapping from attributes
|
||||
|
||||
@ -1914,6 +2029,8 @@ class Proxy(proxy.Proxy):
|
||||
"""
|
||||
return self._update(_mapping.Mapping, mapping, **attrs)
|
||||
|
||||
# ========== Identity providers ==========
|
||||
|
||||
def create_identity_provider(self, **attrs):
|
||||
"""Create a new identity provider from attributes
|
||||
|
||||
|
47
openstack/identity/v3/domain_config.py
Normal file
47
openstack/identity/v3/domain_config.py
Normal file
@ -0,0 +1,47 @@
|
||||
# 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 openstack import resource
|
||||
|
||||
|
||||
class DomainConfigLDAP(resource.Resource):
|
||||
#: The base distinguished name (DN) of LDAP.
|
||||
user_tree_dn = resource.Body('user_tree_dn')
|
||||
#: The LDAP URL.
|
||||
url = resource.Body('url')
|
||||
|
||||
|
||||
class DomainConfigDriver(resource.Resource):
|
||||
#: The Identity backend driver.
|
||||
driver = resource.Body('driver')
|
||||
|
||||
|
||||
class DomainConfig(resource.Resource):
|
||||
resource_key = 'config'
|
||||
base_path = '/domains/%(domain_id)s/config'
|
||||
requires_id = False
|
||||
create_requires_id = False
|
||||
commit_method = 'PATCH'
|
||||
create_method = 'PUT'
|
||||
|
||||
# capabilities
|
||||
allow_create = True
|
||||
allow_fetch = True
|
||||
allow_commit = True
|
||||
allow_delete = True
|
||||
|
||||
#: The domain ID.
|
||||
domain_id = resource.URI('domain_id')
|
||||
#: An identity object.
|
||||
identity = resource.Body('identity', type=DomainConfigDriver)
|
||||
#: The config object.
|
||||
ldap = resource.Body('ldap', type=DomainConfigLDAP)
|
83
openstack/tests/functional/identity/v3/test_domain_config.py
Normal file
83
openstack/tests/functional/identity/v3/test_domain_config.py
Normal file
@ -0,0 +1,83 @@
|
||||
# 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 openstack.identity.v3 import domain as _domain
|
||||
from openstack.identity.v3 import domain_config as _domain_config
|
||||
from openstack.tests.functional import base
|
||||
|
||||
|
||||
class TestDomainConfig(base.BaseFunctionalTest):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.domain_name = self.getUniqueString()
|
||||
|
||||
# create the domain and domain config
|
||||
|
||||
self.domain = self.operator_cloud.create_domain(
|
||||
name=self.domain_name,
|
||||
)
|
||||
self.assertIsInstance(self.domain, _domain.Domain)
|
||||
self.addCleanup(self._delete_domain)
|
||||
|
||||
def _delete_domain(self):
|
||||
self.operator_cloud.identity.update_domain(
|
||||
self.domain,
|
||||
enabled=False,
|
||||
)
|
||||
self.operator_cloud.identity.delete_domain(self.domain)
|
||||
|
||||
def test_domain_config(self):
|
||||
# create the domain config
|
||||
|
||||
domain_config = self.operator_cloud.identity.create_domain_config(
|
||||
self.domain,
|
||||
identity={'driver': uuid.uuid4().hex},
|
||||
ldap={'url': uuid.uuid4().hex},
|
||||
)
|
||||
self.assertIsInstance(
|
||||
domain_config,
|
||||
_domain_config.DomainConfig,
|
||||
)
|
||||
|
||||
# update the domain config
|
||||
|
||||
ldap_url = uuid.uuid4().hex
|
||||
domain_config = self.operator_cloud.identity.update_domain_config(
|
||||
self.domain,
|
||||
ldap={'url': ldap_url},
|
||||
)
|
||||
self.assertIsInstance(
|
||||
domain_config,
|
||||
_domain_config.DomainConfig,
|
||||
)
|
||||
|
||||
# retrieve details of the (updated) domain config
|
||||
|
||||
domain_config = self.operator_cloud.identity.get_domain_config(
|
||||
self.domain,
|
||||
)
|
||||
self.assertIsInstance(
|
||||
domain_config,
|
||||
_domain_config.DomainConfig,
|
||||
)
|
||||
self.assertEqual(ldap_url, domain_config.ldap.url)
|
||||
|
||||
# delete the domain config
|
||||
|
||||
result = self.operator_cloud.identity.delete_domain_config(
|
||||
self.domain,
|
||||
ignore_missing=False,
|
||||
)
|
||||
self.assertIsNone(result)
|
47
openstack/tests/unit/identity/v3/test_domain_config.py
Normal file
47
openstack/tests/unit/identity/v3/test_domain_config.py
Normal file
@ -0,0 +1,47 @@
|
||||
# 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 openstack.identity.v3 import domain_config
|
||||
from openstack.tests.unit import base
|
||||
|
||||
|
||||
EXAMPLE = {
|
||||
'identity': {
|
||||
'driver': 'ldap',
|
||||
},
|
||||
'ldap': {
|
||||
'url': 'ldap://myldap.com:389/',
|
||||
'user_tree_dn': 'ou=Users,dc=my_new_root,dc=org',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class TestDomainConfig(base.TestCase):
|
||||
def test_basic(self):
|
||||
sot = domain_config.DomainConfig()
|
||||
self.assertEqual('config', sot.resource_key)
|
||||
self.assertEqual('/domains/%(domain_id)s/config', sot.base_path)
|
||||
self.assertTrue(sot.allow_create)
|
||||
self.assertTrue(sot.allow_fetch)
|
||||
self.assertTrue(sot.allow_commit)
|
||||
self.assertTrue(sot.allow_delete)
|
||||
|
||||
def test_make_it(self):
|
||||
sot = domain_config.DomainConfig(**EXAMPLE)
|
||||
self.assertIsInstance(sot.identity, domain_config.DomainConfigDriver)
|
||||
self.assertEqual(EXAMPLE['identity']['driver'], sot.identity.driver)
|
||||
self.assertIsInstance(sot.ldap, domain_config.DomainConfigLDAP)
|
||||
self.assertEqual(EXAMPLE['ldap']['url'], sot.ldap.url)
|
||||
self.assertEqual(
|
||||
EXAMPLE['ldap']['user_tree_dn'],
|
||||
sot.ldap.user_tree_dn,
|
||||
)
|
@ -15,6 +15,7 @@ import uuid
|
||||
from openstack.identity.v3 import _proxy
|
||||
from openstack.identity.v3 import credential
|
||||
from openstack.identity.v3 import domain
|
||||
from openstack.identity.v3 import domain_config
|
||||
from openstack.identity.v3 import endpoint
|
||||
from openstack.identity.v3 import group
|
||||
from openstack.identity.v3 import policy
|
||||
@ -85,6 +86,75 @@ class TestIdentityProxyDomain(TestIdentityProxyBase):
|
||||
self.verify_update(self.proxy.update_domain, domain.Domain)
|
||||
|
||||
|
||||
class TestIdentityProxyDomainConfig(TestIdentityProxyBase):
|
||||
def test_domain_config_create_attrs(self):
|
||||
self.verify_create(
|
||||
self.proxy.create_domain_config,
|
||||
domain_config.DomainConfig,
|
||||
method_args=['domain_id'],
|
||||
method_kwargs={},
|
||||
expected_args=[],
|
||||
expected_kwargs={
|
||||
'domain_id': 'domain_id',
|
||||
},
|
||||
)
|
||||
|
||||
def test_domain_config_delete(self):
|
||||
self.verify_delete(
|
||||
self.proxy.delete_domain_config,
|
||||
domain_config.DomainConfig,
|
||||
ignore_missing=False,
|
||||
method_args=['domain_id'],
|
||||
method_kwargs={},
|
||||
expected_args=[],
|
||||
expected_kwargs={
|
||||
'domain_id': 'domain_id',
|
||||
},
|
||||
)
|
||||
|
||||
def test_domain_config_delete_ignore(self):
|
||||
self.verify_delete(
|
||||
self.proxy.delete_domain_config,
|
||||
domain_config.DomainConfig,
|
||||
ignore_missing=True,
|
||||
method_args=['domain_id'],
|
||||
method_kwargs={},
|
||||
expected_args=[],
|
||||
expected_kwargs={
|
||||
'domain_id': 'domain_id',
|
||||
},
|
||||
)
|
||||
|
||||
# no find_domain_config
|
||||
|
||||
def test_domain_config_get(self):
|
||||
self.verify_get(
|
||||
self.proxy.get_domain_config,
|
||||
domain_config.DomainConfig,
|
||||
method_args=['domain_id'],
|
||||
method_kwargs={},
|
||||
expected_args=[],
|
||||
expected_kwargs={
|
||||
'domain_id': 'domain_id',
|
||||
'requires_id': False,
|
||||
},
|
||||
)
|
||||
|
||||
# no domain_configs
|
||||
|
||||
def test_domain_config_update(self):
|
||||
self.verify_update(
|
||||
self.proxy.update_domain_config,
|
||||
domain_config.DomainConfig,
|
||||
method_args=['domain_id'],
|
||||
method_kwargs={},
|
||||
expected_args=[],
|
||||
expected_kwargs={
|
||||
'domain_id': 'domain_id',
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class TestIdentityProxyEndpoint(TestIdentityProxyBase):
|
||||
def test_endpoint_create_attrs(self):
|
||||
self.verify_create(self.proxy.create_endpoint, endpoint.Endpoint)
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add support for creating, updating and deleting domain configurations for
|
||||
the identity service.
|
Loading…
Reference in New Issue
Block a user