From ec970fd6e85b19126409ef39aefa013bac701503 Mon Sep 17 00:00:00 2001 From: Akihiro Motoki Date: Wed, 25 Sep 2019 21:29:05 +0900 Subject: [PATCH] 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 --- horizon/middleware/operation_log.py | 19 +++++---- horizon/utils/settings.py | 19 +++++++++ horizon/views.py | 4 +- openstack_auth/utils.py | 16 +++++++- openstack_dashboard/api/cinder.py | 3 +- openstack_dashboard/api/keystone.py | 24 ++++++------ openstack_dashboard/api/neutron.py | 29 +++++++------- openstack_dashboard/api/nova.py | 16 ++++---- .../contrib/developer/profiler/api.py | 8 ++-- .../contrib/developer/profiler/middleware.py | 17 +++++--- .../contrib/developer/profiler/panel.py | 4 +- .../dashboards/admin/flavors/urls.py | 4 +- .../dashboards/admin/floating_ips/panel.py | 7 ++-- .../dashboards/admin/images/urls.py | 4 +- .../dashboards/admin/images/views.py | 6 +-- .../dashboards/admin/info/tables.py | 6 +-- .../dashboards/admin/instances/views.py | 6 +-- .../dashboards/admin/networks/forms.py | 17 ++++---- .../dashboards/admin/networks/views.py | 7 ++-- .../dashboards/admin/rbac_policies/panel.py | 6 +-- .../dashboards/admin/routers/panel.py | 7 ++-- .../dashboards/admin/routers/views.py | 7 ++-- .../dashboards/admin/volumes/views.py | 6 +-- .../identity/application_credentials/views.py | 6 ++- .../dashboards/identity/domains/urls.py | 4 +- .../dashboards/identity/groups/urls.py | 4 +- .../dashboards/identity/groups/views.py | 6 +-- .../dashboards/identity/projects/views.py | 5 ++- .../dashboards/identity/roles/urls.py | 4 +- .../dashboards/identity/roles/views.py | 6 +-- .../dashboards/identity/users/urls.py | 5 +-- .../dashboards/identity/users/views.py | 5 ++- .../dashboards/project/floating_ips/panel.py | 7 ++-- .../dashboards/project/images/images/urls.py | 4 +- .../dashboards/project/images/urls.py | 4 +- .../dashboards/project/instances/views.py | 5 ++- .../dashboards/project/key_pairs/urls.py | 4 +- .../project/network_topology/utils.py | 6 +-- .../project/network_topology/views.py | 5 ++- .../project/networks/ports/workflows.py | 10 ++--- .../dashboards/project/networks/views.py | 8 ++-- .../dashboards/project/networks/workflows.py | 7 +++- .../dashboards/project/routers/panel.py | 7 ++-- .../project/security_groups/forms.py | 4 +- .../test/unit/utils/test_settings.py | 39 +++++++++++++++++++ openstack_dashboard/utils/settings.py | 25 ++++++++++++ 46 files changed, 274 insertions(+), 148 deletions(-) create mode 100644 openstack_dashboard/test/unit/utils/test_settings.py diff --git a/horizon/middleware/operation_log.py b/horizon/middleware/operation_log.py index 3fe6c8eded..6aa4455e97 100644 --- a/horizon/middleware/operation_log.py +++ b/horizon/middleware/operation_log.py @@ -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) diff --git a/horizon/utils/settings.py b/horizon/utils/settings.py index 9e9b0c04fc..6adffead1d 100644 --- a/horizon/utils/settings.py +++ b/horizon/utils/settings.py @@ -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] diff --git a/horizon/views.py b/horizon/views.py index e20772e83e..68bd836f3e 100644 --- a/horizon/views.py +++ b/horizon/views.py @@ -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: diff --git a/openstack_auth/utils.py b/openstack_auth/utils.py index 60ce32b87b..21d2d9bfe0 100644 --- a/openstack_auth/utils.py +++ b/openstack_auth/utils.py @@ -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): diff --git a/openstack_dashboard/api/cinder.py b/openstack_dashboard/api/cinder.py index 76567560c4..9d3154fa60 100644 --- a/openstack_dashboard/api/cinder.py +++ b/openstack_dashboard/api/cinder.py @@ -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 diff --git a/openstack_dashboard/api/keystone.py b/openstack_dashboard/api/keystone.py index 49ba098ef3..cbf2da107d 100644 --- a/openstack_dashboard/api/keystone.py +++ b/openstack_dashboard/api/keystone.py @@ -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(): diff --git a/openstack_dashboard/api/neutron.py b/openstack_dashboard/api/neutron.py index 3e14c8fd9a..c51ef9e932 100644 --- a/openstack_dashboard/api/neutron.py +++ b/openstack_dashboard/api/neutron.py @@ -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 diff --git a/openstack_dashboard/api/nova.py b/openstack_dashboard/api/nova.py index 54e6518e9a..55efd67457 100644 --- a/openstack_dashboard/api/nova.py +++ b/openstack_dashboard/api/nova.py @@ -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') diff --git a/openstack_dashboard/contrib/developer/profiler/api.py b/openstack_dashboard/contrib/developer/profiler/api.py index 99482362b5..9c49754f65 100644 --- a/openstack_dashboard/contrib/developer/profiler/api.py +++ b/openstack_dashboard/contrib/developer/profiler/api.py @@ -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: diff --git a/openstack_dashboard/contrib/developer/profiler/middleware.py b/openstack_dashboard/contrib/developer/profiler/middleware.py index 3ee4df6132..0baaacda87 100644 --- a/openstack_dashboard/contrib/developer/profiler/middleware.py +++ b/openstack_dashboard/contrib/developer/profiler/middleware.py @@ -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() diff --git a/openstack_dashboard/contrib/developer/profiler/panel.py b/openstack_dashboard/contrib/developer/profiler/panel.py index 8d84632255..5ea5ada657 100644 --- a/openstack_dashboard/contrib/developer/profiler/panel.py +++ b/openstack_dashboard/contrib/developer/profiler/panel.py @@ -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' diff --git a/openstack_dashboard/dashboards/admin/flavors/urls.py b/openstack_dashboard/dashboards/admin/flavors/urls.py index 88ecfe6cfc..882b8d7188 100644 --- a/openstack_dashboard/dashboards/admin/flavors/urls.py +++ b/openstack_dashboard/dashboards/admin/flavors/urls.py @@ -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 = [ diff --git a/openstack_dashboard/dashboards/admin/floating_ips/panel.py b/openstack_dashboard/dashboards/admin/floating_ips/panel.py index 96405c97df..6cd6ecd580 100644 --- a/openstack_dashboard/dashboards/admin/floating_ips/panel.py +++ b/openstack_dashboard/dashboards/admin/floating_ips/panel.py @@ -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') diff --git a/openstack_dashboard/dashboards/admin/images/urls.py b/openstack_dashboard/dashboards/admin/images/urls.py index 1464f37bae..368aec300c 100644 --- a/openstack_dashboard/dashboards/admin/images/urls.py +++ b/openstack_dashboard/dashboards/admin/images/urls.py @@ -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 = [ diff --git a/openstack_dashboard/dashboards/admin/images/views.py b/openstack_dashboard/dashboards/admin/images/views.py index d3aa16f71d..41fd2f3cd0 100644 --- a/openstack_dashboard/dashboards/admin/images/views.py +++ b/openstack_dashboard/dashboards/admin/images/views.py @@ -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 diff --git a/openstack_dashboard/dashboards/admin/info/tables.py b/openstack_dashboard/dashboards/admin/info/tables.py index eeb42da695..e4325e7839 100644 --- a/openstack_dashboard/dashboards/admin/info/tables.py +++ b/openstack_dashboard/dashboards/admin/info/tables.py @@ -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" diff --git a/openstack_dashboard/dashboards/admin/instances/views.py b/openstack_dashboard/dashboards/admin/instances/views.py index f40a8e2177..8ca1987721 100644 --- a/openstack_dashboard/dashboards/admin/instances/views.py +++ b/openstack_dashboard/dashboards/admin/instances/views.py @@ -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 diff --git a/openstack_dashboard/dashboards/admin/networks/forms.py b/openstack_dashboard/dashboards/admin/networks/forms.py index bace11e73a..e3aab72be9 100644 --- a/openstack_dashboard/dashboards/admin/networks/forms.py +++ b/openstack_dashboard/dashboards/admin/networks/forms.py @@ -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( diff --git a/openstack_dashboard/dashboards/admin/networks/views.py b/openstack_dashboard/dashboards/admin/networks/views.py index 03410a2a07..bf6f81f305 100644 --- a/openstack_dashboard/dashboards/admin/networks/views.py +++ b/openstack_dashboard/dashboards/admin/networks/views.py @@ -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 diff --git a/openstack_dashboard/dashboards/admin/rbac_policies/panel.py b/openstack_dashboard/dashboards/admin/rbac_policies/panel.py index c9429fbf89..c23bdb073f 100644 --- a/openstack_dashboard/dashboards/admin/rbac_policies/panel.py +++ b/openstack_dashboard/dashboards/admin/rbac_policies/panel.py @@ -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') ) diff --git a/openstack_dashboard/dashboards/admin/routers/panel.py b/openstack_dashboard/dashboards/admin/routers/panel.py index f11856e95a..81bc0c2bae 100644 --- a/openstack_dashboard/dashboards/admin/routers/panel.py +++ b/openstack_dashboard/dashboards/admin/routers/panel.py @@ -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') diff --git a/openstack_dashboard/dashboards/admin/routers/views.py b/openstack_dashboard/dashboards/admin/routers/views.py index 78e65fd8de..55c3ab3f40 100644 --- a/openstack_dashboard/dashboards/admin/routers/views.py +++ b/openstack_dashboard/dashboards/admin/routers/views.py @@ -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 diff --git a/openstack_dashboard/dashboards/admin/volumes/views.py b/openstack_dashboard/dashboards/admin/volumes/views.py index f9571bd11d..c8cb8ae560 100644 --- a/openstack_dashboard/dashboards/admin/volumes/views.py +++ b/openstack_dashboard/dashboards/admin/volumes/views.py @@ -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 diff --git a/openstack_dashboard/dashboards/identity/application_credentials/views.py b/openstack_dashboard/dashboards/identity/application_credentials/views.py index 26a7335493..4d175b5f11 100644 --- a/openstack_dashboard/dashboards/identity/application_credentials/views.py +++ b/openstack_dashboard/dashboards/identity/application_credentials/views.py @@ -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 diff --git a/openstack_dashboard/dashboards/identity/domains/urls.py b/openstack_dashboard/dashboards/identity/domains/urls.py index d536e4a3f7..56676a2b04 100644 --- a/openstack_dashboard/dashboards/identity/domains/urls.py +++ b/openstack_dashboard/dashboards/identity/domains/urls.py @@ -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'), diff --git a/openstack_dashboard/dashboards/identity/groups/urls.py b/openstack_dashboard/dashboards/identity/groups/urls.py index 96b8fe2610..45e74e8f2e 100644 --- a/openstack_dashboard/dashboards/identity/groups/urls.py +++ b/openstack_dashboard/dashboards/identity/groups/urls.py @@ -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'), diff --git a/openstack_dashboard/dashboards/identity/groups/views.py b/openstack_dashboard/dashboards/identity/groups/views.py index 8eb96d60e5..108c946146 100644 --- a/openstack_dashboard/dashboards/identity/groups/views.py +++ b/openstack_dashboard/dashboards/identity/groups/views.py @@ -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 diff --git a/openstack_dashboard/dashboards/identity/projects/views.py b/openstack_dashboard/dashboards/identity/projects/views.py index c784a814f6..25458b83ac 100644 --- a/openstack_dashboard/dashboards/identity/projects/views.py +++ b/openstack_dashboard/dashboards/identity/projects/views.py @@ -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 diff --git a/openstack_dashboard/dashboards/identity/roles/urls.py b/openstack_dashboard/dashboards/identity/roles/urls.py index f7a4451f27..d440a945e8 100644 --- a/openstack_dashboard/dashboards/identity/roles/urls.py +++ b/openstack_dashboard/dashboards/identity/roles/urls.py @@ -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 = [ diff --git a/openstack_dashboard/dashboards/identity/roles/views.py b/openstack_dashboard/dashboards/identity/roles/views.py index b2335b406d..4a3ac5684a 100644 --- a/openstack_dashboard/dashboards/identity/roles/views.py +++ b/openstack_dashboard/dashboards/identity/roles/views.py @@ -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 diff --git a/openstack_dashboard/dashboards/identity/users/urls.py b/openstack_dashboard/dashboards/identity/users/urls.py index 1c305cc64a..724b16b3c8 100644 --- a/openstack_dashboard/dashboards/identity/users/urls.py +++ b/openstack_dashboard/dashboards/identity/users/urls.py @@ -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 = [ diff --git a/openstack_dashboard/dashboards/identity/users/views.py b/openstack_dashboard/dashboards/identity/users/views.py index b4cccc4e41..3d1b808ba7 100644 --- a/openstack_dashboard/dashboards/identity/users/views.py +++ b/openstack_dashboard/dashboards/identity/users/views.py @@ -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 diff --git a/openstack_dashboard/dashboards/project/floating_ips/panel.py b/openstack_dashboard/dashboards/project/floating_ips/panel.py index 267532caaf..9af9abc1bb 100644 --- a/openstack_dashboard/dashboards/project/floating_ips/panel.py +++ b/openstack_dashboard/dashboards/project/floating_ips/panel.py @@ -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') diff --git a/openstack_dashboard/dashboards/project/images/images/urls.py b/openstack_dashboard/dashboards/project/images/images/urls.py index b82efeed94..f79f7f4f56 100644 --- a/openstack_dashboard/dashboards/project/images/images/urls.py +++ b/openstack_dashboard/dashboards/project/images/images/urls.py @@ -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[^/]+)/$', AngularIndexView.as_view(title=title), diff --git a/openstack_dashboard/dashboards/project/images/urls.py b/openstack_dashboard/dashboards/project/images/urls.py index e4d25f2b99..fc24b90482 100644 --- a/openstack_dashboard/dashboards/project/images/urls.py +++ b/openstack_dashboard/dashboards/project/images/urls.py @@ -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 = [ diff --git a/openstack_dashboard/dashboards/project/instances/views.py b/openstack_dashboard/dashboards/project/instances/views.py index c8634b154b..6e7a76295e 100644 --- a/openstack_dashboard/dashboards/project/instances/views.py +++ b/openstack_dashboard/dashboards/project/instances/views.py @@ -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 diff --git a/openstack_dashboard/dashboards/project/key_pairs/urls.py b/openstack_dashboard/dashboards/project/key_pairs/urls.py index c13e40d1ef..81fd4378d1 100644 --- a/openstack_dashboard/dashboards/project/key_pairs/urls.py +++ b/openstack_dashboard/dashboards/project/key_pairs/urls.py @@ -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'), diff --git a/openstack_dashboard/dashboards/project/network_topology/utils.py b/openstack_dashboard/dashboards/project/network_topology/utils.py index e9ae6a4f86..784828ee05 100644 --- a/openstack_dashboard/dashboards/project/network_topology/utils.py +++ b/openstack_dashboard/dashboards/project/network_topology/utils.py @@ -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 diff --git a/openstack_dashboard/dashboards/project/network_topology/views.py b/openstack_dashboard/dashboards/project/network_topology/views.py index 53c9224e28..87006ffe23 100644 --- a/openstack_dashboard/dashboards/project/network_topology/views.py +++ b/openstack_dashboard/dashboards/project/network_topology/views.py @@ -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 diff --git a/openstack_dashboard/dashboards/project/networks/ports/workflows.py b/openstack_dashboard/dashboards/project/networks/ports/workflows.py index 32dcc12aae..fe9175d445 100644 --- a/openstack_dashboard/dashboards/project/networks/ports/workflows.py +++ b/openstack_dashboard/dashboards/project/networks/ports/workflows.py @@ -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 diff --git a/openstack_dashboard/dashboards/project/networks/views.py b/openstack_dashboard/dashboards/project/networks/views.py index 1daad9de82..d75c75b2b6 100644 --- a/openstack_dashboard/dashboards/project/networks/views.py +++ b/openstack_dashboard/dashboards/project/networks/views.py @@ -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): diff --git a/openstack_dashboard/dashboards/project/networks/workflows.py b/openstack_dashboard/dashboards/project/networks/workflows.py index ed365fef8d..60207fadc1 100644 --- a/openstack_dashboard/dashboards/project/networks/workflows.py +++ b/openstack_dashboard/dashboards/project/networks/workflows.py @@ -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): diff --git a/openstack_dashboard/dashboards/project/routers/panel.py b/openstack_dashboard/dashboards/project/routers/panel.py index d41558aee9..290f1913c2 100644 --- a/openstack_dashboard/dashboards/project/routers/panel.py +++ b/openstack_dashboard/dashboards/project/routers/panel.py @@ -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') diff --git a/openstack_dashboard/dashboards/project/security_groups/forms.py b/openstack_dashboard/dashboards/project/security_groups/forms.py index 2e77da46de..1441a12979 100644 --- a/openstack_dashboard/dashboards/project/security_groups/forms.py +++ b/openstack_dashboard/dashboards/project/security_groups/forms.py @@ -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'}) diff --git a/openstack_dashboard/test/unit/utils/test_settings.py b/openstack_dashboard/test/unit/utils/test_settings.py new file mode 100644 index 0000000000..a3e450ebe9 --- /dev/null +++ b/openstack_dashboard/test/unit/utils/test_settings.py @@ -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')) diff --git a/openstack_dashboard/utils/settings.py b/openstack_dashboard/utils/settings.py index 61c92de76e..afe771a125 100644 --- a/openstack_dashboard/utils/settings.py +++ b/openstack_dashboard/utils/settings.py @@ -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 = {}