Add user_data_update_policy property to OS::Nova::Server

This may be set to either 'REPLACE' (default) or 'IGNORE'.
This allows template authors to choose the desired behaviour when the
user_data property is changed.

Co-Authored-By: Steve Hardy <shardy@redhat.com>

Change-Id: I3239c7252a2c329330283b86181abd52aee9e967
Closes-Bug: #1539541
This commit is contained in:
Steve Baker 2016-02-24 16:25:16 +13:00 committed by huangtianhua
parent edeae75de4
commit d4188127a1
3 changed files with 68 additions and 3 deletions

View File

@ -56,14 +56,14 @@ class Server(stack_user.StackUser, sh.SchedulerHintsMixin,
ADMIN_USER, AVAILABILITY_ZONE, SECURITY_GROUPS, NETWORKS, ADMIN_USER, AVAILABILITY_ZONE, SECURITY_GROUPS, NETWORKS,
SCHEDULER_HINTS, METADATA, USER_DATA_FORMAT, USER_DATA, SCHEDULER_HINTS, METADATA, USER_DATA_FORMAT, USER_DATA,
RESERVATION_ID, CONFIG_DRIVE, DISK_CONFIG, PERSONALITY, RESERVATION_ID, CONFIG_DRIVE, DISK_CONFIG, PERSONALITY,
ADMIN_PASS, SOFTWARE_CONFIG_TRANSPORT ADMIN_PASS, SOFTWARE_CONFIG_TRANSPORT, USER_DATA_UPDATE_POLICY
) = ( ) = (
'name', 'image', 'block_device_mapping', 'block_device_mapping_v2', 'name', 'image', 'block_device_mapping', 'block_device_mapping_v2',
'flavor', 'flavor_update_policy', 'image_update_policy', 'key_name', 'flavor', 'flavor_update_policy', 'image_update_policy', 'key_name',
'admin_user', 'availability_zone', 'security_groups', 'networks', 'admin_user', 'availability_zone', 'security_groups', 'networks',
'scheduler_hints', 'metadata', 'user_data_format', 'user_data', 'scheduler_hints', 'metadata', 'user_data_format', 'user_data',
'reservation_id', 'config_drive', 'diskConfig', 'personality', 'reservation_id', 'config_drive', 'diskConfig', 'personality',
'admin_pass', 'software_config_transport' 'admin_pass', 'software_config_transport', 'user_data_update_policy'
) )
_BLOCK_DEVICE_MAPPING_KEYS = ( _BLOCK_DEVICE_MAPPING_KEYS = (
@ -446,10 +446,22 @@ class Server(stack_user.StackUser, sh.SchedulerHintsMixin,
constraints.AllowedValues(_SOFTWARE_CONFIG_TRANSPORTS), constraints.AllowedValues(_SOFTWARE_CONFIG_TRANSPORTS),
] ]
), ),
USER_DATA_UPDATE_POLICY: properties.Schema(
properties.Schema.STRING,
_('Policy on how to apply a user_data update; either by '
'ignorning it or by replacing the entire server.'),
default='REPLACE',
constraints=[
constraints.AllowedValues(['REPLACE', 'IGNORE']),
],
support_status=support.SupportStatus(version='6.0.0'),
update_allowed=True
),
USER_DATA: properties.Schema( USER_DATA: properties.Schema(
properties.Schema.STRING, properties.Schema.STRING,
_('User data script to be executed by cloud-init.'), _('User data script to be executed by cloud-init.'),
default='' default='',
update_allowed=True
), ),
RESERVATION_ID: properties.Schema( RESERVATION_ID: properties.Schema(
properties.Schema.STRING, properties.Schema.STRING,
@ -1093,6 +1105,12 @@ class Server(stack_user.StackUser, sh.SchedulerHintsMixin,
if image_update_policy == 'REPLACE': if image_update_policy == 'REPLACE':
return True return True
if self.USER_DATA in changed_properties_set:
ud_update_policy = (
after_props.get(self.USER_DATA_UPDATE_POLICY) or
before_props.get(self.USER_DATA_UPDATE_POLICY))
return ud_update_policy == 'REPLACE'
def handle_update(self, json_snippet, tmpl_diff, prop_diff): def handle_update(self, json_snippet, tmpl_diff, prop_diff):
if 'Metadata' in tmpl_diff: if 'Metadata' in tmpl_diff:
# If SOFTWARE_CONFIG user_data_format is enabled we require # If SOFTWARE_CONFIG user_data_format is enabled we require

View File

@ -2129,6 +2129,46 @@ class ServersTest(common.HeatTestCase):
updater = scheduler.TaskRunner(server.update, update_template) updater = scheduler.TaskRunner(server.update, update_template)
self.assertRaises(exception.UpdateReplace, updater) self.assertRaises(exception.UpdateReplace, updater)
def test_server_update_server_userdata_replace(self):
stack_name = 'update_udatrep'
(tmpl, stack) = self._setup_test_stack(stack_name)
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
nova.NovaClientPlugin._create().AndReturn(self.fc)
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
self.m.ReplayAll()
resource_defns = tmpl.resource_definitions(stack)
server = servers.Server('server_update_userdata_replace',
resource_defns['WebServer'], stack)
update_template = copy.deepcopy(server.t)
update_template['Properties']['user_data'] = 'changed'
server.action = server.CREATE
updater = scheduler.TaskRunner(server.update, update_template)
self.assertRaises(exception.UpdateReplace, updater)
def test_server_update_server_userdata_ignore(self):
stack_name = 'update_udatignore'
(tmpl, stack) = self._setup_test_stack(stack_name)
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
nova.NovaClientPlugin._create().AndReturn(self.fc)
self._mock_get_image_id_success('F17-x86_64-gold', 'image_id')
self.m.ReplayAll()
self.patchobject(servers.Server, 'prepare_for_replace')
self.patchobject(servers.Server, 'check_update_complete',
return_value=True)
resource_defns = tmpl.resource_definitions(stack)
server = servers.Server('server_update_userdata_ignore',
resource_defns['WebServer'], stack)
update_template = copy.deepcopy(server.t)
update_template['Properties']['user_data'] = 'changed'
update_template['Properties']['user_data_update_policy'] = 'IGNORE'
server.action = server.CREATE
scheduler.TaskRunner(server.update, update_template)()
self.assertEqual((server.UPDATE, server.COMPLETE), server.state)
self.m.VerifyAll()
def test_server_update_image_replace(self): def test_server_update_image_replace(self):
stack_name = 'update_imgrep' stack_name = 'update_imgrep'
(tmpl, stack) = self._setup_test_stack(stack_name) (tmpl, stack) = self._setup_test_stack(stack_name)

View File

@ -0,0 +1,7 @@
---
features:
- The OS::Nova::Server now supports a new property user_data_update_policy,
which may be set to either 'REPLACE' (default) or 'IGNORE' if you wish to
allow user_data updates to be ignored on stack update. This is useful when
managing a group of servers where changed user_data should apply to new
servers without replacing existing servers.