From 73bb9a59435c287c6ab364d92a6defacbbcfa680 Mon Sep 17 00:00:00 2001 From: Justin Pomeroy Date: Fri, 22 Jan 2016 12:28:10 -0600 Subject: [PATCH] Allow setting default value for config_drive This adds a setting that can be used to specify the default value for the Configuration Drive option when launching an instance. Closes-Bug: #1537106 Change-Id: If402d3331158b462bece27fa6fce2bdb7f6a4a2e --- doc/source/topics/settings.rst | 17 +++++++- doc/source/tutorials/plugin.rst | 2 +- .../dashboards/project/instances/tests.py | 10 +++++ .../dashboards/project/instances/views.py | 3 ++ .../configuration/configuration.controller.js | 15 +------ .../configuration.controller.spec.js | 24 ++--------- .../launch-instance-model.service.js | 12 +++++- .../launch-instance-model.service.spec.js | 43 ++++++++++++++++++- .../local/local_settings.py.example | 9 +++- ...ch-instance-defaults-c6ab65b7ab822162.yaml | 5 +++ 10 files changed, 101 insertions(+), 39 deletions(-) create mode 100644 releasenotes/notes/launch-instance-defaults-c6ab65b7ab822162.yaml diff --git a/doc/source/topics/settings.rst b/doc/source/topics/settings.rst index f449854df0..ceea027d31 100644 --- a/doc/source/topics/settings.rst +++ b/doc/source/topics/settings.rst @@ -508,6 +508,22 @@ This setting can be used in the case where a separate panel is used for managing a custom property or if a certain custom property should never be edited. +``LAUNCH_INSTANCE_DEFAULTS`` +---------------------------- + +.. versionadded:: 9.0.0(Mitaka) + +Default:: + + { + "config_drive": False + } + +A dictionary of settings which can be used to provide the default values for +properties found in the Launch Instance modal. + +The ``config_drive`` setting specifies the default value for the Configuration +Drive property. ``MESSAGES_PATH`` ----------------- @@ -529,7 +545,6 @@ data and must have a .json file extension. For example:: Possible values for level are: success, info, warning and error. - ``OPENSTACK_API_VERSIONS`` -------------------------- diff --git a/doc/source/tutorials/plugin.rst b/doc/source/tutorials/plugin.rst index 000f42e722..2698270145 100644 --- a/doc/source/tutorials/plugin.rst +++ b/doc/source/tutorials/plugin.rst @@ -256,7 +256,7 @@ setup.py pbr=True) setup.cfg --------- +--------- :: [metadata] diff --git a/openstack_dashboard/dashboards/project/instances/tests.py b/openstack_dashboard/dashboards/project/instances/tests.py index 48aa7541a4..fc4bb53cc8 100644 --- a/openstack_dashboard/dashboards/project/instances/tests.py +++ b/openstack_dashboard/dashboards/project/instances/tests.py @@ -1477,6 +1477,7 @@ class InstanceTests(helpers.TestCase): only_one_network=False, disk_config=True, config_drive=True, + config_drive_default=False, test_with_profile=False): image = self.images.first() @@ -1619,6 +1620,10 @@ class InstanceTests(helpers.TestCase): else: self.assertNotContains(res, config_drive_field_label) + step = workflow.get_step("setadvancedaction") + self.assertEqual(step.action.initial['config_drive'], + config_drive_default) + @django.test.utils.override_settings( OPENSTACK_HYPERVISOR_FEATURES={'can_set_password': False}) def test_launch_instance_get_without_password(self): @@ -1634,6 +1639,11 @@ class InstanceTests(helpers.TestCase): self._test_launch_form_instance_requirement_error(image, flavor, keypair_require=True) + @django.test.utils.override_settings( + LAUNCH_INSTANCE_DEFAULTS={'config_drive': True}) + def test_launch_instance_get_with_config_drive_default(self): + self.test_launch_instance_get(config_drive_default=True) + def test_launch_instance_get_no_block_device_mapping_v2_supported(self): self.test_launch_instance_get(block_device_mapping_v2=False) diff --git a/openstack_dashboard/dashboards/project/instances/views.py b/openstack_dashboard/dashboards/project/instances/views.py index 7d3a857160..09e4821e56 100644 --- a/openstack_dashboard/dashboards/project/instances/views.py +++ b/openstack_dashboard/dashboards/project/instances/views.py @@ -22,6 +22,7 @@ Views for managing instances. from collections import OrderedDict import logging +from django.conf import settings from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse_lazy from django import http @@ -147,6 +148,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 = getattr(settings, 'LAUNCH_INSTANCE_DEFAULTS', {}) + initial['config_drive'] = defaults.get('config_drive', False) return initial diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.js index 3aee45ca44..5b5b997cab 100644 --- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.js +++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.js @@ -15,18 +15,11 @@ 'use strict'; var MAX_SCRIPT_SIZE = 16 * 1024; - var DEFAULT_CONFIG_DRIVE = false; - var DEFAULT_USER_DATA = ''; - var DEFAULT_DISK_CONFIG = 'AUTO'; angular .module('horizon.dashboard.project.workflow.launch-instance') .controller('LaunchInstanceConfigurationController', LaunchInstanceConfigurationController); - LaunchInstanceConfigurationController.$inject = [ - '$scope' - ]; - /** * @ngdoc controller * @name LaunchInstanceConfigurationController @@ -39,15 +32,9 @@ * @property {string} disk_config, default to `AUTO`. * @property {boolean} config_drive, default to false. */ - function LaunchInstanceConfigurationController($scope) { + function LaunchInstanceConfigurationController() { var ctrl = this; - var newInstanceSpec = $scope.model.newInstanceSpec; - - newInstanceSpec.user_data = DEFAULT_USER_DATA; - newInstanceSpec.disk_config = DEFAULT_DISK_CONFIG; - newInstanceSpec.config_drive = DEFAULT_CONFIG_DRIVE; - ctrl.MAX_SCRIPT_SIZE = MAX_SCRIPT_SIZE; ctrl.diskConfigOptions = [ diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.spec.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.spec.js index de3a1663ef..c1c87d991f 100644 --- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.spec.js +++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.controller.spec.js @@ -19,20 +19,12 @@ describe('Launch Instance Configuration Step', function() { describe('LaunchInstanceConfigurationController', function() { - var scope, ctrl; + var ctrl; beforeEach(module('horizon.dashboard.project.workflow.launch-instance')); beforeEach(inject(function($controller) { - scope = { - model: { - newInstanceSpec: {} - } - }; - - ctrl = $controller('LaunchInstanceConfigurationController', { - $scope: scope - }); + ctrl = $controller('LaunchInstanceConfigurationController'); })); it('has correct disk configuration options', function() { @@ -43,16 +35,8 @@ expect(vals).toContain('MANUAL'); }); - it('defaults the disk configuration to "AUTO"', function() { - expect(scope.model.newInstanceSpec.disk_config).toBe('AUTO'); - }); - - it('defaults the config_drive configuration to false', function() { - expect(scope.model.newInstanceSpec.config_drive).toBe(false); - }); - - it('defaults the user_data configuration to ""', function() { - expect(scope.model.newInstanceSpec.user_data).toBe(''); + it('sets the user data max script size', function() { + expect(ctrl.MAX_SCRIPT_SIZE).toBe(16 * 1024); }); }); diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.js index 74a920b235..94de0e227b 100644 --- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.js +++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.js @@ -26,6 +26,7 @@ 'horizon.app.core.openstack-service-api.novaExtensions', 'horizon.app.core.openstack-service-api.security-group', 'horizon.app.core.openstack-service-api.serviceCatalog', + 'horizon.app.core.openstack-service-api.settings', 'horizon.framework.widgets.toast.service' ]; @@ -51,6 +52,7 @@ novaExtensions, securityGroup, serviceCatalog, + settings, toast ) { @@ -204,7 +206,8 @@ novaAPI.getLimits().then(onGetNovaLimits, noop), securityGroup.query().then(onGetSecurityGroups, noop), serviceCatalog.ifTypeEnabled('network').then(getNetworks, noop), - serviceCatalog.ifTypeEnabled('volume').then(getVolumes, noop) + serviceCatalog.ifTypeEnabled('volume').then(getVolumes, noop), + settings.getSetting('LAUNCH_INSTANCE_DEFAULTS').then(setDefaultValues, noop) ]); promise.then(onInitSuccess, onInitFail); @@ -227,6 +230,13 @@ model.initialized = false; } + function setDefaultValues(defaults) { + if (!defaults) { return; } + if ('config_drive' in defaults) { + model.newInstanceSpec.config_drive = defaults.config_drive; + } + } + /** * @ngdoc method * @name launchInstanceModel.createInstance diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.spec.js b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.spec.js index 89d0865790..9ed92f01f9 100644 --- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.spec.js +++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/launch-instance-model.service.spec.js @@ -19,7 +19,7 @@ describe('Launch Instance Model', function() { describe('launchInstanceModel Factory', function() { - var model, scope, $q; + var model, scope, settings, $q; var cinderEnabled = false; var neutronEnabled = false; var novaExtensionsEnabled = false; @@ -53,6 +53,14 @@ } }); + beforeEach(function() { + settings = { + LAUNCH_INSTANCE_DEFAULTS: { + config_drive: false + } + }; + }); + $provide.value('horizon.app.core.openstack-service-api.nova', { createServer: function(finalSpec) { return { @@ -175,6 +183,16 @@ } }); + $provide.value('horizon.app.core.openstack-service-api.settings', { + getSetting: function(setting) { + var deferred = $q.defer(); + + deferred.resolve(settings[setting]); + + return deferred.promise; + } + }); + $provide.value('horizon.framework.widgets.toast.service', { add: function() {} }); @@ -310,6 +328,29 @@ expect(model.allowCreateVolumeFromImage).toBe(false); }); + + it('should default config_drive to false', function() { + model.initialize(true); + scope.$apply(); + + expect(model.newInstanceSpec.config_drive).toBe(false); + }); + + it('should default config_drive to false if setting not provided', function() { + delete settings.LAUNCH_INSTANCE_DEFAULTS; + model.initialize(true); + scope.$apply(); + + expect(model.newInstanceSpec.config_drive).toBe(false); + }); + + it('should default config_drive to true based on setting', function() { + settings.LAUNCH_INSTANCE_DEFAULTS.config_drive = true; + model.initialize(true); + scope.$apply(); + + expect(model.newInstanceSpec.config_drive).toBe(true); + }); }); describe('Post Initialization Model - Initializing', function() { diff --git a/openstack_dashboard/local/local_settings.py.example b/openstack_dashboard/local/local_settings.py.example index de9521c6e7..93f7a29a8c 100644 --- a/openstack_dashboard/local/local_settings.py.example +++ b/openstack_dashboard/local/local_settings.py.example @@ -228,6 +228,12 @@ OPENSTACK_KEYSTONE_BACKEND = { #LAUNCH_INSTANCE_LEGACY_ENABLED = True #LAUNCH_INSTANCE_NG_ENABLED = False +# A dictionary of settings which can be used to provide the default values for +# properties found in the Launch Instance modal. +#LAUNCH_INSTANCE_DEFAULTS = { +# 'config_drive': False +#} + # 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 @@ -687,7 +693,8 @@ SECURITY_GROUP_RULES = { # 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'] +REST_API_REQUIRED_SETTINGS = ['OPENSTACK_HYPERVISOR_FEATURES', + 'LAUNCH_INSTANCE_DEFAULTS'] # Additional settings can be made available to the client side for # extensibility by specifying them in REST_API_ADDITIONAL_SETTINGS diff --git a/releasenotes/notes/launch-instance-defaults-c6ab65b7ab822162.yaml b/releasenotes/notes/launch-instance-defaults-c6ab65b7ab822162.yaml new file mode 100644 index 0000000000..ddd87db7d7 --- /dev/null +++ b/releasenotes/notes/launch-instance-defaults-c6ab65b7ab822162.yaml @@ -0,0 +1,5 @@ +--- +features: + - Added the LAUNCH_INSTANCE_DEFAULTS setting which allows specifying default + values for the Launch Instance workflow. Initially only the Configuration + Drive property is supported. \ No newline at end of file