diff --git a/heat/engine/resources/openstack/neutron/net.py b/heat/engine/resources/openstack/neutron/net.py index d04190d27f..13ead4c31b 100644 --- a/heat/engine/resources/openstack/neutron/net.py +++ b/heat/engine/resources/openstack/neutron/net.py @@ -45,9 +45,8 @@ class Net(neutron.NeutronResource): ), VALUE_SPECS: properties.Schema( properties.Schema.MAP, - _('Extra parameters to include in the "network" object in the ' - 'creation request. Parameters are often specific to installed ' - 'hardware or extensions.'), + _('Extra parameters to include in the request. Parameters are ' + 'often specific to installed hardware or extensions.'), default={}, update_allowed=True ), @@ -170,21 +169,24 @@ class Net(neutron.NeutronResource): return True def handle_update(self, json_snippet, tmpl_diff, prop_diff): - props = self.prepare_update_properties(json_snippet) - qos_policy = props.pop(self.QOS_POLICY, None) - if self.QOS_POLICY in prop_diff: - props['qos_policy_id'] = self.client_plugin().get_qos_policy_id( - qos_policy) if qos_policy else None - dhcp_agent_ids = props.pop(self.DHCP_AGENT_IDS, None) - - if self.DHCP_AGENT_IDS in prop_diff: - if dhcp_agent_ids is not None: + if prop_diff: + if self.DHCP_AGENT_IDS in prop_diff: + dhcp_agent_ids = prop_diff.pop(self.DHCP_AGENT_IDS, []) self._replace_dhcp_agents(dhcp_agent_ids) - del prop_diff[self.DHCP_AGENT_IDS] + if self.QOS_POLICY in prop_diff: + qos_policy = prop_diff.pop(self.QOS_POLICY) + prop_diff[ + 'qos_policy_id'] = self.client_plugin().get_qos_policy_id( + qos_policy) if qos_policy else None + if self.VALUE_SPECS in prop_diff: + self.merge_value_specs(prop_diff) + if (self.NAME in prop_diff and + prop_diff[self.NAME] is None): + prop_diff[self.NAME] = self.physical_resource_name() - if len(prop_diff) > 0: - self.client().update_network( - self.resource_id, {'network': props}) + if prop_diff: + self.client().update_network(self.resource_id, + {'network': prop_diff}) def check_update_complete(self, *args): attributes = self._show_resource() diff --git a/heat/tests/openstack/neutron/test_neutron_net.py b/heat/tests/openstack/neutron/test_neutron_net.py index be48998a93..2bb03e575c 100644 --- a/heat/tests/openstack/neutron/test_neutron_net.py +++ b/heat/tests/openstack/neutron/test_neutron_net.py @@ -11,7 +11,6 @@ # License for the specific language governing permissions and limitations # under the License. -import copy import mox from neutronclient.common import exceptions as qe @@ -230,26 +229,36 @@ class NeutronNetTest(common.HeatTestCase): 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' ).AndReturn(None) + # Update script neutronclient.Client.update_network( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766', {'network': { - 'shared': True, 'name': 'mynet', - 'admin_state_up': True, - 'port_security_enabled': False, 'qos_policy_id': '0389f747-7785-4757-b7bb-2ab07e4b09c3' }}).AndReturn(None) # update again to detach qos_policy neutronclient.Client.update_network( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766', {'network': { - 'shared': True, - 'name': 'mynet_update_again', - 'admin_state_up': True, - 'port_security_enabled': False, + 'name': 'mynet', 'qos_policy_id': None }}).AndReturn(None) + neutronclient.Client.update_network( + 'fc68ea2c-b60b-4b4f-bd82-94ec81110766', + {'network': { + 'name': 'mynet', + 'port_security_enabled': True, + 'qos_policy_id': None + }}).AndReturn(None) + + # update with name = None + neutronclient.Client.update_network( + 'fc68ea2c-b60b-4b4f-bd82-94ec81110766', + {'network': { + 'name': utils.PhysName('test_stack', 'test_net'), + }}).AndReturn(None) + # Delete script neutronclient.Client.delete_network( 'fc68ea2c-b60b-4b4f-bd82-94ec81110766' @@ -296,21 +305,23 @@ class NeutronNetTest(common.HeatTestCase): ], 'qos_policy': '0389f747-7785-4757-b7bb-2ab07e4b09c3' } - props = copy.copy(rsrc.properties.data) - props.update(prop_diff) update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), - props) + prop_diff) rsrc.handle_update(update_snippet, {}, prop_diff) - prop_diff1 = { - "name": "mynet_update_again", - 'qos_policy': None - } - props1 = copy.copy(rsrc.properties.data) - props1.update(prop_diff1) - update_snippet = rsrc_defn.ResourceDefinition(rsrc.name, rsrc.type(), - props1) - rsrc.handle_update(update_snippet, {}, prop_diff1) + # Update with None qos_policy + prop_diff['qos_policy'] = None + rsrc.handle_update(update_snippet, {}, prop_diff) + + # Update with value_specs + prop_diff['value_specs'] = {"port_security_enabled": True} + rsrc.handle_update(update_snippet, {}, prop_diff) + + # Update with name = None + rsrc.handle_update(update_snippet, {}, {'name': None}) + + # Update with empty prop_diff + rsrc.handle_update(update_snippet, {}, {}) scheduler.TaskRunner(rsrc.delete)() rsrc.state_set(rsrc.CREATE, rsrc.COMPLETE, 'to delete again')