Handle partial dict setting

In Train cycle, we moved the definition of default values
to openstack_dashboard/defaults.py. The current code accesses
a dict member using []. It requires operators to define a dict
setting with a full member.

This commit allows to use dict-type settings with partial members.

A new function is introduced to retrieve a dict-type setting
considering default values defined in
{openstack_dashboard,horizon,openstack_auth}/defaults.py

Change-Id: I7ff0ad4bca698aef9c0eba370b0570200a14367a
Closes-Bug: #1843104
This commit is contained in:
Akihiro Motoki 2019-09-25 21:29:05 +09:00
parent b3aebb9254
commit ec970fd6e8
46 changed files with 274 additions and 148 deletions

View File

@ -22,6 +22,8 @@ from django.core.exceptions import MiddlewareNotUsed
import six.moves.urllib.parse as urlparse
from horizon.utils import settings as setting_utils
LOG = logging.getLogger(__name__)
@ -44,7 +46,7 @@ class OperationLogMiddleware(object):
- ``http status``
- ``request parameters``
and log format is defined OPERATION_LOG_OPTIONS.
and log format is defined in OPERATION_LOG_OPTIONS.
"""
@property
@ -59,15 +61,18 @@ class OperationLogMiddleware(object):
self.get_response = get_response
# set configurations
_log_option = settings.OPERATION_LOG_OPTIONS
_available_methods = ['POST', 'GET', 'PUT', 'DELETE']
_methods = _log_option["target_methods"]
_methods = setting_utils.get_dict_config(
'OPERATION_LOG_OPTIONS', 'target_methods')
self.target_methods = [x for x in _methods if x in _available_methods]
self.mask_fields = _log_option["mask_fields"]
self.format = _log_option["format"]
self.mask_fields = setting_utils.get_dict_config(
'OPERATION_LOG_OPTIONS', 'mask_fields')
self.format = setting_utils.get_dict_config(
'OPERATION_LOG_OPTIONS', 'format')
self._logger = logging.getLogger('horizon.operation_log')
self._ignored_urls = [re.compile(url)
for url in _log_option["ignore_urls"]]
self._ignored_urls = [re.compile(url) for url
in setting_utils.get_dict_config(
'OPERATION_LOG_OPTIONS', 'ignore_urls')]
def __call__(self, request):
response = self.get_response(request)

View File

@ -15,6 +15,8 @@ import six
from django.conf import settings
from django.utils.module_loading import import_string
from horizon import defaults
def import_object(name_or_object):
if isinstance(name_or_object, six.string_types):
@ -26,3 +28,20 @@ def import_setting(name):
"""Imports an object specified either directly or as a module path."""
value = getattr(settings, name, None)
return import_object(value)
# NOTE(amotoki):
# This is a copy from openstack_dashboard.utils.settings.get_dict_config().
# This copy is needed to look up defaults for horizon.defaults
# instead of openstack_dashboard.defaults.
# NOTE(amotoki): The limitation of this approach is that we cannot handle
# a case where default values in horizon are overridden by
# openstack_dashboard.defaults. This can be addressed by set_override()
# from oslo.config.
# TODO(amotoki): This copy might be cleanup if we can use oslo.config
# for horizon configurations.
def get_dict_config(name, key):
config = getattr(settings, name)
if key in config:
return config[key]
return getattr(defaults, name)[key]

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django import shortcuts
from django import template
from django.utils import encoding
@ -21,6 +20,7 @@ from osprofiler import profiler
import horizon
from horizon import exceptions
from horizon.utils import settings as setting_utils
class PageTitleMixin(object):
@ -73,7 +73,7 @@ class PageTitleMixin(object):
def trace(name):
def decorator(func):
if settings.OPENSTACK_PROFILER['enabled']:
if setting_utils.get_dict_config('OPENSTACK_PROFILER', 'enabled'):
return profiler.trace(name, info=None, hide_args=False,
allow_multiple_trace=True)(func)
else:

View File

@ -25,6 +25,7 @@ from keystoneauth1 import token_endpoint
from keystoneclient.v3 import client as client_v3
from six.moves.urllib import parse as urlparse
from openstack_auth import defaults
LOG = logging.getLogger(__name__)
@ -97,10 +98,23 @@ def is_token_valid(token, margin=None):
return expiration > timezone.now()
# NOTE(amotoki):
# This is a copy from openstack_dashboard.utils.settings.get_dict_config().
# This copy is needed to look up defaults for openstack_auth.defaults
# instead of openstack_dashboard.defaults.
# TODO(amotoki): This copy might be cleanup if we can use oslo.config
# for openstack_auth configurations.
def _get_dict_config(name, key):
config = getattr(settings, name)
if key in config:
return config[key]
return getattr(defaults, name)[key]
# Helper for figuring out keystone version
# Implementation will change when API version discovery is available
def get_keystone_version():
return settings.OPENSTACK_API_VERSIONS['identity']
return _get_dict_config('OPENSTACK_API_VERSIONS', 'identity')
def get_session(**kwargs):

View File

@ -587,8 +587,7 @@ def volume_backup_supported(request):
# backup is configured yet. This is a workaround until that
# capability is available.
# https://bugs.launchpad.net/cinder/+bug/1334856
cinder_config = settings.OPENSTACK_CINDER_FEATURES
return cinder_config['enable_backup']
return utils.get_dict_config('OPENSTACK_CINDER_FEATURES', 'enable_backup')
@profiler.trace

View File

@ -37,6 +37,7 @@ from horizon import exceptions
from openstack_dashboard.api import base
from openstack_dashboard.contrib.developer.profiler import api as profiler
from openstack_dashboard import policy
from openstack_dashboard.utils import settings as setting_utils
LOG = logging.getLogger(__name__)
@ -823,34 +824,35 @@ def delete_user_ec2_credentials(request, user_id, access_token):
def keystone_can_edit_domain():
backend_settings = settings.OPENSTACK_KEYSTONE_BACKEND
can_edit_domain = backend_settings['can_edit_domain']
can_edit_domain = setting_utils.get_dict_config(
'OPENSTACK_KEYSTONE_BACKEND', 'can_edit_domain')
multi_domain_support = settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT
return can_edit_domain and multi_domain_support
def keystone_can_edit_user():
backend_settings = settings.OPENSTACK_KEYSTONE_BACKEND
return backend_settings['can_edit_user']
return setting_utils.get_dict_config(
'OPENSTACK_KEYSTONE_BACKEND', 'can_edit_user')
def keystone_can_edit_project():
backend_settings = settings.OPENSTACK_KEYSTONE_BACKEND
return backend_settings['can_edit_project']
return setting_utils.get_dict_config(
'OPENSTACK_KEYSTONE_BACKEND', 'can_edit_project')
def keystone_can_edit_group():
backend_settings = settings.OPENSTACK_KEYSTONE_BACKEND
return backend_settings['can_edit_group']
return setting_utils.get_dict_config(
'OPENSTACK_KEYSTONE_BACKEND', 'can_edit_group')
def keystone_can_edit_role():
backend_settings = settings.OPENSTACK_KEYSTONE_BACKEND
return backend_settings['can_edit_role']
return setting_utils.get_dict_config(
'OPENSTACK_KEYSTONE_BACKEND', 'can_edit_role')
def keystone_backend_name():
return settings.OPENSTACK_KEYSTONE_BACKEND['name'] or 'unknown'
return setting_utils.get_dict_config(
'OPENSTACK_KEYSTONE_BACKEND', 'name') or 'unknown'
def get_version():

View File

@ -39,6 +39,7 @@ from openstack_dashboard.api import base
from openstack_dashboard.api import nova
from openstack_dashboard.contrib.developer.profiler import api as profiler
from openstack_dashboard import policy
from openstack_dashboard.utils import settings as setting_utils
# Python 3.8 removes the ability to import the abstract base classes from
# 'collections', but 'collections.abc' is not present in Python 2.7
@ -799,8 +800,8 @@ class FloatingIpManager(object):
def is_supported(self):
"""Returns True if floating IP feature is supported."""
network_config = settings.OPENSTACK_NEUTRON_NETWORK
return network_config['enable_router']
return setting_utils.get_dict_config(
'OPENSTACK_NEUTRON_NETWORK', 'enable_router')
def get_ipver_str(ip_version):
@ -1841,11 +1842,12 @@ def is_extension_supported(request, extension_alias):
# values are pre-defined now, so 'default' argument is meaningless
# in most cases.
def is_enabled_by_config(name, default=True):
network_config = settings.OPENSTACK_NEUTRON_NETWORK
# NOTE(amotoki): This function is used by horizon plugins
# via is_service_enabled() function, so we need to keep .get()
# rather than [] dict operator.
return network_config.get(name, default)
try:
return setting_utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK', name)
except KeyError:
# No default value is defined.
# This is a fallback logic for horizon plugins.
return default
# TODO(amotoki): Clean up 'default' parameter because the default
@ -1879,7 +1881,6 @@ FEATURE_MAP = {
'extension': 'dvr',
'config': {
'name': 'enable_distributed_router',
'default': False,
},
'policies': {
'get': 'get_router:distributed',
@ -1889,8 +1890,9 @@ FEATURE_MAP = {
},
'l3-ha': {
'extension': 'l3-ha',
'config': {'name': 'enable_ha_router',
'default': False},
'config': {
'name': 'enable_ha_router',
},
'policies': {
'get': 'get_router:ha',
'create': 'create_router:ha',
@ -1921,7 +1923,6 @@ def get_feature_permission(request, feature, operation=None):
defined in FEATURE_MAP[feature]['policies']
It must be specified if FEATURE_MAP[feature] has 'policies'.
"""
network_config = settings.OPENSTACK_NEUTRON_NETWORK
feature_info = FEATURE_MAP.get(feature)
if not feature_info:
raise ValueError("The requested feature '%(feature)s' is unknown. "
@ -1931,10 +1932,8 @@ def get_feature_permission(request, feature, operation=None):
# Check dashboard settings
feature_config = feature_info.get('config')
if feature_config:
# TODO(amotoki): Drop 'default' from FEATURE_MAP as it will be
# meaningless once all default settings are pre-defined.
if not network_config.get(feature_config['name'],
feature_config['default']):
if not setting_utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK',
feature_config['name']):
return False
# Check policy

View File

@ -1036,8 +1036,8 @@ def extension_supported(extension_name, request):
@profiler.trace
def can_set_server_password():
features = settings.OPENSTACK_HYPERVISOR_FEATURES
return features['can_set_password']
return utils.get_dict_config('OPENSTACK_HYPERVISOR_FEATURES',
'can_set_password')
@profiler.trace
@ -1049,16 +1049,16 @@ def instance_action_list(request, instance_id):
@profiler.trace
def can_set_mount_point():
"""Return the Hypervisor's capability of setting mount points."""
hypervisor_features = settings.OPENSTACK_HYPERVISOR_FEATURES
return hypervisor_features["can_set_mount_point"]
return utils.get_dict_config('OPENSTACK_HYPERVISOR_FEATURES',
'can_set_mount_point')
@profiler.trace
def requires_keypair():
features = settings.OPENSTACK_HYPERVISOR_FEATURES
return features['requires_keypair']
return utils.get_dict_config('OPENSTACK_HYPERVISOR_FEATURES',
'requires_keypair')
def can_set_quotas():
features = settings.OPENSTACK_HYPERVISOR_FEATURES
return features['enable_quotas']
return utils.get_dict_config('OPENSTACK_HYPERVISOR_FEATURES',
'enable_quotas')

View File

@ -25,9 +25,10 @@ from osprofiler import web
import six
from six.moves.urllib.parse import urlparse
from horizon.utils import settings as horizon_settings
ROOT_HEADER = 'PARENT_VIEW_TRACE_ID'
PROFILER_SETTINGS = settings.OPENSTACK_PROFILER
def init_notifier(connection_str, host="localhost"):
@ -71,7 +72,8 @@ def _get_engine_kwargs(request, connection_str):
def _get_engine(request):
connection_str = PROFILER_SETTINGS['receiver_connection_string']
connection_str = horizon_settings.get_dict_config(
'OPENSTACK_PROFILER', 'receiver_connection_string')
kwargs = _get_engine_kwargs(request, connection_str)
return profiler_get_driver(connection_str, **kwargs)
@ -124,7 +126,7 @@ def update_trace_headers(keys, **kwargs):
web.X_TRACE_HMAC: trace_data[1]})
if not PROFILER_SETTINGS['enabled']:
if not horizon_settings.get_dict_config('OPENSTACK_PROFILER', 'enabled'):
def trace(function):
return function
else:

View File

@ -24,13 +24,14 @@ from osprofiler import web
import six
from horizon import messages
from horizon.utils import settings as horizon_settings
from openstack_dashboard.contrib.developer.profiler import api
_REQUIRED_KEYS = ("base_id", "hmac_key")
_OPTIONAL_KEYS = ("parent_id",)
PROFILER_CONF = settings.OPENSTACK_PROFILER
PROFILER_ENABLED = PROFILER_CONF['enabled']
PROFILER_ENABLED = horizon_settings.get_dict_config(
'OPENSTACK_PROFILER', 'enabled')
class ProfilerClientMiddleware(object):
@ -60,7 +61,8 @@ class ProfilerClientMiddleware(object):
return None
if 'profile_page' in request.COOKIES:
hmac_key = PROFILER_CONF['keys'][0]
hmac_key = horizon_settings.get_dict_config(
'OPENSTACK_PROFILER', 'keys')[0]
profiler.init(hmac_key)
for hdr_key, hdr_value in web.get_trace_id_headers().items():
request.META[hdr_key] = hdr_value
@ -69,11 +71,14 @@ class ProfilerClientMiddleware(object):
class ProfilerMiddleware(object):
def __init__(self, get_response):
self.name = PROFILER_CONF['facility_name']
self.hmac_keys = PROFILER_CONF['keys']
self.name = horizon_settings.get_dict_config(
'OPENSTACK_PROFILER', 'facility_name')
self.hmac_keys = horizon_settings.get_dict_config(
'OPENSTACK_PROFILER', 'keys')
self.get_response = get_response
if PROFILER_ENABLED:
api.init_notifier(PROFILER_CONF['notifier_connection_string'])
api.init_notifier(horizon_settings.get_dict_config(
'OPENSTACK_PROFILER', 'notifier_connection_string'))
else:
raise exceptions.MiddlewareNotUsed()

View File

@ -13,13 +13,13 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
import horizon
from horizon.utils import settings as horizon_settings
if settings.OPENSTACK_PROFILER['enabled']:
if horizon_settings.get_dict_config('OPENSTACK_PROFILER', 'enabled'):
class Profiler(horizon.Panel):
name = _("OpenStack Profiler")
slug = 'profiler'

View File

@ -16,15 +16,15 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from horizon.browsers.views import AngularIndexView
from openstack_dashboard.dashboards.admin.flavors import views
from openstack_dashboard.utils import settings as setting_utils
if settings.ANGULAR_FEATURES['flavors_panel']:
if setting_utils.get_dict_config('ANGULAR_FEATURES', 'flavors_panel'):
title = _("Flavors")
# New angular panel
urlpatterns = [

View File

@ -13,11 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
import horizon
from openstack_dashboard.utils import settings as setting_utils
class AdminFloatingIps(horizon.Panel):
name = _("Floating IPs")
@ -27,5 +28,5 @@ class AdminFloatingIps(horizon.Panel):
@staticmethod
def can_register():
network_config = settings.OPENSTACK_NEUTRON_NETWORK
return network_config['enable_router']
return setting_utils.get_dict_config(
'OPENSTACK_NEUTRON_NETWORK', 'enable_router')

View File

@ -16,14 +16,14 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from horizon.browsers.views import AngularIndexView
from openstack_dashboard.dashboards.admin.images import views
from openstack_dashboard.utils import settings as setting_utils
if settings.ANGULAR_FEATURES['images_panel']:
if setting_utils.get_dict_config('ANGULAR_FEATURES', 'images_panel'):
title = _("Images")
# New angular images
urlpatterns = [

View File

@ -21,7 +21,6 @@ import logging
from oslo_utils import units
from six.moves import builtins
from django.conf import settings
from django.urls import reverse
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
@ -33,6 +32,7 @@ from horizon import tables
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.images.images import views
from openstack_dashboard import policy
from openstack_dashboard.utils import settings as setting_utils
from openstack_dashboard.dashboards.admin.images import forms as project_forms
from openstack_dashboard.dashboards.admin.images \
@ -65,8 +65,8 @@ class IndexView(tables.DataTableView):
return images
filters = self.get_filters()
filter_first = settings.FILTER_DATA_FIRST
if (filter_first['admin.images'] and
if (setting_utils.get_dict_config('FILTER_DATA_FIRST',
'admin.images') and
len(filters) == len(self.DEFAULT_FILTERS)):
self._prev = False
self._more = False

View File

@ -10,7 +10,6 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django import template
from django.template import defaultfilters as filters
from django import urls
@ -20,6 +19,7 @@ from django.utils.translation import ugettext_lazy as _
from horizon import tables
from horizon.utils import filters as utils_filters
from openstack_dashboard import api
from openstack_dashboard.utils import settings as setting_utils
SERVICE_ENABLED = "enabled"
@ -187,8 +187,8 @@ class NetworkL3AgentRoutersLinkAction(tables.LinkAction):
verbose_name = _("View Routers")
def allowed(self, request, datum):
network_config = settings.OPENSTACK_NEUTRON_NETWORK
if not network_config['enable_router']:
if not setting_utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK',
'enable_router'):
return False
# Determine whether this action is allowed for the current request.
return datum.agent_type == "L3 agent"

View File

@ -17,7 +17,6 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.urls import reverse
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
@ -38,6 +37,7 @@ from openstack_dashboard.dashboards.project.instances import views
from openstack_dashboard.dashboards.project.instances.workflows \
import update_instance
from openstack_dashboard.utils import futurist_utils
from openstack_dashboard.utils import settings as setting_utils
# re-use console from project.instances.views to make reflection work
@ -142,8 +142,8 @@ class AdminIndexView(tables.PagedTableMixin, tables.DataTableView):
# If filter_first is set and if there are not other filters
# selected, then search criteria must be provided and return an empty
# list
filter_first = settings.FILTER_DATA_FIRST
if (filter_first['admin.instances'] and
if (setting_utils.get_dict_config('FILTER_DATA_FIRST',
'admin.instances') and
len(search_opts) == len(default_search_opts)):
self._needs_filter_first = True
self._more = False

View File

@ -14,7 +14,6 @@
import logging
from django.conf import settings
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
@ -23,6 +22,7 @@ from horizon import forms
from horizon import messages
from openstack_dashboard import api
from openstack_dashboard.utils import settings as setting_utils
LOG = logging.getLogger(__name__)
@ -171,14 +171,15 @@ class CreateNetwork(forms.SelfHandlingForm):
is_extension_supported = False
if is_extension_supported:
neutron_settings = settings.OPENSTACK_NEUTRON_NETWORK
self.seg_id_range = SEGMENTATION_ID_RANGE.copy()
seg_id_range = neutron_settings['segmentation_id_range']
seg_id_range = setting_utils.get_dict_config(
'OPENSTACK_NEUTRON_NETWORK', 'segmentation_id_range')
if seg_id_range:
self.seg_id_range.update(seg_id_range)
self.provider_types = PROVIDER_TYPES.copy()
extra_provider_types = neutron_settings['extra_provider_types']
extra_provider_types = setting_utils.get_dict_config(
'OPENSTACK_NEUTRON_NETWORK', 'extra_provider_types')
if extra_provider_types:
self.provider_types.update(extra_provider_types)
@ -189,8 +190,8 @@ class CreateNetwork(forms.SelfHandlingForm):
net_type for net_type in self.provider_types
if self.provider_types[net_type]['require_physical_network']]
supported_provider_types = neutron_settings[
'supported_provider_types']
supported_provider_types = setting_utils.get_dict_config(
'OPENSTACK_NEUTRON_NETWORK', 'supported_provider_types')
if supported_provider_types == ['*']:
supported_provider_types = DEFAULT_PROVIDER_TYPES
@ -215,8 +216,8 @@ class CreateNetwork(forms.SelfHandlingForm):
for network_type in self.nettypes_with_seg_id)
self.fields['segmentation_id'].widget.attrs.update(attrs)
physical_networks = settings.OPENSTACK_NEUTRON_NETWORK[
'physical_networks']
physical_networks = setting_utils.get_dict_config(
'OPENSTACK_NEUTRON_NETWORK', 'physical_networks')
if physical_networks:
self.fields['physical_network'] = forms.ThemableChoiceField(

View File

@ -14,7 +14,6 @@
from collections import OrderedDict
from django.conf import settings
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
@ -27,6 +26,7 @@ from openstack_dashboard import api
from openstack_dashboard.dashboards.project.networks.tabs import OverviewTab
from openstack_dashboard.dashboards.project.networks import views as user_views
from openstack_dashboard.utils import filters
from openstack_dashboard.utils import settings as setting_utils
from openstack_dashboard.dashboards.admin.networks.agents import tabs \
as agents_tabs
@ -95,8 +95,9 @@ class IndexView(tables.DataTableView):
# If filter_first is set and if there are not other filters
# selected, then search criteria must be provided and return an
# empty list
filter_first = settings.FILTER_DATA_FIRST
if filter_first['admin.networks'] and not search_opts:
if (setting_utils.get_dict_config('FILTER_DATA_FIRST',
'admin.networks') and
not search_opts):
self._needs_filter_first = True
return []
self._needs_filter_first = False

View File

@ -12,12 +12,12 @@
import logging
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
import horizon
from openstack_dashboard.api import neutron
from openstack_dashboard.utils import settings as setting_utils
LOG = logging.getLogger(__name__)
@ -30,10 +30,10 @@ class RBACPolicies(horizon.Panel):
def allowed(self, context):
request = context['request']
network_config = settings.OPENSTACK_NEUTRON_NETWORK
try:
return (
network_config['enable_rbac_policy'] and
setting_utils.get_dict_config(
'OPENSTACK_NEUTRON_NETWORK', 'enable_rbac_policy') and
neutron.is_extension_supported(request,
extension_alias='rbac-policies')
)

View File

@ -12,11 +12,12 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
import horizon
from openstack_dashboard.utils import settings as setting_utils
class Routers(horizon.Panel):
name = _("Routers")
@ -26,5 +27,5 @@ class Routers(horizon.Panel):
@staticmethod
def can_register():
network_config = settings.OPENSTACK_NEUTRON_NETWORK
return network_config['enable_router']
return setting_utils.get_dict_config(
'OPENSTACK_NEUTRON_NETWORK', 'enable_router')

View File

@ -16,7 +16,6 @@
Views for managing Neutron Routers.
"""
from django.conf import settings
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
@ -27,6 +26,7 @@ from openstack_dashboard.dashboards.admin.routers import forms as rforms
from openstack_dashboard.dashboards.admin.routers import tables as rtbl
from openstack_dashboard.dashboards.admin.routers import tabs as rtabs
from openstack_dashboard.dashboards.project.routers import views as r_views
from openstack_dashboard.utils import settings as setting_utils
class IndexView(r_views.IndexView, n_views.IndexView):
@ -50,8 +50,9 @@ class IndexView(r_views.IndexView, n_views.IndexView):
# If admin_filter_first is set and if there are not other filters
# selected, then search criteria must be provided and return an
# empty list
filter_first = settings.FILTER_DATA_FIRST
if filter_first['admin.routers'] and not filters:
if (setting_utils.get_dict_config('FILTER_DATA_FIRST',
'admin.routers') and
not filters):
self._needs_filter_first = True
return []
self._needs_filter_first = False

View File

@ -16,7 +16,6 @@
Admin views for managing volumes and snapshots.
"""
from django.conf import settings
from django.urls import reverse
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
@ -37,6 +36,7 @@ from openstack_dashboard.dashboards.admin.volumes \
from openstack_dashboard.dashboards.project.volumes \
import views as volumes_views
from openstack_dashboard.utils import futurist_utils
from openstack_dashboard.utils import settings as setting_utils
class VolumesView(tables.PagedTableMixin, volumes_views.VolumeTableMixIn,
@ -51,12 +51,12 @@ class VolumesView(tables.PagedTableMixin, volumes_views.VolumeTableMixIn,
default_filters = {'all_tenants': True}
filters = self.get_filters(default_filters.copy())
filter_first = settings.FILTER_DATA_FIRST
volumes = []
self.table.needs_filter_first = False
if (filter_first['admin.volumes'] and
if (setting_utils.get_dict_config('FILTER_DATA_FIRST',
'admin.volumes') and
len(filters) == len(default_filters)):
self.table.needs_filter_first = True
return volumes

View File

@ -26,6 +26,7 @@ from horizon.utils import memoized
from horizon import views
from openstack_dashboard import api
from openstack_dashboard.utils import settings as setting_utils
from openstack_dashboard.dashboards.identity.application_credentials \
import forms as project_forms
@ -52,8 +53,9 @@ class IndexView(tables.DataTableView):
# If filter_first is set and if there are not other filters
# selected, then search criteria must be provided
# and return an empty list
filter_first = settings.FILTER_DATA_FIRST
if filter_first['identity.application_credentials'] and not filters:
if (setting_utils.get_dict_config(
'FILTER_DATA_FIRST',
'identity.application_credentials') and not filters):
self._needs_filter_first = True
return app_creds

View File

@ -12,16 +12,16 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from horizon.browsers import views
from openstack_dashboard.dashboards.identity.domains import views as legacyView
from openstack_dashboard.utils import settings as setting_utils
if settings.ANGULAR_FEATURES.get('domains_panel'):
if setting_utils.get_dict_config('ANGULAR_FEATURES', 'domains_panel'):
title = _("Domains")
urlpatterns = [
url('', views.AngularIndexView.as_view(title=title), name='index'),

View File

@ -12,16 +12,16 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.conf.urls import url
from horizon.browsers.views import AngularIndexView
from openstack_dashboard.dashboards.identity.groups import panel
from openstack_dashboard.dashboards.identity.groups import views
from openstack_dashboard.utils import settings as setting_utils
if settings.ANGULAR_FEATURES.get('groups_panel', False):
if setting_utils.get_dict_config('ANGULAR_FEATURES', 'groups_panel'):
title = panel.Groups.name
urlpatterns = [
url(r'^$', AngularIndexView.as_view(title=title), name='index'),

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.urls import reverse
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
@ -32,6 +31,7 @@ from openstack_dashboard.dashboards.identity.groups \
from openstack_dashboard.dashboards.identity.groups \
import tables as project_tables
from openstack_dashboard.utils import identity
from openstack_dashboard.utils import settings as setting_utils
class IndexView(tables.DataTableView):
@ -53,8 +53,8 @@ class IndexView(tables.DataTableView):
# If filter_first is set and if there are not other filters
# selected, then search criteria must be provided and
# return an empty list
filter_first = settings.FILTER_DATA_FIRST
if filter_first['identity.groups'] and not filters:
if (setting_utils.get_dict_config(
'FILTER_DATA_FIRST', 'identity.groups') and not filters):
self._needs_filter_first = True
return groups

View File

@ -42,6 +42,7 @@ from openstack_dashboard.dashboards.identity.projects \
from openstack_dashboard.dashboards.project.overview \
import views as project_views
from openstack_dashboard.utils import identity
from openstack_dashboard.utils import settings as setting_utils
PROJECT_INFO_FIELDS = ("domain_id",
"domain_name",
@ -95,8 +96,8 @@ class IndexView(tables.DataTableView):
# If filter_first is set and if there are not other filters
# selected, then search criteria must be provided and
# return an empty list
filter_first = settings.FILTER_DATA_FIRST
if filter_first['identity.projects'] and not filters:
if (setting_utils.get_dict_config(
'FILTER_DATA_FIRST', 'identity.projects') and not filters):
self._needs_filter_first = True
self._more = False
return tenants

View File

@ -12,15 +12,15 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from horizon.browsers.views import AngularIndexView
from openstack_dashboard.dashboards.identity.roles import views
from openstack_dashboard.utils import settings as setting_utils
if settings.ANGULAR_FEATURES.get('roles_panel', False):
if setting_utils.get_dict_config('ANGULAR_FEATURES', 'roles_panel'):
# New angular panel
title = _('Roles')
urlpatterns = [

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.urls import reverse
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
@ -25,6 +24,7 @@ from horizon.utils import memoized
from openstack_dashboard import api
from openstack_dashboard import policy
from openstack_dashboard.utils import settings as setting_utils
from openstack_dashboard.dashboards.identity.roles \
import forms as project_forms
@ -51,8 +51,8 @@ class IndexView(tables.DataTableView):
# If filter_first is set and if there are not other filters
# selected, then search criteria must be provided
# and return an empty list
filter_first = settings.FILTER_DATA_FIRST
if filter_first['identity.roles'] and not filters:
if (setting_utils.get_dict_config(
'FILTER_DATA_FIRST', 'identity.roles') and not filters):
self._needs_filter_first = True
return roles

View File

@ -16,16 +16,15 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from horizon.browsers.views import AngularIndexView
from openstack_dashboard.dashboards.identity.users import views
from openstack_dashboard.utils import settings as setting_utils
if settings.ANGULAR_FEATURES.get('users_panel', False):
if setting_utils.get_dict_config('ANGULAR_FEATURES', 'users_panel'):
title = _("Users")
# new angular panel
urlpatterns = [

View File

@ -43,6 +43,7 @@ from openstack_dashboard.dashboards.identity.users \
from openstack_dashboard.dashboards.identity.users \
import tabs as user_tabs
from openstack_dashboard.utils import identity
from openstack_dashboard.utils import settings as setting_utils
LOG = logging.getLogger(__name__)
@ -67,8 +68,8 @@ class IndexView(tables.DataTableView):
# If filter_first is set and if there are not other filters
# selected, then search criteria must be provided
# and return an empty list
filter_first = settings.FILTER_DATA_FIRST
if filter_first['identity.users'] and not filters:
if (setting_utils.get_dict_config(
'FILTER_DATA_FIRST', 'identity.users') and not filters):
self._needs_filter_first = True
return users

View File

@ -12,11 +12,12 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
import horizon
from openstack_dashboard.utils import settings as setting_utils
class FloatingIps(horizon.Panel):
name = _("Floating IPs")
@ -25,5 +26,5 @@ class FloatingIps(horizon.Panel):
@staticmethod
def can_register():
network_config = settings.OPENSTACK_NEUTRON_NETWORK
return network_config['enable_router']
return setting_utils.get_dict_config(
'OPENSTACK_NEUTRON_NETWORK', 'enable_router')

View File

@ -16,15 +16,15 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from horizon.browsers.views import AngularIndexView
from openstack_dashboard.dashboards.project.images.images import views
from openstack_dashboard.utils import settings as setting_utils
if settings.ANGULAR_FEATURES['images_panel']:
if setting_utils.get_dict_config('ANGULAR_FEATURES', 'images_panel'):
title = _("Images")
urlpatterns = [
url(r'^(?P<image_id>[^/]+)/$', AngularIndexView.as_view(title=title),

View File

@ -16,7 +16,6 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.conf.urls import include
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
@ -27,9 +26,10 @@ from openstack_dashboard.dashboards.project.images.images \
from openstack_dashboard.dashboards.project.images.snapshots \
import urls as snapshot_urls
from openstack_dashboard.dashboards.project.images import views
from openstack_dashboard.utils import settings as setting_utils
if settings.ANGULAR_FEATURES['images_panel']:
if setting_utils.get_dict_config('ANGULAR_FEATURES', 'images_panel'):
title = _("Images")
# New angular images
urlpatterns = [

View File

@ -40,6 +40,7 @@ from horizon import workflows
from openstack_dashboard import api
from openstack_dashboard.utils import filters
from openstack_dashboard.utils import settings as setting_utils
from openstack_dashboard.dashboards.project.instances \
import console as project_console
@ -266,8 +267,8 @@ class LaunchInstanceView(workflows.WorkflowView):
initial = super(LaunchInstanceView, self).get_initial()
initial['project_id'] = self.request.user.tenant_id
initial['user_id'] = self.request.user.id
defaults = settings.LAUNCH_INSTANCE_DEFAULTS
initial['config_drive'] = defaults['config_drive']
initial['config_drive'] = setting_utils.get_dict_config(
'LAUNCH_INSTANCE_DEFAULTS', 'config_drive')
return initial

View File

@ -16,15 +16,15 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _
from horizon.browsers import views
from openstack_dashboard.dashboards.project.key_pairs import views as \
legacy_views
from openstack_dashboard.utils import settings as setting_utils
if settings.ANGULAR_FEATURES.get('key_pairs_panel'):
if setting_utils.get_dict_config('ANGULAR_FEATURES', 'key_pairs_panel'):
title = _("Key Pairs")
urlpatterns = [
url('', views.AngularIndexView.as_view(title=title), name='index'),

View File

@ -15,6 +15,7 @@ from django.conf import settings
from openstack_dashboard.api import base
from openstack_dashboard import policy
from openstack_dashboard.usage import quotas
from openstack_dashboard.utils import settings as setting_utils
def _quota_exceeded(request, quota):
@ -28,8 +29,6 @@ def get_context(request, context=None):
if context is None:
context = {}
network_config = settings.OPENSTACK_NEUTRON_NETWORK
context['launch_instance_allowed'] = policy.check(
(("compute", "os_compute_api:servers:create"),), request)
context['instance_quota_exceeded'] = _quota_exceeded(request, 'instances')
@ -37,7 +36,8 @@ def get_context(request, context=None):
(("network", "create_network"),), request)
context['network_quota_exceeded'] = _quota_exceeded(request, 'network')
context['create_router_allowed'] = (
network_config['enable_router'] and
setting_utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK',
'enable_router') and
policy.check((("network", "create_router"),), request))
context['router_quota_exceeded'] = _quota_exceeded(request, 'router')
context['console_type'] = settings.CONSOLE_TYPE

View File

@ -76,6 +76,7 @@ from openstack_dashboard.dashboards.project.routers.tables import \
from openstack_dashboard.dashboards.project.routers import\
views as r_views
from openstack_dashboard import policy
from openstack_dashboard.utils import settings as setting_utils
# List of known server statuses that wont connect to the console
console_invalid_status = {
@ -214,8 +215,8 @@ class JSONView(View):
@property
def is_router_enabled(self):
network_config = settings.OPENSTACK_NEUTRON_NETWORK
return network_config['enable_router']
return setting_utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK',
'enable_router')
def add_resource_url(self, view, resources):
tenant_id = self.request.user.tenant_id

View File

@ -15,7 +15,6 @@
import logging
from django.conf import settings
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
@ -26,6 +25,7 @@ from horizon import workflows
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.networks.ports import sg_base
from openstack_dashboard.utils import filters
from openstack_dashboard.utils import settings as setting_utils
LOG = logging.getLogger(__name__)
@ -160,8 +160,8 @@ class CreatePortInfoAction(workflows.Action):
return is_supproted
def _populate_vnic_type_choices(self, request):
neutron_settings = settings.OPENSTACK_NEUTRON_NETWORK
supported_vnic_types = neutron_settings['supported_vnic_types']
supported_vnic_types = setting_utils.get_dict_config(
'OPENSTACK_NEUTRON_NETWORK', 'supported_vnic_types')
# When a list of VNIC types is empty, hide the corresponding field.
if not supported_vnic_types:
del self.fields['binding__vnic_type']
@ -314,8 +314,8 @@ class UpdatePortInfoAction(workflows.Action):
super(UpdatePortInfoAction, self).__init__(request, *args, **kwargs)
try:
if api.neutron.is_extension_supported(request, 'binding'):
neutron_settings = settings.OPENSTACK_NEUTRON_NETWORK
supported_vnic_types = neutron_settings['supported_vnic_types']
supported_vnic_types = setting_utils.get_dict_config(
'OPENSTACK_NEUTRON_NETWORK', 'supported_vnic_types')
if supported_vnic_types:
if supported_vnic_types == ['*']:
vnic_type_choices = api.neutron.VNIC_TYPES

View File

@ -15,7 +15,6 @@
"""
Views for managing Neutron Networks.
"""
from django.conf import settings
from django.urls import reverse
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
@ -29,6 +28,7 @@ from horizon import workflows
from openstack_dashboard import api
from openstack_dashboard.utils import filters
from openstack_dashboard.utils import settings as setting_utils
from openstack_dashboard.dashboards.project.networks \
import forms as project_forms
@ -67,9 +67,9 @@ class DefaultSubnetWorkflowMixin(object):
def get_default_dns_servers(self):
# this returns the default dns servers to be used for new subnets
dns_default = "\n".join(
settings.OPENSTACK_NEUTRON_NETWORK['default_dns_nameservers'])
return dns_default
default_dns_nameservers = setting_utils.get_dict_config(
'OPENSTACK_NEUTRON_NETWORK', 'default_dns_nameservers')
return "\n".join(default_dns_nameservers)
class CreateView(DefaultSubnetWorkflowMixin, workflows.WorkflowView):

View File

@ -28,6 +28,7 @@ from horizon import workflows
from openstack_dashboard import api
from openstack_dashboard.dashboards.project.networks.subnets import utils
from openstack_dashboard import policy
from openstack_dashboard.utils import settings as setting_utils
LOG = logging.getLogger(__name__)
@ -205,7 +206,8 @@ class CreateSubnetInfoAction(workflows.Action):
def __init__(self, request, context, *args, **kwargs):
super(CreateSubnetInfoAction, self).__init__(request, context, *args,
**kwargs)
if not settings.OPENSTACK_NEUTRON_NETWORK['enable_ipv6']:
if not setting_utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK',
'enable_ipv6'):
self.fields['ip_version'].widget = forms.HiddenInput()
self.fields['ip_version'].initial = 4
@ -380,7 +382,8 @@ class CreateSubnetDetailAction(workflows.Action):
def __init__(self, request, context, *args, **kwargs):
super(CreateSubnetDetailAction, self).__init__(request, context,
*args, **kwargs)
if not settings.OPENSTACK_NEUTRON_NETWORK['enable_ipv6']:
if not setting_utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK',
'enable_ipv6'):
self.fields['ipv6_modes'].widget = forms.HiddenInput()
def populate_ipv6_modes_choices(self, request, context):

View File

@ -12,11 +12,12 @@
# License for the specific language governing permissions and limitations
# under the License.
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
import horizon
from openstack_dashboard.utils import settings as setting_utils
class Routers(horizon.Panel):
name = _("Routers")
@ -25,5 +26,5 @@ class Routers(horizon.Panel):
@staticmethod
def can_register():
network_config = settings.OPENSTACK_NEUTRON_NETWORK
return network_config['enable_router']
return setting_utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK',
'enable_router')

View File

@ -32,6 +32,7 @@ from horizon.utils import validators as utils_validators
from openstack_dashboard import api
from openstack_dashboard.utils import filters
from openstack_dashboard.utils import settings as setting_utils
class GroupBase(forms.SelfHandlingForm):
@ -296,7 +297,8 @@ class AddRule(forms.SelfHandlingForm):
('all', _('All ports')),
]
if not settings.OPENSTACK_NEUTRON_NETWORK['enable_ipv6']:
if not setting_utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK',
'enable_ipv6'):
self.fields['cidr'].version = forms.IPv4
self.fields['ethertype'].widget = forms.TextInput(
attrs={'readonly': 'readonly'})

View File

@ -0,0 +1,39 @@
# 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 django.test import utils as test_utils
from openstack_dashboard.test import helpers as test
from openstack_dashboard.utils import settings as utils
class SettingsTests(test.TestCase):
def test_get_dict_config_default_value(self):
self.assertEqual(
True,
utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK',
'enable_router'))
@test_utils.override_settings(OPENSTACK_NEUTRON_NETWORK={
'enable_router': False})
def test_get_dict_config_configured_value(self):
self.assertEqual(
False,
utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK',
'enable_router'))
@test_utils.override_settings(OPENSTACK_NEUTRON_NETWORK={})
def test_get_dict_config_missing_key(self):
self.assertEqual(
True,
utils.get_dict_config('OPENSTACK_NEUTRON_NETWORK',
'enable_router'))

View File

@ -21,9 +21,34 @@ from django.conf import settings
from horizon.utils import file_discovery
from horizon.utils import functions as utils
from openstack_dashboard import defaults
from openstack_dashboard import theme_settings
def get_dict_config(name, key):
"""Get a config value from a dict-type setting.
If a specified key does not exist in a requested setting,
the default value defined in openstack_dashboard.defaults
is considered.
.. warning::
This function should not be used from horizon plugins
as it only checks openstack_dashboard.defaults
when accessing default values.
:param name: Name of a dict-type setting
:param key: Key name of the dict-type setting
:raises KeyError: Raised if no default value is found for a requested key.
(This can happen only for horizon plugin codes.)
"""
config = getattr(settings, name)
if key in config:
return config[key]
return getattr(defaults, name)[key]
def import_submodules(module):
"""Import all submodules and make them available in a dict."""
submodules = {}