Define default settings explicitly (horizon)

test_parse_isotime_filter in test_filters is updated to match
TIME_ZONE=UTC. Previously TIME_ZONE was not set in horizon.test.settings
and the default value America/Chicago was used. Horizon uses UTC as the
default value of TIME_ZONE, so it is better to use UTC for testing too.

horizon settings in openstack_dashboard.settings are moved to
under horizon.

Part of blueprint ini-based-configuration
Change-Id: I9abdbbe0dcefc08ffea61143e3c0a87ed87b2e2a
This commit is contained in:
Akihiro Motoki 2019-04-18 09:12:57 +09:00
parent 7c897b677c
commit 9b99f17100
20 changed files with 144 additions and 94 deletions

View File

@ -80,7 +80,7 @@ class AngularIndexView(generic.TemplateView):
def get_context_data(self, **kwargs):
context = super(AngularIndexView, self).get_context_data(**kwargs)
context["title"] = self.title
context["csrf_http"] = getattr(settings, 'CSRF_COOKIE_HTTPONLY', False)
context["csrf_http"] = settings.CSRF_COOKIE_HTTPONLY
if self.page_title is None:
context["page_title"] = self.title
else:
@ -102,7 +102,7 @@ class AngularDetailsView(generic.TemplateView):
title = _("Horizon")
context["title"] = title
context["page_title"] = title
context["csrf_http"] = getattr(settings, 'CSRF_COOKIE_HTTPONLY', False)
context["csrf_http"] = settings.CSRF_COOKIE_HTTPONLY
# set default dashboard and panel
dashboard = horizon.get_default_dashboard()
self.request.horizon['dashboard'] = dashboard

View File

@ -45,6 +45,5 @@ HORIZON_CONFIG = {
'password_autocomplete': 'off',
'integration_tests_support':
getattr(settings, 'INTEGRATION_TESTS_SUPPORT', False)
'integration_tests_support': settings.INTEGRATION_TESTS_SUPPORT,
}

95
horizon/defaults.py Normal file
View File

@ -0,0 +1,95 @@
# 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.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from openstack_auth.defaults import * # noqa: F403,H303
from horizon.contrib import bootstrap_datepicker
# From Django
# DEBUG
# LOGIN_URL
# LOGIN_REDIRECT_URL
# STATIC_URL
# CSRF_COOKIE_HTTPONLY = False
# SESSION_ENGINE
# SESSION_COOKIE_NAME
# Django default value of TIME_ZONE is America/Chicago for backward
# compatibility, so we should define this explicitly.
TIME_ZONE = 'UTC'
# ----------------------------------------
# horizon settings
# ----------------------------------------
# TODO(amotoki): Break down into the usage of ROOT_PATH?
# It seems ROOT_PATH is used for various purposes.
# ROOT_PATH
WEBROOT = '/'
LOGOUT_URL = WEBROOT + 'auth/logout/'
POLICY_CHECK_FUNCTION = None
INTEGRATION_TESTS_SUPPORT = False
NG_TEMPLATE_CACHE_AGE = 0
# Control whether the SESSION_TIMEOUT period is refreshed due to activity. If
# False, SESSION_TIMEOUT acts as a hard limit.
SESSION_REFRESH = True
# When using cookie-based sessions, log error when the session cookie exceeds
# the following size (common browsers drop cookies above a certain size):
SESSION_COOKIE_MAX_SIZE = 4093
# MEMOIZED_MAX_SIZE_DEFAULT allows setting a global default to help control
# memory usage when caching. It should at least be 2 x the number of threads
# with a little bit of extra buffer.
MEMOIZED_MAX_SIZE_DEFAULT = 25
HORIZON_COMPRESS_OFFLINE_CONTEXT_BASE = {}
SITE_BRANDING = _("Horizon")
SITE_BRANDING_LINK = reverse_lazy("horizon:user_home")
DATEPICKER_LOCALES = bootstrap_datepicker.LOCALE_MAPPING
# For Bootstrap integration; can be overridden in settings.
ACTION_CSS_CLASSES = ()
SELECTABLE_THEMES = []
# TODO(amotoki): How can we define the default value for this?
# AVAILABLE_THEMES
THEME_COLLECTION_DIR = 'themes'
THEME_COOKIE_NAME = 'theme'
DEFAULT_THEME = 'default'
OPERATION_LOG_ENABLED = False
OPERATION_LOG_OPTIONS = {
'mask_fields': ['password', 'current_password',
'new_password', 'confirm_password'],
'target_methods': ['POST'],
'ignore_urls': ['/js/', '/static/', '^/api/'],
'format': (
"[%(client_ip)s] [%(domain_name)s]"
" [%(domain_id)s] [%(project_name)s]"
" [%(project_id)s] [%(user_name)s] [%(user_id)s]"
" [%(request_scheme)s] [%(referer_url)s] [%(request_url)s]"
" [%(message)s] [%(method)s] [%(http_status)s] [%(param)s]"
),
}
OPENSTACK_PROFILER = {
'enabled': False,
'facility_name': 'horizon',
'keys': [],
'receiver_connection_string': "mongodb://",
'notifier_connection_string': None,
}

View File

@ -47,7 +47,7 @@ class ModalBackdropMixin(object):
def __init__(self, *args, **kwargs):
super(ModalBackdropMixin, self).__init__(*args, **kwargs)
config = getattr(settings, 'HORIZON_CONFIG', {})
config = settings.HORIZON_CONFIG
if 'modal_backdrop' in config:
self.modal_backdrop = config['modal_backdrop']

View File

@ -70,8 +70,8 @@ class HorizonMiddleware(object):
# Since we know the user is present and authenticated, lets refresh the
# session expiry if configured to do so.
if getattr(settings, "SESSION_REFRESH", True):
timeout = getattr(settings, "SESSION_TIMEOUT", 3600)
if settings.SESSION_REFRESH:
timeout = settings.SESSION_TIMEOUT
token_life = request.user.token.expires - datetime.datetime.now(
pytz.utc)
session_time = min(timeout, int(token_life.total_seconds()))
@ -90,10 +90,8 @@ class HorizonMiddleware(object):
settings.SESSION_ENGINE ==
'django.contrib.sessions.backends.signed_cookies'
):
max_cookie_size = getattr(
settings, 'SESSION_COOKIE_MAX_SIZE', None)
session_cookie_name = getattr(
settings, 'SESSION_COOKIE_NAME', None)
max_cookie_size = settings.SESSION_COOKIE_MAX_SIZE
session_cookie_name = settings.SESSION_COOKIE_NAME
session_key = request.COOKIES.get(session_cookie_name)
if max_cookie_size is not None and session_key is not None:
cookie_size = sum((

View File

@ -53,31 +53,21 @@ class OperationLogMiddleware(object):
return self._logger
def __init__(self, get_response):
if not getattr(settings, "OPERATION_LOG_ENABLED", False):
if not settings.OPERATION_LOG_ENABLED:
raise MiddlewareNotUsed
self.get_response = get_response
# set configurations
_log_option = getattr(settings, "OPERATION_LOG_OPTIONS", {})
_log_option = settings.OPERATION_LOG_OPTIONS
_available_methods = ['POST', 'GET', 'PUT', 'DELETE']
_methods = _log_option.get("target_methods", ['POST'])
self._default_format = (
"[%(client_ip)s] [%(domain_name)s]"
" [%(domain_id)s] [%(project_name)s]"
" [%(project_id)s] [%(user_name)s] [%(user_id)s]"
" [%(request_scheme)s] [%(referer_url)s] [%(request_url)s]"
" [%(message)s] [%(method)s] [%(http_status)s] [%(param)s]")
_default_ignored_urls = ['/js/', '/static/', '^/api/']
_default_mask_fields = ['password', 'current_password',
'new_password', 'confirm_password']
_methods = _log_option["target_methods"]
self.target_methods = [x for x in _methods if x in _available_methods]
self.mask_fields = _log_option.get("mask_fields", _default_mask_fields)
self.format = _log_option.get("format", self._default_format)
self.mask_fields = _log_option["mask_fields"]
self.format = _log_option["format"]
self._logger = logging.getLogger('horizon.operation_log')
ignored_urls = _log_option.get("ignore_urls", _default_ignored_urls)
self._ignored_urls = [re.compile(url) for url in ignored_urls]
self._ignored_urls = [re.compile(url)
for url in _log_option["ignore_urls"]]
def __call__(self, request):
response = self.get_response(request)

View File

@ -37,8 +37,6 @@ from horizon.utils import settings as utils_settings
LOG = logging.getLogger(__name__)
# For Bootstrap integration; can be overridden in settings.
ACTION_CSS_CLASSES = ()
STRING_SEPARATOR = "__"
@ -153,7 +151,7 @@ class BaseAction(html.HTMLElement):
Defaults to ``["btn", "btn-default", "btn-sm"]``.
"""
return getattr(settings, "ACTION_CSS_CLASSES", ACTION_CSS_CLASSES)
return settings.ACTION_CSS_CLASSES
def get_default_attrs(self):
"""Returns a list of the default HTML attributes for the action.

View File

@ -495,7 +495,7 @@ class Column(html.HTMLElement):
except urls.NoReverseMatch:
return self.link
if getattr(settings, 'INTEGRATION_TESTS_SUPPORT', False):
if settings.INTEGRATION_TESTS_SUPPORT:
def get_default_attrs(self):
attrs = super(Column, self).get_default_attrs()
attrs.update({'data-selenium': self.name})
@ -753,7 +753,7 @@ class Cell(html.HTMLElement):
if len(data) > column.truncate:
self.attrs['data-toggle'] = 'tooltip'
self.attrs['title'] = data
if getattr(settings, 'INTEGRATION_TESTS_SUPPORT', False):
if settings.INTEGRATION_TESTS_SUPPORT:
self.attrs['data-selenium'] = data
self.data = self.get_data(datum, column, row)

View File

@ -22,8 +22,6 @@ Template tags for customizing Horizon.
from django.conf import settings
from django import template
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
register = template.Library()
@ -31,7 +29,7 @@ register = template.Library()
class SiteBrandingNode(template.Node):
def render(self, context):
return getattr(settings, "SITE_BRANDING", _("Horizon"))
return settings.SITE_BRANDING
@register.tag
@ -46,8 +44,7 @@ def site_title(parser, token):
@register.simple_tag
def site_branding_link():
return getattr(settings, "SITE_BRANDING_LINK",
reverse("horizon:user_home"))
return settings.SITE_BRANDING_LINK
# TODO(jeffjapan): This is just an assignment tag version of the above, replace

View File

@ -25,7 +25,6 @@ from django.utils.translation import ugettext_lazy as _
from horizon.base import Horizon
from horizon import conf
from horizon.contrib import bootstrap_datepicker
register = template.Library()
@ -206,14 +205,13 @@ def load_config():
@register.simple_tag
def datepicker_locale():
locale_mapping = getattr(settings, 'DATEPICKER_LOCALES',
bootstrap_datepicker.LOCALE_MAPPING)
locale_mapping = settings.DATEPICKER_LOCALES
return locale_mapping.get(translation.get_language(), 'en')
@register.simple_tag
def template_cache_age():
return getattr(settings, 'NG_TEMPLATE_CACHE_AGE', 0)
return settings.NG_TEMPLATE_CACHE_AGE
@register.tag

View File

@ -19,13 +19,13 @@
import os
import socket
from horizon.defaults import * # noqa: F403,H303
from openstack_auth.defaults import * # noqa: F403,H303
from openstack_dashboard.utils import settings as settings_utils
socket.setdefaulttimeout(1)
LOGIN_URL = '/auth/login/'
LOGOUT_URL = '/auth/logout/'
LOGIN_REDIRECT_URL = '/'
ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
@ -97,13 +97,11 @@ TEMPLATES = [
]
STATIC_URL = '/static/'
WEBROOT = '/'
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
ROOT_URLCONF = 'horizon.test.urls'
SITE_ID = 1
SITE_BRANDING = 'Horizon'
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'

View File

@ -22,6 +22,7 @@ from django.http import HttpResponseRedirect
from django import test as django_test
from django.test.utils import override_settings
from horizon import defaults
from horizon import middleware
from horizon.test import helpers as test
@ -93,7 +94,7 @@ class OperationLogMiddlewareTest(django_test.TestCase):
self.assertIn(data, logging_str)
@override_settings(OPERATION_LOG_ENABLED=True)
@override_settings(OPERATION_LOG_OPTIONS={'target_methods': ['GET']})
@test.update_settings(OPERATION_LOG_OPTIONS={'target_methods': ['GET']})
@patch(('horizon.middleware.operation_log.OperationLogMiddleware.'
'OPERATION_LOG'))
def test_process_response_for_get(self, mock_logger):
@ -153,7 +154,7 @@ class OperationLogMiddlewareTest(django_test.TestCase):
self.assertIn(data, logging_str)
@override_settings(OPERATION_LOG_ENABLED=True)
@override_settings(OPERATION_LOG_OPTIONS={'target_methods': ['GET']})
@test.update_settings(OPERATION_LOG_OPTIONS={'target_methods': ['GET']})
@patch(('horizon.middleware.operation_log.OperationLogMiddleware.'
'OPERATION_LOG'))
def test_get_log_format(self, mock_logger):
@ -161,7 +162,9 @@ class OperationLogMiddlewareTest(django_test.TestCase):
olm = middleware.OperationLogMiddleware(get_response)
request, _ = self._test_ready_for_get()
self.assertEqual(olm._default_format, olm._get_log_format(request))
self.assertEqual(
defaults.OPERATION_LOG_OPTIONS['format'],
olm._get_log_format(request))
@override_settings(OPERATION_LOG_ENABLED=True)
@patch(('horizon.middleware.operation_log.OperationLogMiddleware.'

View File

@ -47,7 +47,7 @@ class FiltersTests(test.TestCase):
c = django.template.Context({'time': '2007-03-04T21:08:12'})
t = django.template.Template('{{ time|parse_isotime:"test" }}')
output = u"March 4, 2007, 3:08 p.m."
output = u"March 4, 2007, 9:08 p.m."
self.assertEqual(output, t.render(c))

View File

@ -33,11 +33,12 @@ _local = threading.local()
# Get the themes from settings
def get_selectable_themes():
return getattr(settings, 'SELECTABLE_THEMES', [])
return settings.SELECTABLE_THEMES
# Get the themes from settings
def get_themes():
# TODO(amotoki): Consider how to define the default value
return getattr(settings, 'AVAILABLE_THEMES',
[(get_default_theme(),
get_default_theme(),
@ -46,17 +47,17 @@ def get_themes():
# Get the themes dir from settings
def get_theme_dir():
return getattr(settings, 'THEME_COLLECTION_DIR', 'themes')
return settings.THEME_COLLECTION_DIR
# Get the theme cookie name from settings
def get_theme_cookie_name():
return getattr(settings, 'THEME_COOKIE_NAME', 'theme')
return settings.THEME_COOKIE_NAME
# Get the default theme
def get_default_theme():
return getattr(settings, 'DEFAULT_THEME', 'default')
return settings.DEFAULT_THEME
# Find the theme tuple
@ -71,12 +72,7 @@ def find_theme(theme_name):
# Offline Context Generator
def offline_context():
for theme in get_themes():
base_context = \
getattr(
settings,
'HORIZON_COMPRESS_OFFLINE_CONTEXT_BASE',
{}
).copy()
base_context = settings.HORIZON_COMPRESS_OFFLINE_CONTEXT_BASE.copy()
base_context['THEME'] = theme[0]
base_context['THEME_DIR'] = get_theme_dir()
yield base_context

View File

@ -104,8 +104,7 @@ def get_timezone(request):
# Session and cookie store timezone as django_timezone.
# In case there is no timezone neither in session nor in cookie,
# use default value from settings file where it's called TIME_ZONE.
return get_config_value(request, 'django_timezone',
getattr(settings, 'TIME_ZONE', 'UTC'))
return get_config_value(request, 'django_timezone', settings.TIME_ZONE)
def get_language(request):

View File

@ -72,7 +72,7 @@ def memoized(func=None, max_size=None):
if max_size:
max_cache_size = max_size
else:
max_cache_size = getattr(settings, 'MEMOIZED_MAX_SIZE_DEFAULT', 25)
max_cache_size = settings.MEMOIZED_MAX_SIZE_DEFAULT
@functools.wraps(func)
def wrapped(*args, **kwargs):

View File

@ -32,7 +32,7 @@ class HorizonScssFilter(DjangoScssFilter):
# Add variables to the SCSS Global Namespace Here
self.namespace.set_variable(
'$static_url',
String(six.text_type(getattr(settings, 'STATIC_URL', '/static/')))
String(six.text_type(settings.STATIC_URL))
)
# Create a compiler with the right namespace

View File

@ -73,8 +73,7 @@ class PageTitleMixin(object):
def trace(name):
def decorator(func):
# TODO(amotoki): Move OPENSTACK_PROFILER setting to horizon.
if getattr(settings, 'OPENSTACK_PROFILER', {}).get('enabled', False):
if settings.OPENSTACK_PROFILER['enabled']:
return profiler.trace(name, info=None, hide_args=False,
allow_multiple_trace=True)(func)
else:

View File

@ -16,16 +16,17 @@ import os
from django.utils.translation import ugettext_lazy as _
from openstack_auth.defaults import * # noqa: F403,H303
# openstack_auth.default is imported in horizon.defaults.
from horizon.defaults import * # noqa: F403,H303
def _get_root_path():
return os.path.dirname(os.path.abspath(__file__))
# -------------------------------------------
# Override openstack_auth and Django settings
# -------------------------------------------
# ---------------------------------------------------
# Override horizn, openstack_auth and Django settings
# ---------------------------------------------------
WEBROOT = '/' # from openstack_auth
@ -475,14 +476,6 @@ OPENSTACK_CLOUDS_YAML_NAME = 'openstack'
# If this cloud has a vendor profile in os-client-config, put it's name here.
OPENSTACK_CLOUDS_YAML_PROFILE = ''
OPENSTACK_PROFILER = {
'enabled': False,
'facility_name': 'horizon',
'keys': [],
'receiver_connection_string': "mongodb://",
'notifier_connection_string': None,
}
# AngularJS requires some settings to be made available to
# the client side. Some settings are required by in-tree / built-in horizon
# features. These settings must be added to REST_API_REQUIRED_SETTINGS in the

View File

@ -40,6 +40,10 @@ from openstack_dashboard.utils import settings as settings_utils
monkeypatch_escape()
# Load default values
# pylint: disable=wrong-import-position
from openstack_dashboard.defaults import * # noqa: F403,H303
_LOG = logging.getLogger(__name__)
warnings.formatwarning = lambda message, category, *args, **kwargs: \
@ -183,24 +187,11 @@ SESSION_COOKIE_HTTPONLY = True
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_SECURE = False
# Control whether the SESSION_TIMEOUT period is refreshed due to activity. If
# False, SESSION_TIMEOUT acts as a hard limit.
SESSION_REFRESH = True
# When using cookie-based sessions, log error when the session cookie exceeds
# the following size (common browsers drop cookies above a certain size):
SESSION_COOKIE_MAX_SIZE = 4093
# when doing upgrades, it may be wise to stick to PickleSerializer
# NOTE(berendt): Check during the K-cycle if this variable can be removed.
# https://bugs.launchpad.net/horizon/+bug/1349463
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
# MEMOIZED_MAX_SIZE_DEFAULT allows setting a global default to help control
# memory usage when caching. It should at least be 2 x the number of threads
# with a little bit of extra buffer.
MEMOIZED_MAX_SIZE_DEFAULT = 25
CSRF_FAILURE_VIEW = 'openstack_dashboard.views.csrf_failure'
LANGUAGES = (
@ -278,10 +269,6 @@ ANGULAR_FEATURES = {
# Notice all customizable configurations should be above this line
XSTATIC_MODULES = settings_utils.BASE_XSTATIC_MODULES
# Load default values
# pylint: disable=wrong-import-position
from openstack_dashboard.defaults import * # noqa: F403,H303
if not LOCAL_PATH:
LOCAL_PATH = os.path.join(ROOT_PATH, 'local')
LOCAL_SETTINGS_DIR_PATH = os.path.join(LOCAL_PATH, "local_settings.d")