diff --git a/src/config/api-server/tests/test_crud_basic.py b/src/config/api-server/tests/test_crud_basic.py index 535c32db4f0..1e65f8622fa 100644 --- a/src/config/api-server/tests/test_crud_basic.py +++ b/src/config/api-server/tests/test_crud_basic.py @@ -416,7 +416,7 @@ def test_physical_router_credentials(self): raise Exception("ERROR: physical-router: password should be hidden") #end test_physical_router_credentials - def test_bridge_domain_with_vmi_ref_multiple_bd(self): + def test_bridge_domain_with_multiple_bd_in_vn(self): vn1_name = self.id() + '-vn-1' vn1 = VirtualNetwork(vn1_name) logger.info('Creating VN %s', vn1_name) @@ -438,25 +438,85 @@ def test_bridge_domain_with_vmi_ref_multiple_bd(self): bd2 = BridgeDomain(bd2_name, parent_obj=vn1) bd2.set_isid(300300) logger.info('Creating Bridge Domain %s', bd2_name) - self._vnc_lib.bridge_domain_create(bd2) + with ExpectedException(BadRequest) as e: + self._vnc_lib.bridge_domain_create(bd2) + # end test_bridge_domain_with_multiple_bd_in_vn + + def test_bridge_domain_link_vmi_and_bd_in_different_vn(self): + vn1_name = self.id() + '-vn-1' + vn1 = VirtualNetwork(vn1_name) + logger.info('Creating VN %s', vn1_name) + self._vnc_lib.virtual_network_create(vn1) + + vn2_name = self.id() + '-vn-2' + vn2 = VirtualNetwork(vn2_name) + logger.info('Creating VN %s', vn2_name) + self._vnc_lib.virtual_network_create(vn2) + + vmi1_name = self.id() + '-port-1' + logger.info('Creating port %s', vmi1_name) + vmi1 = VirtualMachineInterface(vmi1_name, parent_obj=Project()) + vmi1.add_virtual_network(vn1) + self._vnc_lib.virtual_machine_interface_create(vmi1) - bd_ref_data1 = BridgeDomainMembershipType(); - bd_ref_data1.set_vlan_tag(0); + vmi2_name = self.id() + '-port-2' + logger.info('Creating port %s', vmi2_name) + vmi2 = VirtualMachineInterface(vmi2_name, parent_obj=Project()) + vmi2.add_virtual_network(vn2) + self._vnc_lib.virtual_machine_interface_create(vmi2) + + bd1_name = self.id() + '-bd-1' + bd1 = BridgeDomain(bd1_name, parent_obj=vn1) + bd1.set_isid(200200) + logger.info('Creating Bridge Domain %s', bd1_name) + self._vnc_lib.bridge_domain_create(bd1) - # VMI is referring to two bridge domain(bd1 and bd2) for vlan tag = 0 - vmi.add_bridge_domain(bd1, bd_ref_data1); - vmi.add_bridge_domain(bd2, bd_ref_data1); + bd_ref_data1 = BridgeDomainMembershipType(vlan_tag=0) + vmi2.add_bridge_domain(bd1, bd_ref_data1) with ExpectedException(BadRequest) as e: - self._vnc_lib.virtual_machine_interface_update(vmi) - - # Link the VMI to two bridge domain for different vlan tags(0, 1) - vmi_obj = self._vnc_lib.virtual_machine_interface_read(id=vmi.uuid) - bd_ref_data1 = BridgeDomainMembershipType(vlan_tag=1); - bd_ref_data2 = BridgeDomainMembershipType(vlan_tag=2); - vmi_obj.add_bridge_domain(bd1, bd_ref_data1); - vmi_obj.add_bridge_domain(bd2, bd_ref_data2); - self._vnc_lib.virtual_machine_interface_update(vmi_obj) - # end test_bridge_domain_with_vmi_ref_multiple_bd + self._vnc_lib.virtual_machine_interface_update(vmi2) + + bd_ref_data2 = BridgeDomainMembershipType(vlan_tag=0) + vmi1.add_bridge_domain(bd1, bd_ref_data2) + self._vnc_lib.virtual_machine_interface_update(vmi1) + # end test_bridge_domain_link_vmi_and_bd_in_different_vn + + def test_bridge_domain_delete_vn_ref_with_bd_link(self): + vn1_name = self.id() + '-vn-1' + vn1 = VirtualNetwork(vn1_name) + logger.info('Creating VN %s', vn1_name) + self._vnc_lib.virtual_network_create(vn1) + + vmi_name = self.id() + '-port' + logger.info('Creating port %s', vmi_name) + vmi = VirtualMachineInterface(vmi_name, parent_obj=Project()) + vmi.add_virtual_network(vn1) + self._vnc_lib.virtual_machine_interface_create(vmi) + + bd1_name = self.id() + '-bd-1' + bd1 = BridgeDomain(bd1_name, parent_obj=vn1) + bd1.set_isid(200200) + logger.info('Creating Bridge Domain %s', bd1_name) + self._vnc_lib.bridge_domain_create(bd1) + + bd_ref_data = BridgeDomainMembershipType(vlan_tag=0) + vmi.add_bridge_domain(bd1, bd_ref_data) + self._vnc_lib.virtual_machine_interface_update(vmi) + + # Try to delete the VN link with BD ref + vmi_temp = vmi + vmi_temp.del_virtual_network(vn1) + with ExpectedException(BadRequest) as e: + self._vnc_lib.virtual_machine_interface_update(vmi_temp) + + # Delete the BD ref + vmi.del_bridge_domain(bd1) + self._vnc_lib.virtual_machine_interface_update(vmi) + + vmi.del_virtual_network(vn1) + self._vnc_lib.virtual_machine_interface_update(vmi) + # end test_bridge_domain_with_multiple_bd_in_vn + # end class TestCrud diff --git a/src/config/api-server/vnc_cfg_types.py b/src/config/api-server/vnc_cfg_types.py index 50aaaa42cf5..772a831bc26 100644 --- a/src/config/api-server/vnc_cfg_types.py +++ b/src/config/api-server/vnc_cfg_types.py @@ -777,12 +777,29 @@ def _check_vrouter_link(cls, vmi_data, kvp_dict, obj_dict, db_conn): # end _check_vrouter_link @classmethod - def _check_bridge_domain_vmi_association(cls, obj_dict, - db_conn, create): + def _check_bridge_domain_vmi_association(cls, obj_dict, db_conn, vn_uuid, + create): + vn_fq_name = [] + if vn_uuid: + vn_fq_name = db_conn.uuid_to_fq_name(vn_uuid) + bridge_domain_links = {} bd_refs = obj_dict.get('bridge_domain_refs') or [] + + vn_refs = obj_dict.get('virtual_network_refs') or [] + if len(vn_refs) == 0 and len(bd_refs): + msg = "Virtual network can not be updated on virtual machine "\ + "interface(%s) while it refers a bridge domain"\ + %(obj_dict['uuid']) + return (False, msg) + for bd in bd_refs: bd_fq_name = bd['to'] + if bd_fq_name[0:3] != vn_fq_name: + msg = "Virtual machine interface(%s) can only refer to bridge "\ + "domain belonging to virtual network(%s)"\ + %(obj_dict['uuid'], vn_uuid) + return (False, msg) bd_uuid = bd.get('uuid') if not bd_uuid: bd_uuid = db_conn.fq_name_to_uuid('bridge_domain', bd_fq_name) @@ -820,7 +837,7 @@ def pre_dbe_create(cls, tenant_name, obj_dict, db_conn): vn_dict = result (ok, error) = cls._check_bridge_domain_vmi_association(obj_dict, - db_conn, True) + db_conn, vn_uuid, True) if not ok: return (False, (400, error)) @@ -911,8 +928,11 @@ def pre_dbe_update(cls, id, fq_name, obj_dict, db_conn, if not ok: return ok, read_result + vn_uuid = None + if 'virtual_network_refs' in read_result: + vn_uuid = read_result['virtual_network_refs'][0].get('uuid') (ok, error) = cls._check_bridge_domain_vmi_association(obj_dict, - db_conn, False) + db_conn, vn_uuid, False) if not ok: return (False, (400, error)) @@ -1005,6 +1025,25 @@ def pre_dbe_update(cls, id, fq_name, obj_dict, db_conn, **kwargs): # end pre_dbe_update # end class ServiceApplianceSetServer + +class BridgeDomainServer(Resource, BridgeDomain): + @classmethod + def pre_dbe_create(cls, tenant_name, obj_dict, db_conn): + vn_uuid = obj_dict.get('parent_uuid') + if vn_uuid is None: + vn_uuid = db_conn.fq_name_to_uuid('virtual_network', obj_dict['fq_name'][0:3]) + ok, result = cls.dbe_read(db_conn, 'virtual_network', vn_uuid, obj_fields=['bridge_domains']) + if not ok: + return ok, result + if 'bridge_domains' in result and len(result['bridge_domains']) == 1: + msg = "Virtual network(%s) can have only one bridge domain. Bridge"\ + " domain(%s) is already created under this virtual network" %\ + (vn_uuid, result['bridge_domains'][0]['uuid']) + return (False, (400, msg)) + return True, "" + # end pre_dbe_create +# end class BridgeDomainServer + class VirtualNetworkServer(Resource, VirtualNetwork): @classmethod