Support active-standby mode in openstacknetworking app

Change-Id: I155e1a082078e5c1b7e8a35275dfd517c787ade7
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackHaActiveIpCommand.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackHaActiveIpCommand.java
new file mode 100644
index 0000000..8b59ed1
--- /dev/null
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackHaActiveIpCommand.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.cli;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
+
+/**
+ * Configures openstack active IP address.
+ */
+@Service
+@Command(scope = "onos", name = "openstack-ha-activeip",
+        description = "Configure openstack active IP address.")
+public class OpenstackHaActiveIpCommand extends AbstractShellCommand {
+
+    @Argument(index = 0, name = "active node IP", description = "active node IP",
+            required = true, multiValued = false)
+    private String ip = null;
+
+    @Override
+    protected void doExecute() {
+        OpenstackHaService service = get(OpenstackHaService.class);
+
+        service.setActiveIp(IpAddress.valueOf(ip));
+
+        print("Active node IP address " + ip + " is configured");
+    }
+}
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackHaConfigCommand.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackHaConfigCommand.java
new file mode 100644
index 0000000..c0e15ea
--- /dev/null
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackHaConfigCommand.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.cli;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
+
+/**
+ * Configures openstack HA.
+ */
+@Service
+@Command(scope = "onos", name = "openstack-ha-config",
+        description = "Configure openstack active-standby HA status.")
+public class OpenstackHaConfigCommand extends AbstractShellCommand {
+
+    private static final String FLAG_TRUE = "true";
+    private static final String FLAG_FALSE = "false";
+
+    @Argument(index = 0, name = "active node", description = "active node",
+            required = true, multiValued = false)
+    private String active = null;
+
+    @Override
+    protected void doExecute() {
+        OpenstackHaService service = get(OpenstackHaService.class);
+
+        if (FLAG_TRUE.equalsIgnoreCase(active)) {
+            service.setActive(true);
+        } else if (FLAG_FALSE.equalsIgnoreCase(active)) {
+            service.setActive(false);
+        } else {
+            error("The input value is not correct");
+            return;
+        }
+
+        String role = service.isActive() ? "ACTIVE" : "STANDBY";
+
+        print("Node is configured as " + role);
+    }
+}
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackHaShowCommand.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackHaShowCommand.java
new file mode 100644
index 0000000..af389d6
--- /dev/null
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackHaShowCommand.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.cli;
+
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
+
+/**
+ * Shows openstack HA status.
+ */
+@Service
+@Command(scope = "onos", name = "openstack-ha-show",
+        description = "Show openstack active-standby HA status.")
+public class OpenstackHaShowCommand extends AbstractShellCommand {
+
+    private static final String FORMAT = "%-20s%-30s";
+
+    @Override
+    protected void doExecute() {
+        OpenstackHaService service = get(OpenstackHaService.class);
+
+        print(FORMAT, "Status", "Active Node IP");
+
+        print(FORMAT,
+                service.isActive() ? "Active" : "Standby",
+                service.getActiveIp() == null ? "None" : service.getActiveIp().toString());
+    }
+}
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackHaManager.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackHaManager.java
new file mode 100644
index 0000000..7aed8c3
--- /dev/null
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackHaManager.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.impl;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.core.CoreService;
+import org.onosproject.openstacknetworking.api.Constants;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Provides implementation of administering and interfacing openstack HA service.
+ */
+@Component(
+    immediate = true,
+    service = { OpenstackHaService.class }
+)
+public class OpenstackHaManager implements OpenstackHaService {
+
+    protected final Logger log = getLogger(getClass());
+
+    private static final boolean DEFAULT_ACTIVE_STATUS = true;
+    private static final IpAddress DEFAULT_ACTIVE_IP_ADDRESS = IpAddress.valueOf("127.0.0.1");
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected CoreService coreService;
+
+    boolean activeFlag;
+    IpAddress activeIpAddress;
+
+    @Activate
+    protected void activate() {
+        coreService.registerApplication(Constants.OPENSTACK_NETWORKING_APP_ID);
+        activeFlag = DEFAULT_ACTIVE_STATUS;
+        activeIpAddress = DEFAULT_ACTIVE_IP_ADDRESS;
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        log.info("Stopped");
+    }
+
+    @Override
+    public boolean isActive() {
+        return activeFlag;
+    }
+
+    @Override
+    public IpAddress getActiveIp() {
+        return activeIpAddress;
+    }
+
+    @Override
+    public void setActiveIp(IpAddress ip) {
+        this.activeIpAddress = ip;
+    }
+
+    @Override
+    public void setActive(boolean flag) {
+        this.activeFlag = flag;
+    }
+}
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
index ce12d77..31882c9 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
@@ -42,6 +42,7 @@
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.util.io.NoCloseInputStream;
+import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
 import org.onlab.packet.ARP;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.Ip4Address;
@@ -59,6 +60,7 @@
 import org.onosproject.openstacknetworking.api.Constants.VnicType;
 import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
 import org.onosproject.openstacknetworking.api.InstancePort;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
 import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
@@ -95,6 +97,11 @@
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -115,13 +122,20 @@
 import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Strings.isNullOrEmpty;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
+import static org.apache.commons.io.IOUtils.toInputStream;
 import static org.onlab.packet.Ip4Address.valueOf;
 import static org.onosproject.net.AnnotationKeys.PORT_NAME;
 import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
+import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_REST_PATH;
 import static org.onosproject.openstacknetworking.api.Constants.PCISLOT;
 import static org.onosproject.openstacknetworking.api.Constants.PCI_VENDOR_INFO;
 import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_PREFIX_VM;
 import static org.onosproject.openstacknetworking.api.Constants.PORT_NAME_VHOST_USER_PREFIX_VM;
+import static org.onosproject.openstacknetworking.api.Constants.REST_PASSWORD;
+import static org.onosproject.openstacknetworking.api.Constants.REST_PORT;
+import static org.onosproject.openstacknetworking.api.Constants.REST_USER;
+import static org.onosproject.openstacknetworking.api.Constants.REST_UTF8;
 import static org.onosproject.openstacknetworking.api.Constants.UNSUPPORTED_VENDOR;
 import static org.onosproject.openstacknetworking.api.Constants.portNamePrefixMap;
 import static org.openstack4j.core.transport.ObjectMapperSingleton.getContext;
@@ -177,13 +191,14 @@
     /**
      * Interprets JSON string to corresponding openstack model entity object.
      *
-     * @param input JSON string
+     * @param inputStr JSON string
      * @param entityClazz openstack model entity class
      * @return openstack model entity object
      */
-    public static ModelEntity jsonToModelEntity(InputStream input, Class entityClazz) {
+    public static ModelEntity jsonToModelEntity(String inputStr, Class entityClazz) {
         ObjectMapper mapper = new ObjectMapper();
         try {
+            InputStream input = toInputStream(inputStr, REST_UTF8);
             JsonNode jsonTree = mapper.enable(INDENT_OUTPUT).readTree(input);
             log.trace(new ObjectMapper().writeValueAsString(jsonTree));
             return ObjectMapperSingleton.getContext(entityClazz)
@@ -1088,6 +1103,118 @@
         }
     }
 
+    /**
+     * Returns the REST URL of active node.
+     *
+     * @param haService openstack HA service
+     * @return REST URL of active node
+     */
+    public static String getActiveUrl(OpenstackHaService haService) {
+        return "http://" + haService.getActiveIp().toString() + ":" +
+                REST_PORT + "/" + OPENSTACK_NETWORKING_REST_PATH + "/";
+    }
+
+    /**
+     * Returns the REST client instance with given resource path.
+     *
+     * @param haService         openstack HA service
+     * @param resourcePath      resource path
+     * @return REST client instance
+     */
+    public static WebTarget getActiveClient(OpenstackHaService haService,
+                                            String resourcePath) {
+        HttpAuthenticationFeature feature =
+                HttpAuthenticationFeature.universal(REST_USER, REST_PASSWORD);
+        Client client = ClientBuilder.newClient().register(feature);
+        return client.target(getActiveUrl(haService)).path(resourcePath);
+    }
+
+    /**
+     * Returns the post response from the active node.
+     *
+     * @param haService         openstack HA service
+     * @param resourcePath      resource path
+     * @param input             input
+     * @return post response
+     */
+    public static Response syncPost(OpenstackHaService haService,
+                                    String resourcePath,
+                                    String input) {
+
+        log.debug("Sync POST request with {} on {}",
+                            haService.getActiveIp().toString(), resourcePath);
+
+        return getActiveClient(haService, resourcePath)
+                .request(APPLICATION_JSON_TYPE)
+                .post(Entity.json(input));
+    }
+
+    /**
+     * Returns the put response from the active node.
+     *
+     * @param haService         openstack HA service
+     * @param resourcePath      resource path
+     * @param id                resource identifier
+     * @param input             input
+     * @return put response
+     */
+    public static Response syncPut(OpenstackHaService haService,
+                                   String resourcePath,
+                                   String id, String input) {
+        return syncPut(haService, resourcePath, null, id, input);
+    }
+
+    /**
+     * Returns the put response from the active node.
+     *
+     * @param haService         openstack HA service
+     * @param resourcePath      resource path
+     * @param id                resource identifier
+     * @param suffix            resource suffix
+     * @param input             input
+     * @return put response
+     */
+    public static Response syncPut(OpenstackHaService haService,
+                                   String resourcePath,
+                                   String suffix,
+                                   String id, String input) {
+
+        log.debug("Sync PUT request with {} on {}",
+                haService.getActiveIp().toString(), resourcePath);
+
+        String pathStr = "/" + id;
+
+        if (suffix != null) {
+            pathStr += "/" + suffix;
+        }
+
+        return getActiveClient(haService, resourcePath)
+                .path(pathStr)
+                .request(APPLICATION_JSON_TYPE)
+                .put(Entity.json(input));
+    }
+
+    /**
+     * Returns the delete response from the active node.
+     *
+     * @param haService         openstack HA service
+     * @param resourcePath      resource path
+     * @param id            resource identifier
+     * @return delete response
+     */
+    public static Response syncDelete(OpenstackHaService haService,
+                                      String resourcePath,
+                                      String id) {
+
+        log.debug("Sync DELETE request with {} on {}",
+                haService.getActiveIp().toString(), resourcePath);
+
+        return getActiveClient(haService, resourcePath)
+                .path("/" + id)
+                .request(APPLICATION_JSON_TYPE)
+                .delete();
+    }
+
     private static Router getRouterFromSubnet(Subnet subnet,
                                               OpenstackRouterService osRouterService) {
         RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackFloatingIpWebResource.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackFloatingIpWebResource.java
index 25bc74b..33a0fa6 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackFloatingIpWebResource.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackFloatingIpWebResource.java
@@ -16,6 +16,8 @@
 
 package org.onosproject.openstacknetworking.web;
 
+import org.apache.commons.io.IOUtils;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
 import org.onosproject.rest.AbstractWebResource;
 import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
@@ -34,12 +36,17 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
 import java.io.InputStream;
 
 import static javax.ws.rs.core.Response.created;
 import static javax.ws.rs.core.Response.noContent;
 import static javax.ws.rs.core.Response.status;
+import static org.onosproject.openstacknetworking.api.Constants.REST_UTF8;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.jsonToModelEntity;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncDelete;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncPost;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncPut;
 
 /**
  * Handles floating IP REST API call of Neutron L3 plugin.
@@ -53,6 +60,7 @@
 
     private final OpenstackRouterAdminService adminService =
                                         get(OpenstackRouterAdminService.class);
+    private final OpenstackHaService haService = get(OpenstackHaService.class);
 
     @Context
     private UriInfo uriInfo;
@@ -63,16 +71,23 @@
      * @param input floating ip JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated floating ip already exists
+     * @throws IOException exception
      * @onos.rsModel NeutronFloatingIp
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response createFloatingIp(InputStream input) {
+    public Response createFloatingIp(InputStream input) throws IOException {
         log.trace(String.format(MESSAGE, "CREATE"));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPost(haService, FLOATING_IPS, inputStr);
+        }
+
         final NeutronFloatingIP floatingIp = (NeutronFloatingIP)
-                                jsonToModelEntity(input, NeutronFloatingIP.class);
+                jsonToModelEntity(inputStr, NeutronFloatingIP.class);
 
         adminService.createFloatingIp(floatingIp);
 
@@ -90,17 +105,24 @@
      * @param input floating ip JSON input stream
      * @return 200 OK with the updated floating ip, 400 BAD_REQUEST if the requested
      * floating ip does not exist
+     * @throws IOException exception
      * @onos.rsModel NeutronFloatingIp
      */
     @PUT
     @Path("{id}")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response updateFloatingIp(@PathParam("id") String id, InputStream input) {
+    public Response updateFloatingIp(@PathParam("id") String id, InputStream input) throws IOException {
         log.trace(String.format(MESSAGE, "UPDATE " + id));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPut(haService, FLOATING_IPS, id, inputStr);
+        }
+
         final NeutronFloatingIP floatingIp = (NeutronFloatingIP)
-                                jsonToModelEntity(input, NeutronFloatingIP.class);
+                jsonToModelEntity(inputStr, NeutronFloatingIP.class);
 
         adminService.updateFloatingIp(floatingIp);
 
@@ -119,6 +141,10 @@
     public Response deleteFloatingIp(@PathParam("id") String id) {
         log.trace(String.format(MESSAGE, "DELETE " + id));
 
+        if (!haService.isActive()) {
+            return syncDelete(haService, FLOATING_IPS, id);
+        }
+
         adminService.removeFloatingIp(id);
         return noContent().build();
     }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackManagementWebResource.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackManagementWebResource.java
index 008c5e5..3628848 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackManagementWebResource.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackManagementWebResource.java
@@ -19,12 +19,14 @@
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
+import org.onlab.packet.IpAddress;
 import org.onlab.util.ItemNotFoundException;
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.openstacknetworking.api.Constants;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupAdminService;
@@ -42,7 +44,9 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
@@ -57,6 +61,7 @@
 
 import static java.lang.Thread.sleep;
 import static java.util.stream.StreamSupport.stream;
+import static javax.ws.rs.core.Response.status;
 import static org.onlab.util.Tools.nullIsIllegal;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.addRouterIface;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.checkActivationFlag;
@@ -93,6 +98,9 @@
     private static final String HTTP_HEADER_ACCEPT = "accept";
     private static final String HTTP_HEADER_VALUE_JSON = "application/json";
 
+    private static final String FLAG_TRUE = "true";
+    private static final String FLAG_FALSE = "false";
+
     private final ObjectNode root = mapper().createObjectNode();
     private final ArrayNode floatingipsNode = root.putArray(FLOATINGIPS);
 
@@ -104,6 +112,7 @@
             get(OpenstackRouterAdminService.class);
     private final OpenstackNodeAdminService osNodeAdminService =
             get(OpenstackNodeAdminService.class);
+    private final OpenstackHaService osHaService = get(OpenstackHaService.class);
     private final FlowRuleService flowRuleService = get(FlowRuleService.class);
     private final CoreService coreService = get(CoreService.class);
 
@@ -355,6 +364,46 @@
         return ok(root).build();
     }
 
+    /**
+     * Configures the HA active-standby status.
+     *
+     * @param flag active-standby status
+     * @return 200 OK or 400 BAD_REQUEST
+     */
+    @PUT
+    @Path("active/status/{flag}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response updateActiveStatus(@PathParam("flag") String flag) {
+
+        if (FLAG_TRUE.equalsIgnoreCase(flag)) {
+            osHaService.setActive(true);
+        }
+
+        if (FLAG_FALSE.equalsIgnoreCase(flag)) {
+            osHaService.setActive(false);
+        }
+
+        return status(Response.Status.OK).build();
+    }
+
+    /**
+     * Configures the HA active IP address.
+     *
+     * @param ip IP address of active node
+     * @return 200 OK or 400 BAD_REQUEST
+     */
+    @PUT
+    @Path("active/ip/{ip}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response updateActiveIp(@PathParam("ip") String ip) {
+
+        osHaService.setActiveIp(IpAddress.valueOf(ip));
+
+        return status(Response.Status.OK).build();
+    }
+
     private void syncRulesBase() {
         // we first initialize the COMPUTE node, in order to feed all instance ports
         // by referring to ports' information obtained from neutron server
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackNetworkWebResource.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackNetworkWebResource.java
index 567b7bd..208af92 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackNetworkWebResource.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackNetworkWebResource.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.openstacknetworking.web;
 
+import org.apache.commons.io.IOUtils;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
 import org.onosproject.rest.AbstractWebResource;
 import org.openstack4j.openstack.networking.domain.NeutronNetwork;
@@ -33,12 +35,17 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
 import java.io.InputStream;
 
 import static javax.ws.rs.core.Response.created;
 import static javax.ws.rs.core.Response.noContent;
 import static javax.ws.rs.core.Response.status;
+import static org.onosproject.openstacknetworking.api.Constants.REST_UTF8;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.jsonToModelEntity;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncDelete;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncPost;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncPut;
 
 /**
  * Handles network REST API call of Neutron ML2 plugin.
@@ -52,6 +59,7 @@
 
     private final OpenstackNetworkAdminService adminService =
                                         get(OpenstackNetworkAdminService.class);
+    private final OpenstackHaService haService = get(OpenstackHaService.class);
 
     @Context
     private UriInfo uriInfo;
@@ -62,16 +70,23 @@
      * @param input network JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated network already exists
+     * @throws IOException exception
      * @onos.rsModel NeutronNetwork
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response createNetwork(InputStream input) {
+    public Response createNetwork(InputStream input) throws IOException {
         log.trace(String.format(MESSAGE, "CREATE"));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPost(haService, NETWORKS, inputStr);
+        }
+
         final NeutronNetwork net = (NeutronNetwork)
-                             jsonToModelEntity(input, NeutronNetwork.class);
+                jsonToModelEntity(inputStr, NeutronNetwork.class);
 
         adminService.createNetwork(net);
 
@@ -89,17 +104,24 @@
      * @param input network JSON input stream
      * @return 200 OK with the updated network, 400 BAD_REQUEST if the requested
      * network does not exist
+     * @throws IOException exception
      * @onos.rsModel NeutronNetwork
      */
     @PUT
     @Path("{id}")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response updateNetwork(@PathParam("id") String id, InputStream input) {
+    public Response updateNetwork(@PathParam("id") String id, InputStream input) throws IOException {
         log.trace(String.format(MESSAGE, "UPDATE " + id));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPut(haService, NETWORKS, id, inputStr);
+        }
+
         final NeutronNetwork net = (NeutronNetwork)
-                             jsonToModelEntity(input, NeutronNetwork.class);
+                jsonToModelEntity(inputStr, NeutronNetwork.class);
 
         adminService.updateNetwork(net);
 
@@ -119,6 +141,10 @@
     public Response deleteNetwork(@PathParam("id") String id) {
         log.trace(String.format(MESSAGE, "DELETE " + id));
 
+        if (!haService.isActive()) {
+            return syncDelete(haService, NETWORKS, id);
+        }
+
         adminService.removeNetwork(id);
         return noContent().build();
     }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
index d1a0ab3..c5b9b6e 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
@@ -17,6 +17,8 @@
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.commons.io.IOUtils;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
 import org.onosproject.openstacknode.api.DpdkConfig;
 import org.onosproject.openstacknode.api.OpenstackNode;
@@ -38,12 +40,17 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
 import java.io.InputStream;
 
 import static javax.ws.rs.core.Response.created;
 import static javax.ws.rs.core.Response.noContent;
 import static javax.ws.rs.core.Response.status;
+import static org.onosproject.openstacknetworking.api.Constants.REST_UTF8;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.jsonToModelEntity;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncDelete;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncPost;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncPut;
 
 /**
  * Handles port REST API call from Neutron ML2 plugin.
@@ -61,6 +68,7 @@
     private final OpenstackNetworkAdminService
                         adminService = get(OpenstackNetworkAdminService.class);
     private final OpenstackNodeService nodeService = get(OpenstackNodeService.class);
+    private final OpenstackHaService haService = get(OpenstackHaService.class);
 
     @Context
     private UriInfo uriInfo;
@@ -71,16 +79,23 @@
      * @param input port JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated port already exists
+     * @throws IOException exception
      * @onos.rsModel NeutronPort
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response createPorts(InputStream input) {
+    public Response createPorts(InputStream input) throws IOException {
         log.trace(String.format(MESSAGE, "CREATE"));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPost(haService, PORTS, inputStr);
+        }
+
         final NeutronPort port = (NeutronPort)
-                                 jsonToModelEntity(input, NeutronPort.class);
+                jsonToModelEntity(inputStr, NeutronPort.class);
 
         adminService.createPort(port);
         UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
@@ -97,17 +112,24 @@
      * @param input port JSON input stream
      * @return 200 OK with the updated port, 400 BAD_REQUEST if the requested
      * port does not exist
+     * @throws IOException exception
      * @onos.rsModel NeutronPort
      */
     @PUT
     @Path("{id}")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response updatePort(@PathParam("id") String id, InputStream input) {
+    public Response updatePort(@PathParam("id") String id, InputStream input) throws IOException {
         log.trace(String.format(MESSAGE, "UPDATE " + id));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPut(haService, PORTS, id, inputStr);
+        }
+
         final NeutronPort port = (NeutronPort)
-                                 jsonToModelEntity(input, NeutronPort.class);
+                jsonToModelEntity(inputStr, NeutronPort.class);
 
         adminService.updatePort(port);
         ObjectMapper mapper = new ObjectMapper();
@@ -144,6 +166,10 @@
     public Response deletePorts(@PathParam("id") String id) {
         log.trace(String.format(MESSAGE, "DELETE " + id));
 
+        if (!haService.isActive()) {
+            return syncDelete(haService, PORTS, id);
+        }
+
         adminService.removePort(id);
         return noContent().build();
     }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackRouterWebResource.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackRouterWebResource.java
index 444b351..bdd4b60 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackRouterWebResource.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackRouterWebResource.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.openstacknetworking.web;
 
+import org.apache.commons.io.IOUtils;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
 import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
 import org.onosproject.rest.AbstractWebResource;
 import org.openstack4j.openstack.networking.domain.NeutronRouter;
@@ -34,12 +36,17 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
 import java.io.InputStream;
 
 import static javax.ws.rs.core.Response.created;
 import static javax.ws.rs.core.Response.noContent;
 import static javax.ws.rs.core.Response.status;
+import static org.onosproject.openstacknetworking.api.Constants.REST_UTF8;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.jsonToModelEntity;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncDelete;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncPost;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncPut;
 
 /**
  * Handles router REST API call of Neutron L3 plugin.
@@ -55,6 +62,7 @@
 
     private final OpenstackRouterAdminService adminService =
                                         get(OpenstackRouterAdminService.class);
+    private final OpenstackHaService haService = get(OpenstackHaService.class);
 
     @Context
     private UriInfo uriInfo;
@@ -65,16 +73,23 @@
      * @param input router JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated router already exists
+     * @throws IOException exception
      * @onos.rsModel NeutronRouter
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response createRouter(InputStream input) {
+    public Response createRouter(InputStream input) throws IOException {
         log.trace(String.format(MESSAGE_ROUTER, "CREATE"));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPost(haService, ROUTERS, inputStr);
+        }
+
         final NeutronRouter osRouter = (NeutronRouter)
-                            jsonToModelEntity(input, NeutronRouter.class);
+                            jsonToModelEntity(inputStr, NeutronRouter.class);
 
         adminService.createRouter(osRouter);
 
@@ -92,17 +107,24 @@
      * @param input router JSON input stream
      * @return 200 OK with the updated router, 400 BAD_REQUEST if the requested
      * router does not exist
+     * @throws IOException exception
      * @onos.rsModel NeutronRouter
      */
     @PUT
     @Path("{id}")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response updateRouter(@PathParam("id") String id, InputStream input) {
+    public Response updateRouter(@PathParam("id") String id, InputStream input) throws IOException {
         log.trace(String.format(MESSAGE_ROUTER, "UPDATE " + id));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPut(haService, ROUTERS, id, inputStr);
+        }
+
         final NeutronRouter osRouter = (NeutronRouter)
-                            jsonToModelEntity(input, NeutronRouter.class);
+                jsonToModelEntity(inputStr, NeutronRouter.class);
 
         osRouter.setId(id);
         adminService.updateRouter(osRouter);
@@ -117,17 +139,24 @@
      * @param input router interface JSON input stream
      * @return 200 OK with the updated router interface, 400 BAD_REQUEST if the
      * requested router does not exist
+     * @throws IOException exception
      * @onos.rsModel NeutronRouterInterface
      */
     @PUT
     @Path("{id}/add_router_interface")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response addRouterInterface(@PathParam("id") String id, InputStream input) {
+    public Response addRouterInterface(@PathParam("id") String id, InputStream input) throws IOException {
         log.trace(String.format(MESSAGE_ROUTER_IFACE, "UPDATE " + id));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPut(haService, ROUTERS, "add_router_interface", id, inputStr);
+        }
+
         final NeutronRouterInterface osRouterIface = (NeutronRouterInterface)
-                        jsonToModelEntity(input, NeutronRouterInterface.class);
+                        jsonToModelEntity(inputStr, NeutronRouterInterface.class);
 
         adminService.addRouterInterface(osRouterIface);
 
@@ -141,17 +170,24 @@
      * @param input router interface JSON input stream
      * @return 200 OK with the updated router interface, 400 BAD_REQUEST if the
      * requested router does not exist
+     * @throws IOException exception
      * @onos.rsModel NeutronRouterInterface
      */
     @PUT
     @Path("{id}/remove_router_interface")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response deleteRouterInterface(@PathParam("id") String id, InputStream input) {
+    public Response deleteRouterInterface(@PathParam("id") String id, InputStream input) throws IOException {
         log.trace(String.format(MESSAGE_ROUTER_IFACE, "DELETE " + id));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPut(haService, ROUTERS, "remove_router_interface", id, inputStr);
+        }
+
         final NeutronRouterInterface osRouterIface = (NeutronRouterInterface)
-                        jsonToModelEntity(input, NeutronRouterInterface.class);
+                        jsonToModelEntity(inputStr, NeutronRouterInterface.class);
 
         adminService.removeRouterInterface(osRouterIface.getPortId());
 
@@ -170,6 +206,10 @@
     public Response deleteRouter(@PathParam("id") String id) {
         log.trace(String.format(MESSAGE_ROUTER, "DELETE " + id));
 
+        if (!haService.isActive()) {
+            return syncDelete(haService, ROUTERS, id);
+        }
+
         adminService.removeRouter(id);
         return noContent().build();
     }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupRuleWebResource.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupRuleWebResource.java
index 009e941..895d353 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupRuleWebResource.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupRuleWebResource.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.openstacknetworking.web;
 
+import org.apache.commons.io.IOUtils;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupAdminService;
 import org.onosproject.rest.AbstractWebResource;
 import org.openstack4j.openstack.networking.domain.NeutronSecurityGroupRule;
@@ -32,11 +34,15 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
 import java.io.InputStream;
 
 import static javax.ws.rs.core.Response.created;
 import static javax.ws.rs.core.Response.noContent;
+import static org.onosproject.openstacknetworking.api.Constants.REST_UTF8;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.jsonToModelEntity;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncDelete;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncPost;
 
 /**
  * Handles Security Group Rule Rest API call from Neutron ML2 plugin.
@@ -50,6 +56,7 @@
 
     private final OpenstackSecurityGroupAdminService adminService =
                                     get(OpenstackSecurityGroupAdminService.class);
+    private final OpenstackHaService haService = get(OpenstackHaService.class);
 
     @Context
     private UriInfo uriInfo;
@@ -60,16 +67,23 @@
      * @param input security group JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated security group rule ID already exists
+     * @throws IOException exception
      * @onos.rsModel NeutronSecurityGroupRule
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response createSecurityGroupRules(InputStream input) {
+    public Response createSecurityGroupRules(InputStream input) throws IOException {
         log.trace(String.format(MESSAGE, "CREATE"));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPost(haService, SECURITY_GROUP_RULES, inputStr);
+        }
+
         final NeutronSecurityGroupRule sgRule = (NeutronSecurityGroupRule)
-                        jsonToModelEntity(input, NeutronSecurityGroupRule.class);
+                        jsonToModelEntity(inputStr, NeutronSecurityGroupRule.class);
 
         adminService.createSecurityGroupRule(sgRule);
         UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
@@ -92,6 +106,10 @@
     public Response deleteSecurityGroupRule(@PathParam("id") String id) {
         log.trace(String.format(MESSAGE, "REMOVE " + id));
 
+        if (!haService.isActive()) {
+            return syncDelete(haService, SECURITY_GROUP_RULES, id);
+        }
+
         adminService.removeSecurityGroupRule(id);
         return noContent().build();
     }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupWebResource.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupWebResource.java
index b1f1d47..3c9c2b4 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupWebResource.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSecurityGroupWebResource.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.openstacknetworking.web;
 
+import org.apache.commons.io.IOUtils;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupAdminService;
 import org.onosproject.rest.AbstractWebResource;
 import org.openstack4j.openstack.networking.domain.NeutronSecurityGroup;
@@ -33,11 +35,15 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
 import java.io.InputStream;
 
 import static javax.ws.rs.core.Response.created;
 import static javax.ws.rs.core.Response.noContent;
+import static org.onosproject.openstacknetworking.api.Constants.REST_UTF8;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.jsonToModelEntity;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncDelete;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncPost;
 
 /**
  * Handles Security Group REST API call from Neutron ML2 plugin.
@@ -51,6 +57,7 @@
 
     private final OpenstackSecurityGroupAdminService adminService =
                                     get(OpenstackSecurityGroupAdminService.class);
+    private final OpenstackHaService haService = get(OpenstackHaService.class);
 
     @Context
     private UriInfo uriInfo;
@@ -61,16 +68,23 @@
      * @param input security group JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated security group ID already exists
+     * @throws IOException exception
      * @onos.rsModel NeutronSecurityGroup
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response createSecurityGroups(InputStream input) {
+    public Response createSecurityGroups(InputStream input) throws IOException {
         log.trace(String.format(MESSAGE, "CREATE"));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPost(haService, SECURITY_GROUPS, inputStr);
+        }
+
         final NeutronSecurityGroup sg = (NeutronSecurityGroup)
-                            jsonToModelEntity(input, NeutronSecurityGroup.class);
+                jsonToModelEntity(inputStr, NeutronSecurityGroup.class);
 
         adminService.createSecurityGroup(sg);
         UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
@@ -112,6 +126,10 @@
     public Response removeSecurityGroup(@PathParam("id") String id) {
         log.trace(String.format(MESSAGE, "REMOVE " + id));
 
+        if (!haService.isActive()) {
+            return syncDelete(haService, SECURITY_GROUPS, id);
+        }
+
         adminService.removeSecurityGroup(id);
         return noContent().build();
     }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSubnetWebResource.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSubnetWebResource.java
index d8ab462..3f20c09 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSubnetWebResource.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/web/OpenstackSubnetWebResource.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.openstacknetworking.web;
 
+import org.apache.commons.io.IOUtils;
+import org.onosproject.openstacknetworking.api.OpenstackHaService;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
 import org.onosproject.rest.AbstractWebResource;
 import org.openstack4j.openstack.networking.domain.NeutronSubnet;
@@ -33,12 +35,17 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
 import java.io.InputStream;
 
 import static javax.ws.rs.core.Response.created;
 import static javax.ws.rs.core.Response.noContent;
 import static javax.ws.rs.core.Response.status;
+import static org.onosproject.openstacknetworking.api.Constants.REST_UTF8;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.jsonToModelEntity;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncDelete;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncPost;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.syncPut;
 
 /**
  * Handles subnet REST API call from Neutron ML2 plugin.
@@ -52,6 +59,7 @@
 
     private final OpenstackNetworkAdminService adminService =
                                         get(OpenstackNetworkAdminService.class);
+    private final OpenstackHaService haService = get(OpenstackHaService.class);
 
     @Context
     private UriInfo uriInfo;
@@ -62,16 +70,23 @@
      * @param input subnet JSON input stream
      * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
      * is invalid or duplicated subnet already exists
+     * @throws IOException exception
      * @onos.rsModel NeutronSubnet
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response createSubnet(InputStream input) {
+    public Response createSubnet(InputStream input) throws IOException {
         log.trace(String.format(MESSAGE, "CREATE"));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPost(haService, SUBNETS, inputStr);
+        }
+
         final NeutronSubnet subnet = (NeutronSubnet)
-                            jsonToModelEntity(input, NeutronSubnet.class);
+                jsonToModelEntity(inputStr, NeutronSubnet.class);
 
         adminService.createSubnet(subnet);
         UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
@@ -89,17 +104,24 @@
      * @param input subnet JSON input stream
      * @return 200 OK with the updated subnet, 400 BAD_REQUEST if the requested
      * subnet does not exist
+     * @throws IOException exception
      * @onos.rsModel NeutronSubnet
      */
     @PUT
     @Path("{id}")
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
-    public Response updateSubnet(@PathParam("id") String id, InputStream input) {
+    public Response updateSubnet(@PathParam("id") String id, InputStream input) throws IOException {
         log.trace(String.format(MESSAGE, "UPDATE " + id));
 
+        String inputStr = IOUtils.toString(input, REST_UTF8);
+
+        if (!haService.isActive()) {
+            return syncPut(haService, SUBNETS, id, inputStr);
+        }
+
         final NeutronSubnet subnet = (NeutronSubnet)
-                            jsonToModelEntity(input, NeutronSubnet.class);
+                            jsonToModelEntity(inputStr, NeutronSubnet.class);
 
         adminService.updateSubnet(subnet);
 
@@ -119,6 +141,10 @@
     public Response deleteSubnet(@PathParam("id") String id) {
         log.trace(String.format(MESSAGE, "DELETE " + id));
 
+        if (!haService.isActive()) {
+            return syncDelete(haService, SUBNETS, id);
+        }
+
         adminService.removeSubnet(id);
         return noContent().build();
     }