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_subnet(self, context, id): # REVISIT(rkukura) The super(Ml2Plugin, self).delete_subnet() # function is not used because it auto-deletes ports from the # DB without invoking the derived class's delete_port(), # preventing mechanism drivers from being called. This # approach should be revisited when the API layer is reworked # during icehouse. LOG.debug(_("Deleting subnet %s"), id) session = context.session while True: with session.begin(subtransactions=True): subnet = self.get_subnet(context, id) # Get ports to auto-delete. allocated = (session.query(models_v2.IPAllocation). filter_by(subnet_id=id). join(models_v2.Port). filter_by(network_id=subnet['network_id']). with_lockmode('update').all()) LOG.debug(_("Ports to auto-delete: %s"), allocated) only_auto_del = all(not a.port_id or a.ports.device_owner in db_base_plugin_v2. AUTO_DELETE_PORT_OWNERS for a in allocated) if not only_auto_del: LOG.debug(_("Tenant-owned ports exist")) raise exc.SubnetInUse(subnet_id=id) if not allocated: mech_context = driver_context.SubnetContext(self, context, subnet) self.mechanism_manager.delete_subnet_precommit( mech_context) LOG.debug(_("Deleting subnet record")) record = self._get_subnet(context, id) session.delete(record) LOG.debug(_("Committing transaction")) break for a in allocated: try: self.delete_port(context, a.port_id) except Exception: LOG.exception(_("Exception auto-deleting port %s"), a.port_id) raise try: self.mechanism_manager.delete_subnet_postcommit(mech_context) except ml2_exc.MechanismDriverError: # TODO(apech) - One or more mechanism driver failed to # delete the subnet. Ideally we'd notify the caller of # the fact that an error occurred. LOG.error(_("mechanism_manager.delete_subnet_postcommit failed"))
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 delete_subnet(self, context, id): session = context.session with session.begin(subtransactions=True): subnet = self.get_subnet(context, id) mech_context = driver_context.SubnetContext(self, context, subnet) self.mechanism_manager.delete_subnet_precommit(mech_context) super(Ml2Plugin, self).delete_subnet(context, id) try: self.mechanism_manager.delete_subnet_postcommit(mech_context) except ml2_exc.MechanismDriverError: # TODO(apech) - One or more mechanism driver failed to # delete the subnet. Ideally we'd notify the caller of # the fact that an error occurred. pass
def create_subnet(self, context, subnet): session = context.session with session.begin(subtransactions=True): result = super(Ml2Plugin, self).create_subnet(context, subnet) mech_context = driver_context.SubnetContext(self, context, result) self.mechanism_manager.create_subnet_precommit(mech_context) try: self.mechanism_manager.create_subnet_postcommit(mech_context) except ml2_exc.MechanismDriverError: with excutils.save_and_reraise_exception(): LOG.error(_("mechanism_manager.create_subnet_postcommit " "failed, deleting subnet '%s'"), result['id']) self.delete_subnet(context, result['id']) return result
def update_subnet(self, context, id, subnet): session = context.session with session.begin(subtransactions=True): original_subnet = super(Ml2Plugin, self).get_subnet(context, id) updated_subnet = super(Ml2Plugin, self).update_subnet( context, id, subnet) mech_context = driver_context.SubnetContext( self, context, updated_subnet, original_subnet=original_subnet) self.mechanism_manager.update_subnet_precommit(mech_context) # TODO(apech) - handle errors raised by update_subnet, potentially # by re-calling update_subnet 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_subnet_postcommit(mech_context) return updated_subnet
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 filter_create_attributes_with_plugin(cls, subnet, plugin, dbcontext): network = plugin.get_network(dbcontext, subnet['network_id']) context = driver_context.SubnetContext(plugin, dbcontext, subnet, network) cls.filter_create_attributes(subnet, context) cls._filter_unmapped_null(subnet, cls._UNMAPPED_KEYS)
def filter_create_attributes_with_plugin(cls, subnet, plugin, dbcontext): network = plugin.get_network(dbcontext, subnet['network_id']) context = driver_context.SubnetContext(plugin, dbcontext, subnet, network) cls.filter_create_attributes(subnet, context)
def delete_subnet(self, context, id): # REVISIT(rkukura) The super(Ml2Plugin, self).delete_subnet() # function is not used because it deallocates the subnet's addresses # from ports in the DB without invoking the derived class's # update_port(), preventing mechanism drivers from being called. # This approach should be revisited when the API layer is reworked # during icehouse. LOG.debug(_("Deleting subnet %s"), id) session = context.session while True: with session.begin(subtransactions=True): subnet = self.get_subnet(context, id) # Get ports to auto-deallocate allocated = (session.query(models_v2.IPAllocation).filter_by( subnet_id=id).join(models_v2.Port).filter_by( network_id=subnet['network_id']).with_lockmode( 'update').all()) LOG.debug(_("Ports to auto-deallocate: %s"), allocated) only_auto_del = all(not a.port_id or a.ports.device_owner in db_base_plugin_v2.AUTO_DELETE_PORT_OWNERS for a in allocated) if not only_auto_del: LOG.debug(_("Tenant-owned ports exist")) raise exc.SubnetInUse(subnet_id=id) if not allocated: mech_context = driver_context.SubnetContext( self, context, subnet) self.mechanism_manager.delete_subnet_precommit( mech_context) LOG.debug(_("Deleting subnet record")) record = self._get_subnet(context, id) session.delete(record) LOG.debug(_("Committing transaction")) break for a in allocated: if a.port_id: # calling update_port() for each allocation to remove the # IP from the port and call the MechanismDrivers data = { 'port': { 'fixed_ips': [{ 'subnet_id': ip.subnet_id, 'ip_address': ip.ip_address } for ip in a.ports.fixed_ips if ip.subnet_id != id] } } try: self.update_port(context, a.port_id, data) except Exception: with excutils.save_and_reraise_exception(): LOG.exception( _("Exception deleting fixed_ip from " "port %s"), a.port_id) session.delete(a) try: self.mechanism_manager.delete_subnet_postcommit(mech_context) except ml2_exc.MechanismDriverError: # TODO(apech) - One or more mechanism driver failed to # delete the subnet. Ideally we'd notify the caller of # the fact that an error occurred. LOG.error(_("mechanism_manager.delete_subnet_postcommit failed"))
def delete_subnet(self, context, id): # REVISIT(rkukura) The super(Ml2Plugin, self).delete_subnet() # function is not used because it deallocates the subnet's addresses # from ports in the DB without invoking the derived class's # update_port(), preventing mechanism drivers from being called. # This approach should be revisited when the API layer is reworked # during icehouse. LOG.debug("Deleting subnet %s", id) session = context.session attempt = 0 while True: attempt += 1 LOG.info(i18n._LI("Attempt %(attempt)s to delete subnet %(subnet)s"), { 'attempt': attempt, 'subnet': id }) if attempt > 100: raise InfiniteLoopError() with session.begin(subtransactions=True): record = self._get_subnet(context, id) subnet = self._make_subnet_dict(record, None, context=context) qry_allocated = (session.query(models_v2.IPAllocation).filter_by( subnet_id=id).join(models_v2.Port)) is_auto_addr_subnet = ipv6_utils.is_auto_address_subnet(subnet) # Remove network owned ports, and delete IP allocations # for IPv6 addresses which were automatically generated # via SLAAC if is_auto_addr_subnet: self._subnet_check_ip_allocations_internal_router_ports( context, id) else: qry_allocated = (qry_allocated.filter( models_v2.Port.device_owner.in_( db_base_plugin_v2.AUTO_DELETE_PORT_OWNERS))) allocated = qry_allocated.all() # Delete all the IPAllocation that can be auto-deleted if allocated: for x in allocated: session.delete(x) LOG.debug("Ports to auto-deallocate: %s", allocated) # Check if there are more IP allocations, unless # is_auto_address_subnet is True. In that case the check is # unnecessary. This additional check not only would be wasteful # for this class of subnet, but is also error-prone since when # the isolation level is set to READ COMMITTED allocations made # concurrently will be returned by this query if not is_auto_addr_subnet: alloc = self._subnet_check_ip_allocations(context, id) if alloc: user_alloc = self._subnet_get_user_allocation(context, id) if user_alloc: LOG.info( i18n._LI("Found port (%(port_id)s, %(ip)s) " "having IP allocation on subnet " "%(subnet)s, cannot delete"), { 'ip': user_alloc.ip_address, 'port_id': user_alloc.port_id, 'subnet': id }) raise exc.SubnetInUse(subnet_id=id) else: # allocation found and it was DHCP port # that appeared after autodelete ports were # removed - need to restart whole operation raise os_db_exception.RetryRequest( exc.SubnetInUse(subnet_id=id)) db_base_plugin_v2._check_subnet_not_used(context, id) # If allocated is None, then all the IPAllocation were # correctly deleted during the previous pass. if not allocated: network = self.get_network(context, subnet['network_id']) mech_context = driver_context.SubnetContext( self, context, subnet, network) self.mechanism_manager.delete_subnet_precommit(mech_context) LOG.debug("Deleting subnet record") session.delete(record) # The super(Ml2Plugin, self).delete_subnet() is not called, # so need to manually call delete_subnet for pluggable ipam self.ipam.delete_subnet(context, id) LOG.debug("Committing transaction") break for a in allocated: if a.port: # calling update_port() for each allocation to remove the # IP from the port and call the MechanismDrivers data = { attributes.PORT: { 'fixed_ips': [{ 'subnet_id': ip.subnet_id, 'ip_address': ip.ip_address } for ip in a.port.fixed_ips if ip.subnet_id != id] } } try: self.update_port(context, a.port_id, data) except exc.PortNotFound: LOG.debug("Port %s deleted concurrently", a.port_id) except Exception: with excutils.save_and_reraise_exception(): LOG.exception( i18n._LE("Exception deleting fixed_ip " "from port %s"), a.port_id) try: self.mechanism_manager.delete_subnet_postcommit(mech_context) except ml2_exc.MechanismDriverError: # TODO(apech) - One or more mechanism driver failed to # delete the subnet. Ideally we'd notify the caller of # the fact that an error occurred. LOG.error( i18n._LE("mechanism_manager.delete_subnet_postcommit failed"))
def _get_subnet_context(self, context, network_id, subnet_id): plugin = directory.get_plugin() network = plugin.get_network(context, network_id) subnet = plugin.get_subnet(context, subnet_id) return driver_context.SubnetContext(plugin, context, subnet, network)
def filter_create_attributes_with_plugin(cls, subnet, plugin, dbcontext): context = driver_context.SubnetContext(subnet, plugin, dbcontext) cls.filter_create_attributes(subnet, context)