Add a replace_on_change option to the SW Config input schema
Change-Id: Idf39e48f801de21e63fcceb8dd779f266a07199f Co-Authored-By: Steve Baker <sbaker@redhat.com> Closes-Bug: #1595040
This commit is contained in:
parent
f238a6e1d5
commit
285802bdd5
|
@ -12,6 +12,7 @@
|
|||
# under the License.
|
||||
|
||||
import copy
|
||||
import six
|
||||
import uuid
|
||||
|
||||
from oslo_config import cfg
|
||||
|
@ -223,7 +224,7 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||
self.context, **derived_params)
|
||||
return derived_config[rpc_api.SOFTWARE_CONFIG_ID]
|
||||
|
||||
def _handle_action(self, action):
|
||||
def _load_config(self):
|
||||
if self.properties.get(self.CONFIG):
|
||||
config = self.rpc_client().show_software_config(
|
||||
self.context, self.properties.get(self.CONFIG))
|
||||
|
@ -239,6 +240,12 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||
for o in config.get(rpc_api.SOFTWARE_CONFIG_OUTPUTS, [])
|
||||
]
|
||||
|
||||
return config
|
||||
|
||||
def _handle_action(self, action, config=None):
|
||||
if config is None:
|
||||
config = self._load_config()
|
||||
|
||||
if config.get(rpc_api.SOFTWARE_CONFIG_GROUP) == 'component':
|
||||
valid_actions = set()
|
||||
for conf in config[rpc_api.SOFTWARE_CONFIG_CONFIG]['configs']:
|
||||
|
@ -423,11 +430,28 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
|||
return self._check_complete()
|
||||
|
||||
def handle_update(self, json_snippet, tmpl_diff, prop_diff):
|
||||
if prop_diff:
|
||||
old_config_id = self.properties.get(self.CONFIG)
|
||||
config = self._load_config()
|
||||
old_inputs = {i.name(): i
|
||||
for i in self._build_derived_inputs(self.UPDATE, config)}
|
||||
|
||||
self.properties = json_snippet.properties(self.properties_schema,
|
||||
self.context)
|
||||
|
||||
return self._handle_action(self.UPDATE)
|
||||
new_config_id = self.properties.get(self.CONFIG)
|
||||
if old_config_id != new_config_id:
|
||||
config = self._load_config()
|
||||
new_inputs = {i.name(): i
|
||||
for i in self._build_derived_inputs(self.UPDATE, config)}
|
||||
|
||||
for name, inp in six.iteritems(new_inputs):
|
||||
if inp.replace_on_change() and name in old_inputs:
|
||||
if inp.input_data() != old_inputs[name].input_data():
|
||||
LOG.debug('Replacing SW Deployment due to change in '
|
||||
'input "%s"', name)
|
||||
raise exception.UpdateReplace
|
||||
|
||||
return self._handle_action(self.UPDATE, config=config)
|
||||
|
||||
def check_update_complete(self, sd):
|
||||
if not sd:
|
||||
|
|
|
@ -27,11 +27,11 @@ from heat.engine import properties
|
|||
|
||||
(
|
||||
IO_NAME, DESCRIPTION, TYPE,
|
||||
DEFAULT, VALUE,
|
||||
DEFAULT, REPLACE_ON_CHANGE, VALUE,
|
||||
ERROR_OUTPUT,
|
||||
) = (
|
||||
'name', 'description', 'type',
|
||||
'default', 'value',
|
||||
'default', 'replace_on_change', 'value',
|
||||
'error_output',
|
||||
)
|
||||
|
||||
|
@ -62,6 +62,12 @@ input_config_schema = {
|
|||
properties.Schema.STRING,
|
||||
_('Default value for the input if none is specified.'),
|
||||
),
|
||||
REPLACE_ON_CHANGE: properties.Schema(
|
||||
properties.Schema.BOOLEAN,
|
||||
_('Replace the deployment instead of updating it when the input '
|
||||
'value changes.'),
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
|
||||
output_config_schema = {
|
||||
|
@ -127,9 +133,14 @@ class InputConfig(IOConfig):
|
|||
"""Return the default value of the input."""
|
||||
return self._props[DEFAULT]
|
||||
|
||||
def replace_on_change(self):
|
||||
return self._props[REPLACE_ON_CHANGE]
|
||||
|
||||
def as_dict(self):
|
||||
"""Return a dict representation suitable for persisting."""
|
||||
d = super(InputConfig, self).as_dict()
|
||||
if not self._props[REPLACE_ON_CHANGE]:
|
||||
del d[REPLACE_ON_CHANGE]
|
||||
if self._value is not _no_value:
|
||||
d[VALUE] = self._value
|
||||
return d
|
||||
|
|
|
@ -921,6 +921,7 @@ class SoftwareConfigIOSchemaTest(common.HeatTestCase):
|
|||
name = 'foo'
|
||||
inp = swc_io.InputConfig(name=name)
|
||||
self.assertIsNone(inp.default())
|
||||
self.assertIs(False, inp.replace_on_change())
|
||||
self.assertEqual(name, inp.name())
|
||||
self.assertEqual({'name': name, 'type': 'String'}, inp.as_dict())
|
||||
self.assertEqual((name, None), inp.input_data())
|
||||
|
@ -928,11 +929,13 @@ class SoftwareConfigIOSchemaTest(common.HeatTestCase):
|
|||
def test_input_config(self):
|
||||
name = 'bar'
|
||||
inp = swc_io.InputConfig(name=name, description='test', type='Number',
|
||||
default=0)
|
||||
default=0, replace_on_change=True)
|
||||
self.assertEqual('0', inp.default())
|
||||
self.assertIs(True, inp.replace_on_change())
|
||||
self.assertEqual(name, inp.name())
|
||||
self.assertEqual({'name': name, 'type': 'Number',
|
||||
'description': 'test', 'default': '0'},
|
||||
'description': 'test', 'default': '0',
|
||||
'replace_on_change': True},
|
||||
inp.as_dict())
|
||||
self.assertEqual((name, None), inp.input_data())
|
||||
|
||||
|
@ -941,6 +944,7 @@ class SoftwareConfigIOSchemaTest(common.HeatTestCase):
|
|||
inp = swc_io.InputConfig(name=name, type='Number',
|
||||
default=0, value=42)
|
||||
self.assertEqual('0', inp.default())
|
||||
self.assertIs(False, inp.replace_on_change())
|
||||
self.assertEqual(name, inp.name())
|
||||
self.assertEqual({'name': name, 'type': 'Number',
|
||||
'default': '0', 'value': 42},
|
||||
|
|
|
@ -233,6 +233,11 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
'name': 'bar',
|
||||
'type': 'String',
|
||||
'default': 'baz',
|
||||
}, {
|
||||
'name': 'trigger_replace',
|
||||
'type': 'String',
|
||||
'default': 'default_value',
|
||||
'replace_on_change': True,
|
||||
}],
|
||||
'outputs': [],
|
||||
}
|
||||
|
@ -332,6 +337,12 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
'name': 'bar',
|
||||
'type': 'String',
|
||||
'value': 'baz'
|
||||
}, {
|
||||
'default': 'default_value',
|
||||
'name': 'trigger_replace',
|
||||
'replace_on_change': True,
|
||||
'type': 'String',
|
||||
'value': 'default_value'
|
||||
}, {
|
||||
'name': 'bink',
|
||||
'type': 'String',
|
||||
|
@ -784,6 +795,75 @@ class SoftwareDeploymentTest(common.HeatTestCase):
|
|||
'status_reason': u'Deploy data available'},
|
||||
self.rpc_client.update_software_deployment.call_args[1])
|
||||
|
||||
def test_handle_update_no_replace_on_change(self):
|
||||
self._create_stack(self.template)
|
||||
|
||||
self.mock_software_config()
|
||||
self.mock_derived_software_config()
|
||||
mock_sd = self.mock_deployment()
|
||||
rsrc = self.stack['deployment_mysql']
|
||||
|
||||
self.rpc_client.show_software_deployment.return_value = mock_sd
|
||||
self.deployment.resource_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||
prop_diff = {
|
||||
'input_values': {'trigger_replace': 'default_value'},
|
||||
}
|
||||
props = copy.copy(rsrc.properties.data)
|
||||
props.update(prop_diff)
|
||||
snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
|
||||
|
||||
self.deployment.handle_update(snippet, None, prop_diff)
|
||||
|
||||
self.assertEqual({
|
||||
'deployment_id': 'c8a19429-7fde-47ea-a42f-40045488226c',
|
||||
'action': 'UPDATE',
|
||||
'config_id': '9966c8e7-bc9c-42de-aa7d-f2447a952cb2',
|
||||
'input_values': {'trigger_replace': 'default_value'},
|
||||
'status': 'IN_PROGRESS',
|
||||
'status_reason': u'Deploy data available'},
|
||||
self.rpc_client.update_software_deployment.call_args[1])
|
||||
|
||||
self.assertEqual([
|
||||
{
|
||||
'default': 'baa',
|
||||
'name': 'foo',
|
||||
'type': 'String',
|
||||
'value': 'baa'
|
||||
}, {
|
||||
'default': 'baz',
|
||||
'name': 'bar',
|
||||
'type': 'String',
|
||||
'value': 'baz'
|
||||
}, {
|
||||
'default': 'default_value',
|
||||
'name': 'trigger_replace',
|
||||
'replace_on_change': True,
|
||||
'type': 'String',
|
||||
'value': 'default_value'
|
||||
}],
|
||||
self.rpc_client.create_software_config.call_args[1]['inputs'][:3])
|
||||
|
||||
def test_handle_update_replace_on_change(self):
|
||||
self._create_stack(self.template)
|
||||
|
||||
self.mock_software_config()
|
||||
self.mock_derived_software_config()
|
||||
mock_sd = self.mock_deployment()
|
||||
rsrc = self.stack['deployment_mysql']
|
||||
|
||||
self.rpc_client.show_software_deployment.return_value = mock_sd
|
||||
self.deployment.resource_id = 'c8a19429-7fde-47ea-a42f-40045488226c'
|
||||
prop_diff = {
|
||||
'input_values': {'trigger_replace': 'new_value'},
|
||||
}
|
||||
props = copy.copy(rsrc.properties.data)
|
||||
props.update(prop_diff)
|
||||
snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), props)
|
||||
|
||||
self.assertRaises(exc.UpdateReplace,
|
||||
self.deployment.handle_update,
|
||||
snippet, None, prop_diff)
|
||||
|
||||
def test_handle_suspend_resume(self):
|
||||
self._create_stack(self.template_delete_suspend_resume)
|
||||
|
||||
|
|
Loading…
Reference in New Issue