From 9c19b07a263868ec2d0ba8ac6ed4783fac84e063 Mon Sep 17 00:00:00 2001 From: Akihiro Motoki Date: Thu, 11 Apr 2019 06:26:54 +0900 Subject: [PATCH] Define default settings explicitly (openstack_dashboard 1/5) Currently horizon defines default values of settings in the logic using getattr(settings, , ) and it is not easy to handle the default values of available settings. This commit starts the effort to define default settings explicitly. This is a preparation for ini-based-configurations. It covers settings in openstack_dashboard/api. Part of blueprint ini-based-configuration Change-Id: Id4c3287f0a572fd14ea93b54bcab8fabda39e583 --- openstack_dashboard/api/_nova.py | 4 +- openstack_dashboard/api/base.py | 10 +- openstack_dashboard/api/cinder.py | 8 +- openstack_dashboard/api/glance.py | 10 +- openstack_dashboard/api/keystone.py | 52 ++--- openstack_dashboard/api/neutron.py | 29 ++- openstack_dashboard/api/nova.py | 20 +- openstack_dashboard/api/rest/config.py | 9 +- openstack_dashboard/api/rest/keystone.py | 4 +- openstack_dashboard/api/swift.py | 10 +- .../dashboards/project/instances/tests.py | 10 +- openstack_dashboard/defaults.py | 202 ++++++++++++++++++ .../local/local_settings.py.example | 178 +-------------- openstack_dashboard/settings.py | 6 +- openstack_dashboard/test/settings.py | 41 +--- 15 files changed, 299 insertions(+), 294 deletions(-) create mode 100644 openstack_dashboard/defaults.py diff --git a/openstack_dashboard/api/_nova.py b/openstack_dashboard/api/_nova.py index 05e915fdd8..2773446dc0 100644 --- a/openstack_dashboard/api/_nova.py +++ b/openstack_dashboard/api/_nova.py @@ -35,8 +35,8 @@ VERSIONS = base.APIVersionManager("compute", preferred_version=2) VERSIONS.load_supported_version(1.1, {"client": nova_client, "version": 1.1}) VERSIONS.load_supported_version(2, {"client": nova_client, "version": 2}) -INSECURE = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) -CACERT = getattr(settings, 'OPENSTACK_SSL_CACERT', None) +INSECURE = settings.OPENSTACK_SSL_NO_VERIFY +CACERT = settings.OPENSTACK_SSL_CACERT class Server(base.APIResourceWrapper): diff --git a/openstack_dashboard/api/base.py b/openstack_dashboard/api/base.py index 89d900b320..490b030b54 100644 --- a/openstack_dashboard/api/base.py +++ b/openstack_dashboard/api/base.py @@ -54,8 +54,6 @@ class Version(object): class APIVersionManager(object): """Object to store and manage API versioning data and utility methods.""" - SETTINGS_KEY = "OPENSTACK_API_VERSIONS" - def __init__(self, service_type, preferred_version=None): self.service_type = service_type self.preferred = preferred_version @@ -82,7 +80,7 @@ class APIVersionManager(object): def get_active_version(self): if self._active is not None: return self.supported[self._active] - key = getattr(settings, self.SETTINGS_KEY, {}).get(self.service_type) + key = settings.OPENSTACK_API_VERSIONS.get(self.service_type) if key is None: # TODO(gabriel): support API version discovery here; we'll leave # the setting in as a way of overriding the latest available @@ -324,10 +322,8 @@ def get_url_for_service(service, region, endpoint_type): def url_for(request, service_type, endpoint_type=None, region=None): - endpoint_type = endpoint_type or getattr(settings, - 'OPENSTACK_ENDPOINT_TYPE', - 'publicURL') - fallback_endpoint_type = getattr(settings, 'SECONDARY_ENDPOINT_TYPE', None) + endpoint_type = endpoint_type or settings.OPENSTACK_ENDPOINT_TYPE + fallback_endpoint_type = settings.SECONDARY_ENDPOINT_TYPE catalog = request.user.service_catalog service = get_service_from_catalog(catalog, service_type) diff --git a/openstack_dashboard/api/cinder.py b/openstack_dashboard/api/cinder.py index 2bc6a6d2fb..e433321224 100644 --- a/openstack_dashboard/api/cinder.py +++ b/openstack_dashboard/api/cinder.py @@ -231,8 +231,8 @@ def cinderclient(request, version=None): if version is None: api_version = VERSIONS.get_active_version() version = api_version['version'] - insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) - cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None) + insecure = settings.OPENSTACK_SSL_NO_VERIFY + cacert = settings.OPENSTACK_SSL_CACERT (username, token_id, tenant_id, cinder_urls, auth_url) = get_auth_params_from_request(request) @@ -707,8 +707,8 @@ 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 = getattr(settings, 'OPENSTACK_CINDER_FEATURES', {}) - return cinder_config.get('enable_backup', False) + cinder_config = settings.OPENSTACK_CINDER_FEATURES + return cinder_config['enable_backup'] @profiler.trace diff --git a/openstack_dashboard/api/glance.py b/openstack_dashboard/api/glance.py index 1e7d46aec1..12ce094510 100644 --- a/openstack_dashboard/api/glance.py +++ b/openstack_dashboard/api/glance.py @@ -146,8 +146,8 @@ def glanceclient(request, version=None): api_version = VERSIONS.get_active_version() url = base.url_for(request, 'image') - insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) - cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None) + insecure = settings.OPENSTACK_SSL_NO_VERIFY + cacert = settings.OPENSTACK_SSL_CACERT # TODO(jpichon): Temporarily keep both till we update the API calls # to stop hardcoding a version in this file. Once that's done we @@ -329,7 +329,7 @@ def image_list_detailed(request, marker=None, sort_dir='desc', Set this flag to True when it's necessary to get a reversed list of images from Glance (used for navigating the images list back in UI). """ - limit = getattr(settings, 'API_RESULT_LIMIT', 1000) + limit = settings.API_RESULT_LIMIT page_size = utils.get_page_size(request) if paginate: @@ -412,7 +412,7 @@ def image_update(request, image_id, **kwargs): def get_image_upload_mode(): - mode = getattr(settings, 'HORIZON_IMAGES_UPLOAD_MODE', 'legacy') + mode = settings.HORIZON_IMAGES_UPLOAD_MODE if mode not in ('off', 'legacy', 'direct'): LOG.warning('HORIZON_IMAGES_UPLOAD_MODE has an unrecognized value of ' '"%s", reverting to default "legacy" value', mode) @@ -701,7 +701,7 @@ def metadefs_namespace_list(request, if filters is None: filters = {} - limit = getattr(settings, 'API_RESULT_LIMIT', 1000) + limit = settings.API_RESULT_LIMIT page_size = utils.get_page_size(request) if paginate: diff --git a/openstack_dashboard/api/keystone.py b/openstack_dashboard/api/keystone.py index e99f8c1ba3..7b082c11d8 100644 --- a/openstack_dashboard/api/keystone.py +++ b/openstack_dashboard/api/keystone.py @@ -45,8 +45,7 @@ from openstack_dashboard import policy LOG = logging.getLogger(__name__) DEFAULT_ROLE = None -DEFAULT_DOMAIN = getattr(settings, 'OPENSTACK_KEYSTONE_DEFAULT_DOMAIN', - 'Default') +DEFAULT_DOMAIN = settings.OPENSTACK_KEYSTONE_DEFAULT_DOMAIN # Set up our data structure for managing Identity API versions, and @@ -123,7 +122,7 @@ def _get_endpoint_url(request, endpoint_type, catalog=None): "Keystone endpoint, but v3 is specified as the API version " "to use by Horizon. Using v3 endpoint for authentication.") else: - auth_url = getattr(settings, 'OPENSTACK_KEYSTONE_URL') + auth_url = settings.OPENSTACK_KEYSTONE_URL url = request.session.get('region_endpoint', auth_url) message = ("The OPENSTACK_KEYSTONE_URL setting points to a v2.0 " "Keystone endpoint, but v3 is specified as the API version " @@ -176,9 +175,7 @@ def keystoneclient(request, admin=False): raise exceptions.NotAuthorized endpoint_type = 'adminURL' else: - endpoint_type = getattr(settings, - 'OPENSTACK_ENDPOINT_TYPE', - 'publicURL') + endpoint_type = settings.OPENSTACK_ENDPOINT_TYPE # Take care of client connection caching/fetching a new client. # Admin vs. non-admin clients are cached separately for token matching. @@ -190,8 +187,8 @@ def keystoneclient(request, admin=False): conn = getattr(request, cache_attr) else: endpoint = _get_endpoint_url(request, endpoint_type) - verify = not getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) - cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None) + verify = not settings.OPENSTACK_SSL_NO_VERIFY + cacert = settings.OPENSTACK_SSL_CACERT verify = verify and cacert LOG.debug("Creating a new keystoneclient connection to %s.", endpoint) remote_addr = request.environ.get('REMOTE_ADDR', '') @@ -558,8 +555,8 @@ def user_verify_admin_password(request, admin_password): client = keystone_client_v2 if VERSIONS.active < 3 else keystone_client_v3 try: endpoint = _get_endpoint_url(request, 'publicURL') - insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) - cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None) + insecure = settings.OPENSTACK_SSL_NO_VERIFY + cacert = settings.OPENSTACK_SSL_CACERT client.Client( username=request.user.username, password=admin_password, @@ -899,7 +896,7 @@ def get_default_role(request): to request. Supports lookup by name or id. """ global DEFAULT_ROLE - default = getattr(settings, "OPENSTACK_KEYSTONE_DEFAULT_ROLE", None) + default = settings.OPENSTACK_KEYSTONE_DEFAULT_ROLE if default and DEFAULT_ROLE is None: try: roles = keystoneclient(request, admin=True).roles.list() @@ -944,39 +941,34 @@ def delete_user_ec2_credentials(request, user_id, access_token): def keystone_can_edit_domain(): - backend_settings = getattr(settings, "OPENSTACK_KEYSTONE_BACKEND", {}) - can_edit_domain = backend_settings.get('can_edit_domain', True) - multi_domain_support = getattr(settings, - 'OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT', - False) + backend_settings = settings.OPENSTACK_KEYSTONE_BACKEND + can_edit_domain = backend_settings['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 = getattr(settings, "OPENSTACK_KEYSTONE_BACKEND", {}) - return backend_settings.get('can_edit_user', True) + backend_settings = settings.OPENSTACK_KEYSTONE_BACKEND + return backend_settings['can_edit_user'] def keystone_can_edit_project(): - backend_settings = getattr(settings, "OPENSTACK_KEYSTONE_BACKEND", {}) - return backend_settings.get('can_edit_project', True) + backend_settings = settings.OPENSTACK_KEYSTONE_BACKEND + return backend_settings['can_edit_project'] def keystone_can_edit_group(): - backend_settings = getattr(settings, "OPENSTACK_KEYSTONE_BACKEND", {}) - return backend_settings.get('can_edit_group', True) + backend_settings = settings.OPENSTACK_KEYSTONE_BACKEND + return backend_settings['can_edit_group'] def keystone_can_edit_role(): - backend_settings = getattr(settings, "OPENSTACK_KEYSTONE_BACKEND", {}) - return backend_settings.get('can_edit_role', True) + backend_settings = settings.OPENSTACK_KEYSTONE_BACKEND + return backend_settings['can_edit_role'] def keystone_backend_name(): - if hasattr(settings, "OPENSTACK_KEYSTONE_BACKEND"): - return settings.OPENSTACK_KEYSTONE_BACKEND['name'] - else: - return 'unknown' + return settings.OPENSTACK_KEYSTONE_BACKEND['name'] or 'unknown' def get_version(): @@ -985,11 +977,11 @@ def get_version(): def is_multi_domain_enabled(): return (VERSIONS.active >= 3 and - getattr(settings, 'OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT', False)) + settings.OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT) def is_federation_management_enabled(): - return getattr(settings, 'OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT', False) + return settings.OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT def identity_provider_create(request, idp_id, description=None, diff --git a/openstack_dashboard/api/neutron.py b/openstack_dashboard/api/neutron.py index 1edc038c38..a29ecf113a 100644 --- a/openstack_dashboard/api/neutron.py +++ b/openstack_dashboard/api/neutron.py @@ -670,7 +670,7 @@ class FloatingIpManager(object): {'floatingip': update_dict}) def _get_reachable_subnets(self, ports, fetch_router_ports=False): - if not is_enabled_by_config('enable_fip_topology_check', True): + if not is_enabled_by_config('enable_fip_topology_check'): # All subnets are reachable from external network return set( p.fixed_ips[0]['subnet_id'] for p in ports if p.fixed_ips @@ -788,8 +788,8 @@ class FloatingIpManager(object): def is_supported(self): """Returns True if floating IP feature is supported.""" - network_config = getattr(settings, 'OPENSTACK_NEUTRON_NETWORK', {}) - return network_config.get('enable_router', True) + network_config = settings.OPENSTACK_NEUTRON_NETWORK + return network_config['enable_router'] def get_ipver_str(ip_version): @@ -808,8 +808,8 @@ def get_auth_params_from_request(request): @memoized def neutronclient(request): token_id, neutron_url, auth_url = get_auth_params_from_request(request) - insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) - cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None) + insecure = settings.OPENSTACK_SSL_NO_VERIFY + cacert = settings.OPENSTACK_SSL_CACERT c = neutron_client.Client(token=token_id, auth_url=auth_url, endpoint_url=neutron_url, @@ -1026,7 +1026,7 @@ def _is_auto_allocated_network_supported(request): try: neutron_auto_supported = is_service_enabled( request, 'enable_auto_allocated_network', - 'auto-allocated-topology', default=False) + 'auto-allocated-topology') except Exception: exceptions.handle(request, _('Failed to check if neutron supports ' '"auto_allocated_network".')) @@ -1823,11 +1823,20 @@ def is_extension_supported(request, extension_alias): return False +# TODO(amotoki): Clean up 'default' parameter because the default +# values are pre-defined now, so 'default' argument is meaningless +# in most cases. def is_enabled_by_config(name, default=True): - network_config = getattr(settings, 'OPENSTACK_NEUTRON_NETWORK', {}) + 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) +# TODO(amotoki): Clean up 'default' parameter because the default +# values are pre-defined now, so 'default' argument is meaningless +# in most cases. @memoized def is_service_enabled(request, config_name, ext_name, default=True): return (is_enabled_by_config(config_name, default) and @@ -1836,7 +1845,7 @@ def is_service_enabled(request, config_name, ext_name, default=True): @memoized def is_quotas_extension_supported(request): - return (is_enabled_by_config('enable_quotas', False) and + return (is_enabled_by_config('enable_quotas') and is_extension_supported(request, 'quotas')) @@ -1898,7 +1907,7 @@ 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 = getattr(settings, 'OPENSTACK_NEUTRON_NETWORK', {}) + 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. " @@ -1908,6 +1917,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']): return False diff --git a/openstack_dashboard/api/nova.py b/openstack_dashboard/api/nova.py index b07a4b09b7..987bb938e6 100644 --- a/openstack_dashboard/api/nova.py +++ b/openstack_dashboard/api/nova.py @@ -1011,8 +1011,7 @@ def interface_detach(request, server, port_id): @memoized.memoized def list_extensions(request): """List all nova extensions, except the ones in the blacklist.""" - blacklist = set(getattr(settings, - 'OPENSTACK_NOVA_EXTENSIONS_BLACKLIST', [])) + blacklist = set(settings.OPENSTACK_NOVA_EXTENSIONS_BLACKLIST) nova_api = _nova.novaclient(request) return tuple( extension for extension in @@ -1037,8 +1036,8 @@ def extension_supported(extension_name, request): @profiler.trace def can_set_server_password(): - features = getattr(settings, 'OPENSTACK_HYPERVISOR_FEATURES', {}) - return features.get('can_set_password', False) + features = settings.OPENSTACK_HYPERVISOR_FEATURES + return features['can_set_password'] @profiler.trace @@ -1050,17 +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 = getattr( - settings, "OPENSTACK_HYPERVISOR_FEATURES", {}) - return hypervisor_features.get("can_set_mount_point", False) + hypervisor_features = settings.OPENSTACK_HYPERVISOR_FEATURES + return hypervisor_features["can_set_mount_point"] @profiler.trace def requires_keypair(): - features = getattr(settings, 'OPENSTACK_HYPERVISOR_FEATURES', {}) - return features.get('requires_keypair', False) + features = settings.OPENSTACK_HYPERVISOR_FEATURES + return features['requires_keypair'] def can_set_quotas(): - features = getattr(settings, 'OPENSTACK_HYPERVISOR_FEATURES', {}) - return features.get('enable_quotas', True) + features = settings.OPENSTACK_HYPERVISOR_FEATURES + return features['enable_quotas'] diff --git a/openstack_dashboard/api/rest/config.py b/openstack_dashboard/api/rest/config.py index 9bca3fd39b..61cdd3eb6c 100644 --- a/openstack_dashboard/api/rest/config.py +++ b/openstack_dashboard/api/rest/config.py @@ -24,8 +24,8 @@ from openstack_dashboard.api.rest import utils as rest_utils # settings that we allow to be retrieved via REST API # these settings are available to the client and are not secured. # *** THEY SHOULD BE TREATED WITH EXTREME CAUTION *** -settings_required = getattr(settings, 'REST_API_REQUIRED_SETTINGS', []) -settings_additional = getattr(settings, 'REST_API_ADDITIONAL_SETTINGS', []) +settings_required = settings.REST_API_REQUIRED_SETTINGS +settings_additional = settings.REST_API_ADDITIONAL_SETTINGS settings_allowed = settings_required + settings_additional @@ -42,14 +42,15 @@ class Settings(generic.View): SPECIALS = { 'HORIZON_IMAGES_UPLOAD_MODE': api.glance.get_image_upload_mode(), 'HORIZON_ACTIVE_IMAGE_VERSION': str(api.glance.VERSIONS.active), - 'IMAGES_ALLOW_LOCATION': getattr(settings, 'IMAGES_ALLOW_LOCATION', - False), + 'IMAGES_ALLOW_LOCATION': settings.IMAGES_ALLOW_LOCATION, 'AJAX_POLL_INTERVAL': settings.HORIZON_CONFIG.get( 'ajax_poll_interval', 2500) } @rest_utils.ajax() def get(self, request): + # TODO(amotoki): Drop the default value of getattr. + # It will be unnecessary once all default settings are defined. plain_settings = {k: getattr(settings, k, None) for k in settings_allowed if k not in self.SPECIALS} plain_settings.update(self.SPECIALS) diff --git a/openstack_dashboard/api/rest/keystone.py b/openstack_dashboard/api/rest/keystone.py index 9c348d780a..8fe1e7bf42 100644 --- a/openstack_dashboard/api/rest/keystone.py +++ b/openstack_dashboard/api/rest/keystone.py @@ -156,7 +156,7 @@ class User(generic.View): user = api.keystone.user_get(request, id) if 'password' in keys: - if getattr(settings, 'ENFORCE_PASSWORD_CHECK', False): + if settings.ENFORCE_PASSWORD_CHECK: admin_password = request.DATA['admin_password'] if not api.keystone.user_verify_admin_password(request, admin_password): @@ -577,7 +577,7 @@ class UserSession(generic.View): def get(self, request): """Get the current user session.""" res = {k: getattr(request.user, k, None) for k in self.allowed_fields} - if getattr(settings, 'ENABLE_CLIENT_TOKEN', True): + if settings.ENABLE_CLIENT_TOKEN: res['token'] = request.user.token.id return res diff --git a/openstack_dashboard/api/swift.py b/openstack_dashboard/api/swift.py index bbca5065a7..0947c130f7 100644 --- a/openstack_dashboard/api/swift.py +++ b/openstack_dashboard/api/swift.py @@ -32,7 +32,7 @@ from openstack_dashboard.api import base from openstack_dashboard.contrib.developer.profiler import api as profiler FOLDER_DELIMITER = "/" -CHUNK_SIZE = getattr(settings, 'SWIFT_FILE_TRANSFER_CHUNK_SIZE', 512 * 1024) +CHUNK_SIZE = settings.SWIFT_FILE_TRANSFER_CHUNK_SIZE # Swift ACL GLOBAL_READ_ACL = ".r:*" LIST_CONTENTS_ACL = ".rlistings" @@ -119,8 +119,8 @@ def _metadata_to_header(metadata): def swift_api(request): endpoint = base.url_for(request, 'object-store') - cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None) - insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) + cacert = settings.OPENSTACK_SSL_CACERT + insecure = settings.OPENSTACK_SSL_NO_VERIFY return swiftclient.client.Connection(None, request.user.username, None, @@ -152,7 +152,7 @@ def swift_object_exists(request, container_name, object_name): @profiler.trace @safe_swift_exception def swift_get_containers(request, marker=None, prefix=None): - limit = getattr(settings, 'API_RESULT_LIMIT', 1000) + limit = settings.API_RESULT_LIMIT headers, containers = swift_api(request).get_account(limit=limit + 1, marker=marker, prefix=prefix, @@ -236,7 +236,7 @@ def swift_delete_container(request, name): @safe_swift_exception def swift_get_objects(request, container_name, prefix=None, marker=None, limit=None): - limit = limit or getattr(settings, 'API_RESULT_LIMIT', 1000) + limit = limit or settings.API_RESULT_LIMIT kwargs = dict(prefix=prefix, marker=marker, limit=limit + 1, diff --git a/openstack_dashboard/dashboards/project/instances/tests.py b/openstack_dashboard/dashboards/project/instances/tests.py index 2edc2ee995..fd428f618a 100644 --- a/openstack_dashboard/dashboards/project/instances/tests.py +++ b/openstack_dashboard/dashboards/project/instances/tests.py @@ -2290,12 +2290,12 @@ class InstanceLaunchInstanceTests(InstanceTestBase, def test_launch_instance_get_glance_v1(self): self.test_launch_instance_get() - @django.test.utils.override_settings( + @helpers.update_settings( OPENSTACK_HYPERVISOR_FEATURES={'can_set_password': False}) def test_launch_instance_get_without_password(self): self.test_launch_instance_get(expect_password_fields=False) - @django.test.utils.override_settings( + @helpers.update_settings( OPENSTACK_HYPERVISOR_FEATURES={'requires_keypair': True}) def test_launch_instance_required_key(self): flavor = self.flavors.first() @@ -3960,7 +3960,7 @@ class InstanceLaunchInstanceTests(InstanceTestBase, ]) self.assertEqual(2, self.mock_tenant_quota_usages.call_count) - @override_settings( + @helpers.update_settings( OPENSTACK_HYPERVISOR_FEATURES={'can_set_mount_point': True},) def test_launch_form_instance_device_name_showed(self): self._test_launch_form_instance_show_device_name( @@ -3969,7 +3969,7 @@ class InstanceLaunchInstanceTests(InstanceTestBase, 'attrs': {'id': 'id_device_name'}} ) - @override_settings( + @helpers.update_settings( OPENSTACK_HYPERVISOR_FEATURES={'can_set_mount_point': True}, OPENSTACK_API_VERSIONS={'image': 1} ) @@ -3980,7 +3980,7 @@ class InstanceLaunchInstanceTests(InstanceTestBase, 'attrs': {'id': 'id_device_name'}} ) - @django.test.utils.override_settings( + @helpers.update_settings( OPENSTACK_HYPERVISOR_FEATURES={'can_set_mount_point': False}) def test_launch_form_instance_device_name_hidden(self): self._test_launch_form_instance_show_device_name( diff --git a/openstack_dashboard/defaults.py b/openstack_dashboard/defaults.py new file mode 100644 index 0000000000..a8398014be --- /dev/null +++ b/openstack_dashboard/defaults.py @@ -0,0 +1,202 @@ +# 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. + +"""Default settings for openstack_dashboard""" + +# This must be configured +# OPENSTACK_KEYSTONE_URL = 'http://localhost/identity/v3' + +# The number of objects (Swift containers/objects or images) to display +# on a single page before providing a paging element (a "more" link) +# to paginate results. +API_RESULT_LIMIT = 1000 +API_RESULT_PAGE_SIZE = 20 + +ENABLE_CLIENT_TOKEN = True +# Set this to True to display an 'Admin Password' field on the Change Password +# form to verify that it is indeed the admin logged-in who wants to change +# the password. +ENFORCE_PASSWORD_CHECK = False +# Set to 'legacy' or 'direct' to allow users to upload images to glance via +# Horizon server. When enabled, a file form field will appear on the create +# image form. If set to 'off', there will be no file form field on the create +# image form. See documentation for deployment considerations. +HORIZON_IMAGES_UPLOAD_MODE = 'legacy' +# Allow a location to be set when creating or updating Glance images. +# If using Glance V2, this value should be False unless the Glance +# configuration and policies allow setting locations. +IMAGES_ALLOW_LOCATION = False + +# The size of chunk in bytes for downloading objects from Swift +SWIFT_FILE_TRANSFER_CHUNK_SIZE = 512 * 1024 + +# Overrides for OpenStack API versions. Use this setting to force the +# OpenStack dashboard to use a specific API version for a given service API. +# Versions specified here should be integers or floats, not strings. +# NOTE: The version should be formatted as it appears in the URL for the +# service API. For example, The identity service APIs have inconsistent +# use of the decimal point, so valid options would be 2.0 or 3. +# Minimum compute version to get the instance locked status is 2.9. +OPENSTACK_API_VERSIONS = { + "identity": 3, + "image": 2, + "volume": 3, + "compute": 2, +} + +# OPENSTACK_ENDPOINT_TYPE specifies the endpoint type to use for the endpoints +# in the Keystone service catalog. Use this setting when Horizon is running +# external to the OpenStack environment. The default is 'publicURL'. +OPENSTACK_ENDPOINT_TYPE = 'publicURL' +# SECONDARY_ENDPOINT_TYPE specifies the fallback endpoint type to use in the +# case that OPENSTACK_ENDPOINT_TYPE is not present in the endpoints +# in the Keystone service catalog. Use this setting when Horizon is running +# external to the OpenStack environment. The default is None. This +# value should differ from OPENSTACK_ENDPOINT_TYPE if used. +SECONDARY_ENDPOINT_TYPE = None + +# Set True to disable SSL certificate checks +# (useful for self-signed certificates): +OPENSTACK_SSL_NO_VERIFY = False +# The CA certificate to use to verify SSL connections +# Example: OPENSTACK_SSL_CACERT = '/path/to/cacert.pem' +OPENSTACK_SSL_CACERT = None +# The OPENSTACK_CINDER_FEATURES settings can be used to enable optional +# services provided by cinder that is not exposed by its extension API. +OPENSTACK_CINDER_FEATURES = { + 'enable_backup': False, +} +# Overrides the default domain used when running on single-domain model +# with Keystone V3. All entities will be created in the default domain. +# NOTE: This value must be the name of the default domain, NOT the ID. +# Also, you will most likely have a value in the keystone policy file like this +# "cloud_admin": "rule:admin_required and domain_id:" +# This value must be the name of the domain whose ID is specified there. +OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = 'Default' +OPENSTACK_KEYSTONE_DEFAULT_ROLE = '_member_' +# The OPENSTACK_KEYSTONE_BACKEND settings can be used to identify the +# capabilities of the auth backend for Keystone. +# If Keystone has been configured to use LDAP as the auth backend then set +# can_edit_user to False and name to 'ldap'. +# +# TODO(tres): Remove these once Keystone has an API to identify auth backend. +OPENSTACK_KEYSTONE_BACKEND = { + 'name': 'native', + 'can_edit_domain': True, + 'can_edit_group': True, + 'can_edit_project': True, + 'can_edit_role': True, + 'can_edit_user': True, +} +# Set this to True if running on a multi-domain model. When this is enabled, it +# will require the user to enter the Domain name in addition to the username +# for login. +OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = False +# Set this to True to enable panels that provide the ability for users to +# manage Identity Providers (IdPs) and establish a set of rules to map +# federation protocol attributes to Identity API attributes. +# This extension requires v3.0+ of the Identity API. +OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT = False +# The OPENSTACK_NEUTRON_NETWORK settings can be used to enable optional +# services provided by neutron. Options currently available are load +# balancer service, security groups, quotas, VPN service. +OPENSTACK_NEUTRON_NETWORK = { + 'enable_auto_allocated_network': False, + 'enable_distributed_router': False, + 'enable_fip_topology_check': True, + 'enable_ha_router': False, + 'enable_ipv6': True, + # TODO(amotoki): Change the default value to True? See local_settings.py + 'enable_quotas': False, + 'enable_router': True, + + # Default dns servers you would like to use when a subnet is + # created. This is only a default, users can still choose a different + # list of dns servers when creating a new subnet. + # The entries below are examples only, and are not appropriate for + # real deployments + # 'default_dns_nameservers': ["8.8.8.8", "8.8.4.4", "208.67.222.222"], + + # Set which provider network types are supported. Only the network types + # in this list will be available to choose from when creating a network. + # Network types include local, flat, vlan, gre, vxlan and geneve. + # 'supported_provider_types': ['*'], + + # You can configure available segmentation ID range per network type + # in your deployment. + # 'segmentation_id_range': { + # 'vlan': [1024, 2048], + # 'vxlan': [4094, 65536], + # }, + + # You can define additional provider network types here. + # 'extra_provider_types': { + # 'awesome_type': { + # 'display_name': 'Awesome New Type', + # 'require_physical_network': False, + # 'require_segmentation_id': True, + # } + # }, + + # Set which VNIC types are supported for port binding. Only the VNIC + # types in this list will be available to choose from when creating a + # port. + # VNIC types include 'normal', 'direct', 'direct-physical', 'macvtap', + # 'baremetal' and 'virtio-forwarder' + # Set to empty list or None to disable VNIC type selection. + 'supported_vnic_types': ['*'], + + # Set list of available physical networks to be selected in the physical + # network field on the admin create network modal. If it's set to an empty + # list, the field will be a regular input field. + # e.g. ['default', 'test'] + 'physical_networks': [], +} +OPENSTACK_NOVA_EXTENSIONS_BLACKLIST = [] +# The Xen Hypervisor has the ability to set the mount point for volumes +# attached to instances (other Hypervisors currently do not). Setting +# can_set_mount_point to True will add the option to set the mount point +# from the UI. +OPENSTACK_HYPERVISOR_FEATURES = { + 'can_set_mount_point': False, + 'can_set_password': False, + 'enable_quotas': True, + 'requires_keypair': False, +} + +# 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 +# form of ['SETTING_1','SETTING_2'], etc. +# +# You may remove settings from this list for security purposes, but do so at +# the risk of breaking a built-in horizon feature. These settings are required +# for horizon to function properly. Only remove them if you know what you +# are doing. These settings may in the future be moved to be defined within +# the enabled panel configuration. +# You should not add settings to this list for out of tree extensions. +# See: https://wiki.openstack.org/wiki/Horizon/RESTAPI +REST_API_REQUIRED_SETTINGS = [ + 'CREATE_IMAGE_DEFAULTS', + 'ENFORCE_PASSWORD_CHECK' + 'LAUNCH_INSTANCE_DEFAULTS', + 'OPENSTACK_HYPERVISOR_FEATURES', + 'OPENSTACK_IMAGE_FORMATS', + 'OPENSTACK_KEYSTONE_BACKEND', + 'OPENSTACK_KEYSTONE_DEFAULT_DOMAIN', +] +# Additional settings can be made available to the client side for +# extensibility by specifying them in REST_API_ADDITIONAL_SETTINGS +# !! Please use extreme caution as the settings are transferred via HTTP/S +# and are not encrypted on the browser. This is an experimental API and +# may be deprecated in the future without notice. +REST_API_ADDITIONAL_SETTINGS = [] diff --git a/openstack_dashboard/local/local_settings.py.example b/openstack_dashboard/local/local_settings.py.example index 58cd7b2f27..deb1d419ac 100644 --- a/openstack_dashboard/local/local_settings.py.example +++ b/openstack_dashboard/local/local_settings.py.example @@ -56,25 +56,6 @@ WEBROOT = '/' # horizon, the message files collected are processed and displayed to the user. #MESSAGES_PATH=None -# Overrides for OpenStack API versions. Use this setting to force the -# OpenStack dashboard to use a specific API version for a given service API. -# Versions specified here should be integers or floats, not strings. -# NOTE: The version should be formatted as it appears in the URL for the -# service API. For example, The identity service APIs have inconsistent -# use of the decimal point, so valid options would be 2.0 or 3. -# Minimum compute version to get the instance locked status is 2.9. -#OPENSTACK_API_VERSIONS = { -# "identity": 3, -# "image": 2, -# "volume": 3, -# "compute": 2, -#} - -# Set this to True if running on a multi-domain model. When this is enabled, it -# will require the user to enter the Domain name in addition to the username -# for login. -#OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = False - # Set this to True if you want available domains displayed as a dropdown menu # on the login screen. It is strongly advised NOT to enable this for public # clouds, as advertising enabled domains to unauthenticated customers @@ -89,20 +70,6 @@ WEBROOT = '/' # ('Default', 'Default'), #) -# Overrides the default domain used when running on single-domain model -# with Keystone V3. All entities will be created in the default domain. -# NOTE: This value must be the name of the default domain, NOT the ID. -# Also, you will most likely have a value in the keystone policy file like this -# "cloud_admin": "rule:admin_required and domain_id:" -# This value must be the name of the domain whose ID is specified there. -#OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = 'Default' - -# Set this to True to enable panels that provide the ability for users to -# manage Identity Providers (IdPs) and establish a set of rules to map -# federation protocol attributes to Identity API attributes. -# This extension requires v3.0+ of the Identity API. -#OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT = False - # Set Console type: # valid options are "AUTO"(default), "VNC", "SPICE", "RDP", "SERIAL", "MKS" # or None. Set to None explicitly if you want to deactivate the console. @@ -195,7 +162,6 @@ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' OPENSTACK_HOST = "127.0.0.1" OPENSTACK_KEYSTONE_URL = "http://%s:5000/v3" % OPENSTACK_HOST -OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_" # For setting the default service region on a per-endpoint basis. Note that the # default value for this setting is {}, and below is just an example of how it @@ -272,27 +238,6 @@ OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_" # should not match any service provider IDs. #KEYSTONE_PROVIDER_IDP_ID = "localkeystone" -# Disable SSL certificate checks (useful for self-signed certificates): -#OPENSTACK_SSL_NO_VERIFY = True - -# The CA certificate to use to verify SSL connections -#OPENSTACK_SSL_CACERT = '/path/to/cacert.pem' - -# The OPENSTACK_KEYSTONE_BACKEND settings can be used to identify the -# capabilities of the auth backend for Keystone. -# If Keystone has been configured to use LDAP as the auth backend then set -# can_edit_user to False and name to 'ldap'. -# -# TODO(tres): Remove these once Keystone has an API to identify auth backend. -OPENSTACK_KEYSTONE_BACKEND = { - 'name': 'native', - 'can_edit_user': True, - 'can_edit_group': True, - 'can_edit_project': True, - 'can_edit_domain': True, - 'can_edit_role': True, -} - # Setting this to True, will add a new "Retrieve Password" action on instance, # allowing Admin session password retrieval/decryption. #OPENSTACK_ENABLE_PASSWORD_RETRIEVE = False @@ -323,79 +268,24 @@ OPENSTACK_KEYSTONE_BACKEND = { # 'create_volume': True, #} -# The Xen Hypervisor has the ability to set the mount point for volumes -# attached to instances (other Hypervisors currently do not). Setting -# can_set_mount_point to True will add the option to set the mount point -# from the UI. -OPENSTACK_HYPERVISOR_FEATURES = { - 'can_set_mount_point': False, - 'can_set_password': False, - 'requires_keypair': False, - 'enable_quotas': True -} - # This settings controls whether IP addresses of servers are retrieved from # neutron in the project instance table. Setting this to ``False`` may mitigate # a performance issue in the project instance table in large deployments. #OPENSTACK_INSTANCE_RETRIEVE_IP_ADDRESSES = True -# The OPENSTACK_CINDER_FEATURES settings can be used to enable optional -# services provided by cinder that is not exposed by its extension API. -OPENSTACK_CINDER_FEATURES = { - 'enable_backup': False, -} - # The OPENSTACK_NEUTRON_NETWORK settings can be used to enable optional # services provided by neutron. Options currently available are load # balancer service, security groups, quotas, VPN service. OPENSTACK_NEUTRON_NETWORK = { 'enable_router': True, + # TODO(amotoki): Drop OPENSTACK_NEUTRON_NETWORK completely from here. + # enable_quotas has the different default value here. 'enable_quotas': True, 'enable_ipv6': True, 'enable_distributed_router': False, 'enable_ha_router': False, 'enable_fip_topology_check': True, - - # Default dns servers you would like to use when a subnet is - # created. This is only a default, users can still choose a different - # list of dns servers when creating a new subnet. - # The entries below are examples only, and are not appropriate for - # real deployments - # 'default_dns_nameservers': ["8.8.8.8", "8.8.4.4", "208.67.222.222"], - - # Set which provider network types are supported. Only the network types - # in this list will be available to choose from when creating a network. - # Network types include local, flat, vlan, gre, vxlan and geneve. - # 'supported_provider_types': ['*'], - - # You can configure available segmentation ID range per network type - # in your deployment. - # 'segmentation_id_range': { - # 'vlan': [1024, 2048], - # 'vxlan': [4094, 65536], - # }, - - # You can define additional provider network types here. - # 'extra_provider_types': { - # 'awesome_type': { - # 'display_name': 'Awesome New Type', - # 'require_physical_network': False, - # 'require_segmentation_id': True, - # } - # }, - - # Set which VNIC types are supported for port binding. Only the VNIC - # types in this list will be available to choose from when creating a - # port. - # VNIC types include 'normal', 'direct', 'direct-physical', 'macvtap', - # 'baremetal' and 'virtio-forwarder' - # Set to empty list or None to disable VNIC type selection. 'supported_vnic_types': ['*'], - - # Set list of available physical networks to be selected in the physical - # network field on the admin create network modal. If it's set to an empty - # list, the field will be a regular input field. - # e.g. ['default', 'test'] 'physical_networks': [], } @@ -443,43 +333,11 @@ IMAGE_CUSTOM_PROPERTY_TITLES = { # table. IMAGE_RESERVED_CUSTOM_PROPERTIES = [] -# Set to 'legacy' or 'direct' to allow users to upload images to glance via -# Horizon server. When enabled, a file form field will appear on the create -# image form. If set to 'off', there will be no file form field on the create -# image form. See documentation for deployment considerations. -#HORIZON_IMAGES_UPLOAD_MODE = 'legacy' - -# Allow a location to be set when creating or updating Glance images. -# If using Glance V2, this value should be False unless the Glance -# configuration and policies allow setting locations. -#IMAGES_ALLOW_LOCATION = False - # A dictionary of default settings for create image modal. #CREATE_IMAGE_DEFAULTS = { # 'image_visibility': "public", #} -# OPENSTACK_ENDPOINT_TYPE specifies the endpoint type to use for the endpoints -# in the Keystone service catalog. Use this setting when Horizon is running -# external to the OpenStack environment. The default is 'publicURL'. -#OPENSTACK_ENDPOINT_TYPE = "publicURL" - -# SECONDARY_ENDPOINT_TYPE specifies the fallback endpoint type to use in the -# case that OPENSTACK_ENDPOINT_TYPE is not present in the endpoints -# in the Keystone service catalog. Use this setting when Horizon is running -# external to the OpenStack environment. The default is None. This -# value should differ from OPENSTACK_ENDPOINT_TYPE if used. -#SECONDARY_ENDPOINT_TYPE = None - -# The number of objects (Swift containers/objects or images) to display -# on a single page before providing a paging element (a "more" link) -# to paginate results. -API_RESULT_LIMIT = 1000 -API_RESULT_PAGE_SIZE = 20 - -# The size of chunk in bytes for downloading objects from Swift -SWIFT_FILE_TRANSFER_CHUNK_SIZE = 512 * 1024 - # The default number of lines displayed for instance console log. INSTANCE_LOG_LENGTH = 35 @@ -503,11 +361,6 @@ TIME_ZONE = "UTC" # 'reverse': False, #} -# Set this to True to display an 'Admin Password' field on the Change Password -# form to verify that it is indeed the admin logged-in who wants to change -# the password. -#ENFORCE_PASSWORD_CHECK = False - # Modules that provide /auth routes that can be used to handle different types # of user authentication. Add auth plugins that require extra route handling to # this list. @@ -805,33 +658,6 @@ SECURITY_GROUP_RULES = { # See Metadata Definitions on: # https://docs.openstack.org/glance/latest/user/glancemetadefcatalogapi.html -# 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 -# form of ['SETTING_1','SETTING_2'], etc. -# -# You may remove settings from this list for security purposes, but do so at -# the risk of breaking a built-in horizon feature. These settings are required -# for horizon to function properly. Only remove them if you know what you -# are doing. These settings may in the future be moved to be defined within -# the enabled panel configuration. -# You should not add settings to this list for out of tree extensions. -# See: https://wiki.openstack.org/wiki/Horizon/RESTAPI -REST_API_REQUIRED_SETTINGS = ['OPENSTACK_HYPERVISOR_FEATURES', - 'LAUNCH_INSTANCE_DEFAULTS', - 'OPENSTACK_IMAGE_FORMATS', - 'OPENSTACK_KEYSTONE_BACKEND', - 'OPENSTACK_KEYSTONE_DEFAULT_DOMAIN', - 'CREATE_IMAGE_DEFAULTS', - 'ENFORCE_PASSWORD_CHECK'] - -# Additional settings can be made available to the client side for -# extensibility by specifying them in REST_API_ADDITIONAL_SETTINGS -# !! Please use extreme caution as the settings are transferred via HTTP/S -# and are not encrypted on the browser. This is an experimental API and -# may be deprecated in the future without notice. -#REST_API_ADDITIONAL_SETTINGS = [] - # DISALLOW_IFRAME_EMBED can be used to prevent Horizon from being embedded # within an iframe. Legacy browsers are still vulnerable to a Cross-Frame # Scripting (XFS) vulnerability, so this option allows extra security hardening diff --git a/openstack_dashboard/settings.py b/openstack_dashboard/settings.py index 6527bfd6e3..58cf320723 100644 --- a/openstack_dashboard/settings.py +++ b/openstack_dashboard/settings.py @@ -272,8 +272,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_KEYSTONE_DEFAULT_ROLE = '_member_' - DEFAULT_EXCEPTION_REPORTER_FILTER = 'horizon.exceptions.HorizonReporterFilter' POLICY_FILES_PATH = os.path.join(ROOT_PATH, "conf") @@ -372,6 +370,10 @@ OPENSTACK_PROFILER = { 'enabled': False } +# 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") diff --git a/openstack_dashboard/test/settings.py b/openstack_dashboard/test/settings.py index 34d87300fa..99845dbb78 100644 --- a/openstack_dashboard/test/settings.py +++ b/openstack_dashboard/test/settings.py @@ -28,6 +28,9 @@ from openstack_dashboard.utils import settings as settings_utils # enabling in our test setup to find any issues it might cause monkeypatch_escape() +# Load default values +from openstack_dashboard.defaults import * # noqa: F403,H303 + TEST_DIR = os.path.dirname(os.path.abspath(__file__)) ROOT_PATH = os.path.abspath(os.path.join(TEST_DIR, "..")) @@ -124,11 +127,6 @@ OPENSTACK_PROFILER = {'enabled': False} settings_utils.find_static_files(HORIZON_CONFIG, AVAILABLE_THEMES, THEME_COLLECTION_DIR, ROOT_PATH) -# Set to 'legacy' or 'direct' to allow users to upload images to glance via -# Horizon server. When enabled, a file form field will appear on the create -# image form. If set to 'off', there will be no file form field on the create -# image form. See documentation for deployment considerations. -HORIZON_IMAGES_UPLOAD_MODE = 'legacy' IMAGES_ALLOW_LOCATION = True AVAILABLE_REGIONS = [ @@ -136,41 +134,20 @@ AVAILABLE_REGIONS = [ ('http://remote:5000/v3', 'remote'), ] -OPENSTACK_API_VERSIONS = { - "identity": 3, - "image": 2 -} - OPENSTACK_KEYSTONE_URL = "http://localhost:5000/v3" -OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_" OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = 'test_domain' OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT = True -OPENSTACK_KEYSTONE_BACKEND = { - 'name': 'native', - 'can_edit_user': True, - 'can_edit_group': True, - 'can_edit_project': True, - 'can_edit_domain': True, - 'can_edit_role': True -} +OPENSTACK_CINDER_FEATURES['enable_backup'] = True -OPENSTACK_CINDER_FEATURES = { - 'enable_backup': True, -} +OPENSTACK_NEUTRON_NETWORK['enable_router'] = True +# network quota is Enabled in specific tests only +OPENSTACK_NEUTRON_NETWORK['enable_quotas'] = False +OPENSTACK_NEUTRON_NETWORK['enable_distributed_router'] = False -OPENSTACK_NEUTRON_NETWORK = { - 'enable_router': True, - 'enable_quotas': False, # Enabled in specific tests only - 'enable_distributed_router': False, -} - -OPENSTACK_HYPERVISOR_FEATURES = { - 'can_set_mount_point': False, - 'can_set_password': True, -} +OPENSTACK_HYPERVISOR_FEATURES['can_set_password'] = True OPENSTACK_IMAGE_BACKEND = { 'image_formats': [