Don't replace failed neutron resources always

Override needs_replace_failed() for all
neutron resource.

Change-Id: I1789540fe2caae18fb446cd069b827036dd86f1c
Blueprint: custom-update-replace-for-failed-resources
This commit is contained in:
huangtianhua 2016-12-12 20:05:16 +08:00
parent 3c53b24567
commit 52de872899
3 changed files with 79 additions and 0 deletions

View File

@ -100,6 +100,18 @@ class NeutronResource(resource.Resource):
attributes = self._show_resource()
return attributes[name]
def needs_replace_failed(self):
if not self.resource_id:
return True
with self.client_plugin().ignore_not_found:
res_attrs = self._show_resource()
if 'status' in res_attrs:
return res_attrs['status'] == 'ERROR'
return False
return True
def get_reference_id(self):
return self.resource_id

View File

@ -109,3 +109,49 @@ class NeutronTest(common.HeatTestCase):
# and return None due to resource_id is None
res.attributes.reset_resolved_values()
self.assertIsNone(res.FnGetAtt('show'))
def test_needs_replace_failed(self):
class SomeNeutronResource(nr.NeutronResource):
properties_schema = {}
@classmethod
def is_service_available(cls, context):
return (True, None)
tmpl = rsrc_defn.ResourceDefinition('test_res', 'Foo')
stack = mock.MagicMock()
stack.has_cache_data = mock.Mock(return_value=False)
res = SomeNeutronResource('aresource', tmpl, stack)
res.state_set(res.CREATE, res.FAILED)
mock_show_resource = mock.MagicMock()
mock_show_resource.side_effect = [
{'attr1': 'val1', 'status': 'ACTIVE'},
{'attr1': 'val1', 'status': 'ERROR'},
{'attr1': 'val1', 'attr2': 'val2'},
qe.NotFound]
res._show_resource = mock_show_resource
nclientplugin = neutron.NeutronClientPlugin(mock.MagicMock())
res.client_plugin = mock.Mock(return_value=nclientplugin)
# needs replace because res not created yet
res.resource_id = None
self.assertTrue(res.needs_replace_failed())
self.assertEqual(0, mock_show_resource.call_count)
# no need to replace because res is ACTIVE underlying
res.resource_id = 'I am a resource'
self.assertFalse(res.needs_replace_failed())
self.assertEqual(1, mock_show_resource.call_count)
# needs replace because res is ERROR underlying
self.assertTrue(res.needs_replace_failed())
self.assertEqual(2, mock_show_resource.call_count)
# no need to replace because res exists and no status
# to check
self.assertFalse(res.needs_replace_failed())
self.assertEqual(3, mock_show_resource.call_count)
# needs replace because res can not be found
self.assertTrue(res.needs_replace_failed())
self.assertEqual(4, mock_show_resource.call_count)

View File

@ -352,6 +352,27 @@ class NeutronPortTest(common.HeatTestCase):
self.assertEqual((port.CREATE, port.COMPLETE), port.state)
self.create_mock.assert_called_once_with({'port': port_prop})
def test_update_failed_port_no_replace(self):
t = template_format.parse(neutron_port_template)
stack = utils.parse_stack(t)
port = stack['port']
port.resource_id = 'r_id'
port.state_set(port.CREATE, port.FAILED)
new_props = port.properties.data.copy()
new_props['name'] = 'new_one'
self.find_mock.return_value = 'net_or_sub'
self.port_show_mock.return_value = {'port': {
"status": "ACTIVE",
"id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766",
"fixed_ips": {
"subnet_id": "d0e971a6-a6b4-4f4c-8c88-b75e9c120b7e",
"ip_address": "10.0.3.21"}}}
update_snippet = rsrc_defn.ResourceDefinition(port.name, port.type(),
new_props)
scheduler.TaskRunner(port.update, update_snippet)()
self.assertEqual((port.UPDATE, port.COMPLETE), port.state)
self.assertEqual(1, self.update_mock.call_count)
def test_port_needs_update(self):
t = template_format.parse(neutron_port_template)
t['resources']['port']['properties'].pop('fixed_ips')