- getBitRate() function 43/1043/1
authorKatrina LaCurts <katrina.lacurts@plexxi.com>
Thu, 29 Aug 2013 18:37:36 +0000 (14:37 -0400)
committerKatrina LaCurts <katrina.lacurts@plexxi.com>
Thu, 29 Aug 2013 19:36:31 +0000 (15:36 -0400)
- Northbound API for analytics

Signed-off-by: Katrina LaCurts <katrina.lacurts@plexxi.com>
21 files changed:
analytics/api/pom.xml [new file with mode: 0644]
analytics/api/src/main/java/org/opendaylight/controller/analytics/IAnalyticsManager.java [new file with mode: 0644]
analytics/implementation/pom.xml [moved from analytics/pom.xml with 79% similarity]
analytics/implementation/src/main/java/org/opendaylight/controller/analytics/internal/Activator.java [moved from analytics/src/main/java/org/opendaylight/controller/analytics/internal/Activator.java with 75% similarity]
analytics/implementation/src/main/java/org/opendaylight/controller/analytics/internal/AnalyticsManager.java [moved from analytics/src/main/java/org/opendaylight/controller/analytics/internal/AnalyticsManager.java with 69% similarity]
analytics/implementation/src/main/java/org/opendaylight/controller/analytics/internal/HostStats.java [new file with mode: 0644]
analytics/implementation/src/test/java/org/opendaylight/controller/analytics/internal/AnalyticsManagerTest.java [new file with mode: 0644]
analytics/northbound/enunciate.xml [new file with mode: 0644]
analytics/northbound/pom.xml [new file with mode: 0644]
analytics/northbound/src/main/java/org/opendaylight/controller/analytics/northbound/AnalyticsNorthbound.java [new file with mode: 0644]
analytics/northbound/src/main/java/org/opendaylight/controller/analytics/northbound/AnalyticsNorthboundRSApplication.java [new file with mode: 0644]
analytics/northbound/src/main/java/org/opendaylight/controller/analytics/northbound/HostStatistics.java [new file with mode: 0644]
analytics/northbound/src/main/resources/META-INF/spring.factories [new file with mode: 0644]
analytics/northbound/src/main/resources/META-INF/spring.handlers [new file with mode: 0644]
analytics/northbound/src/main/resources/META-INF/spring.schemas [new file with mode: 0644]
analytics/northbound/src/main/resources/META-INF/spring.tooling [new file with mode: 0644]
analytics/northbound/src/main/resources/WEB-INF/web.xml [new file with mode: 0644]
analytics/northbound/test/java/org/opendaylight/controller/analytics/northbound/AnalyticsNorthboundTest.java [new file with mode: 0644]
analytics/src/test/java/org/opendaylight/controller/analytics/internal/AnalyticsManagerTest.java [deleted file]
pom.xml
scripts/analytics.py [new file with mode: 0644]

diff --git a/analytics/api/pom.xml b/analytics/api/pom.xml
new file mode 100644 (file)
index 0000000..0a89790
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+    <relativePath>../../commons/opendaylight</relativePath>
+  </parent>
+  <artifactId>analytics</artifactId>
+  <version>0.4.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.3.6</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Import-Package>
+              org.opendaylight.controller.sal.core,
+            </Import-Package>
+            <Export-Package>
+              org.opendaylight.controller.analytics
+            </Export-Package>
+          </instructions>
+          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/analytics/api/src/main/java/org/opendaylight/controller/analytics/IAnalyticsManager.java b/analytics/api/src/main/java/org/opendaylight/controller/analytics/IAnalyticsManager.java
new file mode 100644 (file)
index 0000000..8c44585
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2013 Plexxi, 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.controller.analytics;
+
+import org.opendaylight.controller.sal.core.Host;
+
+public interface IAnalyticsManager {
+
+    long getByteCountBetweenHosts(Host src, Host dst);
+
+    double getBitRateBetweenHosts(Host src, Host dst);
+}
similarity index 79%
rename from analytics/pom.xml
rename to analytics/implementation/pom.xml
index d63315d948033635c285a4b85c9dafa7ef1d05c4..14702499a40187f9859684aedaacaf583f2f6a9f 100644 (file)
@@ -4,13 +4,13 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>affinity</artifactId>
-    <version>0.4.1-SNAPSHOT</version>
-    <relativePath>..</relativePath>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+    <relativePath>../commons/opendaylight</relativePath>
   </parent>
 
-  <artifactId>analytics</artifactId>
-  <version>0.4.1-SNAPSHOT</version>
+  <artifactId>analytics.implementation</artifactId>
+  <version>0.4.0-SNAPSHOT</version>
   <packaging>bundle</packaging>
 
   <build>
         <configuration>
           <instructions>
             <Import-Package>
+              org.opendaylight.controller.analytics,
               org.opendaylight.controller.clustering.services,
-              org.opendaylight.controller.containermanager,
-              org.opendaylight.controller.forwardingrulesmanager,
               org.opendaylight.controller.hosttracker,
               org.opendaylight.controller.hosttracker.hostAware,
               org.opendaylight.controller.sal.core,
               org.opendaylight.controller.sal.flowprogrammer,
-              org.opendaylight.controller.sal.inventory,
               org.opendaylight.controller.sal.match,
-              org.opendaylight.controller.sal.packet,
               org.opendaylight.controller.sal.packet.address,
               org.opendaylight.controller.sal.reader,
               org.opendaylight.controller.sal.utils,
@@ -53,7 +50,7 @@
   <dependencies>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
-      <artifactId>containermanager</artifactId>
+      <artifactId>analytics</artifactId>
       <version>0.4.0-SNAPSHOT</version>
     </dependency>
     <dependency>
       <artifactId>clustering.services</artifactId>
       <version>0.4.0-SNAPSHOT</version>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>forwardingrulesmanager</artifactId>
-      <version>0.4.0-SNAPSHOT</version>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>hosttracker</artifactId>
@@ -84,7 +76,7 @@
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>switchmanager</artifactId>
-      <version>0.4.0-SNAPSHOT</version>
+      <version>0.5.0-SNAPSHOT</version>
     </dependency>
   </dependencies>
 </project>
similarity index 75%
rename from analytics/src/main/java/org/opendaylight/controller/analytics/internal/Activator.java
rename to analytics/implementation/src/main/java/org/opendaylight/controller/analytics/internal/Activator.java
index 9d1d00759269bc2ead574820bad6a942403dfcbd..e3dfac2e29081d54f2a0bf1850986eb4baa1fb97 100644 (file)
@@ -13,9 +13,12 @@ import org.apache.felix.dm.Component;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.opendaylight.controller.analytics.IAnalyticsManager;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
 import org.opendaylight.controller.hosttracker.IfIptoHost;
-import org.opendaylight.controller.hosttracker.IfHostListener;
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.core.IContainer;
+import org.opendaylight.controller.sal.reader.IReadService;
 import org.opendaylight.controller.sal.reader.IReadServiceListener;
 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
 import org.opendaylight.controller.switchmanager.ISwitchManager;
@@ -69,7 +72,8 @@ public class Activator extends ComponentActivatorAbstractBase {
         if (imp.equals(AnalyticsManager.class)) {
             // set interfaces
             c.setInterface(new String[] {
-                    IReadServiceListener.class.getName() }, null);
+                    IReadServiceListener.class.getName(),
+                    IAnalyticsManager.class.getName()}, null);
 
             c.add(createContainerServiceDependency(containerName).setService(IfIptoHost.class)
                   .setCallbacks("setHostTracker", "unsetHostTracker").setRequired(true));
@@ -77,6 +81,13 @@ public class Activator extends ComponentActivatorAbstractBase {
                   .setCallbacks("setStatisticsManager", "unsetStatisticsManager").setRequired(false));
             c.add(createContainerServiceDependency(containerName).setService(ISwitchManager.class)
                   .setCallbacks("setSwitchManager", "unsetSwitchManager").setRequired(true));
+
+            c.add(createContainerServiceDependency(containerName).setService(IReadService.class)
+                    .setCallbacks("setReaderService", "unsetReaderService").setRequired(true));
+            c.add(createContainerServiceDependency(containerName).setService(IClusterContainerServices.class)
+                    .setCallbacks("setClusterContainerService", "unsetClusterContainerService").setRequired(true));
+            c.add(createContainerServiceDependency(containerName).setService(IContainer.class)
+                    .setCallbacks("setIContainer", "unsetIContainer").setRequired(true));
         }
     }
 }
similarity index 69%
rename from analytics/src/main/java/org/opendaylight/controller/analytics/internal/AnalyticsManager.java
rename to analytics/implementation/src/main/java/org/opendaylight/controller/analytics/internal/AnalyticsManager.java
index b2edc0b05e45bfb4d792699bfff16dc851c16c19..68f1f632b8b248159d7ff32a4756c94ace5f2c43 100644 (file)
@@ -8,24 +8,18 @@
 
 package org.opendaylight.controller.analytics.internal;
 
-import java.lang.reflect.Constructor;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.Future;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.opendaylight.controller.containermanager.IContainerManager;
+import org.opendaylight.controller.analytics.IAnalyticsManager;
 import org.opendaylight.controller.hosttracker.IfIptoHost;
-import org.opendaylight.controller.hosttracker.IfHostListener;
 import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
 import org.opendaylight.controller.sal.core.Host;
 import org.opendaylight.controller.sal.core.Node;
@@ -34,20 +28,17 @@ import org.opendaylight.controller.sal.flowprogrammer.Flow;
 import org.opendaylight.controller.sal.match.Match;
 import org.opendaylight.controller.sal.match.MatchField;
 import org.opendaylight.controller.sal.match.MatchType;
-import org.opendaylight.controller.sal.packet.address.DataLinkAddress;
 import org.opendaylight.controller.sal.packet.address.EthernetAddress;
 import org.opendaylight.controller.sal.reader.FlowOnNode;
 import org.opendaylight.controller.sal.reader.IReadServiceListener;
 import org.opendaylight.controller.sal.reader.NodeConnectorStatistics;
 import org.opendaylight.controller.sal.reader.NodeDescription;
 import org.opendaylight.controller.sal.reader.NodeTableStatistics;
-import org.opendaylight.controller.sal.utils.ServiceHelper;
-import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.statisticsmanager.IStatisticsManager;
 import org.opendaylight.controller.switchmanager.ISwitchManager;
 import org.opendaylight.controller.switchmanager.SubnetConfig;
 
-public class AnalyticsManager implements IReadServiceListener {
+public class AnalyticsManager implements IReadServiceListener, IAnalyticsManager {
 
     private static final Logger log = LoggerFactory.getLogger(AnalyticsManager.class);
 
@@ -55,15 +46,15 @@ public class AnalyticsManager implements IReadServiceListener {
     private ISwitchManager switchManager;
     private IfIptoHost hostTracker;
 
-    private Map<Host, Map<Host, Object>> hostToFlowStats; // TODO: Tighter object types
     private Map<MatchField, Host> destinationHostCache;
     private Map<MatchField, Host> sourceHostCache;
+    private Map<Host, Map<Host, HostStats>> hostsToStats;
 
     void init() {
         log.debug("INIT called!");
-        this.hostToFlowStats = new HashMap<Host, Map<Host, Object>>();
         this.destinationHostCache = new HashMap<MatchField, Host>();
         this.sourceHostCache = new HashMap<MatchField, Host>();
+        this.hostsToStats = new HashMap<Host, Map<Host, HostStats>>();
     }
 
     void destroy() {
@@ -106,13 +97,7 @@ public class AnalyticsManager implements IReadServiceListener {
 
         // Add a default subnet to allow the hostTracker to populate
         // the host lists.
-        //
-        // TODO: Is this really the correct way to get the hosts
-        // populated?
-        //
-        // TODO: This is should really use the second SubnetConfig
-        // constructor; see a note in that file.
-        SubnetConfig defaultSubnet = new SubnetConfig();
+        SubnetConfig defaultSubnet = new SubnetConfig("default", "10.0.0.254/8", new HashSet<String>());
         this.switchManager.addSubnet(defaultSubnet);
     }
 
@@ -125,7 +110,7 @@ public class AnalyticsManager implements IReadServiceListener {
     /* Returns the destination host associated with this flow, if one
      * exists.  Returns null otherwise.
      */
-    private Host getDestinationHostFromFlow(Flow flow) {
+    protected Host getDestinationHostFromFlow(Flow flow, Set<HostNodeConnector> hosts) {
         Host dstHost = null;
         Match match = flow.getMatch();
 
@@ -143,7 +128,7 @@ public class AnalyticsManager implements IReadServiceListener {
             // strings (comparing MAC address bytes, surprisingly, did
             // not work).
             String dstMac = MatchType.DL_DST.stringify(dlDst.getValue());
-            for (HostNodeConnector h : this.hostTracker.getAllHosts()) {
+            for (HostNodeConnector h : hosts) {
                 String hostMac = ((EthernetAddress) h.getDataLayerAddress()).getMacAddress();
                 if (dstMac.equals(hostMac)) {
                     dstHost = h;
@@ -159,7 +144,7 @@ public class AnalyticsManager implements IReadServiceListener {
     /* Returns the source Host associated with this flow, if one
      * exists.  Returns null otherwise.
      */
-    private Host getSourceHostFromFlow(Flow flow) {
+    protected Host getSourceHostFromFlow(Flow flow, Set<HostNodeConnector> hosts) {
         Host srcHost = null;
         Match match = flow.getMatch();
 
@@ -176,7 +161,7 @@ public class AnalyticsManager implements IReadServiceListener {
 
             // Find the source host by comparing the NodeConnectors
             NodeConnector inPortNc = (NodeConnector) inPort.getValue();
-            for (HostNodeConnector h : this.hostTracker.getAllHosts()) {
+            for (HostNodeConnector h : hosts) {
                 NodeConnector hostNc = h.getnodeConnector();
                 if (hostNc.equals(inPortNc)) {
                     srcHost = h;
@@ -191,52 +176,41 @@ public class AnalyticsManager implements IReadServiceListener {
 
     public long getByteCountBetweenHosts(Host src, Host dst) {
 
-        // TODO: Need a cache so that we don't have to search through all nodes.
-
-        List<FlowOnNode> relevantFlows = new ArrayList<FlowOnNode>();
-
-        Set<Node> allNodes = this.switchManager.getNodes();
-        for (Node node : allNodes) {
-            List<FlowOnNode> flowsOnNode = this.statisticsManager.getFlows(node);
-            for (FlowOnNode f : flowsOnNode) {
-                Host dstHost = getDestinationHostFromFlow(f.getFlow());
-                Host srcHost = getSourceHostFromFlow(f.getFlow());
-
-                // This does not indicate error, it's just a flow we're
-                // not interested in (ARP traffic, e.g.)
-                if (dstHost == null || srcHost == null) {
-                    continue;
-                }
-
-                if (dstHost.equals(dst) && srcHost.equals(src)) {
-                    relevantFlows.add(f);
-                }
-            }
-        }
-
         long byteCount = 0;
-        for (FlowOnNode f : relevantFlows) {
-            if (f.getByteCount() > byteCount) {
-                byteCount = f.getByteCount();
-            }
+        if (this.hostsToStats.get(src) != null &&
+            this.hostsToStats.get(src).get(dst) != null) {
+            byteCount = this.hostsToStats.get(src).get(dst).getByteCount();
         }
 
         return byteCount;
     }
 
+    public double getBitRateBetweenHosts(Host src, Host dst) {
+        double bitRate = 0;
+        if (this.hostsToStats.get(src) != null &&
+            this.hostsToStats.get(src).get(dst) != null) {
+            bitRate = this.hostsToStats.get(src).get(dst).getBitRate();
+        }
+
+        return bitRate;
+    }
+
     @Override
     public void nodeFlowStatisticsUpdated(Node node, List<FlowOnNode> flowStatsList) {
-        // TODO: un-comment out if testing
-        /*
-        for (HostNodeConnector h1 : this.hostTracker.getAllHosts()) {
-            for (HostNodeConnector h2 : this.hostTracker.getAllHosts()) {
-                long b = getByteCountBetweenHosts(h1, h2);
-                System.out.println("!!! result:");
-                System.out.println("!!!   " + h1);
-                System.out.println("!!!   " + h2);
-                System.out.println("!!!   " + b);
+
+        Set<HostNodeConnector> allHosts = this.hostTracker.getAllHosts();
+        for (FlowOnNode f : flowStatsList) {
+            Host srcHost = getSourceHostFromFlow(f.getFlow(), allHosts);
+            Host dstHost = getDestinationHostFromFlow(f.getFlow(), allHosts);
+
+            if (this.hostsToStats.get(srcHost) == null) {
+                this.hostsToStats.put(srcHost, new HashMap<Host, HostStats>());
             }
-            }*/
+            if (this.hostsToStats.get(srcHost).get(dstHost) == null) {
+                this.hostsToStats.get(srcHost).put(dstHost, new HostStats());
+            }
+            this.hostsToStats.get(srcHost).get(dstHost).setStatsFromFlow(f);
+        }
     }
 
     @Override
@@ -253,4 +227,4 @@ public class AnalyticsManager implements IReadServiceListener {
     public void descriptionStatisticsUpdated(Node node, NodeDescription nodeDescription) {
         // Not interested in this update
     }
-}
+}
\ No newline at end of file
diff --git a/analytics/implementation/src/main/java/org/opendaylight/controller/analytics/internal/HostStats.java b/analytics/implementation/src/main/java/org/opendaylight/controller/analytics/internal/HostStats.java
new file mode 100644 (file)
index 0000000..0ac28ec
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013 Plexxi, Inc.  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.controller.analytics.internal;
+
+import org.opendaylight.controller.sal.reader.FlowOnNode;
+
+public class HostStats {
+
+    private long byteCount;
+    private double duration;
+
+    public HostStats() {
+        this.byteCount = 0;
+        this.duration = 0;
+    }
+
+    public long getByteCount() {
+        return this.byteCount;
+    }
+
+    public void setByteCount(long byteCount) {
+        this.byteCount = byteCount;
+    }
+
+    public double getDuration() {
+        return this.duration;
+    }
+
+    public void setDuration(double duration) {
+        this.duration = duration;
+    }
+
+    public void setStatsFromFlow(FlowOnNode flow) {
+        this.byteCount = flow.getByteCount();
+        this.duration = flow.getDurationSeconds() + .000000001 * flow.getDurationNanoseconds();
+    }
+
+    public double getBitRate() {
+        System.out.println("!!! byte count: " + this.byteCount);
+        System.out.println("!!! duration: " + this.duration);
+        return (this.byteCount * 8)/(this.duration);
+    }
+}
\ No newline at end of file
diff --git a/analytics/implementation/src/test/java/org/opendaylight/controller/analytics/internal/AnalyticsManagerTest.java b/analytics/implementation/src/test/java/org/opendaylight/controller/analytics/internal/AnalyticsManagerTest.java
new file mode 100644 (file)
index 0000000..f1c5afe
--- /dev/null
@@ -0,0 +1,123 @@
+/*\r
+ * Copyright (c) 2013 Plexxi, Inc.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.controller.analytics.internal;\r
+\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import junit.framework.TestCase;\r
+import org.junit.Assert;\r
+import org.junit.Test;\r
+\r
+import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;\r
+import org.opendaylight.controller.sal.core.ConstructionException;\r
+import org.opendaylight.controller.sal.core.Host;\r
+import org.opendaylight.controller.sal.core.Node;\r
+import org.opendaylight.controller.sal.core.NodeConnector;\r
+import org.opendaylight.controller.sal.flowprogrammer.Flow;\r
+import org.opendaylight.controller.sal.match.Match;\r
+import org.opendaylight.controller.sal.match.MatchField;\r
+import org.opendaylight.controller.sal.match.MatchType;\r
+import org.opendaylight.controller.sal.reader.FlowOnNode;\r
+\r
+public class AnalyticsManagerTest extends TestCase {\r
+\r
+    @Test\r
+    public void testAnalyticsManagerCreation() {\r
+        AnalyticsManager am = new AnalyticsManager();\r
+        Assert.assertTrue(am != null);\r
+    }\r
+\r
+    @Test\r
+    public void testGetHostsFromFlows() {\r
+\r
+        AnalyticsManager am = new AnalyticsManager();\r
+        am.init();\r
+\r
+        try {\r
+            // Set up nodes\r
+            Node n1 = new Node(Node.NodeIDType.OPENFLOW, new Long(100L));\r
+            Node n2 = new Node(Node.NodeIDType.OPENFLOW, new Long(101L));\r
+            Node n3 = new Node(Node.NodeIDType.OPENFLOW, new Long(110L));\r
+            Node n4 = new Node(Node.NodeIDType.OPENFLOW, new Long(111L));\r
+\r
+            // Set up node connectors\r
+            NodeConnector nc1 = new NodeConnector(NodeConnector.NodeConnectorIDType.OPENFLOW, new Short((short) 0xCAFC), n1);\r
+            NodeConnector nc2 = new NodeConnector(NodeConnector.NodeConnectorIDType.OPENFLOW, new Short((short) 0xCAFD), n2);\r
+            NodeConnector nc3 = new NodeConnector(NodeConnector.NodeConnectorIDType.OPENFLOW, new Short((short) 0xCAFE), n3);\r
+            NodeConnector nc4 = new NodeConnector(NodeConnector.NodeConnectorIDType.OPENFLOW, new Short((short) 0xCAFF), n4);\r
+\r
+            // Set up host node connectors\r
+            HostNodeConnector hnc1 = new HostNodeConnector(new byte[]{0,0,0,0,0,1}, InetAddress.getByName("10.0.0.1"), nc1, (short) 1);\r
+            HostNodeConnector hnc2 = new HostNodeConnector(new byte[]{0,0,0,0,0,2}, InetAddress.getByName("10.0.0.2"), nc2, (short) 1);\r
+            HostNodeConnector hnc3 = new HostNodeConnector(new byte[]{0,0,0,0,0,3}, InetAddress.getByName("10.0.0.3"), nc3, (short) 1);\r
+            Set<HostNodeConnector> hosts = new HashSet<HostNodeConnector>(Arrays.asList(hnc1, hnc2, hnc3));\r
+\r
+            // Set up a flow from nc1 to nc2\r
+            Match match = new Match();\r
+            match.setField(new MatchField(MatchType.IN_PORT, nc1));\r
+            match.setField(new MatchField(MatchType.DL_DST, new byte[]{0,0,0,0,0,2}));\r
+            Flow f = new Flow();\r
+            f.setMatch(match);\r
+\r
+            Host dstHost = am.getDestinationHostFromFlow(f, hosts);\r
+            Host srcHost = am.getSourceHostFromFlow(f, hosts);\r
+\r
+            Assert.assertTrue(dstHost.equals(hnc2));\r
+            Assert.assertTrue(srcHost.equals(hnc1));\r
+\r
+            // Set up a flow from nc3 to nc1\r
+            match = new Match();\r
+            match.setField(new MatchField(MatchType.IN_PORT, nc3));\r
+            match.setField(new MatchField(MatchType.DL_DST, new byte[]{0,0,0,0,0,1}));\r
+            f = new Flow();\r
+            f.setMatch(match);\r
+\r
+            dstHost = am.getDestinationHostFromFlow(f, hosts);\r
+            srcHost = am.getSourceHostFromFlow(f, hosts);\r
+\r
+            Assert.assertTrue(dstHost.equals(hnc1));\r
+            Assert.assertTrue(srcHost.equals(hnc3));\r
+\r
+            // Set up a flow from a switch to a non-host..\r
+            match = new Match();\r
+            match.setField(new MatchField(MatchType.IN_PORT, nc4));\r
+            match.setField(new MatchField(MatchType.DL_DST, new byte[]{0,0,0,0,0,2}));\r
+            f = new Flow();\r
+            f.setMatch(match);\r
+\r
+            dstHost = am.getDestinationHostFromFlow(f, hosts);\r
+            srcHost = am.getSourceHostFromFlow(f, hosts);\r
+\r
+            Assert.assertTrue(dstHost.equals(hnc2));\r
+            Assert.assertTrue(srcHost == null);\r
+        } catch (ConstructionException e) {\r
+            Assert.assertTrue(false);\r
+        } catch (UnknownHostException e ) {\r
+            Assert.assertTrue(false);\r
+        } finally {\r
+            am.destroy();\r
+        }\r
+    }\r
+\r
+    @Test\r
+    public void testGetByteCountBetweenHosts() {\r
+        // TODO: This test should exist, but it involves a lot of\r
+        // integration with the statisticsManager, switchManager, and\r
+        // hostTracker, and I'm not entirely sure how to go about that.\r
+        Assert.assertTrue(true);\r
+    }\r
+}\r
diff --git a/analytics/northbound/enunciate.xml b/analytics/northbound/enunciate.xml
new file mode 100644 (file)
index 0000000..c642349
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<enunciate label="full" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="http://enunciate.codehaus.org/schemas/enunciate-1.26.xsd">
+
+  <services>
+    <rest defaultRestSubcontext="/controller/nb/v2/analytics"/>
+  </services>
+
+  <modules>
+    <docs docsDir="rest" title="Analytics REST API" includeExampleXml="true" includeExampleJson="true"/>
+  </modules>
+</enunciate>
diff --git a/analytics/northbound/pom.xml b/analytics/northbound/pom.xml
new file mode 100644 (file)
index 0000000..22f1371
--- /dev/null
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.0-SNAPSHOT</version>
+    <relativePath>../../commons/opendaylight</relativePath>
+  </parent>
+
+  <artifactId>analytics.northbound</artifactId>
+  <version>0.4.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.enunciate</groupId>
+        <artifactId>maven-enunciate-plugin</artifactId>
+        <version>${enunciate.version}</version>
+        <dependencies>
+          <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>sal</artifactId>
+            <version>0.5.0-SNAPSHOT</version>
+          </dependency>
+        </dependencies>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.3.6</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Export-Package>
+            </Export-Package>
+              <Import-Package>
+                com.sun.jersey.spi.container.servlet,
+                javax.ws.rs,
+                javax.ws.rs.core,
+                javax.xml.bind.annotation,
+                org.opendaylight.controller.analytics,
+                org.opendaylight.controller.containermanager,
+                org.opendaylight.controller.hosttracker,
+                org.opendaylight.controller.hosttracker.hostAware,
+                org.opendaylight.controller.northbound.commons,
+                org.opendaylight.controller.northbound.commons.exception,
+                org.opendaylight.controller.northbound.commons.utils,
+                org.opendaylight.controller.sal.authorization,
+                org.opendaylight.controller.sal.core,
+                org.opendaylight.controller.sal.utils,
+                org.opendaylight.controller.switchmanager,
+                !org.codehaus.enunciate.jaxrs
+              </Import-Package>
+            <Export-Package>
+            </Export-Package>
+            <Web-ContextPath>/controller/nb/v2/analytics</Web-ContextPath>
+          </instructions>
+          <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>analytics</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>containermanager</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>hosttracker</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+      <version>0.5.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.thirdparty</groupId>
+      <artifactId>com.sun.jersey.jersey-servlet</artifactId>
+      <version>1.17-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>commons.northbound</artifactId>
+      <version>0.4.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.enunciate</groupId>
+      <artifactId>enunciate-core-annotations</artifactId>
+      <version>${enunciate.version}</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/analytics/northbound/src/main/java/org/opendaylight/controller/analytics/northbound/AnalyticsNorthbound.java b/analytics/northbound/src/main/java/org/opendaylight/controller/analytics/northbound/AnalyticsNorthbound.java
new file mode 100644 (file)
index 0000000..2375811
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2013 Plexxi, 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.controller.analytics.northbound;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.SecurityContext;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.codehaus.enunciate.jaxrs.TypeHint;
+
+import org.opendaylight.controller.analytics.IAnalyticsManager;
+import org.opendaylight.controller.containermanager.IContainerManager;
+import org.opendaylight.controller.hosttracker.IfIptoHost;
+import org.opendaylight.controller.hosttracker.hostAware.HostNodeConnector;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.*;
+import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
+import org.opendaylight.controller.sal.authorization.Privilege;
+import org.opendaylight.controller.sal.core.Host;
+import org.opendaylight.controller.sal.utils.GlobalConstants;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.opendaylight.controller.switchmanager.ISwitchManager;
+
+/**
+ * Northbound APIs that returns various Analytics exposed by the Southbound
+ * plugins such as Openflow.
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+@Path("/")
+public class AnalyticsNorthbound {
+
+    private String username;
+
+    @Context
+    public void setSecurityContext(SecurityContext context) {
+        username = context.getUserPrincipal().getName();
+    }
+
+    protected String getUserName() {
+        return username;
+    }
+
+    private IAnalyticsManager getAnalyticsService(String containerName) {
+        IContainerManager containerManager = (IContainerManager) ServiceHelper.getGlobalInstance(IContainerManager.class, this);
+        if (containerManager == null) {
+            throw new ServiceUnavailableException("Container " + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        boolean found = false;
+        List<String> containerNames = containerManager.getContainerNames();
+        for (String cName : containerNames) {
+            if (cName.trim().equalsIgnoreCase(containerName.trim())) {
+                found = true;
+            }
+        }
+
+        if (found == false) {
+            throw new ResourceNotFoundException(containerName + " " + RestMessages.NOCONTAINER.toString());
+        }
+
+        IAnalyticsManager analyticsManager = (IAnalyticsManager) ServiceHelper.getInstance(IAnalyticsManager.class, containerName, this);
+        if (analyticsManager == null) {
+            throw new ServiceUnavailableException("Analytics " + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        return analyticsManager;
+    }
+
+    /**
+     * Returns a list of Host Statistics for a given Node.
+     *
+     * @param containerName
+     *            Name of the Container. The Container name for the base
+     *            controller is "default".
+     * @param dataLayerAddr
+     *            DataLayerAddress for the host
+     * @param networkAddr
+     *            NetworkAddress for the host
+     * @return List of Flow Statistics for a given Node. // TODO:
+     */
+    @Path("/{containerName}/hoststats/{srcNetworkAddr}/{dstNetworkAddr}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(HostStatistics.class)
+    @StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 404, condition = "The containerName is not found"),
+        @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
+    // TODO: This will need other parameters
+    public HostStatistics getHostStatistics(
+        @PathParam("containerName") String containerName,
+        @PathParam("srcNetworkAddr") String srcNetworkAddr,
+        @PathParam("dstNetworkAddr") String dstNetworkAddr) {
+        if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
+            throw new UnauthorizedException("User is not authorized to perform this operation on container " + containerName);
+        }
+        handleDefaultDisabled(containerName);
+
+        IAnalyticsManager analyticsManager = getAnalyticsService(containerName);
+        if (analyticsManager == null) {
+            throw new ServiceUnavailableException("Analytics " + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, containerName, this);
+        if (switchManager == null) {
+            throw new ServiceUnavailableException("Switch manager " + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        Host srcHost = handleHostAvailability(containerName, srcNetworkAddr);
+        Host dstHost = handleHostAvailability(containerName, dstNetworkAddr);
+        long byteCount = analyticsManager.getByteCountBetweenHosts(srcHost, dstHost);
+        double bitRate = analyticsManager.getBitRateBetweenHosts(srcHost, dstHost);
+
+        return new HostStatistics(srcHost, dstHost, byteCount, bitRate);
+
+    }
+
+    private void handleDefaultDisabled(String containerName) {
+        IContainerManager containerManager = (IContainerManager) ServiceHelper.getGlobalInstance(IContainerManager.class, this);
+        if (containerManager == null) {
+            throw new InternalServerErrorException(RestMessages.INTERNALERROR.toString());
+        }
+
+        if (containerName.equals(GlobalConstants.DEFAULT.toString()) && containerManager.hasNonDefaultContainer()) {
+            throw new ResourceConflictException(RestMessages.DEFAULTDISABLED.toString());
+        }
+    }
+
+    private Host handleHostAvailability(String containerName, String networkAddr) {
+
+        IfIptoHost hostTracker = (IfIptoHost) ServiceHelper.getInstance(IfIptoHost.class, containerName, this);
+        if (hostTracker == null) {
+            throw new ServiceUnavailableException("Host tracker " + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        Set<HostNodeConnector> allHosts = hostTracker.getAllHosts();
+        if (allHosts == null) {
+            throw new ResourceNotFoundException(networkAddr + " : " + RestMessages.NOHOST.toString());
+        }
+
+        Host host = null;
+        try {
+            InetAddress networkAddress = InetAddress.getByName(networkAddr);
+            for (Host h : allHosts) {
+                if (h.getNetworkAddress().equals(networkAddress)) {
+                    host = h;
+                    break;
+                }
+            }
+        } catch (UnknownHostException e) {
+        }
+
+        if (host == null) {
+            throw new ResourceNotFoundException(networkAddr + " : " + RestMessages.NOHOST.toString());
+        }
+
+        return host;
+    }
+}
\ No newline at end of file
diff --git a/analytics/northbound/src/main/java/org/opendaylight/controller/analytics/northbound/AnalyticsNorthboundRSApplication.java b/analytics/northbound/src/main/java/org/opendaylight/controller/analytics/northbound/AnalyticsNorthboundRSApplication.java
new file mode 100644 (file)
index 0000000..5a60064
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013 Plexxio, 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.controller.analytics.northbound;
+
+import java.util.HashSet;
+import java.util.Set;
+import javax.ws.rs.core.Application;
+
+/**
+ * Instance of javax.ws.rs.core.Application used to return the classes
+ * that will be instantiated for JAXRS processing, this is necessary
+ * because the package scanning in jersey doesn't yet work in OSGi
+ * environment.
+ *
+ */
+public class AnalyticsNorthboundRSApplication extends Application {
+    @Override
+    public Set<Class<?>> getClasses() {
+        Set<Class<?>> classes = new HashSet<Class<?>>();
+        classes.add(AnalyticsNorthbound.class);
+        return classes;
+    }
+}
diff --git a/analytics/northbound/src/main/java/org/opendaylight/controller/analytics/northbound/HostStatistics.java b/analytics/northbound/src/main/java/org/opendaylight/controller/analytics/northbound/HostStatistics.java
new file mode 100644 (file)
index 0000000..905fd59
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013 Plexxi, 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.controller.analytics.northbound;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import org.opendaylight.controller.sal.core.Host;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class HostStatistics {
+    @XmlElement
+    private Host srcHost;
+    @XmlElement
+    private Host dstHost;
+    @XmlElement(name="byteCount")
+    private long byteCount;
+    @XmlElement(name="bitRate")
+    private double bitRate;
+
+    // To satisfy JAXB
+    @SuppressWarnings("unused")
+    private HostStatistics() {
+    }
+
+    public HostStatistics(Host srcHost, Host dstHost, long byteCount, double bitRate) {
+        super();
+        this.srcHost = srcHost;
+        this.dstHost = dstHost;
+        this.byteCount = byteCount;
+        this.bitRate = bitRate;
+    }
+
+    public Host getSrcHost() {
+        return this.srcHost;
+    }
+
+    public void setSrcHost(Host host) {
+        this.srcHost = host;
+    }
+
+    public Host getDstHost() {
+        return this.dstHost;
+    }
+
+    public void setDstHost(Host host) {
+        this.dstHost = host;
+    }
+
+    public long getByteCount() {
+        return this.byteCount;
+    }
+
+    public void setByteCount(long byteCount) {
+        this.byteCount = byteCount;
+    }
+
+    public double getBitRate() {
+        return this.bitRate;
+    }
+
+    public void setBitRate(double bitRate) {
+        this.bitRate = bitRate;
+    }
+}
diff --git a/analytics/northbound/src/main/resources/META-INF/spring.factories b/analytics/northbound/src/main/resources/META-INF/spring.factories
new file mode 100644 (file)
index 0000000..93db02e
--- /dev/null
@@ -0,0 +1 @@
+org.springframework.beans.BeanInfoFactory=org.springframework.beans.ExtendedBeanInfoFactory
diff --git a/analytics/northbound/src/main/resources/META-INF/spring.handlers b/analytics/northbound/src/main/resources/META-INF/spring.handlers
new file mode 100644 (file)
index 0000000..957af91
--- /dev/null
@@ -0,0 +1,10 @@
+http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
+http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
+http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
+http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
+http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
+http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
+http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
+http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
+http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
+http\://www.springframework.org/schema/security=org.springframework.security.config.SecurityNamespaceHandler
diff --git a/analytics/northbound/src/main/resources/META-INF/spring.schemas b/analytics/northbound/src/main/resources/META-INF/spring.schemas
new file mode 100644 (file)
index 0000000..d865edc
--- /dev/null
@@ -0,0 +1,49 @@
+http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
+http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
+http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd
+http\://www.springframework.org/schema/beans/spring-beans-3.1.xsd=org/springframework/beans/factory/xml/spring-beans-3.1.xsd
+http\://www.springframework.org/schema/beans/spring-beans-3.2.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsd
+http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.2.xsd
+http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd
+http\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd
+http\://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd
+http\://www.springframework.org/schema/tool/spring-tool-3.1.xsd=org/springframework/beans/factory/xml/spring-tool-3.1.xsd
+http\://www.springframework.org/schema/tool/spring-tool-3.2.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsd
+http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.2.xsd
+http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd
+http\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd
+http\://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd
+http\://www.springframework.org/schema/util/spring-util-3.1.xsd=org/springframework/beans/factory/xml/spring-util-3.1.xsd
+http\://www.springframework.org/schema/util/spring-util-3.2.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsd
+http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.2.xsd
+http\://www.springframework.org/schema/context/spring-context-2.5.xsd=org/springframework/context/config/spring-context-2.5.xsd
+http\://www.springframework.org/schema/context/spring-context-3.0.xsd=org/springframework/context/config/spring-context-3.0.xsd
+http\://www.springframework.org/schema/context/spring-context-3.1.xsd=org/springframework/context/config/spring-context-3.1.xsd
+http\://www.springframework.org/schema/context/spring-context-3.2.xsd=org/springframework/context/config/spring-context-3.2.xsd
+http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-3.2.xsd
+http\://www.springframework.org/schema/jee/spring-jee-2.0.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd
+http\://www.springframework.org/schema/jee/spring-jee-2.5.xsd=org/springframework/ejb/config/spring-jee-2.5.xsd
+http\://www.springframework.org/schema/jee/spring-jee-3.0.xsd=org/springframework/ejb/config/spring-jee-3.0.xsd
+http\://www.springframework.org/schema/jee/spring-jee-3.1.xsd=org/springframework/ejb/config/spring-jee-3.1.xsd
+http\://www.springframework.org/schema/jee/spring-jee-3.2.xsd=org/springframework/ejb/config/spring-jee-3.2.xsd
+http\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-3.2.xsd
+http\://www.springframework.org/schema/lang/spring-lang-2.0.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd
+http\://www.springframework.org/schema/lang/spring-lang-2.5.xsd=org/springframework/scripting/config/spring-lang-2.5.xsd
+http\://www.springframework.org/schema/lang/spring-lang-3.0.xsd=org/springframework/scripting/config/spring-lang-3.0.xsd
+http\://www.springframework.org/schema/lang/spring-lang-3.1.xsd=org/springframework/scripting/config/spring-lang-3.1.xsd
+http\://www.springframework.org/schema/lang/spring-lang-3.2.xsd=org/springframework/scripting/config/spring-lang-3.2.xsd
+http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-3.2.xsd
+http\://www.springframework.org/schema/task/spring-task-3.0.xsd=org/springframework/scheduling/config/spring-task-3.0.xsd
+http\://www.springframework.org/schema/task/spring-task-3.1.xsd=org/springframework/scheduling/config/spring-task-3.1.xsd
+http\://www.springframework.org/schema/task/spring-task-3.2.xsd=org/springframework/scheduling/config/spring-task-3.2.xsd
+http\://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task-3.2.xsd
+http\://www.springframework.org/schema/cache/spring-cache-3.1.xsd=org/springframework/cache/config/spring-cache-3.1.xsd
+http\://www.springframework.org/schema/cache/spring-cache-3.2.xsd=org/springframework/cache/config/spring-cache-3.2.xsd
+http\://www.springframework.org/schema/cache/spring-cache.xsd=org/springframework/cache/config/spring-cache-3.2.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd=org/springframework/web/servlet/config/spring-mvc-3.0.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd=org/springframework/web/servlet/config/spring-mvc-3.1.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd=org/springframework/web/servlet/config/spring-mvc-3.2.xsd
+http\://www.springframework.org/schema/mvc/spring-mvc.xsd=org/springframework/web/servlet/config/spring-mvc-3.2.xsd
+http\://www.springframework.org/schema/security/spring-security-3.1.xsd=org/springframework/security/config/spring-security-3.1.xsd
+http\://www.springframework.org/schema/security/spring-security-3.2.xsd=org/springframework/security/config/spring-security-3.2.xsd
+
diff --git a/analytics/northbound/src/main/resources/META-INF/spring.tooling b/analytics/northbound/src/main/resources/META-INF/spring.tooling
new file mode 100644 (file)
index 0000000..057d834
--- /dev/null
@@ -0,0 +1,39 @@
+# Tooling related information for the beans namespace
+http\://www.springframework.org/schema/beans@name=beans Namespace
+http\://www.springframework.org/schema/beans@prefix=beans
+http\://www.springframework.org/schema/beans@icon=org/springframework/beans/factory/xml/spring-beans.gif
+
+# Tooling related information for the util namespace
+http\://www.springframework.org/schema/util@name=util Namespace
+http\://www.springframework.org/schema/util@prefix=util
+http\://www.springframework.org/schema/util@icon=org/springframework/beans/factory/xml/spring-util.gif
+
+# Tooling related information for the context namespace
+http\://www.springframework.org/schema/context@name=context Namespace
+http\://www.springframework.org/schema/context@prefix=context
+http\://www.springframework.org/schema/context@icon=org/springframework/context/config/spring-context.gif
+
+# Tooling related information for the jee namespace
+http\://www.springframework.org/schema/jee@name=jee Namespace
+http\://www.springframework.org/schema/jee@prefix=jee
+http\://www.springframework.org/schema/jee@icon=org/springframework/ejb/config/spring-jee.gif
+
+# Tooling related information for the scheduling namespace
+http\://www.springframework.org/schema/task@name=task Namespace
+http\://www.springframework.org/schema/task@prefix=task
+http\://www.springframework.org/schema/task@icon=org/springframework/scheduling/config/spring-task.gif
+
+# Tooling related information for the lang namespace
+http\://www.springframework.org/schema/lang@name=lang Namespace
+http\://www.springframework.org/schema/lang@prefix=lang
+http\://www.springframework.org/schema/lang@icon=org/springframework/scripting/config/spring-lang.gif
+
+# Tooling related information for the cache namespace
+http\://www.springframework.org/schema/cache@name=cache Namespace
+http\://www.springframework.org/schema/cache@prefix=cache
+http\://www.springframework.org/schema/cache@icon=org/springframework/cache/config/spring-cache.gif
+
+# Tooling related information for the mvc namespace
+http\://www.springframework.org/schema/mvc@name=mvc Namespace
+http\://www.springframework.org/schema/mvc@prefix=mvc
+http\://www.springframework.org/schema/mvc@icon=org/springframework/web/servlet/config/spring-mvc.gif
diff --git a/analytics/northbound/src/main/resources/WEB-INF/web.xml b/analytics/northbound/src/main/resources/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..fd28fd0
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+        version="3.0">
+  <servlet>
+    <servlet-name>JAXRSAnalytics</servlet-name>
+    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+    <init-param>
+      <param-name>javax.ws.rs.Application</param-name>
+      <param-value>org.opendaylight.controller.analytics.northbound.AnalyticsNorthboundRSApplication</param-value>
+    </init-param>
+    <load-on-startup>1</load-on-startup>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>JAXRSAnalytics</servlet-name>
+    <url-pattern>/*</url-pattern>
+  </servlet-mapping>
+
+        <security-constraint>
+                <web-resource-collection>
+                        <web-resource-name>NB api</web-resource-name>
+                        <url-pattern>/*</url-pattern>
+                </web-resource-collection>
+                <auth-constraint>
+                        <role-name>System-Admin</role-name>
+                        <role-name>Network-Admin</role-name>
+                        <role-name>Network-Operator</role-name>
+                        <role-name>Container-User</role-name>
+                </auth-constraint>
+        </security-constraint>
+
+        <security-role>
+                <role-name>System-Admin</role-name>
+        </security-role>
+        <security-role>
+                <role-name>Network-Admin</role-name>
+        </security-role>
+        <security-role>
+                <role-name>Network-Operator</role-name>
+        </security-role>
+        <security-role>
+                <role-name>Container-User</role-name>
+        </security-role>
+
+        <login-config>
+                <auth-method>BASIC</auth-method>
+                <realm-name>opendaylight</realm-name>
+        </login-config>
+</web-app>
diff --git a/analytics/northbound/test/java/org/opendaylight/controller/analytics/northbound/AnalyticsNorthboundTest.java b/analytics/northbound/test/java/org/opendaylight/controller/analytics/northbound/AnalyticsNorthboundTest.java
new file mode 100644 (file)
index 0000000..7cbb9b3
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013 Plexxi, 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.controller.analytics.northbound;
+
+import junit.framework.TestCase;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class AnalyticsNorthboundTest extends TestCase {
+
+    @Test
+    public void testAnalytics() {
+        Assert.assertTrue(true);
+    }
+}
diff --git a/analytics/src/test/java/org/opendaylight/controller/analytics/internal/AnalyticsManagerTest.java b/analytics/src/test/java/org/opendaylight/controller/analytics/internal/AnalyticsManagerTest.java
deleted file mode 100644 (file)
index 5058bc7..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*\r
- * Copyright (c) 2013 Plexxi, Inc.  All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-\r
-package org.opendaylight.controller.analytics.internal;\r
-\r
-\r
-import junit.framework.TestCase;\r
-\r
-import org.junit.Assert;\r
-import org.junit.Test;\r
-\r
-public class AnalyticsManagerTest extends TestCase {\r
-\r
-        @Test\r
-        public void testAnalyticsManagerCreation() {\r
-                AnalyticsManager am = new AnalyticsManager();\r
-                Assert.assertTrue(am != null);\r
-        }\r
-\r
-}\r
diff --git a/pom.xml b/pom.xml
index 7ce0e7c1c55bef34e0d92da4d949b9ca36372a55..2da39a4a1f58b88ae78a5b5751b43d13f03c9b9e 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -40,7 +40,9 @@
        <module>affinity/api</module>\r
        <module>affinity/implementation</module>\r
        <module>affinity/northbound</module>\r
-       <module>analytics</module>\r
+       <module>analytics/api</module>\r
+        <module>analytics/implementation</module>\r
+        <module>analytics/northbound</module>\r
     </modules>\r
 \r
     <repositories>\r
diff --git a/scripts/analytics.py b/scripts/analytics.py
new file mode 100644 (file)
index 0000000..a5f63d4
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/local/bin/python
+
+import httplib2
+import json
+import sys
+
+# 1. Start the controller
+# 2. On the mininet VM, run:
+#    > sudo mn --controller=remote,ip=192.168.56.1 --topo tree,2
+#    > h1 ping h2
+# 3. On the local machine (e.g., your laptop), run this script.
+#    > python analytics.py
+# Should see output like: "xxx bytes between 10.0.0.1 and 10.0.0.2",
+# where xxx is a positive integer.
+
+class HostStats:
+
+    def __init__(self, src, dst):
+        self.http = httplib2.Http(".cache")
+        self.http.add_credentials('admin', 'admin')
+        self.refresh()
+
+    def refresh(self):
+        resp, content = self.http.request("http://localhost:8080/controller/nb/v2/analytics/default/hoststats/" + src + "/" + dst, "GET")
+        if (resp.status == 404):
+            print "404 Error; exiting"
+            sys.exit()
+        if (resp.status == 503):
+            print "503 Error; exiting"
+            sys.exit()
+        self.host_stats = json.loads(content)
+
+    def get_bytes(self):
+        try:
+            bytes = long(self.host_stats["byteCount"])
+        except Exception as e:
+            print "exception: ", e
+            bytes = None
+        return bytes
+
+    def get_bit_rate(self):
+
+        try:
+            bitrate = float(self.host_stats["bitRate"])
+        except Exception as e:
+            print "exception: ", e
+            bitrate = None
+        return bitrate
+
+src = "10.0.0.1"
+dst = "10.0.0.2"
+
+h = HostStats(src, dst)
+print("%d bytes between %s and %s" % (h.get_bytes(), src, dst))
+print("%f mbit/s between %s and %s" % (h.get_bit_rate(), src, dst))