Initial code for Southbound plugin to the OpenContrail Platform
[plugin2oc.git] / neutron / src / main / java / org / opendaylight / plugin2oc / neutron / PortHandler.java
diff --git a/neutron/src/main/java/org/opendaylight/plugin2oc/neutron/PortHandler.java b/neutron/src/main/java/org/opendaylight/plugin2oc/neutron/PortHandler.java
new file mode 100755 (executable)
index 0000000..bae5b9a
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * Copyright (C) 2014 Juniper Networks, Inc.
+ *
+ * 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.plugin2oc.neutron;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.util.List;
+import java.util.UUID;
+
+import net.juniper.contrail.api.ApiConnector;
+import net.juniper.contrail.api.ApiPropertyBase;
+import net.juniper.contrail.api.ObjectReference;
+import net.juniper.contrail.api.types.InstanceIp;
+import net.juniper.contrail.api.types.MacAddressesType;
+import net.juniper.contrail.api.types.Project;
+import net.juniper.contrail.api.types.VirtualMachine;
+import net.juniper.contrail.api.types.VirtualMachineInterface;
+import net.juniper.contrail.api.types.VirtualNetwork;
+import net.juniper.contrail.api.types.VnSubnetsType;
+
+import org.opendaylight.controller.networkconfig.neutron.INeutronPortAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
+import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handle requests for Neutron Port.
+ */
+public class PortHandler implements INeutronPortAware {
+    /**
+     * Logger instance.
+     */
+    static final Logger LOGGER = LoggerFactory.getLogger(PortHandler.class);
+    static ApiConnector apiConnector;
+
+    /**
+     * Invoked when a port creation is requested to check if the specified Port
+     * can be created and then creates the port
+     *
+     * @param NeutronPort
+     *            An instance of proposed new Neutron Port object.
+     * @return A HTTP status code to the creation request.
+     */
+    @Override
+    public int canCreatePort(NeutronPort neutronPort) {
+        apiConnector = Activator.apiConnector;
+        if (neutronPort == null) {
+            LOGGER.error("NeutronPort object can't be null..");
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        }
+        if (neutronPort.getID().equals("")) {
+            LOGGER.error("Port Device Id or Port Uuid can't be empty/null...");
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        }
+        if (neutronPort.getTenantID() == null) {
+            LOGGER.error("Tenant ID can't be null...");
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        }
+
+        List<Neutron_IPs> ips = neutronPort.getFixedIPs();
+        if (ips == null) {
+            LOGGER.warn("Neutron Fixed Ips can't be null..");
+            return HttpURLConnection.HTTP_FORBIDDEN;
+        }
+        try {
+            return createPort(neutronPort);
+        } catch (Exception e) {
+            LOGGER.error("exception :   ", e);
+            return HttpURLConnection.HTTP_INTERNAL_ERROR;
+        }
+    }
+
+    /**
+     * Invoked to create the specified Neutron port.
+     *
+     * @param network
+     *            An instance of new Neutron Port object.
+     *
+     * @return A HTTP status code to the creation request.
+     */
+    private int createPort(NeutronPort neutronPort) {
+        String networkID = neutronPort.getNetworkUUID();
+        String portID = neutronPort.getID();
+        String portDesc = neutronPort.getID();
+        String deviceID = neutronPort.getDeviceID();
+        String projectID = neutronPort.getTenantID();
+        String portMACAddress = neutronPort.getMacAddress();
+        VirtualMachineInterface virtualMachineInterface = null;
+        VirtualMachine virtualMachine = null;
+        VirtualNetwork virtualNetwork = null;
+        Project project = null;
+        MacAddressesType macAddressesType = new MacAddressesType();
+        try {
+            networkID = UUID.fromString(neutronPort.getNetworkUUID()).toString();
+            portID = UUID.fromString(neutronPort.getID()).toString();
+            if (neutronPort.getDeviceID() != null && !(("").equals(neutronPort.getDeviceID()))) {
+                if (!(deviceID.contains("-"))) {
+                    deviceID = uuidFormater(deviceID);
+                }
+                deviceID = UUID.fromString(deviceID).toString();
+            }
+            if (!(projectID.contains("-"))) {
+                projectID = uuidFormater(projectID);
+            }
+            projectID = UUID.fromString(projectID).toString();
+        } catch (Exception ex) {
+            LOGGER.error("exception :   ", ex);
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        }
+        try {
+            LOGGER.debug("portId:    " + portID);
+            virtualMachineInterface = (VirtualMachineInterface) apiConnector.findById(VirtualMachineInterface.class, portID);
+            if (virtualMachineInterface != null) {
+                LOGGER.warn("Port already exist.");
+                return HttpURLConnection.HTTP_FORBIDDEN;
+            } else {
+                if (deviceID != null && !(("").equals(deviceID))) {
+                    virtualMachine = (VirtualMachine) apiConnector.findById(VirtualMachine.class, deviceID);
+                    LOGGER.debug("virtualMachine:   " + virtualMachine);
+                    if (virtualMachine == null) {
+                        virtualMachine = new VirtualMachine();
+                        virtualMachine.setName(deviceID);
+                        virtualMachine.setUuid(deviceID);
+                        boolean virtualMachineCreated = apiConnector.create(virtualMachine);
+                        LOGGER.debug("virtualMachineCreated: " + virtualMachineCreated);
+                        if (!virtualMachineCreated) {
+                            LOGGER.warn("virtualMachine creation failed..");
+                            return HttpURLConnection.HTTP_INTERNAL_ERROR;
+                        }
+                        LOGGER.info("virtualMachine : " + virtualMachine.getName() + "  having UUID : " + virtualMachine.getUuid()
+                                + "  sucessfully created...");
+                    }
+                }
+                project = (Project) apiConnector.findById(Project.class, projectID);
+                if (project == null) {
+                    try {
+                        Thread.currentThread();
+                        Thread.sleep(3000);
+                    } catch (InterruptedException e) {
+                        LOGGER.error("InterruptedException :      ", e);
+                    }
+                    project = (Project) apiConnector.findById(Project.class, projectID);
+                    if (project == null) {
+                        LOGGER.error("Could not find projectUUID...");
+                        return HttpURLConnection.HTTP_NOT_FOUND;
+                    }
+                }
+                virtualNetwork = (VirtualNetwork) apiConnector.findById(VirtualNetwork.class, networkID);
+                LOGGER.info("virtualNetwork: " + virtualNetwork);
+                if (virtualNetwork == null) {
+                    LOGGER.warn("virtualNetwork does not exist..");
+                    return HttpURLConnection.HTTP_BAD_REQUEST;
+                } else {
+                    virtualMachineInterface = new VirtualMachineInterface();
+                    virtualMachineInterface.setUuid(portID);
+                    virtualMachineInterface.setName(portDesc);
+                    virtualMachineInterface.setParent(project);
+                    virtualMachineInterface.setVirtualNetwork(virtualNetwork);
+                    macAddressesType.addMacAddress(portMACAddress);
+                    virtualMachineInterface.setMacAddresses(macAddressesType);
+                    if (deviceID != null && !(("").equals(deviceID))) {
+                        virtualMachineInterface.setVirtualMachine(virtualMachine);
+                    }
+                    boolean virtualMachineInterfaceCreated = apiConnector.create(virtualMachineInterface);
+                    if (!virtualMachineInterfaceCreated) {
+                        LOGGER.warn("actual virtualMachineInterface creation failed..");
+                        return HttpURLConnection.HTTP_INTERNAL_ERROR;
+                    }
+                    LOGGER.info("virtualMachineInterface : " + virtualMachineInterface.getName() + "  having UUID : "
+                            + virtualMachineInterface.getUuid() + "  sucessfully created...");
+                }
+
+            }
+            INeutronSubnetCRUD systemCRUD = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
+            NeutronSubnet subnet = null;
+            List<Neutron_IPs> ips = neutronPort.getFixedIPs();
+            InstanceIp instanceIp = new InstanceIp();
+            String instaneIpUuid = UUID.randomUUID().toString();
+            for (Neutron_IPs ipValues : ips) {
+                if (ipValues.getIpAddress() == null) {
+                    subnet = systemCRUD.getSubnet(ipValues.getSubnetUUID());
+                    instanceIp.setAddress(subnet.getLowAddr());
+                } else {
+                    instanceIp.setAddress(ipValues.getIpAddress());
+                }
+            }
+
+            instanceIp.setName(instaneIpUuid);
+            instanceIp.setUuid(instaneIpUuid);
+            instanceIp.setParent(virtualMachineInterface);
+            instanceIp.setVirtualMachineInterface(virtualMachineInterface);
+            instanceIp.setVirtualNetwork(virtualNetwork);
+
+            boolean instanceIpCreated = apiConnector.create(instanceIp);
+            if (!instanceIpCreated) {
+                LOGGER.warn("instanceIp addition failed..");
+                return HttpURLConnection.HTTP_INTERNAL_ERROR;
+            }
+            LOGGER.info("Instance IP added sucessfully...");
+            return HttpURLConnection.HTTP_OK;
+        } catch (IOException ie) {
+            LOGGER.error("IOException :    ", ie);
+            return HttpURLConnection.HTTP_INTERNAL_ERROR;
+        }
+    }
+
+    /**
+     * Invoked to take action after a port has been created.
+     *
+     * @param network
+     *            An instance of new Neutron port object.
+     */
+    @Override
+    public void neutronPortCreated(NeutronPort neutronPort) {
+        VirtualMachineInterface virtualMachineInterface = null;
+        try {
+            virtualMachineInterface = (VirtualMachineInterface) apiConnector.findById(VirtualMachineInterface.class, neutronPort.getPortUUID());
+            if (virtualMachineInterface != null) {
+                LOGGER.info("Port creation verified....");
+            }
+        } catch (Exception e) {
+            LOGGER.error("Exception :    " + e);
+        }
+    }
+
+    /**
+     * Invoked when a port deletion is requested to check if the specified Port
+     * can be deleted and then delete the port
+     *
+     * @param NeutronPort
+     *            An instance of proposed Neutron Port object.
+     * @return A HTTP status code to the deletion request.
+     */
+    @Override
+    public int canDeletePort(NeutronPort neutronPort) {
+        if (neutronPort == null) {
+            LOGGER.info("Port object can't be null...");
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        }
+        apiConnector = Activator.apiConnector;
+        try {
+            return deletePort(neutronPort);
+        } catch (Exception e) {
+            LOGGER.error("exception :   ", e);
+            return HttpURLConnection.HTTP_INTERNAL_ERROR;
+        }
+    }
+
+    /**
+     * Invoked to delete the specified Neutron port.
+     *
+     * @param network
+     *            An instance of new Neutron Port object.
+     *
+     * @return A HTTP status code to the deletion request.
+     */
+    private int deletePort(NeutronPort neutronPort) {
+        String portID = neutronPort.getID();
+        String deviceID = neutronPort.getDeviceID();
+        VirtualMachineInterface virtualMachineInterface = null;
+        VirtualMachine virtualMachine = null;
+        InstanceIp instanceIP = null;
+        List<ObjectReference<ApiPropertyBase>> virtualMachineInterfaceBackRefs = null;
+        try {
+            virtualMachineInterface = (VirtualMachineInterface) apiConnector.findById(VirtualMachineInterface.class, portID);
+            if (virtualMachineInterface == null) {
+                LOGGER.info("Specified port does not exist...");
+                return HttpURLConnection.HTTP_BAD_REQUEST;
+            } else {
+                List<ObjectReference<ApiPropertyBase>> instanceIPs = virtualMachineInterface.getInstanceIpBackRefs();
+                if (instanceIPs != null) {
+                    for (ObjectReference<ApiPropertyBase> ref : instanceIPs) {
+                        String instanceIPUUID = ref.getUuid();
+                        if (instanceIPUUID != null) {
+                            instanceIP = (InstanceIp) apiConnector.findById(InstanceIp.class, instanceIPUUID);
+                            apiConnector.delete(instanceIP);
+                        }
+                    }
+                }
+                apiConnector.delete(virtualMachineInterface);
+                virtualMachine = (VirtualMachine) apiConnector.findById(VirtualMachine.class, deviceID);
+                if (virtualMachine != null) {
+                    virtualMachineInterfaceBackRefs = virtualMachine.getVirtualMachineInterfaceBackRefs();
+                    if (virtualMachineInterfaceBackRefs == null) {
+                        apiConnector.delete(virtualMachine);
+                    }
+                }
+                LOGGER.info("Specified port deleted sucessfully...");
+                return HttpURLConnection.HTTP_OK;
+            }
+        } catch (IOException io) {
+            LOGGER.error("Exception  :   " + io);
+            return HttpURLConnection.HTTP_INTERNAL_ERROR;
+        } catch (Exception e) {
+            LOGGER.error("Exception  :   " + e);
+            return HttpURLConnection.HTTP_INTERNAL_ERROR;
+        }
+    }
+
+    /**
+     * Invoked to take action after a port has been deleted.
+     *
+     * @param network
+     *            An instance of new Neutron port object.
+     */
+    @Override
+    public void neutronPortDeleted(NeutronPort neutronPort) {
+        VirtualMachineInterface virtualMachineInterface = new VirtualMachineInterface();
+        try {
+            virtualMachineInterface = (VirtualMachineInterface) apiConnector.findById(VirtualMachineInterface.class, neutronPort.getPortUUID());
+            if (virtualMachineInterface == null) {
+                LOGGER.info("Port deletion verified....");
+            }
+        } catch (Exception e) {
+            LOGGER.error("Exception :    " + e);
+        }
+    }
+
+    /**
+     * Invoked when a port update is requested to indicate if the specified port
+     * can be updated using the specified delta and update the port
+     *
+     * @param delta
+     *            Updates to the port object using patch semantics.
+     * @param original
+     *            An instance of the Neutron Port object to be updated.
+     *
+     * @return A HTTP status code to the update request.
+     */
+    @Override
+    public int canUpdatePort(NeutronPort deltaPort, NeutronPort originalPort) {
+        apiConnector = Activator.apiConnector;
+        VirtualMachineInterface virtualMachineInterface = null;
+        if (deltaPort == null || originalPort == null) {
+            LOGGER.error("Neutron Port objects can't be null..");
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        }
+        if (deltaPort.getMacAddress() != null) {
+            LOGGER.error("MAC Address for the port can't be updated..");
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        }
+        try {
+            virtualMachineInterface = (VirtualMachineInterface) apiConnector.findById(VirtualMachineInterface.class, originalPort.getPortUUID());
+            return updatePort(deltaPort, virtualMachineInterface, originalPort);
+        } catch (IOException ie) {
+            LOGGER.error("IOException:     " + ie);
+            return HttpURLConnection.HTTP_INTERNAL_ERROR;
+        } catch (Exception e) {
+            LOGGER.error("Exception:     " + e);
+            return HttpURLConnection.HTTP_INTERNAL_ERROR;
+        }
+    }
+
+    /**
+     * Invoked to update the port
+     *
+     * @param delta_network
+     *            An instance of Neutron Port.
+     * @param An
+     *            instance of new {@link VirtualMachineInterface} object.
+     *
+     * @return A HTTP status code to the updation request.
+     */
+    private int updatePort(NeutronPort deltaPort, VirtualMachineInterface virtualMachineInterface, NeutronPort originalPort) throws IOException {
+        VirtualMachine virtualMachine = null;
+        String deviceID = deltaPort.getDeviceID();
+        String portName = deltaPort.getName();
+        List<Neutron_IPs> fixedIPs = deltaPort.getFixedIPs();
+        boolean instanceIpUpdate = false;
+        String networkUUID = deltaPort.getNetworkUUID();
+        VirtualNetwork virtualnetwork = null;
+        if (fixedIPs != null) {
+            if (networkUUID == null) {
+                for (ObjectReference<ApiPropertyBase> networks : virtualMachineInterface.getVirtualNetwork()) {
+                    networkUUID = networks.getUuid();
+                }
+            }
+            boolean subnetExist = false;
+            virtualnetwork = (VirtualNetwork) apiConnector.findById(VirtualNetwork.class, networkUUID);
+            if (virtualnetwork == null) {
+                LOGGER.error(" Virtual network does not exist");
+                return HttpURLConnection.HTTP_FORBIDDEN;
+            }
+            if (virtualnetwork != null && virtualnetwork.getNetworkIpam() != null) {
+                for (Neutron_IPs fixedIp : fixedIPs) {
+                    for (ObjectReference<VnSubnetsType> ref : virtualnetwork.getNetworkIpam()) {
+                        VnSubnetsType vnSubnetsType = ref.getAttr();
+                        if (vnSubnetsType != null) {
+                            List<VnSubnetsType.IpamSubnetType> subnets = vnSubnetsType.getIpamSubnets();
+                            if (subnets != null) {
+                                for (VnSubnetsType.IpamSubnetType subnetValue : subnets) {
+                                    Boolean doesSubnetExist = subnetValue.getSubnetUuid().matches(fixedIp.getSubnetUUID());
+                                    if (doesSubnetExist) {
+                                        subnetExist = true;
+                                        for (ObjectReference<ApiPropertyBase> instanceIp : virtualMachineInterface.getInstanceIpBackRefs()) {
+                                            InstanceIp instanceIpLocal = (InstanceIp) apiConnector.findById(InstanceIp.class, instanceIp.getUuid());
+                                            instanceIpLocal.setVirtualNetwork(virtualnetwork);
+                                            INeutronSubnetCRUD systemCRUD = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
+                                            NeutronSubnet subnet = null;
+                                            for (Neutron_IPs ip : originalPort.getFixedIPs()) {
+                                                subnet = systemCRUD.getSubnet(ip.getSubnetUUID());
+                                                subnet.releaseIP(ip.getIpAddress());
+                                            }
+                                            if (fixedIp.getIpAddress() == null) {
+                                                subnet = systemCRUD.getSubnet(fixedIp.getSubnetUUID());
+                                                instanceIpLocal.setAddress(subnet.getLowAddr());
+                                            } else {
+                                                instanceIpLocal.setAddress(fixedIp.getIpAddress());
+                                            }
+                                            instanceIpUpdate = apiConnector.update(instanceIpLocal);
+                                            virtualMachineInterface.setVirtualNetwork(virtualnetwork);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if (!subnetExist) {
+                LOGGER.error("Subnet UUID must exist in the network..");
+                return HttpURLConnection.HTTP_BAD_REQUEST;
+            }
+        } else if (networkUUID != null && fixedIPs == null) {
+            LOGGER.error("Subnet UUID must exist in the network..");
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        }
+        if (deviceID != null) {
+            if (("").equals(deviceID)) {
+                virtualMachineInterface.clearVirtualMachine();
+            } else {
+                deviceID = UUID.fromString(deltaPort.getDeviceID()).toString();
+                try {
+                    virtualMachine = (VirtualMachine) apiConnector.findById(VirtualMachine.class, deviceID);
+                } catch (Exception e) {
+                    LOGGER.error("Exception:     " + e);
+                    return HttpURLConnection.HTTP_INTERNAL_ERROR;
+                }
+                if (virtualMachine == null) {
+                    virtualMachine = new VirtualMachine();
+                    virtualMachine.setName(deviceID);
+                    virtualMachine.setUuid(deviceID);
+                    boolean virtualMachineCreated = apiConnector.create(virtualMachine);
+                    LOGGER.debug("virtualMachineCreated: " + virtualMachineCreated);
+                    if (!virtualMachineCreated) {
+                        LOGGER.warn("virtualMachine creation failed..");
+                        return HttpURLConnection.HTTP_INTERNAL_ERROR;
+                    }
+                    LOGGER.info("virtualMachine : " + virtualMachine.getName() + "  having UUID : " + virtualMachine.getUuid()
+                            + "  sucessfully created...");
+                }
+                virtualMachineInterface.setVirtualMachine(virtualMachine);
+            }
+        }
+        if (portName != null) {
+            virtualMachineInterface.setDisplayName(portName);
+        }
+        if ((deviceID != null && !(("").equals(deviceID))) || portName != null || instanceIpUpdate) {
+            if ((deviceID != null && !(("").equals(deviceID))) || portName != null) {
+                boolean portUpdate = apiConnector.update(virtualMachineInterface);
+                if (!portUpdate) {
+                    LOGGER.warn("Port Updation failed..");
+                    return HttpURLConnection.HTTP_INTERNAL_ERROR;
+                }
+            }
+            LOGGER.info("Port having UUID : " + virtualMachineInterface.getUuid() + "  has been sucessfully updated...");
+            return HttpURLConnection.HTTP_OK;
+        } else {
+            LOGGER.info("Nothing to update...");
+            return HttpURLConnection.HTTP_BAD_REQUEST;
+        }
+    }
+
+    /**
+     * Invoked to take action after a port has been updated.
+     *
+     * @param network
+     *            An instance of modified Neutron Port object.
+     */
+    @Override
+    public void neutronPortUpdated(NeutronPort neutronPort) {
+        try {
+            VirtualMachineInterface virtualMachineInterface;
+            virtualMachineInterface = (VirtualMachineInterface) apiConnector.findById(VirtualMachineInterface.class, neutronPort.getPortUUID());
+            if (("").equals(neutronPort.getDeviceID())) { // TODO : VM Refs not getting cleared correctly - to be fixed
+                if (neutronPort.getName().matches(virtualMachineInterface.getDisplayName()) && virtualMachineInterface.getVirtualMachine() == null) {
+                    LOGGER.info("Port updatation verified....");
+                }
+            } else if (neutronPort.getName().matches(virtualMachineInterface.getDisplayName())
+                    && neutronPort.getDeviceID().matches(virtualMachineInterface.getVirtualMachine().get(0).getUuid())) {
+                LOGGER.info("Port updatation verified....");
+            } else {
+                LOGGER.info("Port updatation failed....");
+            }
+        } catch (Exception e) {
+            LOGGER.error("Exception :" + e);
+        }
+    }
+
+    /**
+     * Invoked to format the UUID if UUID is not in correct format.
+     *
+     * @param String
+     *            An instance of UUID string.
+     *
+     * @return Correctly formated UUID string.
+     */
+    private String uuidFormater(String uuid) {
+        String uuidPattern = null;
+        try {
+            String id1 = uuid.substring(0, 8);
+            String id2 = uuid.substring(8, 12);
+            String id3 = uuid.substring(12, 16);
+            String id4 = uuid.substring(16, 20);
+            String id5 = uuid.substring(20, 32);
+            uuidPattern = (id1 + "-" + id2 + "-" + id3 + "-" + id4 + "-" + id5);
+
+        } catch (Exception e) {
+            LOGGER.error("UUID is not in correct format ");
+            LOGGER.error("Exception :" + e);
+        }
+        return uuidPattern;
+    }
+}