Websocket pre-registration for port status update 73/77273/10
authorJosh <jhershbe@redhat.com>
Thu, 25 Oct 2018 08:49:35 +0000 (11:49 +0300)
committerStephen Kitt <skitt@redhat.com>
Wed, 31 Oct 2018 17:27:10 +0000 (18:27 +0100)
Due to load balancing between networking-odl
and ODL the registration REST calls do not
always hit the same ODL node as the actual
websocket connection. This causes the websocket
connection to fail. This patch pre-registers
the websockets on each ODL node during
initialization time.

Change-Id: I0b1f574c2735de0426a16c4473add99f2e512680
Signed-off-by: Josh <jhershbe@redhat.com>
Signed-off-by: Stephen Kitt <skitt@redhat.com>
features/production/odl-neutron-northbound-api/pom.xml
features/production/odl-neutron-northbound-api/src/main/feature/feature.xml [new file with mode: 0644]
northbound-api/pom.xml
northbound-api/src/main/java/org/opendaylight/neutron/northbound/impl/PortStatusUpdateInitializer.java [new file with mode: 0644]
northbound-api/src/main/resources/OSGI-INF/blueprint/blueprint.xml
northbound-api/src/main/resources/initial/neutron-northbound-api-config.xml [new file with mode: 0644]
northbound-api/src/main/yang/northbound-api-config.yang [new file with mode: 0644]

index 226a7dfa967563367b9318c622809bacbec742e8..08944b9180cbed4341be964fa9f6655fdc68c430 100644 (file)
     <packaging>feature</packaging>
     <name>OpenDaylight :: Neutron :: Northbound</name>
 
+    <properties>
+        <config.configfile.directory>etc/opendaylight/datastore/initial/config</config.configfile.directory>
+        <config.configfile.file>neutron-northbound-api-config.xml</config.configfile.file>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.opendaylight.infrautils</groupId>
+                <artifactId>infrautils-artifacts</artifactId>
+                <version>1.5.0-SNAPSHOT</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.opendaylight.aaa</groupId>
+                <artifactId>aaa-artifacts</artifactId>
+                <version>0.9.0-SNAPSHOT</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.opendaylight.netconf</groupId>
+                <artifactId>restconf-artifacts</artifactId>
+                <version>1.9.0-SNAPSHOT</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
     <dependencies>
         <dependency>
             <groupId>org.opendaylight.infrautils</groupId>
             <artifactId>odl-infrautils-utils</artifactId>
-            <version>1.5.0-SNAPSHOT</version>
+            <type>xml</type>
+            <classifier>features</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.infrautils</groupId>
+            <artifactId>odl-infrautils-inject</artifactId>
             <type>xml</type>
             <classifier>features</classifier>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.aaa</groupId>
             <artifactId>odl-aaa-shiro</artifactId>
-            <version>0.9.0-SNAPSHOT</version>
+            <type>xml</type>
+            <classifier>features</classifier>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.netconf</groupId>
+            <artifactId>odl-restconf</artifactId>
             <type>xml</type>
             <classifier>features</classifier>
         </dependency>
             <artifactId>northbound-api</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.neutron</groupId>
+            <artifactId>northbound-api</artifactId>
+            <version>${project.version}</version>
+            <type>xml</type>
+            <classifier>config</classifier>
+        </dependency>
         <!-- because the REST API classes @Inject @Reference INeutronCRUD dependencies,
              we do need a dependency to the implementation of those INeutronCRUDs in transcriber;
              otherwise this feature would not work standalone, and SFT will fail. -->
diff --git a/features/production/odl-neutron-northbound-api/src/main/feature/feature.xml b/features/production/odl-neutron-northbound-api/src/main/feature/feature.xml
new file mode 100644 (file)
index 0000000..77fcdeb
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.1" name="odl-neutron-northbound-api-${project.version}">
+   <feature name="odl-neutron-northbound-api" version="${project.version}">
+      <configfile finalname="${config.configfile.directory}/${config.configfile.file}">mvn:org.opendaylight.neutron/northbound-api/${project.version}/xml/config</configfile>
+   </feature>
+</features>
index 239f1c54c006b606426af5c83d11cf03b84e58d3..ee40f8ee5efe47c3f2ebbcf101335bee1ea3495a 100644 (file)
         <type>pom</type>
         <scope>import</scope>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.netconf</groupId>
+        <artifactId>restconf-artifacts</artifactId>
+        <version>1.9.0-SNAPSHOT</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 
       <groupId>org.opendaylight.aaa.web</groupId>
       <artifactId>servlet-api</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>restconf-nb-bierman02</artifactId>
+      <!-- The following fails the classpath duplicate test in test-standalone -->
+      <exclusions>
+        <exclusion>
+          <groupId>io.netty</groupId>
+          <artifactId>netty-codec-http</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
           </dependency>
         </dependencies>
       </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-artifacts</id>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <phase>package</phase>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>${project.build.directory}/classes/initial/neutron-northbound-api-config.xml</file>
+                  <type>xml</type>
+                  <classifier>config</classifier>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
   <scm>
diff --git a/northbound-api/src/main/java/org/opendaylight/neutron/northbound/impl/PortStatusUpdateInitializer.java b/northbound-api/src/main/java/org/opendaylight/neutron/northbound/impl/PortStatusUpdateInitializer.java
new file mode 100644 (file)
index 0000000..271477f
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018 Red Hat, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.neutron.northbound.impl;
+
+import com.google.common.base.Optional;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import javax.ws.rs.core.MultivaluedHashMap;
+
+import org.opendaylight.netconf.sal.restconf.api.JSONRestconfService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.northbound.api.config.rev181024.NeutronNorthboundApiConfig;
+import org.opendaylight.yangtools.yang.common.OperationFailedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class PortStatusUpdateInitializer {
+    private static final Logger LOG = LoggerFactory.getLogger(PortStatusUpdateInitializer.class);
+
+    private static final String SUBSCRIBE_JSON = "{\n"
+            + "  \"input\": {\n"
+            + "    \"path\": \"/neutron:neutron/neutron:ports\", \n"
+            + "    \"sal-remote-augment:notification-output-type\": \"JSON\", \n"
+            + "    \"sal-remote-augment:datastore\": \"OPERATIONAL\", \n"
+            + "    \"sal-remote-augment:scope\": \"SUBTREE\"\n"
+            + "  }\n"
+            + "}\n";
+
+    private final NeutronNorthboundApiConfig cfg;
+    private final JSONRestconfService jsonRestconfService;
+
+    @Inject
+    public PortStatusUpdateInitializer(JSONRestconfService jsonRestconfService,
+                                       final NeutronNorthboundApiConfig neutronNorthboundApiConfig) {
+        this.cfg = neutronNorthboundApiConfig;
+        this.jsonRestconfService = jsonRestconfService;
+
+        boolean preRegister = cfg.isPreRegisterPortStatusWebsocket() == null || cfg.isPreRegisterPortStatusWebsocket();
+
+        if (preRegister) {
+            subscribeWebsocket();
+        } else {
+            LOG.info("PortStatusUpdateInitializer: Skipping pre-register of websockets");
+        }
+    }
+
+    private void subscribeWebsocket() {
+        dataChangeEventSubscription();
+        streamSubscribe();
+    }
+
+    private void dataChangeEventSubscription() {
+        try {
+            Optional<String> res = jsonRestconfService.invokeRpc(
+                    "sal-remote:create-data-change-event-subscription", Optional.of(SUBSCRIBE_JSON));
+            LOG.info("create-data-change-event-subscription returned {}", res.toString());
+        } catch (OperationFailedException e) {
+            LOG.error("exception while calling create-data-change-event-subscription", e);
+        }
+    }
+
+    private void streamSubscribe() {
+        String identifier = "data-change-event-subscription/neutron:neutron/neutron:ports"
+                                                                        + "/datastore=OPERATIONAL/scope=SUBTREE";
+        MultivaluedHashMap map = new MultivaluedHashMap<String, String>();
+        map.add("odl-leaf-nodes-only", "true");
+        Optional<String> res = null;
+        try {
+            res = jsonRestconfService.subscribeToStream(identifier, map);
+            LOG.info("subscribeToStream returned {}", res.toString());
+        } catch (OperationFailedException e) {
+            LOG.error("exception while calling subscribeToStream", e);
+        }
+    }
+}
index fab85014f1b1cb4f4cbc1cbce9bc178df513ba00..a9dc57a97091d6c90da3e216a13523adbe698887 100644 (file)
@@ -7,4 +7,12 @@
   <reference id="webContextSecurer" interface="org.opendaylight.aaa.web.WebContextSecurer" />
 
   <reference id="servletSupport" interface="org.opendaylight.aaa.web.servlet.ServletSupport" />
+
+  <reference id="jSONRestconfService" interface="org.opendaylight.netconf.sal.restconf.api.JSONRestconfService" />
+
+  <odl:clustered-app-config id="neutronNorthboundApiConfig"
+                        binding-class="org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.northbound.api.config.rev181024.NeutronNorthboundApiConfig"
+                        default-config-file-name="neutron-northbound-api-config.xml"
+                        update-strategy="none">
+  </odl:clustered-app-config>
 </blueprint>
diff --git a/northbound-api/src/main/resources/initial/neutron-northbound-api-config.xml b/northbound-api/src/main/resources/initial/neutron-northbound-api-config.xml
new file mode 100644 (file)
index 0000000..c24968f
--- /dev/null
@@ -0,0 +1,3 @@
+<neutron-northbound-api-config xmlns="urn:opendaylight:neutron:northbound-api:config">
+    <pre-register-port-status-websocket>true</pre-register-port-status-websocket>
+</neutron-northbound-api-config>
\ No newline at end of file
diff --git a/northbound-api/src/main/yang/northbound-api-config.yang b/northbound-api/src/main/yang/northbound-api-config.yang
new file mode 100644 (file)
index 0000000..eae2a20
--- /dev/null
@@ -0,0 +1,22 @@
+module neutron-northbound-api-config {
+
+    namespace "urn:opendaylight:neutron:northbound-api:config";
+
+    prefix neutron-northbound-api-config;
+
+    import ietf-yang-types {
+        prefix yang;
+    }
+
+    description "This YANG module defines neutron northbound-api configuration.";
+    revision "2018-10-24";
+
+    container neutron-northbound-api-config {
+        config true;
+        leaf pre-register-port-status-websocket {
+           type boolean;
+           default true;
+           description "Pre-register the port status update websocket";
+        }
+    }
+}