When the controller already exists, the caller still expects to get its uuid.
[ovsdb.git] / ovsdb / src / main / java / org / opendaylight / ovsdb / plugin / ConfigurationService.java
index c01f3c55c8d2f064f3d3efe1b8e703aaa721ab46..5184457745ddf9fb97d8fd083349c8f26f9893eb 100755 (executable)
@@ -2,12 +2,8 @@ package org.opendaylight.ovsdb.plugin;
 
 import java.math.BigInteger;
 import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
-import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -15,13 +11,11 @@ import java.util.Map;
 
 import org.eclipse.osgi.framework.console.CommandInterpreter;
 import org.eclipse.osgi.framework.console.CommandProvider;
-import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
 import org.opendaylight.controller.sal.connection.ConnectionConstants;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.networkconfig.bridgedomain.ConfigConstants;
 import org.opendaylight.controller.sal.networkconfig.bridgedomain.IPluginInBridgeDomainConfigService;
-import org.opendaylight.controller.sal.utils.NetUtils;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
 import org.opendaylight.ovsdb.lib.database.OVSInstance;
@@ -69,7 +63,6 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
 
     IConnectionServiceInternal connectionService;
     InventoryServiceInternal inventoryServiceInternal;
-    private IClusterGlobalServices clusterServices;
     boolean forceConnect = false;
 
     void init() {
@@ -129,16 +122,6 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
         }
     }
 
-    public void setClusterServices(IClusterGlobalServices i) {
-        this.clusterServices = i;
-    }
-
-    public void unsetClusterServices(IClusterGlobalServices i) {
-        if (this.clusterServices == i) {
-            this.clusterServices = null;
-        }
-    }
-
     private Connection getConnection (Node node) {
         Connection connection = connectionService.getConnection(node);
         if (connection == null || !connection.getChannel().isActive()) {
@@ -263,7 +246,7 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
             }
             return status;
         } catch(Exception e){
-            e.printStackTrace();
+            logger.error("Error in createBridgeDomain(): ",e);
         }
         return new Status(StatusCode.INTERNALERROR);
     }
@@ -387,7 +370,7 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
                 return new Status(StatusCode.INTERNALERROR);
             }
         } catch(Exception e){
-            e.printStackTrace();
+            logger.error("Error in addPort()",e);
         }
         return new Status(StatusCode.INTERNALERROR);
     }
@@ -454,7 +437,7 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
 
             }
         }catch(Exception e){
-            e.printStackTrace();
+            logger.error("Error in setManager(): ",e);
         }
         return true;
     }
@@ -553,7 +536,7 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
             }
             return status;
         } catch(Exception e){
-            e.printStackTrace();
+            logger.error("Error in deletePort()",e);
         }
         return new Status(StatusCode.INTERNALERROR);
     }
@@ -642,13 +625,13 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
 
             if (tr.size() > requests.size()) {
                 OperationResult result = tr.get(tr.size() - 1);
-                logger.error("Error creating Bridge : {}\n Error : {}\n Details : {}",
+                logger.error("Error deleting Bridge : {}\n Error : {}\n Details : {}",
                         bridgeIdentifier, result.getError(), result.getDetails());
                 status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
             }
             return status;
         } catch (Exception e) {
-            e.printStackTrace();
+            logger.error("Error in deleteBridgeDomain(): ",e);
         }
         return new Status(StatusCode.INTERNALERROR);
     }
@@ -677,166 +660,30 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
         return null;
     }
 
-    private short getControllerOFPort() {
-        Short defaultOpenFlowPort = 6633;
-        Short openFlowPort = defaultOpenFlowPort;
-        String portString = System.getProperty("of.listenPort");
-        if (portString != null) {
-            try {
-                openFlowPort = Short.decode(portString).shortValue();
-            } catch (NumberFormatException e) {
-                logger.warn("Invalid port:{}, use default({})", portString,
-                        openFlowPort);
-            }
-        }
-        return openFlowPort;
-    }
-
-    private List<InetAddress> getControllerIPAddresses() {
-        List<InetAddress> controllers = null;
-        if (clusterServices != null) {
-            controllers = clusterServices.getClusteredControllers();
-            if (controllers != null && controllers.size() > 0) {
-                if (controllers.size() == 1) {
-                    InetAddress controller = controllers.get(0);
-                    if (!controller.equals(InetAddress.getLoopbackAddress())) {
-                        return controllers;
-                    }
-                } else {
-                    return controllers;
-                }
-            }
-        }
-
-        controllers = new ArrayList<InetAddress>();
-        String addressString = System.getProperty("of.address");
-        if (addressString != null) {
-            InetAddress controllerIP = null;
-            try {
-                controllerIP = InetAddress.getByName(addressString);
-                if (controllerIP != null) {
-                    controllers.add(controllerIP);
-                    return controllers;
-                }
-            } catch (Exception e) {
-                logger.debug("Invalid IP: {}, use wildcard *", addressString);
-            }
-        }
-
-        Enumeration<NetworkInterface> nets;
-        try {
-            nets = NetworkInterface.getNetworkInterfaces();
-            for (NetworkInterface netint : Collections.list(nets)) {
-                Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
-                for (InetAddress inetAddress : Collections.list(inetAddresses)) {
-                    if (!inetAddress.isLoopbackAddress() &&
-                            NetUtils.isIPv4AddressValid(inetAddress.getHostAddress())) {
-                        controllers.add(inetAddress);
-                    }
-                }
-            }
-        } catch (SocketException e) {
-            controllers.add(InetAddress.getLoopbackAddress());
+    Boolean setBridgeOFController(Node node, String bridgeIdentifier) {
+        if (connectionService == null) {
+            logger.error("Couldn't refer to the ConnectionService");
+            return false;
         }
-        return controllers;
-    }
 
-    public Boolean setBridgeOFController(Node node, String bridgeIdentifier) {
         try{
-            if (connectionService == null) {
-                logger.error("Couldn't refer to the ConnectionService");
-                return false;
-            }
-            Connection connection = this.getConnection(node);
-            if (connection == null) {
-                return false;
-            }
-
-            if (connection != null) {
-                List<InetAddress> ofControllerAddrs = getControllerIPAddresses();
-                short ofControllerPort = getControllerOFPort();
-                OvsDBSet<UUID> controllerUUIDs = new OvsDBSet<UUID>();
-                List<Operation> controllerInsertOperations = new ArrayList<Operation>();
-                Map<String, Table<?>> controllerCache = inventoryServiceInternal.getTableCache(node, Controller.NAME.getName());
-
-                int count = 0;
-                for (InetAddress ofControllerAddress : ofControllerAddrs) {
-                    String cntrlUuid = null;
-                    String newController = "tcp:"+ofControllerAddress.getHostAddress()+":"+ofControllerPort;
-                    if (controllerCache != null) {
-                        for (String uuid : controllerCache.keySet()) {
-                            Controller controller = (Controller)controllerCache.get(uuid);
-                            if (controller.getTarget().equals(newController)) {
-                                cntrlUuid = uuid;
-                                controllerUUIDs.add(new UUID(uuid));
-                                break;
-                            }
-                        }
-                    }
-                    if (cntrlUuid == null) {
-                        count++;
-                        String uuid_name = "new_controller_"+count;
-                        controllerUUIDs.add(new UUID(uuid_name));
-                        Controller controllerRow = new Controller();
-                        controllerRow.setTarget(newController);
-                        InsertOperation addCtlRequest = new InsertOperation(Controller.NAME.getName(), uuid_name, controllerRow);
-                        controllerInsertOperations.add(addCtlRequest);
-                    }
-                }
-                String brCntrlUuid = null;
-                Map<String, Table<?>> brTableCache = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
-                for (String uuid : brTableCache.keySet()) {
-                    Bridge bridge = (Bridge)brTableCache.get(uuid);
-                    if (bridge.getName().contains(bridgeIdentifier)) {
-                        brCntrlUuid = uuid;
-                    }
-                }
-                Operation addControlRequest = null;
-                Mutation bm = new Mutation("controller", Mutator.INSERT, controllerUUIDs);
-                List<Mutation> mutations = new ArrayList<Mutation>();
-                mutations.add(bm);
-
-                UUID uuid = new UUID(brCntrlUuid);
-                Condition condition = new Condition("_uuid", Function.EQUALS, uuid);
-                List<Condition> where = new ArrayList<Condition>();
-                where.add(condition);
-                addControlRequest = new MutateOperation(Bridge.NAME.getName(), where, mutations);
-
-                TransactBuilder transaction = new TransactBuilder();
-                transaction.addOperations(controllerInsertOperations);
-                transaction.addOperation(addControlRequest);
-
-                ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
-                List<OperationResult> tr = transResponse.get();
-                List<Operation> requests = transaction.getRequests();
-                Status status = new Status(StatusCode.SUCCESS);
-                for (int i = 0; i < tr.size() ; i++) {
-                    if (i < requests.size()) requests.get(i).setResult(tr.get(i));
-                    if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
-                        OperationResult result = tr.get(i);
-                        status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
-                    }
-                }
-
-                if (tr.size() > requests.size()) {
-                    OperationResult result = tr.get(tr.size()-1);
-                    logger.error("Error creating Bridge : {}\n Error : {}\n Details : {}", bridgeIdentifier,
-                            result.getError(),
-                            result.getDetails());
-                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
-
+            Map<String, Table<?>> brTableCache = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
+            for (String uuid : brTableCache.keySet()) {
+                Bridge bridge = (Bridge)brTableCache.get(uuid);
+                if (bridge.getName().contains(bridgeIdentifier)) {
+                    return connectionService.setOFController(node, uuid);
                 }
             }
-        }catch(Exception e){
-            e.printStackTrace();
+        } catch(Exception e) {
+            logger.error("Error in setBridgeOFController()",e);
         }
-        return true;
+        return false;
     }
 
     @Override
-    public Status insertRow(Node node, String tableName, String parent_uuid, Table<?> row) {
+    public StatusWithUuid insertRow(Node node, String tableName, String parent_uuid, Table<?> row) {
         logger.info("tableName : {}, parent_uuid : {} Row : {}", tableName, parent_uuid, row.toString());
-        Status statusWithUUID = null;
+        StatusWithUuid statusWithUUID = null;
 
         // Schema based Table handling will help fix this static Table handling.
 
@@ -936,7 +783,7 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
             }
             return status;
         } catch(Exception e){
-            e.printStackTrace();
+            logger.error("Error in updateRow(): ",e);
         }
         return new Status(StatusCode.INTERNALERROR);
     }
@@ -1042,22 +889,16 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
         return null;
     }
 
-    private Status insertBridgeRow(Node node, String open_VSwitch_uuid, Bridge bridgeRow) {
-        try{
-            if (connectionService == null) {
-                logger.error("Couldn't refer to the ConnectionService");
-                return new Status(StatusCode.NOSERVICE);
-            }
+    private StatusWithUuid insertBridgeRow(Node node, String open_VSwitch_uuid, Bridge bridgeRow) {
 
-            Connection connection = this.getConnection(node);
-            if (connection == null) {
-                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
-            }
+        String insertErrorMsg = "bridge";
+        String rowName=bridgeRow.getName();
 
+        try{
             Map<String, Table<?>> ovsTable = inventoryServiceInternal.getTableCache(node, Open_vSwitch.NAME.getName());
 
             if (ovsTable == null) {
-                return new Status(StatusCode.NOTFOUND, "There are no Open_vSwitch instance in the Open_vSwitch table");
+                return new StatusWithUuid(StatusCode.NOTFOUND, "There are no Open_vSwitch instance in the Open_vSwitch table");
             }
 
             String newBridge = "new_bridge";
@@ -1086,50 +927,24 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
 
             int bridgeInsertIndex = transaction.getRequests().indexOf(addBridgeRequest);
 
-            ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
-            List<OperationResult> tr = transResponse.get();
-            List<Operation> requests = transaction.getRequests();
-            Status status = new Status(StatusCode.SUCCESS);
-            for (int i = 0; i < tr.size() ; i++) {
-                if (i < requests.size()) requests.get(i).setResult(tr.get(i));
-                if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
-                    OperationResult result = tr.get(i);
-                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
-                }
-            }
+            return _insertTableRow(node,transaction,bridgeInsertIndex,insertErrorMsg,rowName);
 
-            if (tr.size() > requests.size()) {
-                OperationResult result = tr.get(tr.size()-1);
-                logger.error("Error creating Bridge : {}\n Error : {}\n Details : {}", bridgeRow.getName(),
-                                                                                       result.getError(),
-                                                                                       result.getDetails());
-                status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
-            }
-            if (status.isSuccess()) {
-                UUID bridgeUUID = tr.get(bridgeInsertIndex).getUuid();
-                status = new Status(StatusCode.SUCCESS, bridgeUUID.toString());
-            }
-            return status;
         } catch(Exception e){
-            e.printStackTrace();
+            logger.error("Error in insertBridgeRow(): ",e);
         }
-        return new Status(StatusCode.INTERNALERROR);
+        return new StatusWithUuid(StatusCode.INTERNALERROR);
     }
 
-    private Status insertPortRow(Node node, String bridge_uuid, Port portRow) {
-        try{
-            if (connectionService == null) {
-                logger.error("Couldn't refer to the ConnectionService");
-                return new Status(StatusCode.NOSERVICE);
-            }
-            Connection connection = this.getConnection(node);
-            if (connection == null) {
-                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
-            }
 
+    private StatusWithUuid insertPortRow(Node node, String bridge_uuid, Port portRow) {
+
+        String insertErrorMsg = "port";
+        String rowName=portRow.getName();
+
+        try{
             Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
             if (brTable == null ||  brTable.get(bridge_uuid) == null) {
-                return new Status(StatusCode.NOTFOUND, "Bridge with UUID "+bridge_uuid+" Not found");
+                return new StatusWithUuid(StatusCode.NOTFOUND, "Bridge with UUID "+bridge_uuid+" Not found");
             }
             String newPort = "new_port";
             UUID portUUID = new UUID(newPort);
@@ -1163,52 +978,26 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
             transaction.addOperations(new ArrayList<Operation>
             (Arrays.asList(addBrMutRequest, addPortRequest, addIntfRequest)));
             int portInsertIndex = transaction.getRequests().indexOf(addPortRequest);
-            ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
-            List<OperationResult> tr = transResponse.get();
-            List<Operation> requests = transaction.getRequests();
-            Status status = new Status(StatusCode.SUCCESS);
-            for (int i = 0; i < tr.size() ; i++) {
-                if (i < requests.size()) requests.get(i).setResult(tr.get(i));
-                if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
-                    OperationResult result = tr.get(i);
-                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
-                }
-            }
 
-            if (tr.size() > requests.size()) {
-                OperationResult result = tr.get(tr.size()-1);
-                logger.error("Error creating port : {}\n Error : {}\n Details : {}", portRow.getName(),
-                        result.getError(),
-                        result.getDetails());
-                status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
-            }
-            if (status.isSuccess()) {
-                uuid = tr.get(portInsertIndex).getUuid();
-                status = new Status(StatusCode.SUCCESS, uuid.toString());
-            }
+            return _insertTableRow(node,transaction,portInsertIndex,insertErrorMsg,rowName);
 
-            return status;
-        } catch (Exception e) {
-            e.printStackTrace();
+            } catch (Exception e) {
+            logger.error("Error in insertPortRow(): ",e);
         }
-        return new Status(StatusCode.INTERNALERROR);
+        return new StatusWithUuid(StatusCode.INTERNALERROR);
     }
 
-    private Status insertInterfaceRow(Node node, String port_uuid, Interface interfaceRow) {
+    private StatusWithUuid insertInterfaceRow(Node node, String port_uuid, Interface interfaceRow) {
+
+        String insertErrorMsg = "interface";
+        String rowName=interfaceRow.getName();
+
         try{
-            if (connectionService == null) {
-                logger.error("Couldn't refer to the ConnectionService");
-                return new Status(StatusCode.NOSERVICE);
-            }
-            Connection connection = this.getConnection(node);
-            if (connection == null) {
-                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
-            }
 
             // Interface table must have entry in Port table, checking port table for port
             Map<String, Table<?>> portTable = inventoryServiceInternal.getTableCache(node, Port.NAME.getName());
             if (portTable == null ||  portTable.get(port_uuid) == null) {
-                return new Status(StatusCode.NOTFOUND, "Port with UUID "+port_uuid+" Not found");
+                return new StatusWithUuid(StatusCode.NOTFOUND, "Port with UUID "+port_uuid+" Not found");
             }
             // MUTATOR, need to insert the interface UUID to LIST of interfaces in PORT TABLE for port_uuid
             String newInterface = "new_interface";
@@ -1232,59 +1021,48 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
             transaction.addOperations(new ArrayList<Operation>(Arrays.asList(addIntfRequest,addPortMutationRequest)));
 
             // Check the results. Iterates over the results of the Array of transaction Operations, and reports STATUS
-            int intInsertIndex = transaction.getRequests().indexOf(addIntfRequest);
-            ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
-            List<OperationResult> tr = transResponse.get();
-            List<Operation> requests = transaction.getRequests();
-            Status status = new Status(StatusCode.SUCCESS);
-            System.out.print(tr.size());
-            for (int i = 0; i < tr.size() ; i++) {
-                if (i < requests.size()) requests.get(i).setResult(tr.get(i));
-                if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
-                    OperationResult result = tr.get(i);
-                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
-                }
-            }
-            if (tr.size() > requests.size()) {
-                OperationResult result = tr.get(tr.size()-1);
-                logger.error("Error creating interface : {}\n Error : {}\n Details : {}", interfaceRow.getName(),
-                        result.getError(),
-                        result.getDetails());
-                status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
-            }
-            if (status.isSuccess()) {
-                uuid = tr.get(intInsertIndex).getUuid();
-                status = new Status(StatusCode.SUCCESS, uuid.toString());
-            }
-            return status;
+            int interfaceInsertIndex = transaction.getRequests().indexOf(addIntfRequest);
+
+            return _insertTableRow(node,transaction,interfaceInsertIndex,insertErrorMsg,rowName);
 
         } catch (Exception e) {
-            e.printStackTrace();
+            logger.error("Error in insertInterfaceRow(): ",e);
         }
-        return new Status(StatusCode.INTERNALERROR);
+        return new StatusWithUuid(StatusCode.INTERNALERROR);
     }
 
-    private Status insertOpen_vSwitchRow(Node node, Open_vSwitch row) {
-        return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+    private StatusWithUuid insertOpen_vSwitchRow(Node node, Open_vSwitch row) {
+        return new StatusWithUuid(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
     }
 
-    private Status insertControllerRow(Node node, String bridge_uuid, Controller row) {
+    private StatusWithUuid insertControllerRow(Node node, String bridge_uuid, Controller row) {
+
+        String insertErrorMsg = "controller";
+        String rowName=row.getTableName().toString();
+
         try{
-            if (connectionService == null) {
-                logger.error("Couldn't refer to the ConnectionService");
-                return new Status(StatusCode.NOSERVICE);
-            }
-            Connection connection = this.getConnection(node);
-            if (connection == null) {
-                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
-            }
 
             Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
             if (brTable == null ||  brTable.get(bridge_uuid) == null) {
-                return new Status(StatusCode.NOTFOUND, "Bridge with UUID "+bridge_uuid+" Not found");
+                return new StatusWithUuid(StatusCode.NOTFOUND, "Bridge with UUID "+bridge_uuid+" Not found");
             }
-            String newController = "new_controller";
-            UUID controllerUUID = new UUID(newController);
+
+            Map<String, Table<?>> controllerCache = inventoryServiceInternal.getTableCache(node, Controller.NAME.getName());
+
+            String uuid_name = "new_controller";
+            boolean controllerExists = false;
+            if (controllerCache != null) {
+                for (String uuid : controllerCache.keySet()) {
+                    Controller controller = (Controller)controllerCache.get(uuid);
+                    if (controller.getTarget().equals(row.getTarget())) {
+                        uuid_name = uuid;
+                        controllerExists = true;
+                        break;
+                    }
+                }
+            }
+
+            UUID controllerUUID = new UUID(uuid_name);
             Mutation bm = new Mutation("controller", Mutator.INSERT, controllerUUID);
             List<Mutation> mutations = new ArrayList<Mutation>();
             mutations.add(bm);
@@ -1294,147 +1072,170 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
             List<Condition> where = new ArrayList<Condition>();
             where.add(condition);
             Operation addBrMutRequest = new MutateOperation(Bridge.NAME.getName(), where, mutations);
-
-            InsertOperation addControllerRequest = new InsertOperation(Controller.NAME.getName(), newController, row);
+            InsertOperation addControllerRequest = null;
 
             TransactBuilder transaction = new TransactBuilder();
-            transaction.addOperations(new ArrayList<Operation>
-            (Arrays.asList(addBrMutRequest, addControllerRequest)));
-            int portInsertIndex = transaction.getRequests().indexOf(addControllerRequest);
-            ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
-            List<OperationResult> tr = transResponse.get();
-            List<Operation> requests = transaction.getRequests();
-            Status status = new Status(StatusCode.SUCCESS);
-            for (int i = 0; i < tr.size() ; i++) {
-                if (i < requests.size()) requests.get(i).setResult(tr.get(i));
-                if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
-                    OperationResult result = tr.get(i);
-                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
-                }
+            transaction.addOperation(addBrMutRequest);
+            int portInsertIndex = -1;
+            if (!controllerExists) {
+                addControllerRequest = new InsertOperation(Controller.NAME.getName(), uuid_name, row);
+                transaction.addOperation(addControllerRequest);
+                portInsertIndex = transaction.getRequests().indexOf(addControllerRequest);
             }
 
-            if (tr.size() > requests.size()) {
-                OperationResult result = tr.get(tr.size()-1);
-                logger.error("Error creating port : {}\n Error : {}\n Details : {}", row.getTarget(),
-                        result.getError(),
-                        result.getDetails());
-                status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
-            }
-            if (status.isSuccess()) {
-                uuid = tr.get(portInsertIndex).getUuid();
-                status = new Status(StatusCode.SUCCESS, uuid.toString());
+            StatusWithUuid status = _insertTableRow(node,transaction,portInsertIndex,insertErrorMsg,rowName);
+            if (status.isSuccess() && controllerExists) {
+                // We won't get the uuid from the transact, so we set it here
+                status = new StatusWithUuid(status.getCode(), controllerUUID);
             }
-
             return status;
+
         } catch (Exception e) {
-            e.printStackTrace();
+            logger.error("Error in insertControllerRow(): ",e);
         }
-        return new Status(StatusCode.INTERNALERROR);
+        return new StatusWithUuid(StatusCode.INTERNALERROR);
     }
 
-    private Status insertSSLRow(Node node, String parent_uuid, SSL row) {
-        return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+    private StatusWithUuid insertSSLRow(Node node, String parent_uuid, SSL row) {
+        return new StatusWithUuid(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
     }
 
-    private Status insertSflowRow(Node node, String parent_uuid, SFlow row) {
-        return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+    private StatusWithUuid insertSflowRow(Node node, String parent_uuid, SFlow row) {
+        return new StatusWithUuid(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
     }
 
-    private Status insertQueueRow(Node node, String parent_uuid, Queue row) {
-        return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+    private StatusWithUuid insertQueueRow(Node node, String parent_uuid, Queue row) {
+        return new StatusWithUuid(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
     }
 
-    private Status insertQosRow(Node node, String parent_uuid, Qos row) {
-        return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+    private StatusWithUuid insertQosRow(Node node, String parent_uuid, Qos row) {
+        return new StatusWithUuid(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
     }
 
-    private Status insertNetFlowRow(Node node, String parent_uuid, NetFlow row) {
-        return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+    private StatusWithUuid insertNetFlowRow(Node node, String parent_uuid, NetFlow row) {
+        return new StatusWithUuid(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
     }
 
-    private Status insertMirrorRow(Node node, String parent_uuid, Mirror row) {
-        return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+    private StatusWithUuid insertMirrorRow(Node node, String parent_uuid, Mirror row) {
+        return new StatusWithUuid(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
     }
 
-    private Status insertManagerRow(Node node, String parent_uuid, Manager row) {
-        return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+    private StatusWithUuid insertManagerRow(Node node, String parent_uuid, Manager row) {
+        return new StatusWithUuid(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
     }
 
-    private Status insertCapabilityRow(Node node, String parent_uuid, Capability row) {
-        return new Status(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
+    private StatusWithUuid insertCapabilityRow(Node node, String parent_uuid, Capability row) {
+        return new StatusWithUuid(StatusCode.NOTIMPLEMENTED, "Insert operation for this Table is not implemented yet.");
     }
 
-    private Status deleteBridgeRow(Node node, String uuid) {
+    private StatusWithUuid _insertTableRow(Node node, TransactBuilder transaction, Integer insertIndex, String insertErrorMsg,String rowName){
 
-        try {
+        try{
+            //Check for connection before calling RPC to perform transaction
             if (connectionService == null) {
                 logger.error("Couldn't refer to the ConnectionService");
-                return new Status(StatusCode.NOSERVICE);
+                return new StatusWithUuid(StatusCode.NOSERVICE);
             }
+
             Connection connection = this.getConnection(node);
             if (connection == null) {
-                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
-            }
-            Map<String, Table<?>> ovsTable = inventoryServiceInternal.getTableCache(node, Open_vSwitch.NAME.getName());
-            Map<String, Table<?>> brTable = inventoryServiceInternal.getTableCache(node, Bridge.NAME.getName());
-            Operation delBrRequest = null;
-
-            if (ovsTable == null || brTable == null || uuid == null || brTable.get(uuid) == null) {
-                return new Status(StatusCode.NOTFOUND, "");
+                return new StatusWithUuid(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
             }
 
-            UUID bridgeUuidPair = new UUID(uuid);
-            Mutation bm = new Mutation("bridges", Mutator.DELETE, bridgeUuidPair);
-            List<Mutation> mutations = new ArrayList<Mutation>();
-            mutations.add(bm);
-
-            UUID ovsUuid = new UUID((String) ovsTable.keySet().toArray()[0]);
-            Condition condition = new Condition("_uuid", Function.EQUALS, ovsUuid);
-            List<Condition> where = new ArrayList<Condition>();
-            where.add(condition);
-            delBrRequest = new MutateOperation(Open_vSwitch.NAME.getName(), where, mutations);
-
-            TransactBuilder transaction = new TransactBuilder();
-            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(delBrRequest)));
-
             ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
             List<OperationResult> tr = transResponse.get();
             List<Operation> requests = transaction.getRequests();
-            Status status = new Status(StatusCode.SUCCESS);
-            for (int i = 0; i < tr.size(); i++) {
+            StatusWithUuid status = new StatusWithUuid(StatusCode.SUCCESS);
+            for (int i = 0; i < tr.size() ; i++) {
                 if (i < requests.size()) requests.get(i).setResult(tr.get(i));
                 if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
                     OperationResult result = tr.get(i);
-                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
+                    status = new StatusWithUuid(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
                 }
             }
 
             if (tr.size() > requests.size()) {
-                OperationResult result = tr.get(tr.size() - 1);
-                logger.error("Error creating Bridge : {}\n Error : {}\n Details : {}",
-                        uuid, result.getError(), result.getDetails());
-                status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
+                OperationResult result = tr.get(tr.size()-1);
+                logger.error("Error creating {} : {}\n Error : {}\n Details : {}",     insertErrorMsg,
+                                                                                       rowName,
+                                                                                       result.getError(),
+                                                                                       result.getDetails());
+                status = new StatusWithUuid(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
+            }
+            if (status.isSuccess()) {
+                if (insertIndex >0 && insertIndex < tr.size() && tr.get(insertIndex) != null) {
+                    UUID uuid = tr.get(insertIndex).getUuid();
+                    status = new StatusWithUuid(StatusCode.SUCCESS, uuid);
+                } else {
+                    // We can't get the uuid from the transact as the insertIndex is invalid or -1
+                    // return null uuid.
+                    status = new StatusWithUuid(StatusCode.SUCCESS, (UUID) null);
+                }
             }
             return status;
-        } catch (Exception e) {
-            e.printStackTrace();
+        } catch(Exception e){
+            logger.error("Error in _insertTableRow(): ",e);
         }
-        return new Status(StatusCode.INTERNALERROR);
+        return new StatusWithUuid(StatusCode.INTERNALERROR);
+    }
+
+
+    private Status deleteBridgeRow(Node node, String uuid) {
+        // Set up variables for generic _deleteTableRow()
+        String parentTableName=Open_vSwitch.NAME.getName();
+        String childTableName=Bridge.NAME.getName();
+        String parentColumn = "bridges";
+
+        return _deleteTableRow(node,uuid,parentTableName,childTableName,parentColumn);
     }
 
     private Status deletePortRow(Node node, String uuid) {
-        return new Status(StatusCode.INTERNALERROR);
+        // Set up variables for generic _deleteTableRow()
+        String parentTableName=Bridge.NAME.getName();
+        String childTableName=Port.NAME.getName();
+        String parentColumn = "ports";
+
+        return _deleteTableRow(node,uuid,parentTableName,childTableName,parentColumn);
     }
 
     private Status deleteInterfaceRow(Node node, String uuid) {
-        return new Status(StatusCode.NOTIMPLEMENTED, "delete operation for this Table is not implemented yet.");
-    }
+        // Since Port<-Interface tables have a 1:n relationship, need to test if this is the last interface
+        // assigned to a port before attempting delete.
+        Map<String, Table<?>> portTable = inventoryServiceInternal.getTableCache(node, Port.NAME.getName());
+        Map<String, Table<?>> interfaceTable = inventoryServiceInternal.getTableCache(node, Interface.NAME.getName());
+        // Check that the UUID exists
+        if (portTable == null || interfaceTable == null || uuid == null || interfaceTable.get(uuid) == null) {
+            return new Status(StatusCode.NOTFOUND, "");
+        }
 
-    private Status deleteOpen_vSwitchRow(Node node, String uuid) {
-        return new Status(StatusCode.NOTIMPLEMENTED, "delete operation for this Table is not implemented yet.");
+        // Need to check if this is the last interface for that port. Cannot delete last interface.
+        UUID compareUuid = new UUID(uuid);
+        for (int i=0 ; i < portTable.values().size(); i++){
+            Port port = (Port)portTable.values().toArray()[i];
+            if ((port.getInterfaces().size() == 1) && (port.getInterfaces().contains(compareUuid))){
+                return new Status(StatusCode.BADREQUEST, "Cannot delete last interface from port");
+            }
+        }
+
+        // Since the above past, it's safe to use the generic _deleteTableRow method
+        // Set up variables for generic _deleteTableRow()
+        String parentTableName=Port.NAME.getName();
+        String childTableName=Interface.NAME.getName();
+        String parentColumn = "interfaces";
+
+        return _deleteTableRow(node,uuid,parentTableName,childTableName,parentColumn);
     }
 
     private Status deleteControllerRow(Node node, String uuid) {
+        // Set up variables for generic _deleteTableRow()
+        String parentTableName=Bridge.NAME.getName();
+        String childTableName=Controller.NAME.getName();
+        String parentColumn = "controller";
+
+        return _deleteTableRow(node,uuid,parentTableName,childTableName,parentColumn);
+    }
+
+    private Status deleteOpen_vSwitchRow(Node node, String uuid) {
         return new Status(StatusCode.NOTIMPLEMENTED, "delete operation for this Table is not implemented yet.");
     }
 
@@ -1469,6 +1270,76 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
     private Status deleteCapabilityRow(Node node, String uuid) {
         return new Status(StatusCode.NOTIMPLEMENTED, "delete operation for this Table is not implemented yet.");
     }
+    private Status _deleteTableRow(Node node,String uuid,String parentTableName, String childTableName, String parentColumn) {
+        try {
+            // Check there is a connectionService
+            if (connectionService == null) {
+                logger.error("Couldn't refer to the ConnectionService");
+                return new Status(StatusCode.NOSERVICE);
+            }
+
+            // Establish the connection
+            Connection connection = this.getConnection(node);
+            if (connection == null) {
+                return new Status(StatusCode.NOSERVICE, "Connection to ovsdb-server not available");
+            }
+
+            // Ports have a 0:n relationship with Bridges, so need to MUTATE BRIDGE row and DELETE PORT row
+            Map<String, Table<?>> parentTable = inventoryServiceInternal.getTableCache(node, parentTableName);
+            Map<String, Table<?>> childTable = inventoryServiceInternal.getTableCache(node, childTableName);
+
+            // Check that the UUID exists
+            if (parentTable == null || childTable == null || uuid == null || childTable.get(uuid) == null) {
+                return new Status(StatusCode.NOTFOUND, "");
+            }
+
+            // Initialise the actual request var
+            Operation delRequest = null;
+
+            // Prepare the mutator to remove the port UUID from the "ports" list in the BRIDGE TABLE
+            UUID rowUuid = new UUID(uuid);
+            Mutation mutator = new Mutation(parentColumn, Mutator.DELETE, rowUuid);
+            List<Mutation> mutations = new ArrayList<Mutation>();
+            mutations.add(mutator);
+
+            Status status = new Status(StatusCode.SUCCESS);
+
+            // INCLUDES condition ensures that it captures all rows in the parent table (ie duplicates) that have the child UUID
+            Condition condition = new Condition(parentColumn, Function.INCLUDES, rowUuid);
+            List<Condition> where = new ArrayList<Condition>();
+            where.add(condition);
+            delRequest = new MutateOperation(parentTableName, where, mutations);
+
+            TransactBuilder transaction = new TransactBuilder();
+            transaction.addOperations(new ArrayList<Operation>(Arrays.asList(delRequest)));
+
+            // This executes the transaction.
+            ListenableFuture<List<OperationResult>> transResponse = connection.getRpc().transact(transaction);
+
+            // Pull the responses
+            List<OperationResult> tr = transResponse.get();
+            List<Operation> requests = transaction.getRequests();
+
+            for (int i = 0; i < tr.size(); i++) {
+                if (i < requests.size()) requests.get(i).setResult(tr.get(i));
+                if (tr.get(i) != null && tr.get(i).getError() != null && tr.get(i).getError().trim().length() > 0) {
+                    OperationResult result = tr.get(i);
+                    status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
+                }
+            }
+
+            if (tr.size() > requests.size()) {
+                OperationResult result = tr.get(tr.size() - 1);
+                logger.error("Error deleting: {}\n Error : {}\n Details : {}",
+                        uuid, result.getError(), result.getDetails());
+                status = new Status(StatusCode.BADREQUEST, result.getError() + " : " + result.getDetails());
+            }
+            return status;
+        } catch (Exception e) {
+            logger.error("Error in _deleteTableRow",e);
+        }
+        return new Status(StatusCode.INTERNALERROR);
+    }
 
     public void _ovsconnect (CommandInterpreter ci) {
         String bridgeName = ci.nextArgument();
@@ -1823,3 +1694,4 @@ public class ConfigurationService implements IPluginInBridgeDomainConfigService,
         return help.toString();
     }
 }
+