<commit_before>/*
 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.netvirt.neutronvpn;

import static org.opendaylight.netvirt.neutronvpn.NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier;

import edu.umd.cs.findbugs.annotations.CheckReturnValue;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.infrautils.utils.concurrent.Executors;
import org.opendaylight.infrautils.utils.concurrent.NamedLocks;
import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.AcquireResult;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPortsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPortsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMapping;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.Floatingips;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Singleton
public class NeutronFloatingToFixedIpMappingChangeListener extends AbstractAsyncDataTreeChangeListener<Floatingip> {
    private static final Logger LOG = LoggerFactory.getLogger(NeutronFloatingToFixedIpMappingChangeListener.class);
    private static final long LOCK_WAIT_TIME = 10L;

    private final DataBroker dataBroker;
    private final NamedLocks<String> routerLock = new NamedLocks<>();

    @Inject
    public NeutronFloatingToFixedIpMappingChangeListener(final DataBroker dataBroker) {
        super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Neutron.class)
                        .child(Floatingips.class).child(Floatingip.class),
                Executors.newSingleThreadExecutor("NeutronFloatingToFixedIpMappingChangeListener", LOG));
        this.dataBroker = dataBroker;
    }

    public void init() {
        LOG.info("{} init", getClass().getSimpleName());
    }

    @Override
    @PreDestroy
    public void close() {
        super.close();
        Executors.shutdownAndAwaitTermination(getExecutorService());
    }

    @Override
    public void add(InstanceIdentifier<Floatingip> identifier, Floatingip input) {
        LOG.trace("Neutron Floating IP created: key: {}, value={}", identifier, input);
        IpAddress fixedIp = input.getFixedIpAddress();
        String floatingIp = input.getFloatingIpAddress().getIpv4Address().getValue();
        if (fixedIp != null) {
            addToFloatingIpInfo(input.getRouterId().getValue(), input.getFloatingNetworkId(), input.getPortId()
                    .getValue(), fixedIp.getIpv4Address().getValue(), floatingIp, input.getUuid());
        }
    }

    @Override
    public void remove(InstanceIdentifier<Floatingip> identifier, Floatingip input) {
        LOG.trace("Neutron Floating IP deleted : key: {}, value={}", identifier, input);
        IpAddress fixedIp = input.getFixedIpAddress();
        if (fixedIp != null) {
            // update FloatingIpPortInfo to set isFloatingIpDeleted as true to enable deletion of FloatingIpPortInfo
            // map once it is used for processing in the NAT removal path
            updateFloatingIpPortInfo(input.getUuid(), input.getPortId());
            clearFromFloatingIpInfo(input.getRouterId().getValue(), input.getPortId().getValue(), fixedIp
                    .getIpv4Address().getValue());
        } else {
            // delete FloatingIpPortInfo mapping since floating IP is deleted and no fixed IP is associated to it
            removeFromFloatingIpPortInfo(input.getUuid());
        }
    }

    // populate the floating to fixed ip map upon association/dissociation from fixed ip
    @Override
    public void update(InstanceIdentifier<Floatingip> identifier, Floatingip original, Floatingip update) {
        LOG.trace("Handling FloatingIptoFixedIp mapping : key: {}, original value={}, update value={}", identifier,
                original, update);
        IpAddress oldFixedIp = original.getFixedIpAddress();
        IpAddress newFixedIp = update.getFixedIpAddress();
        String floatingIp = update.getFloatingIpAddress().getIpv4Address().getValue();

        if (oldFixedIp != null && !oldFixedIp.equals(newFixedIp)) {
            clearFromFloatingIpInfo(original.getRouterId().getValue(), original.getPortId().getValue(), oldFixedIp
                    .getIpv4Address().getValue());
        }
        if (newFixedIp != null && !newFixedIp.equals(oldFixedIp)) {
            addToFloatingIpInfo(update.getRouterId().getValue(), update.getFloatingNetworkId(), update.getPortId()
                    .getValue(), newFixedIp.getIpv4Address().getValue(), floatingIp, update.getUuid());
        }
    }

    // TODO Clean up the exception handling
    @SuppressWarnings("checkstyle:IllegalCatch")
    private void addToFloatingIpInfo(String routerName, Uuid extNetworkId, String fixedNeutronPortName, String
            fixedIpAddress, String floatingIpAddress, Uuid floatingIpId) {
        RouterPortsBuilder routerPortsBuilder;
        InstanceIdentifier<RouterPorts> routerPortsIdentifier = InstanceIdentifier.builder(FloatingIpInfo.class)
                .child(RouterPorts.class, new RouterPortsKey(routerName)).build();
        try {
            Optional<RouterPorts> optionalRouterPorts =
                    SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
                            routerPortsIdentifier);
            if (optionalRouterPorts.isPresent()) {
                LOG.debug("Updating routerPorts node {} in floatingIpInfo DS for floating IP {} on fixed "
                    + "neutron port {} : ", routerName, floatingIpAddress, fixedNeutronPortName);
                routerPortsBuilder = new RouterPortsBuilder(optionalRouterPorts.get());
            } else {
                LOG.debug("Creating new routerPorts node {} in floatingIpInfo DS for floating IP {} on fixed "
                    + "neutron port {} : ", routerName, floatingIpAddress, fixedNeutronPortName);
                routerPortsBuilder =
                    new RouterPortsBuilder().withKey(new RouterPortsKey(routerName)).setRouterId(routerName);
            }
            if (extNetworkId != null) {
                routerPortsBuilder.setExternalNetworkId(extNetworkId);
            }
            if (fixedNeutronPortName != null) {
                List<Ports> portsList = routerPortsBuilder.getPorts() != null
                        ? new ArrayList<Ports>(routerPortsBuilder.getPorts().values()) : new ArrayList<Ports>();
                PortsBuilder fixedNeutronPortBuilder = null;
                for (Ports neutronPort : portsList) {
                    if (neutronPort.getPortName().equals(fixedNeutronPortName)) {
                        fixedNeutronPortBuilder = new PortsBuilder(neutronPort);
                        break;
                    }
                }
                if (fixedNeutronPortBuilder == null) {
                    fixedNeutronPortBuilder = new PortsBuilder().withKey(new PortsKey(fixedNeutronPortName))
                            .setPortName(fixedNeutronPortName);
                }
                if (fixedIpAddress != null) {
                    List<InternalToExternalPortMap> intExtPortMapList
                            = new ArrayList<InternalToExternalPortMap>(fixedNeutronPortBuilder
                            .getInternalToExternalPortMap().values());
                    if (intExtPortMapList == null) {
                        intExtPortMapList = new ArrayList<>();
                    }
                    InternalToExternalPortMap intExtPortMap = new InternalToExternalPortMapBuilder().withKey(new
                            InternalToExternalPortMapKey(fixedIpAddress)).setInternalIp(fixedIpAddress)
                            .setExternalIp(floatingIpAddress).setExternalId(floatingIpId).build();
                    intExtPortMapList.add(intExtPortMap);
                    fixedNeutronPortBuilder.setInternalToExternalPortMap(intExtPortMapList);
                }
                portsList.add(fixedNeutronPortBuilder.build());
                routerPortsBuilder.setPorts(portsList);
            }

            try (AcquireResult lock = tryRouterLock(routerName)) {
                if (!lock.wasAcquired()) {
                    // FIXME: why do we even bother with locking if we do not honor it?!
                    logTryLockFailure(routerName);
                }

                LOG.debug("Creating/Updating routerPorts node {} in floatingIpInfo DS for floating IP {} on fixed "
                        + "neutron port {} : ", routerName, floatingIpAddress, fixedNeutronPortName);
                MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsIdentifier,
                    routerPortsBuilder.build());
                LOG.debug("FloatingIpInfo DS updated for floating IP {} ", floatingIpAddress);<commit_msg>Netvirt CSIT Exception from NAT Module<commit_after>/*
 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.netvirt.neutronvpn;

import static org.opendaylight.netvirt.neutronvpn.NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier;

import edu.umd.cs.findbugs.annotations.CheckReturnValue;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
import org.opendaylight.infrautils.utils.concurrent.Executors;
import org.opendaylight.infrautils.utils.concurrent.NamedLocks;
import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.AcquireResult;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPortsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPortsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMapping;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.Floatingips;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Singleton
public class NeutronFloatingToFixedIpMappingChangeListener extends AbstractAsyncDataTreeChangeListener<Floatingip> {
    private static final Logger LOG = LoggerFactory.getLogger(NeutronFloatingToFixedIpMappingChangeListener.class);
    private static final long LOCK_WAIT_TIME = 10L;

    private final DataBroker dataBroker;
    private final NamedLocks<String> routerLock = new NamedLocks<>();

    @Inject
    public NeutronFloatingToFixedIpMappingChangeListener(final DataBroker dataBroker) {
        super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Neutron.class)
                        .child(Floatingips.class).child(Floatingip.class),
                Executors.newSingleThreadExecutor("NeutronFloatingToFixedIpMappingChangeListener", LOG));
        this.dataBroker = dataBroker;
    }

    public void init() {
        LOG.info("{} init", getClass().getSimpleName());
    }

    @Override
    @PreDestroy
    public void close() {
        super.close();
        Executors.shutdownAndAwaitTermination(getExecutorService());
    }

    @Override
    public void add(InstanceIdentifier<Floatingip> identifier, Floatingip input) {
        LOG.trace("Neutron Floating IP created: key: {}, value={}", identifier, input);
        IpAddress fixedIp = input.getFixedIpAddress();
        String floatingIp = input.getFloatingIpAddress().getIpv4Address().getValue();
        if (fixedIp != null) {
            addToFloatingIpInfo(input.getRouterId().getValue(), input.getFloatingNetworkId(), input.getPortId()
                    .getValue(), fixedIp.getIpv4Address().getValue(), floatingIp, input.getUuid());
        }
    }

    @Override
    public void remove(InstanceIdentifier<Floatingip> identifier, Floatingip input) {
        LOG.trace("Neutron Floating IP deleted : key: {}, value={}", identifier, input);
        IpAddress fixedIp = input.getFixedIpAddress();
        if (fixedIp != null) {
            // update FloatingIpPortInfo to set isFloatingIpDeleted as true to enable deletion of FloatingIpPortInfo
            // map once it is used for processing in the NAT removal path
            updateFloatingIpPortInfo(input.getUuid(), input.getPortId());
            clearFromFloatingIpInfo(input.getRouterId().getValue(), input.getPortId().getValue(), fixedIp
                    .getIpv4Address().getValue());
        } else {
            // delete FloatingIpPortInfo mapping since floating IP is deleted and no fixed IP is associated to it
            removeFromFloatingIpPortInfo(input.getUuid());
        }
    }

    // populate the floating to fixed ip map upon association/dissociation from fixed ip
    @Override
    public void update(InstanceIdentifier<Floatingip> identifier, Floatingip original, Floatingip update) {
        LOG.trace("Handling FloatingIptoFixedIp mapping : key: {}, original value={}, update value={}", identifier,
                original, update);
        IpAddress oldFixedIp = original.getFixedIpAddress();
        IpAddress newFixedIp = update.getFixedIpAddress();
        String floatingIp = update.getFloatingIpAddress().getIpv4Address().getValue();

        if (oldFixedIp != null && !oldFixedIp.equals(newFixedIp)) {
            clearFromFloatingIpInfo(original.getRouterId().getValue(), original.getPortId().getValue(), oldFixedIp
                    .getIpv4Address().getValue());
        }
        if (newFixedIp != null && !newFixedIp.equals(oldFixedIp)) {
            addToFloatingIpInfo(update.getRouterId().getValue(), update.getFloatingNetworkId(), update.getPortId()
                    .getValue(), newFixedIp.getIpv4Address().getValue(), floatingIp, update.getUuid());
        }
    }

    // TODO Clean up the exception handling
    @SuppressWarnings("checkstyle:IllegalCatch")
    private void addToFloatingIpInfo(String routerName, Uuid extNetworkId, String fixedNeutronPortName, String
            fixedIpAddress, String floatingIpAddress, Uuid floatingIpId) {
        RouterPortsBuilder routerPortsBuilder;
        InstanceIdentifier<RouterPorts> routerPortsIdentifier = InstanceIdentifier.builder(FloatingIpInfo.class)
                .child(RouterPorts.class, new RouterPortsKey(routerName)).build();
        try {
            Optional<RouterPorts> optionalRouterPorts =
                    SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
                            routerPortsIdentifier);
            if (optionalRouterPorts.isPresent()) {
                LOG.debug("Updating routerPorts node {} in floatingIpInfo DS for floating IP {} on fixed "
                    + "neutron port {} : ", routerName, floatingIpAddress, fixedNeutronPortName);
                routerPortsBuilder = new RouterPortsBuilder(optionalRouterPorts.get());
            } else {
                LOG.debug("Creating new routerPorts node {} in floatingIpInfo DS for floating IP {} on fixed "
                    + "neutron port {} : ", routerName, floatingIpAddress, fixedNeutronPortName);
                routerPortsBuilder =
                    new RouterPortsBuilder().withKey(new RouterPortsKey(routerName)).setRouterId(routerName);
            }
            if (extNetworkId != null) {
                routerPortsBuilder.setExternalNetworkId(extNetworkId);
            }
            if (fixedNeutronPortName != null) {
                List<Ports> portsList = routerPortsBuilder.getPorts() != null
                        ? new ArrayList<Ports>(routerPortsBuilder.getPorts().values()) : new ArrayList<Ports>();
                PortsBuilder fixedNeutronPortBuilder = null;
                for (Ports neutronPort : portsList) {
                    if (neutronPort.getPortName().equals(fixedNeutronPortName)) {
                        fixedNeutronPortBuilder = new PortsBuilder(neutronPort);
                        break;
                    }
                }
                if (fixedNeutronPortBuilder == null) {
                    fixedNeutronPortBuilder = new PortsBuilder().withKey(new PortsKey(fixedNeutronPortName))
                            .setPortName(fixedNeutronPortName);
                }
                if (fixedIpAddress != null) {
                    List<InternalToExternalPortMap> intExtPortMapList
                            = new ArrayList<InternalToExternalPortMap>(fixedNeutronPortBuilder
                            .getInternalToExternalPortMap().size() != 0 ? fixedNeutronPortBuilder
                            .getInternalToExternalPortMap().values() : null);
                    if (intExtPortMapList == null) {
                        intExtPortMapList = new ArrayList<>();
                    }
                    InternalToExternalPortMap intExtPortMap = new InternalToExternalPortMapBuilder().withKey(new
                            InternalToExternalPortMapKey(fixedIpAddress)).setInternalIp(fixedIpAddress)
                            .setExternalIp(floatingIpAddress).setExternalId(floatingIpId).build();
                    intExtPortMapList.add(intExtPortMap);
                    fixedNeutronPortBuilder.setInternalToExternalPortMap(intExtPortMapList);
                }
                portsList.add(fixedNeutronPortBuilder.build());
                routerPortsBuilder.setPorts(portsList);
            }

            try (AcquireResult lock = tryRouterLock(routerName)) {
                if (!lock.wasAcquired()) {
                    // FIXME: why do we even bother with locking if we do not honor it?!
                    logTryLockFailure(routerName);
                }

                LOG.debug("Creating/Updating routerPorts node {} in floatingIpInfo DS for floating IP {} on fixed "
                        + "neutron port {} : ", routerName, floatingIpAddress, fixedNeutronPortName);
                MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsIdentifier,
                    routerPortsBuilder.build());
                LOG.debug("FloatingIpInfo DS updated for floating IP {} ", floatingIpAddress);
{'fraction_non_alphanumeric': 0.09505736220132839, 'fraction_numerical': 0.012033123436556542, 'mean_word_length': 3.2028276237085374, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '989390', 'n_tokens_mistral': 6890, 'n_tokens_neox': 6554, 'n_words': 1062}