Implement backend driver support for domain config
Add support for the backend driver storage for domain configs, both whitelisted and sensitive. A subsequent patch will add the support in the manager layer for actually implementing the whitelist checking, using the underlying driver provided in this patch. Partially Implements: blueprint domain-config-ext Change-Id: Id98da28f83ccc1e81d20cfda96da895edcc8a703
This commit is contained in:
parent
ec8f6070ab
commit
508b11a5b8
|
@ -43,6 +43,7 @@ def load_backends():
|
|||
assignment_api=_ASSIGNMENT_API,
|
||||
catalog_api=catalog.Manager(),
|
||||
credential_api=credential.Manager(),
|
||||
domain_config_api=resource.DomainConfigManager(),
|
||||
endpoint_filter_api=endpoint_filter.Manager(),
|
||||
endpoint_policy_api=endpoint_policy.Manager(),
|
||||
federation_api=federation.Manager(),
|
||||
|
|
|
@ -445,6 +445,12 @@ FILE_OPTIONS = {
|
|||
help='Maximum number of entities that will be returned '
|
||||
'in a resource collection.'),
|
||||
],
|
||||
'domain_config': [
|
||||
cfg.StrOpt('driver',
|
||||
default='keystone.resource.config_backends.sql.'
|
||||
'DomainConfig',
|
||||
help='Domain config backend driver.'),
|
||||
],
|
||||
'role': [
|
||||
# The role driver has no default for backward compatibility reasons.
|
||||
# If role driver is not specified, the assignment driver chooses
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
# 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 sqlalchemy as sql
|
||||
|
||||
from keystone.common import sql as ks_sql
|
||||
|
||||
WHITELIST_TABLE = 'whitelisted_config'
|
||||
SENSITIVE_TABLE = 'sensitive_config'
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
meta = sql.MetaData()
|
||||
meta.bind = migrate_engine
|
||||
|
||||
whitelist_table = sql.Table(
|
||||
WHITELIST_TABLE,
|
||||
meta,
|
||||
sql.Column('domain_id', sql.String(64), primary_key=True),
|
||||
sql.Column('group', sql.String(255), primary_key=True),
|
||||
sql.Column('option', sql.String(255), primary_key=True),
|
||||
sql.Column('value', ks_sql.JsonBlob.impl, nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8')
|
||||
whitelist_table.create(migrate_engine, checkfirst=True)
|
||||
|
||||
sensitive_table = sql.Table(
|
||||
SENSITIVE_TABLE,
|
||||
meta,
|
||||
sql.Column('domain_id', sql.String(64), primary_key=True),
|
||||
sql.Column('group', sql.String(255), primary_key=True),
|
||||
sql.Column('option', sql.String(255), primary_key=True),
|
||||
sql.Column('value', ks_sql.JsonBlob.impl, nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8')
|
||||
sensitive_table.create(migrate_engine, checkfirst=True)
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta = sql.MetaData()
|
||||
meta.bind = migrate_engine
|
||||
|
||||
table = sql.Table(WHITELIST_TABLE, meta, autoload=True)
|
||||
table.drop(migrate_engine, checkfirst=True)
|
||||
table = sql.Table(SENSITIVE_TABLE, meta, autoload=True)
|
||||
table.drop(migrate_engine, checkfirst=True)
|
|
@ -335,6 +335,12 @@ class PublicIDNotFound(NotFound):
|
|||
message_format = "%(id)s"
|
||||
|
||||
|
||||
class DomainConfigNotFound(NotFound):
|
||||
message_format = _('Could not find Domain Configuration for domain: '
|
||||
'%(domain_id)s, for group: %(group)s and '
|
||||
'option: %(option)s')
|
||||
|
||||
|
||||
class Conflict(Error):
|
||||
message_format = _("Conflict occurred attempting to store %(type)s -"
|
||||
" %(details)s")
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
# 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 keystone.common import sql
|
||||
from keystone import exception
|
||||
from keystone import resource
|
||||
|
||||
|
||||
class WhiteListedConfig(sql.ModelBase, sql.ModelDictMixin):
|
||||
__tablename__ = 'whitelisted_config'
|
||||
domain_id = sql.Column(sql.String(64), primary_key=True)
|
||||
group = sql.Column(sql.String(255), primary_key=True)
|
||||
option = sql.Column(sql.String(255), primary_key=True)
|
||||
value = sql.Column(sql.JsonBlob(), nullable=False)
|
||||
|
||||
def to_dict(self):
|
||||
d = super(WhiteListedConfig, self).to_dict()
|
||||
d.pop('domain_id')
|
||||
return d
|
||||
|
||||
|
||||
class SensitiveConfig(sql.ModelBase, sql.ModelDictMixin):
|
||||
__tablename__ = 'sensitive_config'
|
||||
domain_id = sql.Column(sql.String(64), primary_key=True)
|
||||
group = sql.Column(sql.String(255), primary_key=True)
|
||||
option = sql.Column(sql.String(255), primary_key=True)
|
||||
value = sql.Column(sql.JsonBlob(), nullable=False)
|
||||
|
||||
def to_dict(self):
|
||||
d = super(SensitiveConfig, self).to_dict()
|
||||
d.pop('domain_id')
|
||||
return d
|
||||
|
||||
|
||||
class DomainConfig(resource.DomainConfigDriver):
|
||||
|
||||
def choose_table(self, sensitive):
|
||||
if sensitive:
|
||||
return SensitiveConfig
|
||||
else:
|
||||
return WhiteListedConfig
|
||||
|
||||
@sql.handle_conflicts(conflict_type='domain_config')
|
||||
def create_config_option(self, domain_id, group, option, value,
|
||||
sensitive=False):
|
||||
with sql.transaction() as session:
|
||||
config_table = self.choose_table(sensitive)
|
||||
ref = config_table(domain_id=domain_id, group=group,
|
||||
option=option, value=value)
|
||||
session.add(ref)
|
||||
return ref.to_dict()
|
||||
|
||||
def _get_config_option(self, session, domain_id, group, option, sensitive):
|
||||
try:
|
||||
config_table = self.choose_table(sensitive)
|
||||
ref = (session.query(config_table).
|
||||
filter_by(domain_id=domain_id, group=group,
|
||||
option=option).one())
|
||||
except sql.NotFound:
|
||||
raise exception.DomainConfigNotFound(
|
||||
domain_id=domain_id, group=group, option=option)
|
||||
return ref
|
||||
|
||||
def get_config_option(self, domain_id, group, option, sensitive=False):
|
||||
with sql.transaction() as session:
|
||||
ref = self._get_config_option(session, domain_id, group, option,
|
||||
sensitive)
|
||||
return ref.to_dict()
|
||||
|
||||
def list_config_options(self, domain_id, group=None, option=None,
|
||||
sensitive=False):
|
||||
with sql.transaction() as session:
|
||||
config_table = self.choose_table(sensitive)
|
||||
query = session.query(config_table)
|
||||
query = query.filter_by(domain_id=domain_id)
|
||||
if group:
|
||||
query = query.filter_by(group=group)
|
||||
if option:
|
||||
query = query.filter_by(option=option)
|
||||
return [ref.to_dict() for ref in query.all()]
|
||||
|
||||
def update_config_option(self, domain_id, group, option, value,
|
||||
sensitive=False):
|
||||
with sql.transaction() as session:
|
||||
ref = self._get_config_option(session, domain_id, group, option,
|
||||
sensitive)
|
||||
ref.value = value
|
||||
return ref.to_dict()
|
||||
|
||||
def delete_config_options(self, domain_id, group=None, option=None,
|
||||
sensitive=False):
|
||||
"""Deletes config options that match the filter parameters.
|
||||
|
||||
Since the public API is broken down into calls for delete in both the
|
||||
whitelisted and sensitive methods, we are silent at the driver level
|
||||
if there was nothing to delete.
|
||||
|
||||
"""
|
||||
with sql.transaction() as session:
|
||||
config_table = self.choose_table(sensitive)
|
||||
query = session.query(config_table)
|
||||
query = query.filter_by(domain_id=domain_id)
|
||||
if group:
|
||||
query = query.filter_by(group=group)
|
||||
if option:
|
||||
query = query.filter_by(option=option)
|
||||
query.delete(False)
|
|
@ -47,8 +47,8 @@ def calc_default_domain():
|
|||
|
||||
|
||||
@dependency.provider('resource_api')
|
||||
@dependency.requires('assignment_api', 'credential_api', 'identity_api',
|
||||
'revoke_api')
|
||||
@dependency.requires('assignment_api', 'credential_api', 'domain_config_api',
|
||||
'identity_api', 'revoke_api')
|
||||
class Manager(manager.Manager):
|
||||
"""Default pivot point for the resource backend.
|
||||
|
||||
|
@ -446,6 +446,9 @@ class Manager(manager.Manager):
|
|||
'please disable it first.'))
|
||||
|
||||
self._delete_domain_contents(domain_id)
|
||||
# Delete any database stored domain config
|
||||
self.domain_config_api.delete_config_options(domain_id)
|
||||
self.domain_config_api.delete_config_options(domain_id, sensitive=True)
|
||||
# TODO(henry-nash): Although the controller will ensure deletion of
|
||||
# all users & groups within the domain (which will cause all
|
||||
# assignments for those users/groups to also be deleted), there
|
||||
|
@ -782,3 +785,105 @@ class Driver(object):
|
|||
"""
|
||||
if domain_id != CONF.identity.default_domain_id:
|
||||
raise exception.DomainNotFound(domain_id=domain_id)
|
||||
|
||||
|
||||
@dependency.provider('domain_config_api')
|
||||
class DomainConfigManager(manager.Manager):
|
||||
"""Default pivot point for the Domain Config backend."""
|
||||
|
||||
def __init__(self):
|
||||
super(DomainConfigManager, self).__init__(CONF.domain_config.driver)
|
||||
|
||||
# TODO(henry-nash): The manager layer will handle all the whitelist
|
||||
# checking of the config options, using the appropriate driver methods for
|
||||
# the whitelisted and sensitive data.
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class DomainConfigDriver(object):
|
||||
"""Interface description for a Domain Config driver."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_config_option(self, domain_id, group, option, value,
|
||||
sensitive=False):
|
||||
"""Creates a config option for a domain.
|
||||
|
||||
:param domain_id: the domain for this option
|
||||
:param group: the group name
|
||||
:param option: the option name
|
||||
:param value: the value to assign to this option
|
||||
:param sensitive: whether the option is sensitive
|
||||
|
||||
:returns: dict containing group, option and value
|
||||
:raises: keystone.exception.Conflict
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_config_option(self, domain_id, group, option, sensitive=False):
|
||||
"""Gets the config option for a domain.
|
||||
|
||||
:param domain_id: the domain for this option
|
||||
:param group: the group name
|
||||
:param option: the option name
|
||||
:param sensitive: whether the option is sensitive
|
||||
|
||||
:returns: dict containing group, option and value
|
||||
:raises: keystone.exception.DomainConfigNotFound: the option doesn't
|
||||
exist.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def list_config_options(self, domain_id, group=None, option=False,
|
||||
sensitive=False):
|
||||
"""Gets a config options for a domain.
|
||||
|
||||
:param domain_id: the domain for this option
|
||||
:param group: optional group option name
|
||||
:param option: optional option name. If group is None, then this
|
||||
paramater is ignored
|
||||
:param sensitive: whether the option is sensitive
|
||||
|
||||
:returns: list of dicts containing group, option and value
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_config_option(self, domain_id, group, option, value,
|
||||
sensitive=False):
|
||||
"""Updates a config option for a domain.
|
||||
|
||||
:param domain_id: the domain for this option
|
||||
:param group: the group option name
|
||||
:param option: the option name
|
||||
:param value: the value to assign to this option
|
||||
:param sensitive: whether the option is sensitive
|
||||
|
||||
:returns: dict containing updated group, option and value
|
||||
:raises: keystone.exception.DomainConfigNotFound: the option doesn't
|
||||
exist.
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_config_options(self, domain_id, group=None, option=None,
|
||||
sensitive=False):
|
||||
"""Deletes config options for a domain.
|
||||
|
||||
Allows deletion of all options for a domain, all options in a group
|
||||
or a specific option. The driver is silent if there are no options
|
||||
to delete.
|
||||
|
||||
:param domain_id: the domain for this option
|
||||
:param group: optional group option name
|
||||
:param option: optional option name. If group is None, then this
|
||||
paramater is ignored
|
||||
:param sensitive: whether the option is sensitive
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented() # pragma: no cover
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
# 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 testtools import matchers
|
||||
|
||||
from keystone import exception
|
||||
|
||||
|
||||
class DomainConfigTests(object):
|
||||
|
||||
def setUp(self):
|
||||
self.domain = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
|
||||
self.resource_api.create_domain(self.domain['id'], self.domain)
|
||||
self.addCleanup(self.clean_up_domain)
|
||||
|
||||
def clean_up_domain(self):
|
||||
# NOTE(henry-nash): Deleting the domain will also delete any domain
|
||||
# configs for this domain.
|
||||
self.domain['enabled'] = False
|
||||
self.resource_api.update_domain(self.domain['id'], self.domain)
|
||||
self.resource_api.delete_domain(self.domain['id'])
|
||||
del self.domain
|
||||
|
||||
def _domain_config_crud(self, sensitive):
|
||||
group = uuid.uuid4().hex
|
||||
option = uuid.uuid4().hex
|
||||
value = uuid.uuid4().hex
|
||||
self.domain_config_api.create_config_option(
|
||||
self.domain['id'], group, option, value, sensitive)
|
||||
res = self.domain_config_api.get_config_option(
|
||||
self.domain['id'], group, option, sensitive)
|
||||
config = {'group': group, 'option': option, 'value': value}
|
||||
self.assertEqual(config, res)
|
||||
|
||||
value = uuid.uuid4().hex
|
||||
self.domain_config_api.update_config_option(
|
||||
self.domain['id'], group, option, value, sensitive)
|
||||
res = self.domain_config_api.get_config_option(
|
||||
self.domain['id'], group, option, sensitive)
|
||||
config = {'group': group, 'option': option, 'value': value}
|
||||
self.assertEqual(config, res)
|
||||
|
||||
self.domain_config_api.delete_config_options(
|
||||
self.domain['id'], group, option, sensitive)
|
||||
self.assertRaises(exception.DomainConfigNotFound,
|
||||
self.domain_config_api.get_config_option,
|
||||
self.domain['id'], group, option, sensitive)
|
||||
# ...and silent if we try to delete it again
|
||||
self.domain_config_api.delete_config_options(
|
||||
self.domain['id'], group, option, sensitive)
|
||||
|
||||
def test_whitelisted_domain_config_crud(self):
|
||||
self._domain_config_crud(sensitive=False)
|
||||
|
||||
def test_sensitive_domain_config_crud(self):
|
||||
self._domain_config_crud(sensitive=True)
|
||||
|
||||
def _list_domain_config(self, sensitive):
|
||||
"""Test listing by combination of domain, group & option."""
|
||||
|
||||
config1 = {'group': uuid.uuid4().hex, 'option': uuid.uuid4().hex,
|
||||
'value': uuid.uuid4().hex}
|
||||
# Put config2 in the same group as config1
|
||||
config2 = {'group': config1['group'], 'option': uuid.uuid4().hex,
|
||||
'value': uuid.uuid4().hex}
|
||||
config3 = {'group': uuid.uuid4().hex, 'option': uuid.uuid4().hex,
|
||||
'value': 100}
|
||||
for config in [config1, config2, config3]:
|
||||
self.domain_config_api.create_config_option(
|
||||
self.domain['id'], config['group'], config['option'],
|
||||
config['value'], sensitive)
|
||||
|
||||
# Try listing all items from a domain
|
||||
res = self.domain_config_api.list_config_options(
|
||||
self.domain['id'], sensitive=sensitive)
|
||||
self.assertThat(res, matchers.HasLength(3))
|
||||
for res_entry in res:
|
||||
self.assertIn(res_entry, [config1, config2, config3])
|
||||
|
||||
# Try listing by domain and group
|
||||
res = self.domain_config_api.list_config_options(
|
||||
self.domain['id'], group=config1['group'], sensitive=sensitive)
|
||||
self.assertThat(res, matchers.HasLength(2))
|
||||
for res_entry in res:
|
||||
self.assertIn(res_entry, [config1, config2])
|
||||
|
||||
# Try listing by domain, group and option
|
||||
res = self.domain_config_api.list_config_options(
|
||||
self.domain['id'], group=config2['group'],
|
||||
option=config2['option'], sensitive=sensitive)
|
||||
self.assertThat(res, matchers.HasLength(1))
|
||||
self.assertEqual(config2, res[0])
|
||||
|
||||
def test_list_whitelisted_domain_config_crud(self):
|
||||
self._list_domain_config(False)
|
||||
|
||||
def test_list_sensitive_domain_config_crud(self):
|
||||
self._list_domain_config(True)
|
||||
|
||||
def _delete_domain_configs(self, sensitive):
|
||||
"""Test deleting by combination of domain, group & option."""
|
||||
|
||||
config1 = {'group': uuid.uuid4().hex, 'option': uuid.uuid4().hex,
|
||||
'value': uuid.uuid4().hex}
|
||||
# Put config2 and config3 in the same group as config1
|
||||
config2 = {'group': config1['group'], 'option': uuid.uuid4().hex,
|
||||
'value': uuid.uuid4().hex}
|
||||
config3 = {'group': config1['group'], 'option': uuid.uuid4().hex,
|
||||
'value': uuid.uuid4().hex}
|
||||
config4 = {'group': uuid.uuid4().hex, 'option': uuid.uuid4().hex,
|
||||
'value': uuid.uuid4().hex}
|
||||
for config in [config1, config2, config3, config4]:
|
||||
self.domain_config_api.create_config_option(
|
||||
self.domain['id'], config['group'], config['option'],
|
||||
config['value'], sensitive)
|
||||
|
||||
# Try deleting by domain, group and option
|
||||
res = self.domain_config_api.delete_config_options(
|
||||
self.domain['id'], group=config2['group'],
|
||||
option=config2['option'], sensitive=sensitive)
|
||||
res = self.domain_config_api.list_config_options(
|
||||
self.domain['id'], sensitive=sensitive)
|
||||
self.assertThat(res, matchers.HasLength(3))
|
||||
for res_entry in res:
|
||||
self.assertIn(res_entry, [config1, config3, config4])
|
||||
|
||||
# Try deleting by domain and group
|
||||
res = self.domain_config_api.delete_config_options(
|
||||
self.domain['id'], group=config4['group'], sensitive=sensitive)
|
||||
res = self.domain_config_api.list_config_options(
|
||||
self.domain['id'], sensitive=sensitive)
|
||||
self.assertThat(res, matchers.HasLength(2))
|
||||
for res_entry in res:
|
||||
self.assertIn(res_entry, [config1, config3])
|
||||
|
||||
# Try deleting all items from a domain
|
||||
res = self.domain_config_api.delete_config_options(
|
||||
self.domain['id'], sensitive=sensitive)
|
||||
res = self.domain_config_api.list_config_options(
|
||||
self.domain['id'], sensitive=sensitive)
|
||||
self.assertThat(res, matchers.HasLength(0))
|
||||
|
||||
def test_delete_whitelisted_domain_configs(self):
|
||||
self._delete_domain_configs(False)
|
||||
|
||||
def test_delete_sensitive_domain_configs(self):
|
||||
self._delete_domain_configs(True)
|
||||
|
||||
def _create_domain_config_twice(self, sensitive):
|
||||
"""Test conflict error thrown if create the same option twice."""
|
||||
|
||||
config = {'group': uuid.uuid4().hex, 'option': uuid.uuid4().hex,
|
||||
'value': uuid.uuid4().hex}
|
||||
|
||||
self.domain_config_api.create_config_option(
|
||||
self.domain['id'], config['group'], config['option'],
|
||||
config['value'], sensitive=sensitive)
|
||||
self.assertRaises(exception.Conflict,
|
||||
self.domain_config_api.create_config_option,
|
||||
self.domain['id'], config['group'], config['option'],
|
||||
config['value'], sensitive=sensitive)
|
||||
|
||||
def test_create_whitelisted_domain_config_twice(self):
|
||||
self._create_domain_config_twice(False)
|
||||
|
||||
def test_create_sensitive_domain_config_twice(self):
|
||||
self._create_domain_config_twice(True)
|
||||
|
||||
def test_delete_domain_deletes_configs(self):
|
||||
"""Test domain deletion clears the domain configs."""
|
||||
|
||||
domain = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
|
||||
self.resource_api.create_domain(domain['id'], domain)
|
||||
config1 = {'group': uuid.uuid4().hex, 'option': uuid.uuid4().hex,
|
||||
'value': uuid.uuid4().hex}
|
||||
# Put config2 in the same group as config1
|
||||
config2 = {'group': config1['group'], 'option': uuid.uuid4().hex,
|
||||
'value': uuid.uuid4().hex}
|
||||
self.domain_config_api.create_config_option(
|
||||
domain['id'], config1['group'], config1['option'],
|
||||
config1['value'])
|
||||
self.domain_config_api.create_config_option(
|
||||
domain['id'], config2['group'], config2['option'],
|
||||
config2['value'], sensitive=True)
|
||||
res = self.domain_config_api.list_config_options(
|
||||
domain['id'])
|
||||
self.assertThat(res, matchers.HasLength(1))
|
||||
res = self.domain_config_api.list_config_options(
|
||||
domain['id'], sensitive=True)
|
||||
self.assertThat(res, matchers.HasLength(1))
|
||||
|
||||
# Now delete the domain
|
||||
domain['enabled'] = False
|
||||
self.resource_api.update_domain(domain['id'], domain)
|
||||
self.resource_api.delete_domain(domain['id'])
|
||||
|
||||
# Check domain configs have also been deleted
|
||||
res = self.domain_config_api.list_config_options(
|
||||
domain['id'])
|
||||
self.assertThat(res, matchers.HasLength(0))
|
||||
res = self.domain_config_api.list_config_options(
|
||||
domain['id'], sensitive=True)
|
||||
self.assertThat(res, matchers.HasLength(0))
|
|
@ -0,0 +1,41 @@
|
|||
# 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 keystone.common import sql
|
||||
from keystone.tests.unit.backend import core_sql
|
||||
from keystone.tests.unit.backend.domain_config import core
|
||||
|
||||
|
||||
class SqlDomainConfigModels(core_sql.BaseBackendSqlModels):
|
||||
|
||||
def test_whitelisted_model(self):
|
||||
cols = (('domain_id', sql.String, 64),
|
||||
('group', sql.String, 255),
|
||||
('option', sql.String, 255),
|
||||
('value', sql.JsonBlob, None))
|
||||
self.assertExpectedSchema('whitelisted_config', cols)
|
||||
|
||||
def test_sensitive_model(self):
|
||||
cols = (('domain_id', sql.String, 64),
|
||||
('group', sql.String, 255),
|
||||
('option', sql.String, 255),
|
||||
('value', sql.JsonBlob, None))
|
||||
self.assertExpectedSchema('sensitive_config', cols)
|
||||
|
||||
|
||||
class SqlDomainConfig(core_sql.BaseBackendSqlTests, core.DomainConfigTests):
|
||||
def setUp(self):
|
||||
super(SqlDomainConfig, self).setUp()
|
||||
# core.DomainConfigTests is effectively a mixin class, so make sure we
|
||||
# call its setup
|
||||
core.DomainConfigTests.setUp(self)
|
|
@ -1553,6 +1553,21 @@ class SqlUpgradeTests(SqlMigrateBase):
|
|||
self.assertTrue(self.does_fk_exist('group', 'domain_id'))
|
||||
self.assertTrue(self.does_fk_exist('user', 'domain_id'))
|
||||
|
||||
def test_add_domain_config(self):
|
||||
whitelisted_table = 'whitelisted_config'
|
||||
sensitive_table = 'sensitive_config'
|
||||
self.upgrade(64)
|
||||
self.assertTableDoesNotExist(whitelisted_table)
|
||||
self.assertTableDoesNotExist(sensitive_table)
|
||||
self.upgrade(65)
|
||||
self.assertTableColumns(whitelisted_table,
|
||||
['domain_id', 'group', 'option', 'value'])
|
||||
self.assertTableColumns(sensitive_table,
|
||||
['domain_id', 'group', 'option', 'value'])
|
||||
self.downgrade(64)
|
||||
self.assertTableDoesNotExist(whitelisted_table)
|
||||
self.assertTableDoesNotExist(sensitive_table)
|
||||
|
||||
def populate_user_table(self, with_pass_enab=False,
|
||||
with_pass_enab_domain=False):
|
||||
# Populate the appropriate fields in the user
|
||||
|
|
Loading…
Reference in New Issue