Browse Source

Merge "Add a replace_on_change option to the SW Config input schema"

changes/70/356870/6
Jenkins 6 years ago committed by Gerrit Code Review
parent
commit
570511850b
  1. 36
      heat/engine/resources/openstack/heat/software_deployment.py
  2. 15
      heat/engine/software_config_io.py
  3. 8
      heat/tests/engine/service/test_software_config.py
  4. 80
      heat/tests/openstack/heat/test_software_deployment.py

36
heat/engine/resources/openstack/heat/software_deployment.py

@ -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:
self.properties = json_snippet.properties(self.properties_schema,
self.context)
return self._handle_action(self.UPDATE)
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)
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:

15
heat/engine/software_config_io.py

@ -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

8
heat/tests/engine/service/test_software_config.py

@ -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},

80
heat/tests/openstack/heat/test_software_deployment.py

@ -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…
Cancel
Save