def create_port(self, context, port): port_id = uuidutils.generate_uuid() tags = utils.build_v3_tags_payload(port['port']) port['port']['id'] = port_id # TODO(salv-orlando): Undo logical switch creation on failure with context.session.begin(subtransactions=True): neutron_db = super(NsxV3Plugin, self).create_port(context, port) port["port"].update(neutron_db) address_bindings = self._build_address_bindings(port['port']) # FIXME(arosen): we might need to pull this out of the transaction # here later. result = nsxlib.create_logical_port( lswitch_id=port['port']['network_id'], vif_uuid=port_id, name=port['port']['name'], tags=tags, admin_state=port['port']['admin_state_up'], address_bindings=address_bindings) # TODO(salv-orlando): The logical switch identifier in the mapping # object is not necessary anymore. nsx_db.add_neutron_nsx_port_mapping( context.session, neutron_db['id'], neutron_db['network_id'], result['id']) self._process_portbindings_create_and_update(context, port['port'], neutron_db) neutron_db[pbin.VNIC_TYPE] = pbin.VNIC_NORMAL return neutron_db
def create_port(self, context, port): # NOTE(salv-orlando): This method currently first performs the backend # operation. However it is important to note that this workflow might # change in the future as the backend might need parameter generated # from the neutron side such as port MAC address port_id = uuidutils.generate_uuid() result = nsxlib.create_logical_port( lswitch_id=port['port']['network_id'], vif_uuid=port_id) port['port']['id'] = port_id # TODO(salv-orlando): Undo logical switch creation on failure with context.session.begin(): neutron_db = super(NsxV3Plugin, self).create_port(context, port) port["port"].update(neutron_db) # TODO(salv-orlando): The logical switch identifier in the mapping # object is not necessary anymore. nsx_db.add_neutron_nsx_port_mapping( context.session, neutron_db['id'], neutron_db['network_id'], result['id']) self._process_portbindings_create_and_update(context, port['port'], neutron_db) neutron_db[pbin.VNIC_TYPE] = pbin.VNIC_NORMAL return neutron_db
def get_nsx_switch_and_port_id(session, cluster, neutron_port_id): """Return the NSX switch and port uuids for a given neutron port. First, look up the Neutron database. If not found, execute a query on NSX platform as the mapping might be missing because the port was created before upgrading to grizzly. This routine also retrieves the identifier of the logical switch in the backend where the port is plugged. Prior to Icehouse this information was not available in the Neutron Database. For dealing with pre-existing records, this routine will query the backend for retrieving the correct switch identifier. As of Icehouse release it is not indeed anymore possible to assume the backend logical switch identifier is equal to the neutron network identifier. """ nsx_switch_id, nsx_port_id = nsx_db.get_nsx_switch_and_port_id( session, neutron_port_id) if not nsx_switch_id: # Find logical switch for port from backend # This is a rather expensive query, but it won't be executed # more than once for each port in Neutron's lifetime nsx_ports = switchlib.query_lswitch_lports( cluster, '*', relations='LogicalSwitchConfig', filters={'tag': neutron_port_id, 'tag_scope': 'q_port_id'}) # Only one result expected # NOTE(salv-orlando): Not handling the case where more than one # port is found with the same neutron port tag if not nsx_ports: LOG.warn(_LW("Unable to find NSX port for Neutron port %s"), neutron_port_id) # This method is supposed to return a tuple return None, None nsx_port = nsx_ports[0] nsx_switch_id = (nsx_port['_relations'] ['LogicalSwitchConfig']['uuid']) if nsx_port_id: # Mapping already exists. Delete before recreating nsx_db.delete_neutron_nsx_port_mapping( session, neutron_port_id) else: nsx_port_id = nsx_port['uuid'] # (re)Create DB mapping nsx_db.add_neutron_nsx_port_mapping( session, neutron_port_id, nsx_switch_id, nsx_port_id) return nsx_switch_id, nsx_port_id
def test_add_neutron_nsx_port_mapping_raise_on_duplicate_constraint(self): neutron_net_id = 'foo_neutron_network_id' neutron_port_id = 'foo_neutron_port_id' nsx_port_id_1 = 'foo_nsx_port_id_1' nsx_port_id_2 = 'foo_nsx_port_id_2' nsx_switch_id = 'foo_nsx_switch_id' self._setup_neutron_network_and_port(neutron_net_id, neutron_port_id) nsx_db.add_neutron_nsx_port_mapping( self.ctx.session, neutron_port_id, nsx_switch_id, nsx_port_id_1) # Call the method twice to trigger a db duplicate constraint error, # this time with a different nsx port id! self.assertRaises(d_exc.DBDuplicateEntry, nsx_db.add_neutron_nsx_port_mapping, self.ctx.session, neutron_port_id, nsx_switch_id, nsx_port_id_2)
def test_add_neutron_nsx_port_mapping_handle_duplicate_constraint(self): neutron_net_id = 'foo_neutron_network_id' neutron_port_id = 'foo_neutron_port_id' nsx_port_id = 'foo_nsx_port_id' nsx_switch_id = 'foo_nsx_switch_id' self._setup_neutron_network_and_port(neutron_net_id, neutron_port_id) nsx_db.add_neutron_nsx_port_mapping( self.ctx.session, neutron_port_id, nsx_switch_id, nsx_port_id) # Call the method twice to trigger a db duplicate constraint error nsx_db.add_neutron_nsx_port_mapping( self.ctx.session, neutron_port_id, nsx_switch_id, nsx_port_id) result = (self.ctx.session.query(nsx_models.NeutronNsxPortMapping). filter_by(neutron_id=neutron_port_id).one()) self.assertEqual(nsx_port_id, result.nsx_port_id) self.assertEqual(neutron_port_id, result.neutron_id)