mirror of
https://github.com/ansible/awx.git
synced 2026-01-12 18:40:01 -03:30
Merge pull request #5143 from ryanpetrello/fix-4876
add a field to OPTIONS that tells if the setting came from a .py file
This commit is contained in:
commit
1d8b8a6d11
@ -32,6 +32,7 @@ class Metadata(metadata.SimpleMetadata):
|
||||
'min_length', 'max_length',
|
||||
'min_value', 'max_value',
|
||||
'category', 'category_slug',
|
||||
'defined_in_file'
|
||||
]
|
||||
|
||||
for attr in text_attrs:
|
||||
@ -156,6 +157,10 @@ class Metadata(metadata.SimpleMetadata):
|
||||
|
||||
# For PUT/POST methods, remove read-only fields.
|
||||
if method in ('PUT', 'POST'):
|
||||
# This value should always be False for PUT/POST, so don't
|
||||
# show it (file-based read-only settings can't be updated)
|
||||
meta.pop('defined_in_file', False)
|
||||
|
||||
if meta.pop('read_only', False):
|
||||
actions[method].pop(field)
|
||||
|
||||
|
||||
@ -116,6 +116,7 @@ class SettingsRegistry(object):
|
||||
placeholder = field_kwargs.pop('placeholder', empty)
|
||||
feature_required = field_kwargs.pop('feature_required', empty)
|
||||
encrypted = bool(field_kwargs.pop('encrypted', False))
|
||||
defined_in_file = bool(field_kwargs.pop('defined_in_file', False))
|
||||
if getattr(field_kwargs.get('child', None), 'source', None) is not None:
|
||||
field_kwargs['child'].source = None
|
||||
field_instance = field_class(**field_kwargs)
|
||||
@ -126,6 +127,13 @@ class SettingsRegistry(object):
|
||||
field_instance.placeholder = placeholder
|
||||
if feature_required is not empty:
|
||||
field_instance.feature_required = feature_required
|
||||
field_instance.defined_in_file = defined_in_file
|
||||
if field_instance.defined_in_file:
|
||||
field_instance.help_text = (
|
||||
str(_('This value has been set manually in a settings file.')) +
|
||||
'\n\n' +
|
||||
str(field_instance.help_text)
|
||||
)
|
||||
field_instance.encrypted = encrypted
|
||||
original_field_instance = field_instance
|
||||
if field_class != original_field_class:
|
||||
|
||||
@ -205,6 +205,7 @@ class SettingsWrapper(UserSettingsHolder):
|
||||
if file_default != init_default and file_default is not None:
|
||||
logger.warning('Setting %s has been marked read-only!', key)
|
||||
self.registry._registry[key]['read_only'] = True
|
||||
self.registry._registry[key]['defined_in_file'] = True
|
||||
self.__dict__['_awx_conf_init_readonly'] = True
|
||||
# If local preload timer has expired, check to see if another process
|
||||
# has already preloaded the cache and skip preloading if so.
|
||||
|
||||
@ -25,11 +25,11 @@ def reg(request):
|
||||
settings = LazySettings()
|
||||
registry = SettingsRegistry(settings)
|
||||
|
||||
# @pytest.mark.readonly can be used to mark specific setting values as
|
||||
# "read-only". This is analogous to manually specifying a setting on the
|
||||
# filesystem (e.g., in a local_settings.py in development, or in
|
||||
# /etc/tower/conf.d/<something>.py)
|
||||
defaults = request.node.get_marker('readonly')
|
||||
# @pytest.mark.defined_in_file can be used to mark specific setting values
|
||||
# as "defined in a settings file". This is analogous to manually
|
||||
# specifying a setting on the filesystem (e.g., in a local_settings.py in
|
||||
# development, or in /etc/tower/conf.d/<something>.py)
|
||||
defaults = request.node.get_marker('defined_in_file')
|
||||
if defaults:
|
||||
settings.configure(**defaults.kwargs)
|
||||
settings._wrapped = SettingsWrapper(settings._wrapped,
|
||||
@ -280,7 +280,7 @@ def test_field_with_custom_mixin(reg):
|
||||
assert field.is_great() is True
|
||||
|
||||
|
||||
@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT')
|
||||
@pytest.mark.defined_in_file(AWX_SOME_SETTING='DEFAULT')
|
||||
def test_default_value_from_settings(reg):
|
||||
reg.register(
|
||||
'AWX_SOME_SETTING',
|
||||
@ -293,7 +293,7 @@ def test_default_value_from_settings(reg):
|
||||
assert field.default == 'DEFAULT'
|
||||
|
||||
|
||||
@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT')
|
||||
@pytest.mark.defined_in_file(AWX_SOME_SETTING='DEFAULT')
|
||||
def test_default_value_from_settings_with_custom_representation(reg):
|
||||
class LowercaseCharField(fields.CharField):
|
||||
|
||||
|
||||
@ -40,12 +40,12 @@ def settings(request):
|
||||
settings = LazySettings()
|
||||
registry = SettingsRegistry(settings)
|
||||
|
||||
# @pytest.mark.readonly can be used to mark specific setting values as
|
||||
# "read-only". This is analogous to manually specifying a setting on the
|
||||
# filesystem (e.g., in a local_settings.py in development, or in
|
||||
# /etc/tower/conf.d/<something>.py)
|
||||
readonly_marker = request.node.get_marker('readonly')
|
||||
defaults = readonly_marker.kwargs if readonly_marker else {}
|
||||
# @pytest.mark.defined_in_file can be used to mark specific setting values
|
||||
# as "defined in a settings file". This is analogous to manually
|
||||
# specifying a setting on the filesystem (e.g., in a local_settings.py in
|
||||
# development, or in /etc/tower/conf.d/<something>.py)
|
||||
in_file_marker = request.node.get_marker('defined_in_file')
|
||||
defaults = in_file_marker.kwargs if in_file_marker else {}
|
||||
defaults['DEFAULTS_SNAPSHOT'] = {}
|
||||
settings.configure(**defaults)
|
||||
settings._wrapped = SettingsWrapper(settings._wrapped,
|
||||
@ -54,14 +54,14 @@ def settings(request):
|
||||
return settings
|
||||
|
||||
|
||||
@pytest.mark.readonly(DEBUG=True)
|
||||
@pytest.mark.defined_in_file(DEBUG=True)
|
||||
def test_unregistered_setting(settings):
|
||||
"native Django settings are not stored in DB, and aren't cached"
|
||||
assert settings.DEBUG is True
|
||||
assert settings.cache.get('DEBUG') is None
|
||||
|
||||
|
||||
@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT')
|
||||
@pytest.mark.defined_in_file(AWX_SOME_SETTING='DEFAULT')
|
||||
def test_read_only_setting(settings):
|
||||
settings.registry.register(
|
||||
'AWX_SOME_SETTING',
|
||||
@ -75,7 +75,7 @@ def test_read_only_setting(settings):
|
||||
assert settings == ['AWX_SOME_SETTING']
|
||||
|
||||
|
||||
@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT')
|
||||
@pytest.mark.defined_in_file(AWX_SOME_SETTING='DEFAULT')
|
||||
def test_read_only_setting_with_empty_default(settings):
|
||||
settings.registry.register(
|
||||
'AWX_SOME_SETTING',
|
||||
@ -90,7 +90,7 @@ def test_read_only_setting_with_empty_default(settings):
|
||||
assert settings == ['AWX_SOME_SETTING']
|
||||
|
||||
|
||||
@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT')
|
||||
@pytest.mark.defined_in_file(AWX_SOME_SETTING='DEFAULT')
|
||||
def test_read_only_defaults_are_cached(settings):
|
||||
"read-only settings are stored in the cache"
|
||||
settings.registry.register(
|
||||
@ -103,7 +103,7 @@ def test_read_only_defaults_are_cached(settings):
|
||||
assert settings.cache.get('AWX_SOME_SETTING') == 'DEFAULT'
|
||||
|
||||
|
||||
@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT')
|
||||
@pytest.mark.defined_in_file(AWX_SOME_SETTING='DEFAULT')
|
||||
def test_cache_respects_timeout(settings):
|
||||
"only preload the cache every SETTING_CACHE_TIMEOUT settings"
|
||||
settings.registry.register(
|
||||
@ -137,6 +137,33 @@ def test_default_setting(settings, mocker):
|
||||
assert settings.cache.get('AWX_SOME_SETTING') == 'DEFAULT'
|
||||
|
||||
|
||||
@pytest.mark.defined_in_file(AWX_SOME_SETTING='DEFAULT')
|
||||
def test_setting_is_from_setting_file(settings, mocker):
|
||||
settings.registry.register(
|
||||
'AWX_SOME_SETTING',
|
||||
field_class=fields.CharField,
|
||||
category=_('System'),
|
||||
category_slug='system'
|
||||
)
|
||||
assert settings.AWX_SOME_SETTING == 'DEFAULT'
|
||||
assert settings.registry.get_setting_field('AWX_SOME_SETTING').defined_in_file is True
|
||||
|
||||
|
||||
def test_setting_is_not_from_setting_file(settings, mocker):
|
||||
settings.registry.register(
|
||||
'AWX_SOME_SETTING',
|
||||
field_class=fields.CharField,
|
||||
category=_('System'),
|
||||
category_slug='system',
|
||||
default='DEFAULT'
|
||||
)
|
||||
|
||||
settings_to_cache = mocker.Mock(**{'order_by.return_value': []})
|
||||
with mocker.patch('awx.conf.models.Setting.objects.filter', return_value=settings_to_cache):
|
||||
assert settings.AWX_SOME_SETTING == 'DEFAULT'
|
||||
assert settings.registry.get_setting_field('AWX_SOME_SETTING').defined_in_file is False
|
||||
|
||||
|
||||
def test_empty_setting(settings, mocker):
|
||||
"settings with no default and no defined value are not valid"
|
||||
settings.registry.register(
|
||||
@ -180,7 +207,7 @@ def test_setting_from_db(settings, mocker):
|
||||
assert settings.cache.get('AWX_SOME_SETTING') == 'FROM_DB'
|
||||
|
||||
|
||||
@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT')
|
||||
@pytest.mark.defined_in_file(AWX_SOME_SETTING='DEFAULT')
|
||||
def test_read_only_setting_assignment(settings):
|
||||
"read-only settings cannot be overwritten"
|
||||
settings.registry.register(
|
||||
@ -255,7 +282,7 @@ def test_db_setting_deletion(settings, mocker):
|
||||
assert existing_setting.delete.call_count == 1
|
||||
|
||||
|
||||
@pytest.mark.readonly(AWX_SOME_SETTING='DEFAULT')
|
||||
@pytest.mark.defined_in_file(AWX_SOME_SETTING='DEFAULT')
|
||||
def test_read_only_setting_deletion(settings):
|
||||
"read-only settings cannot be deleted"
|
||||
settings.registry.register(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user