diff --git a/doc/source/configuration/settings.rst b/doc/source/configuration/settings.rst
index 674cc0de90..5128582569 100644
--- a/doc/source/configuration/settings.rst
+++ b/doc/source/configuration/settings.rst
@@ -2224,7 +2224,7 @@ hide_create_volume
Default: ``False``
-This setting allow your to hide the "Create New Volume" option and rely on the
+This setting allows you to hide the "Create New Volume" option and rely on the
default value you select with ``create_volume`` to be the most suitable for your
users.
@@ -2314,6 +2314,17 @@ specified in this setting is not found in the availability zone list,
the setting will be ignored and the behavior will be same as when ``Any``
is specified.
+OPENSTACK_SERVER_DEFAULT_USER_DATA
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. versionadded:: 22.3.0(Zed)
+
+Default: ``""``
+
+An administrator can specify a default user data (e.g. comments or instructions
+for cloudinit) via this settings. It can be a string or template string that
+accepts a request object.
+
OPENSTACK_ENABLE_PASSWORD_RETRIEVE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/horizon/static/framework/widgets/load-edit/load-edit.directive.js b/horizon/static/framework/widgets/load-edit/load-edit.directive.js
index 7b5e94babc..4f33ebfff6 100644
--- a/horizon/static/framework/widgets/load-edit/load-edit.directive.js
+++ b/horizon/static/framework/widgets/load-edit/load-edit.directive.js
@@ -26,6 +26,7 @@
*
* @param {object} title
* @param {object} model
+ * @param {object} modelDefaultValue
* @param {object} maxBytes
* @param {object} key
* @param {object} required
@@ -49,6 +50,7 @@
scope: {
title: '@',
model: '=',
+ modelDefaultValue: '=',
maxBytes: '@',
key: '@',
required: '=',
@@ -141,6 +143,12 @@
textarea.focus();
}
+ $scope.$watch('modelDefaultValue', function(newValue, oldValue) {
+ if (newValue !== undefined && oldValue !== newValue) {
+ updateTextArea(newValue);
+ }
+ });
+
/* The length property for string shows only number of character.
* If text includes multibyte string, it doesn't mean number of bytes.
* So to count bytes, convert to Blob object and get its size.
diff --git a/horizon/static/framework/widgets/load-edit/load-edit.directive.spec.js b/horizon/static/framework/widgets/load-edit/load-edit.directive.spec.js
index b08514040e..c5031b96c8 100644
--- a/horizon/static/framework/widgets/load-edit/load-edit.directive.spec.js
+++ b/horizon/static/framework/widgets/load-edit/load-edit.directive.spec.js
@@ -39,8 +39,9 @@
$compile = $injector.get('$compile');
key = 'elementKey';
element = $compile(
- ''
+ '' +
+ ''
)($scope);
$scope.$apply();
}));
@@ -75,6 +76,15 @@
expect(element.isolateScope().model).toBe('user input');
});
+
+ it('should update text area with default user data', function () {
+ element.isolateScope().modelDefaultValue = 'default user data';
+ $scope.$apply();
+ textarea.trigger('input');
+ $scope.$apply();
+
+ expect(element.isolateScope().model).toBe('default user data');
+ });
});
describe('onFileLoadListener', function() {
diff --git a/openstack_dashboard/api/rest/config.py b/openstack_dashboard/api/rest/config.py
index eeea25e892..175d83f143 100644
--- a/openstack_dashboard/api/rest/config.py
+++ b/openstack_dashboard/api/rest/config.py
@@ -17,6 +17,7 @@ from datetime import datetime
from django.conf import settings
from django.http import JsonResponse
+import django.template as django_template
from django.views import generic
import pytz
@@ -59,6 +60,7 @@ class Settings(generic.View):
in settings_allowed if k not in self.SPECIALS}
plain_settings.update(self.SPECIALS)
plain_settings.update(self.disk_formats(request))
+ plain_settings.update(self.default_user_data(request))
return plain_settings
def disk_formats(self, request):
@@ -70,6 +72,18 @@ class Settings(generic.View):
for (value, name) in api.glance.get_image_formats(request)
]}
+ def default_user_data(self, request):
+ template_code = settings.OPENSTACK_SERVER_DEFAULT_USER_DATA
+ if template_code:
+ engine = django_template.engine.Engine.get_default()
+ template = engine.from_string(template_code)
+ default_user_data = template.render(
+ django_template.Context(dict(request=request))
+ )
+ else:
+ default_user_data = ""
+ return {"OPENSTACK_SERVER_DEFAULT_USER_DATA": default_user_data}
+
@urls.register
class Timezones(generic.View):
diff --git a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.html b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.html
index a9fb915825..1ef19adec8 100644
--- a/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.html
+++ b/openstack_dashboard/dashboards/project/static/dashboard/project/workflow/launch-instance/configuration/configuration.html
@@ -6,6 +6,7 @@
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 810858829c..26086bc14e 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
@@ -182,6 +182,7 @@
description: null,
// REQUIRED Server Key. Null allowed.
user_data: '',
+ default_user_data: '',
disk_config: 'AUTO',
// REQUIRED
flavor: null,
@@ -249,6 +250,10 @@
function (response) {
model.defaultBootSource = response;
});
+ settings.getSetting("OPENSTACK_SERVER_DEFAULT_USER_DATA").then(
+ function (response) {
+ model.newInstanceSpec.default_user_data = response.OPENSTACK_SERVER_DEFAULT_USER_DATA;
+ });
promise = $q.all([
launchInstanceDefaults.then(setDefaultValues, noop),
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 4b6acfdb1d..fa15af9100 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
@@ -186,7 +186,8 @@
disable_volume_snapshot: false,
default_availability_zone: 'Any'
},
- DEFAULT_BOOT_SOURCE: 'image'
+ DEFAULT_BOOT_SOURCE: 'image',
+ OPENSTACK_SERVER_DEFAULT_USER_DATA: ''
};
IMAGE = {type: 'image', label: 'Image', selected: true};
VOLUME = {type: 'volume', label: 'Volume', selected: false};
@@ -883,7 +884,7 @@
// This is here to ensure that as people add/change items, they
// don't forget to implement tests for them.
it('has the right number of properties', function() {
- expect(Object.keys(model.newInstanceSpec).length).toBe(22);
+ expect(Object.keys(model.newInstanceSpec).length).toBe(23);
});
it('sets availability zone to null', function() {
@@ -910,6 +911,10 @@
expect(model.newInstanceSpec.user_data).toBe('');
});
+ it('sets default user data to an empty string', function() {
+ expect(model.newInstanceSpec.default_user_data).toBe('');
+ });
+
it('sets disk config to AUTO', function() {
expect(model.newInstanceSpec.disk_config).toBe('AUTO');
});
diff --git a/openstack_dashboard/defaults.py b/openstack_dashboard/defaults.py
index 0023d2aaf4..8d8e4ae8a1 100644
--- a/openstack_dashboard/defaults.py
+++ b/openstack_dashboard/defaults.py
@@ -256,6 +256,9 @@ LAUNCH_INSTANCE_DEFAULTS = {
'default_availability_zone': 'Any',
}
+# A Django template astring that will be used as default user_data for new VMs
+OPENSTACK_SERVER_DEFAULT_USER_DATA = ""
+
# The absolute path to the directory where message files are collected.
# The message file must have a .json file extension. When the user logins to
# horizon, the message files collected are processed and displayed to the user.
diff --git a/releasenotes/notes/add_default_user_data-76d9c17e474fc34e.yaml b/releasenotes/notes/add_default_user_data-76d9c17e474fc34e.yaml
new file mode 100644
index 0000000000..0a533cfd38
--- /dev/null
+++ b/releasenotes/notes/add_default_user_data-76d9c17e474fc34e.yaml
@@ -0,0 +1,7 @@
+---
+features:
+ - |
+ The new setting ``OPENSTACK_SERVER_DEFAULT_USER_DATA`` allows an
+ administrator to specify a default user data (e.g. comments or
+ instructions for cloudinit) for new VMs. It can be a raw string or string
+ template that accepts the request.