diff --git a/src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py b/src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py index 0e88756846f..bd18900091f 100644 --- a/src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py +++ b/src/config/vnc_openstack/vnc_openstack/neutron_plugin_db.py @@ -1826,16 +1826,17 @@ def _port_neutron_to_vnc(self, port_q, net_obj, oper): if 'device_owner' in port_q: port_obj.set_virtual_machine_interface_device_owner(port_q.get('device_owner')) - # pick binding keys from neutron repr and persist as kvp elements. + # pick binding keys from neutron repr and persist as kvp elements + # that are string/string(k/v). # it is assumed allowing/denying oper*key is done at neutron-server. if oper == CREATE: - vmi_binding_kvps = dict((k.replace('binding:',''), v) + vmi_binding_kvps = dict((k.replace('binding:',''), json.dumps(v)) for k,v in port_q.items() if k.startswith('binding:')) port_obj.set_virtual_machine_interface_bindings( KeyValuePairs([KeyValuePair(k,v) for k,v in vmi_binding_kvps.items()])) elif oper == UPDATE: - vmi_binding_kvps = dict((k.replace('binding:',''), v) + vmi_binding_kvps = dict((k.replace('binding:',''), json.dumps(v)) for k,v in port_q.items() if k.startswith('binding:')) for k,v in vmi_binding_kvps.items(): port_obj.add_virtual_machine_interface_bindings( @@ -2024,7 +2025,12 @@ def _port_vnc_to_neutron(self, port_obj, port_req_memo=None): if bindings: kvps = bindings.get_key_value_pair() for kvp in kvps: - port_q_dict['binding:'+kvp.key] = kvp.value + try: + port_q_dict['binding:'+kvp.key] = json.loads(kvp.value) + except ValueError: + # upgrade case, earlier version might have saved it + # in non-json format OR vif_details/vif_type/vnic_type + port_q_dict['binding:'+kvp.key] = kvp.value # 1. upgrade case, port created before bindings prop was # defined on vmi OR diff --git a/src/config/vnc_openstack/vnc_openstack/tests/test_basic.py b/src/config/vnc_openstack/vnc_openstack/tests/test_basic.py index d72ee492315..ec50bd3705a 100644 --- a/src/config/vnc_openstack/vnc_openstack/tests/test_basic.py +++ b/src/config/vnc_openstack/vnc_openstack/tests/test_basic.py @@ -255,6 +255,33 @@ def test_extra_fields_on_network(self): net_dict = json.loads(resp.text) self.assertIn('contrail:fq_name', net_dict) # end test_extra_fields_on_network + + def test_port_bindings(self): + vn_obj = vnc_api.VirtualNetwork(self.id()) + vn_obj.add_network_ipam(vnc_api.NetworkIpam(), + vnc_api.VnSubnetsType( + [vnc_api.IpamSubnetType( + vnc_api.SubnetType('1.1.1.0', 24))])) + self._vnc_lib.virtual_network_create(vn_obj) + + sg_obj = vnc_api.SecurityGroup('default') + self._vnc_lib.security_group_create(sg_obj) + + proj_uuid = self._vnc_lib.fq_name_to_id('project', + fq_name=['default-domain', 'default-project']) + + context = {'operation': 'CREATE', + 'user_id': '', + 'is_admin': True, + 'roles': ''} + data = {'resource':{'network_id': vn_obj.uuid, + 'tenant_id': proj_uuid, + 'binding:profile': {'foo': 'bar'}}} + body = {'context': context, 'data': data} + resp = self._api_svr_app.post_json('/neutron/port', body) + port_dict = json.loads(resp.text) + self.assertTrue(isinstance(port_dict['binding:profile'], dict)) + # end test_port_bindings # end class TestBasic class TestExtraFieldsPresenceByKnob(test_case.NeutronBackendTestCase):