def create_network(self, context, network): net_data = network['network'] segments = self._process_provider_create(net_data) tenant_id = self._get_tenant_id_for_create(context, net_data) session = context.session with session.begin(subtransactions=True): self._ensure_default_security_group(context, tenant_id) result = super(Ml2Plugin, self).create_network(context, network) network_id = result['id'] self._process_l3_create(context, result, net_data) # REVISIT(rkukura): Consider moving all segment management # to TypeManager. if segments: for segment in segments: self.type_manager.reserve_provider_segment(session, segment) db.add_network_segment(session, network_id, segment) else: segment = self.type_manager.allocate_tenant_segment(session) db.add_network_segment(session, network_id, segment) self._extend_network_dict_provider(context, result) mech_context = driver_context.NetworkContext(self, context, result) self.mechanism_manager.create_network_precommit(mech_context) try: self.mechanism_manager.create_network_postcommit(mech_context) except ml2_exc.MechanismDriverError: with excutils.save_and_reraise_exception(): LOG.error(_("mechanism_manager.create_network_postcommit " "failed, deleting network '%s'"), result['id']) self.delete_network(context, result['id']) return result
def _sync_base(self): ctx = context.get_admin_context() # Sync Networks for network in self.core_plugin.get_networks(ctx): mech_context = driver_context.NetworkContext(self.core_plugin, ctx, network) try: self.driver.create_network_postcommit(mech_context) except Exception: LOG.warn(_LW("Create network postcommit failed for " "network %s"), network['id']) # Sync Subnets for subnet in self.core_plugin.get_subnets(ctx): mech_context = driver_context.SubnetContext(self.core_plugin, ctx, subnet) try: self.driver.create_subnet_postcommit(mech_context) except Exception: LOG.warn(_LW("Create subnet postcommit failed for" " subnet %s"), subnet['id']) # Sync Ports (compute/gateway/dhcp) for port in self.core_plugin.get_ports(ctx): _, binding = l2_db.get_locked_port_and_binding(ctx.session, port['id']) network = self.core_plugin.get_network(ctx, port['network_id']) mech_context = driver_context.PortContext(self.core_plugin, ctx, port, network, binding, []) try: self.driver.create_port_postcommit(mech_context) except Exception: LOG.warn(_LW("Create port postcommit failed for" " port %s"), port['id'])
def delete_network(self, context, id): # REVISIT(rkukura) The super(Ml2Plugin, self).delete_network() # function is not used because it auto-deletes ports and # subnets from the DB without invoking the derived class's # delete_port() or delete_subnet(), preventing mechanism # drivers from being called. This approach should be revisited # when the API layer is reworked during icehouse. session = context.session while True: with session.begin(subtransactions=True): filter = {'network_id': [id]} # Get ports to auto-delete. ports = self.get_ports(context, filters=filter) only_auto_del = all(p['device_owner'] in db_base_plugin_v2.AUTO_DELETE_PORT_OWNERS for p in ports) if not only_auto_del: raise exc.NetworkInUse(net_id=id) # Get subnets to auto-delete. subnets = self.get_subnets(context, filters=filter) if not ports or subnets: network = self.get_network(context, id) mech_context = driver_context.NetworkContext( self, context, network) self.mechanism_manager.delete_network_precommit( mech_context) record = self._get_network(context, id) context.session.delete(record) for segment in mech_context.network_segments: self.type_manager.release_segment(session, segment) # The segment records are deleted via cascade from the # network record, so explicit removal is not necessary. break for port in ports: self.delete_port(context, port['id']) for subnet in subnets: self.delete_subnet(context, subnet['id']) try: self.mechanism_manager.delete_network_postcommit(mech_context) except ml2_exc.MechanismDriverError: # TODO(apech) - One or more mechanism driver failed to # delete the network. Ideally we'd notify the caller of # the fact that an error occurred. pass self.notifier.network_delete(context, id)
def _sync_base(self): ctx = context.get_admin_context() # Sync Networks # Unroll to avoid unwanted additions during sync networks = [x for x in self.core_plugin.get_networks(ctx)] for network in networks: if (network['name'].startswith( constants.HOST_SNAT_NETWORK_PREFIX) or constants.APIC_SYNC_NETWORK == network['name']): continue mech_context = driver_context.NetworkContext( self.core_plugin, ctx, network) try: self.driver.create_network_postcommit(mech_context) except aexc.ReservedSynchronizationName as e: LOG.debug(e.message) except Exception as e: LOG.exception(e) # Sync Subnets subnets = [x for x in self.core_plugin.get_subnets(ctx)] for subnet in subnets: if constants.HOST_SNAT_POOL in subnet['name']: continue network = self.core_plugin.get_network( ctx, subnet['network_id']) mech_context = driver_context.SubnetContext(self.core_plugin, ctx, subnet, network) try: self.driver.create_subnet_postcommit(mech_context) except Exception as e: LOG.exception(e) # Sync Ports (compute/gateway/dhcp) ports = [x for x in self.core_plugin.get_ports(ctx)] for port in ports: if constants.HOST_SNAT_POOL_PORT in port['name']: continue _, binding = l2_db.get_locked_port_and_binding(ctx.session, port['id']) levels = l2_db.get_binding_levels(ctx.session, port['id'], binding.host) network = self.core_plugin.get_network(ctx, port['network_id']) mech_context = driver_context.PortContext(self.core_plugin, ctx, port, network, binding, levels) try: self.driver.create_port_postcommit(mech_context) except Exception as e: LOG.exception(e)
def _sync_base(self): ctx = context.get_admin_context() # Sync Networks # Unroll to avoid unwanted additions during sync networks = [x for x in self.core_plugin.get_networks(ctx)] for network in networks: if constants.APIC_SYNC_NETWORK == network['name']: continue mech_context = driver_context.NetworkContext( self.core_plugin, ctx, network) try: self.driver.create_network_postcommit(mech_context) except aexc.ReservedSynchronizationName as e: LOG.debug(e.message) except Exception as e: LOG.warning(_LW("Create network postcommit failed for " "network %(net_id)s: %(message)s"), net_id=network['id'], message=e.message) # Sync Subnets subnets = [x for x in self.core_plugin.get_subnets(ctx)] for subnet in subnets: mech_context = driver_context.SubnetContext(self.core_plugin, ctx, subnet) try: self.driver.create_subnet_postcommit(mech_context) except Exception as e: LOG.warning(_LW("Create subnet postcommit failed for " "subnet %(sub_id)s: %(message)s"), sub_id=subnet['id'], message=e.message) # Sync Ports (compute/gateway/dhcp) ports = [x for x in self.core_plugin.get_ports(ctx)] for port in ports: binding = l2_db.get_locked_port_and_binding(ctx.session, port['id'])[1] levels = l2_db.get_binding_levels(ctx.session, port['id'], binding.host) network = self.core_plugin.get_network(ctx, port['network_id']) mech_context = driver_context.PortContext(self.core_plugin, ctx, port, network, binding, levels) try: self.driver.create_port_postcommit(mech_context) except Exception as e: LOG.warning(_LW("Create port postcommit failed for " "port %(port_id)s: %(message)s"), port_id=port['id'], message=e.message)
def delete_network(self, context, id): session = context.session with session.begin(subtransactions=True): network = self.get_network(context, id) mech_context = driver_context.NetworkContext( self, context, network) self.mechanism_manager.delete_network_precommit(mech_context) super(Ml2Plugin, self).delete_network(context, id) for segment in mech_context.network_segments: self.type_manager.release_segment(session, segment) # The segment records are deleted via cascade from the # network record, so explicit removal is not necessary. try: self.mechanism_manager.delete_network_postcommit(mech_context) except ml2_exc.MechanismDriverError: # TODO(apech) - One or more mechanism driver failed to # delete the network. Ideally we'd notify the caller of # the fact that an error occurred. pass self.notifier.network_delete(context, id)
def update_network(self, context, id, network): provider._raise_if_updates_provider_attributes(network['network']) session = context.session with session.begin(subtransactions=True): original_network = super(Ml2Plugin, self).get_network(context, id) updated_network = super(Ml2Plugin, self).update_network(context, id, network) self._process_l3_update(context, updated_network, network['network']) self._extend_network_dict_provider(context, updated_network) mech_context = driver_context.NetworkContext( self, context, updated_network, original_network=original_network) self.mechanism_manager.update_network_precommit(mech_context) # TODO(apech) - handle errors raised by update_network, potentially # by re-calling update_network with the previous attributes. For # now the error is propogated to the caller, which is expected to # either undo/retry the operation or delete the resource. self.mechanism_manager.update_network_postcommit(mech_context) return updated_network
def delete_network(self, context, id): # REVISIT(rkukura) The super(Ml2Plugin, self).delete_network() # function is not used because it auto-deletes ports and # subnets from the DB without invoking the derived class's # delete_port() or delete_subnet(), preventing mechanism # drivers from being called. This approach should be revisited # when the API layer is reworked during icehouse. LOG.debug(_("Deleting network %s"), id) session = context.session while True: try: with session.begin(subtransactions=True): # Get ports to auto-delete. ports = (session.query(models_v2.Port). enable_eagerloads(False). filter_by(network_id=id). with_lockmode('update').all()) LOG.debug(_("Ports to auto-delete: %s"), ports) only_auto_del = all(p.device_owner in db_base_plugin_v2. AUTO_DELETE_PORT_OWNERS for p in ports) if not only_auto_del: LOG.debug(_("Tenant-owned ports exist")) raise exc.NetworkInUse(net_id=id) # Get subnets to auto-delete. subnets = (session.query(models_v2.Subnet). enable_eagerloads(False). filter_by(network_id=id). with_lockmode('update').all()) LOG.debug(_("Subnets to auto-delete: %s"), subnets) if not (ports or subnets): network = self.get_network(context, id) mech_context = driver_context.NetworkContext(self, context, network) self.mechanism_manager.delete_network_precommit( mech_context) record = self._get_network(context, id) LOG.debug(_("Deleting network record %s"), record) session.delete(record) for segment in mech_context.network_segments: self.type_manager.release_segment(session, segment) # The segment records are deleted via cascade from the # network record, so explicit removal is not necessary. LOG.debug(_("Committing transaction")) break except os_db.exception.DBError as e: if isinstance(e.inner_exception, sql_exc.IntegrityError): msg = _("A concurrent port creation has occurred") LOG.warning(msg) continue else: raise for port in ports: try: self.delete_port(context, port.id) except Exception: LOG.exception(_("Exception auto-deleting port %s"), port.id) raise for subnet in subnets: try: self.delete_subnet(context, subnet.id) except Exception: LOG.exception(_("Exception auto-deleting subnet %s"), subnet.id) raise try: self.mechanism_manager.delete_network_postcommit(mech_context) except ml2_exc.MechanismDriverError: # TODO(apech) - One or more mechanism driver failed to # delete the network. Ideally we'd notify the caller of # the fact that an error occurred. LOG.error(_("mechanism_manager.delete_network_postcommit failed")) self.notifier.network_delete(context, id)
def filter_create_attributes_with_plugin(cls, network, plugin, dbcontext): context = driver_context.NetworkContext(plugin, dbcontext, network) cls.filter_create_attributes(network, context)
def delete_network(self, context, id): # REVISIT(rkukura) The super(Ml2Plugin, self).delete_network() # function is not used because it auto-deletes ports and # subnets from the DB without invoking the derived class's # delete_port() or delete_subnet(), preventing mechanism # drivers from being called. This approach should be revisited # when the API layer is reworked during icehouse. LOG.debug("Deleting network %s", id) session = context.session attempt = 0 while True: attempt += 1 LOG.info(i18n._LI("Attempt %(attempt)s to delete network %(net)s"), { 'attempt': attempt, 'net': id }) if attempt > 100: raise InfiniteLoopError() try: # REVISIT: Serialize this operation with a semaphore # to prevent deadlock waiting to acquire a DB lock # held by another thread in the same process, leading # to 'lock wait timeout' errors. # # Process L3 first, since, depending on the L3 plugin, it may # involve sending RPC notifications, and/or calling delete_port # on this plugin. # Additionally, a rollback may not be enough to undo the # deletion of a floating IP with certain L3 backends. self._process_l3_delete(context, id) # Using query().with_lockmode isn't necessary. Foreign-key # constraints prevent deletion if concurrent creation happens. with session.begin(subtransactions=True): # Get ports to auto-delete. ports = (session.query( models_v2.Port).enable_eagerloads(False).filter_by( network_id=id).all()) LOG.debug("Ports to auto-delete: %s", ports) only_auto_del = all( p.device_owner in db_base_plugin_v2.AUTO_DELETE_PORT_OWNERS for p in ports) if not only_auto_del: LOG.debug("Tenant-owned ports exist") raise exc.NetworkInUse(net_id=id) # Get subnets to auto-delete. subnets = (session.query( models_v2.Subnet).enable_eagerloads(False).filter_by( network_id=id).all()) LOG.debug("Subnets to auto-delete: %s", subnets) if not (ports or subnets): network = self.get_network(context, id) mech_context = driver_context.NetworkContext( self, context, network) self.mechanism_manager.delete_network_precommit( mech_context) self.type_manager.release_network_segments(session, id) record = self._get_network(context, id) LOG.debug("Deleting network record %s", record) session.delete(record) # The segment records are deleted via cascade from the # network record, so explicit removal is not necessary. LOG.debug("Committing transaction") break port_ids = [port.id for port in ports] subnet_ids = [subnet.id for subnet in subnets] except os_db_exception.DBError as e: with excutils.save_and_reraise_exception() as ctxt: if isinstance(e.inner_exception, sql_exc.IntegrityError): ctxt.reraise = False LOG.warning( i18n._LW("A concurrent port creation has " "occurred")) continue LOG.info(i18n._LI("Auto-deleting ports %(ports)s for network %(net)s"), { 'ports': ports, 'net': id }) self._delete_ports(context, port_ids) LOG.info( i18n._LI("Auto-deleting subnets %(subnets)s for network " "%(net)s"), { 'subnets': subnets, 'net': id }) self._delete_subnets(context, subnet_ids) try: self.mechanism_manager.delete_network_postcommit(mech_context) except ml2_exc.MechanismDriverError: # TODO(apech) - One or more mechanism driver failed to # delete the network. Ideally we'd notify the caller of # the fact that an error occurred. LOG.error( i18n._LE("mechanism_manager.delete_network_postcommit" " failed")) self.notifier.network_delete(context, id)