# Path: networking_odl/common/constants.py
# ODL_NETWORK = 'network'
# ODL_NETWORKS = 'networks'
# ODL_SUBNET = 'subnet'
# ODL_SUBNETS = 'subnets'
# ODL_PORT = 'port'
# ODL_PORTS = 'ports'
# ODL_SG = 'security_group'
# ODL_SGS = 'security_groups'
# ODL_SG_RULE = 'security_group_rule'
# ODL_SG_RULES = 'security_group_rules'
# ODL_ROUTER = 'router'
# ODL_ROUTERS = 'routers'
# ODL_FLOATINGIP = 'floatingip'
# ODL_FLOATINGIPS = 'floatingips'
# ODL_QOS = 'qos'
# ODL_QOS_POLICY = 'policy'
# ODL_QOS_POLICIES = 'policies'
# ODL_SFC = 'sfc'
# ODL_SFC_FLOW_CLASSIFIER = 'flowclassifier'
# ODL_SFC_FLOW_CLASSIFIERS = 'flowclassifiers'
# ODL_SFC_PORT_PAIR = 'portpair'
# ODL_SFC_PORT_PAIRS = 'portpairs'
# ODL_SFC_PORT_PAIR_GROUP = 'portpairgroup'
# ODL_SFC_PORT_PAIR_GROUPS = 'portpairgroups'
# ODL_SFC_PORT_CHAIN = 'portchain'
# ODL_SFC_PORT_CHAINS = 'portchains'
# NETWORKING_SFC_FLOW_CLASSIFIER = 'flow_classifier'
# NETWORKING_SFC_FLOW_CLASSIFIERS = 'flow_classifiers'
# NETWORKING_SFC_PORT_PAIR = 'port_pair'
# NETWORKING_SFC_PORT_PAIRS = 'port_pairs'
# NETWORKING_SFC_PORT_PAIR_GROUP = 'port_pair_group'
# NETWORKING_SFC_PORT_PAIR_GROUPS = 'port_pair_groups'
# NETWORKING_SFC_PORT_CHAIN = 'port_chain'
# NETWORKING_SFC_PORT_CHAINS = 'port_chains'
# ODL_TRUNK = 'trunk'
# ODL_TRUNKS = 'trunks'
# ODL_L2GATEWAY = 'l2_gateway'
# ODL_L2GATEWAYS = 'l2_gateways'
# ODL_L2GATEWAY_CONNECTION = 'l2gateway_connection'
# ODL_L2GATEWAY_CONNECTIONS = 'l2_gateway_connections'
# ODL_BGPVPN = 'bgpvpn'
# ODL_BGPVPNS = 'bgpvpns'
# ODL_BGPVPN_NETWORK_ASSOCIATION = 'bgpvpn_network_association'
# ODL_BGPVPN_NETWORK_ASSOCIATIONS = 'bgpvpn_network_associations'
# ODL_BGPVPN_ROUTER_ASSOCIATION = 'bgpvpn_router_association'
# ODL_BGPVPN_ROUTER_ASSOCIATIONS = 'bgpvpn_router_associations'
# ODL_ML2_MECH_DRIVER_V2 = "opendaylight_v2"
# ODL_DEVICE_ID_START = 'OpenDaylight'
# ODL_CREATE = 'create'
# ODL_UPDATE = 'update'
# ODL_DELETE = 'delete'
# PENDING = 'pending'
# PROCESSING = 'processing'
# FAILED = 'failed'
# COMPLETED = 'completed'
# BEFORE_COMPLETE = 'before_complete'
# AFTER_DELETE = 'after_delete'
# RESOURCE_URL_MAPPINGS = {
#     ODL_QOS_POLICY: "%s/%s" % (ODL_QOS, ODL_QOS_POLICIES),
#     ODL_SFC_FLOW_CLASSIFIER: "%s/%s" % (ODL_SFC, ODL_SFC_FLOW_CLASSIFIERS),
#     ODL_SFC_PORT_CHAIN: "%s/%s" % (ODL_SFC, ODL_SFC_PORT_CHAINS),
#     ODL_SFC_PORT_PAIR: "%s/%s" % (ODL_SFC, ODL_SFC_PORT_PAIRS),
#     ODL_SFC_PORT_PAIR_GROUP: "%s/%s" % (ODL_SFC, ODL_SFC_PORT_PAIR_GROUPS)
# }
# 
# Path: networking_odl/dhcp/odl_dhcp_driver_base.py
# LOG = logging.getLogger(__name__)
# class OdlDhcpDriverBase(object):
#     def create_or_delete_dhcp_port(self, subnet_context):
#     def _delete_port(self, plugin, context, port_id):
#     def _make_dhcp_port_dict(self, subnet_context):
#     def get_dhcp_port_if_exists(self, subnet_context):


from neutron_lib.callbacks import registry
from neutron_lib import constants as n_const
from neutron_lib.plugins import directory
from oslo_log import log as logging
from neutron.plugins.ml2 import driver_context
from networking_odl.common import constants
from networking_odl.dhcp import odl_dhcp_driver_base as driver_base
LOG = logging.getLogger(__name__)


@registry.has_registry_receivers
class OdlDhcpDriver(driver_base.OdlDhcpDriverBase):

    @registry.receives(constants.ODL_SUBNET, [constants.BEFORE_COMPLETE])
    def handle_subnet_event(self, resource, event, trigger, payload):
        context = payload.context
        operation = payload.metadata['operation']
        row = payload.metadata['row']
        if (operation == constants.ODL_CREATE or
                operation == constants.ODL_UPDATE):
            try:
                subnet_ctxt = self._get_subnet_context(context,
                                                       row.data['network_id'],
                                                       row.data['id'])
                self.create_or_delete_dhcp_port(subnet_ctxt)
            except Exception as e:
                LOG.error("Error while processing %s subnet %s: %s", operation,
                          row.data['id'], e)

    # Note(lajoskatona): When subnet locking was introduced in neutron
    # (see [0]) that caused that subnet deletion wasn't triggered dhcp port
    # deletion any more.
    # To workaround this let's catch subnet after_delete event and delete port
    # if that is a dhcp port.
    # The new functionality can't be added to handle_subnet_event as here
    # subnet context is not available.
    # [0]: https://review.opendev.org/713045

# Path: networking_odl/common/constants.py
# ODL_NETWORK = 'network'
# ODL_NETWORKS = 'networks'
# ODL_SUBNET = 'subnet'
# ODL_SUBNETS = 'subnets'
# ODL_PORT = 'port'
# ODL_PORTS = 'ports'
# ODL_SG = 'security_group'
# ODL_SGS = 'security_groups'
# ODL_SG_RULE = 'security_group_rule'
# ODL_SG_RULES = 'security_group_rules'
# ODL_ROUTER = 'router'
# ODL_ROUTERS = 'routers'
# ODL_FLOATINGIP = 'floatingip'
# ODL_FLOATINGIPS = 'floatingips'
# ODL_QOS = 'qos'
# ODL_QOS_POLICY = 'policy'
# ODL_QOS_POLICIES = 'policies'
# ODL_SFC = 'sfc'
# ODL_SFC_FLOW_CLASSIFIER = 'flowclassifier'
# ODL_SFC_FLOW_CLASSIFIERS = 'flowclassifiers'
# ODL_SFC_PORT_PAIR = 'portpair'
# ODL_SFC_PORT_PAIRS = 'portpairs'
# ODL_SFC_PORT_PAIR_GROUP = 'portpairgroup'
# ODL_SFC_PORT_PAIR_GROUPS = 'portpairgroups'
# ODL_SFC_PORT_CHAIN = 'portchain'
# ODL_SFC_PORT_CHAINS = 'portchains'
# NETWORKING_SFC_FLOW_CLASSIFIER = 'flow_classifier'
# NETWORKING_SFC_FLOW_CLASSIFIERS = 'flow_classifiers'
# NETWORKING_SFC_PORT_PAIR = 'port_pair'
# NETWORKING_SFC_PORT_PAIRS = 'port_pairs'
# NETWORKING_SFC_PORT_PAIR_GROUP = 'port_pair_group'
# NETWORKING_SFC_PORT_PAIR_GROUPS = 'port_pair_groups'
# NETWORKING_SFC_PORT_CHAIN = 'port_chain'
# NETWORKING_SFC_PORT_CHAINS = 'port_chains'
# ODL_TRUNK = 'trunk'
# ODL_TRUNKS = 'trunks'
# ODL_L2GATEWAY = 'l2_gateway'
# ODL_L2GATEWAYS = 'l2_gateways'
# ODL_L2GATEWAY_CONNECTION = 'l2gateway_connection'
# ODL_L2GATEWAY_CONNECTIONS = 'l2_gateway_connections'
# ODL_BGPVPN = 'bgpvpn'
# ODL_BGPVPNS = 'bgpvpns'
# ODL_BGPVPN_NETWORK_ASSOCIATION = 'bgpvpn_network_association'
# ODL_BGPVPN_NETWORK_ASSOCIATIONS = 'bgpvpn_network_associations'
# ODL_BGPVPN_ROUTER_ASSOCIATION = 'bgpvpn_router_association'
# ODL_BGPVPN_ROUTER_ASSOCIATIONS = 'bgpvpn_router_associations'
# ODL_ML2_MECH_DRIVER_V2 = "opendaylight_v2"
# ODL_DEVICE_ID_START = 'OpenDaylight'
# ODL_CREATE = 'create'
# ODL_UPDATE = 'update'
# ODL_DELETE = 'delete'
# PENDING = 'pending'
# PROCESSING = 'processing'
# FAILED = 'failed'
# COMPLETED = 'completed'
# BEFORE_COMPLETE = 'before_complete'
# AFTER_DELETE = 'after_delete'
# RESOURCE_URL_MAPPINGS = {
#     ODL_QOS_POLICY: "%s/%s" % (ODL_QOS, ODL_QOS_POLICIES),
#     ODL_SFC_FLOW_CLASSIFIER: "%s/%s" % (ODL_SFC, ODL_SFC_FLOW_CLASSIFIERS),
#     ODL_SFC_PORT_CHAIN: "%s/%s" % (ODL_SFC, ODL_SFC_PORT_CHAINS),
#     ODL_SFC_PORT_PAIR: "%s/%s" % (ODL_SFC, ODL_SFC_PORT_PAIRS),
#     ODL_SFC_PORT_PAIR_GROUP: "%s/%s" % (ODL_SFC, ODL_SFC_PORT_PAIR_GROUPS)
# }
# 
# Path: networking_odl/dhcp/odl_dhcp_driver_base.py
# LOG = logging.getLogger(__name__)
# class OdlDhcpDriverBase(object):
#     def create_or_delete_dhcp_port(self, subnet_context):
#     def _delete_port(self, plugin, context, port_id):
#     def _make_dhcp_port_dict(self, subnet_context):
#     def get_dhcp_port_if_exists(self, subnet_context):


# Path: networking_odl/dhcp/odl_dhcp_driver.py
from neutron_lib.callbacks import registry
from neutron_lib import constants as n_const
from neutron_lib.plugins import directory
from oslo_log import log as logging
from neutron.plugins.ml2 import driver_context
from networking_odl.common import constants
from networking_odl.dhcp import odl_dhcp_driver_base as driver_base

LOG = logging.getLogger(__name__)


@registry.has_registry_receivers
class OdlDhcpDriver(driver_base.OdlDhcpDriverBase):

    @registry.receives(constants.ODL_SUBNET, [constants.BEFORE_COMPLETE])
    def handle_subnet_event(self, resource, event, trigger, payload):
        context = payload.context
        operation = payload.metadata['operation']
        row = payload.metadata['row']
        if (operation == constants.ODL_CREATE or
                operation == constants.ODL_UPDATE):
            try:
                subnet_ctxt = self._get_subnet_context(context,
                                                       row.data['network_id'],
                                                       row.data['id'])
                self.create_or_delete_dhcp_port(subnet_ctxt)
            except Exception as e:
                LOG.error("Error while processing %s subnet %s: %s", operation,
                          row.data['id'], e)

    # Note(lajoskatona): When subnet locking was introduced in neutron
    # (see [0]) that caused that subnet deletion wasn't triggered dhcp port
    # deletion any more.
    # To workaround this let's catch subnet after_delete event and delete port
    # if that is a dhcp port.
    # The new functionality can't be added to handle_subnet_event as here
    # subnet context is not available.
    # [0]: https://review.opendev.org/713045

    @registry.receives(constants.ODL_SUBNET, [constants.AFTER_DELETE])