Complete northbound API for host statistics; usage demonstrated in analytics.py.... 14/2914/1
authorKatrina LaCurts <katrina.lacurts@plexxi.com>
Wed, 20 Nov 2013 15:10:57 +0000 (10:10 -0500)
committerKatrina LaCurts <katrina.lacurts@plexxi.com>
Wed, 20 Nov 2013 15:10:57 +0000 (10:10 -0500)
Signed-off-by: Katrina LaCurts <katrina.lacurts@plexxi.com>
analytics/api/src/main/java/org/opendaylight/affinity/analytics/IAnalyticsManager.java
analytics/implementation/src/main/java/org/opendaylight/affinity/analytics/internal/AnalyticsManager.java
analytics/northbound/src/main/java/org/opendaylight/affinity/analytics/northbound/AllHostStatistics.java [new file with mode: 0644]
analytics/northbound/src/main/java/org/opendaylight/affinity/analytics/northbound/AnalyticsNorthbound.java
scripts/analytics.py

index f1dfa0ef24a46558b80413db10eecd4a9705e879..337f3570a95af75f7065b53e387cd70aaceeceb2 100644 (file)
@@ -23,7 +23,6 @@ public interface IAnalyticsManager {
     double getBitRate(Host src, Host dst, Byte protocol);
     Map<Byte, Long> getAllByteCounts(Host src, Host dst);
     Map<Byte, Double> getAllBitRates(Host src, Host dst);
-    Set<Byte> getProtocols(Host src, Host dst);
 
     // AffinityLink statistics
     long getByteCount(AffinityLink al);
@@ -32,7 +31,6 @@ public interface IAnalyticsManager {
     double getBitRate(AffinityLink al, Byte protocol);
     Map<Byte, Long> getAllByteCounts(AffinityLink al);
     Map<Byte, Double> getAllBitRates(AffinityLink al);
-    Set<Byte> getProtocols(AffinityLink al);
 
     // Subnet statistics
     long getByteCount(String srcSubnet, String dstSubnet);
@@ -41,7 +39,6 @@ public interface IAnalyticsManager {
     double getBitRate(String srcSubnet, String dstSubnet, Byte protocol);
     Map<Byte, Long> getAllByteCounts(String srcSubnet, String dstSubnet);
     Map<Byte, Double> getAllBitRates(String srcSubnet, String dstSubnet);
-    Set<Byte> getProtocols(String srcSubnet, String dstSubnet);
 
     // Miscellaneous
     Map<Host, Long> getIncomingHostByteCounts(String subnet);
index 852d81546dfe53b1b487bd85f94abbd0647a4945..ac85dbe6ef4b0112b951215de06db367a07ba549 100644 (file)
@@ -202,13 +202,6 @@ public class AnalyticsManager implements IReadServiceListener, IAnalyticsManager
         return this.hostsToStats.get(src).get(dst).getAllBitRates();
     }
 
-    public Set<Byte> getProtocols(Host src, Host dst) {
-        if (this.hostsToStats.get(src) == null ||
-            this.hostsToStats.get(src).get(dst) == null)
-            return new HashSet<Byte>();
-        return this.hostsToStats.get(src).get(dst).getProtocols();
-    }
-
     public long getByteCount(AffinityLink al) {
         return getByteCountOnAffinityLinkInternal(al, null);
     }
@@ -217,17 +210,6 @@ public class AnalyticsManager implements IReadServiceListener, IAnalyticsManager
         return getByteCountOnAffinityLinkInternal(al, protocol);
     }
 
-    public Set<Byte> getProtocols(AffinityLink al) {
-        Set<Byte> protocols = new HashSet<Byte>();
-        for (Entry<Host, Host> flow : this.affinityManager.getAllFlowsByHost(al)) {
-            Host h1 = flow.getKey();
-            Host h2 = flow.getValue();
-            Set<Byte> thisProtocols = getProtocols(h1, h2);
-            protocols.addAll(thisProtocols);
-        }
-        return protocols;
-    }
-
     public Map<Byte, Long> getAllByteCounts(AffinityLink al) {
         Map<Byte, Long> byteCounts = new HashMap<Byte, Long>();
         Set<Byte> protocols = getProtocols(al);
@@ -287,31 +269,6 @@ public class AnalyticsManager implements IReadServiceListener, IAnalyticsManager
         return bitRates;
     }
 
-    public Set<Byte> getProtocols(String srcSubnet, String dstSubnet) {
-        if (srcSubnet == null && dstSubnet == null) {
-            log.debug("Source and destination subnets cannot both be null.");
-            return null;
-        }
-        Set<Byte> protocols = new HashSet<Byte>();
-        Set<Host> srcHosts;
-        Set<Host> dstHosts;
-        if (srcSubnet == null) {
-            dstHosts = getHostsInSubnet(dstSubnet);
-            srcHosts = getHostsNotInSubnet(dstSubnet);
-        } else if (dstSubnet == null) {
-            srcHosts = getHostsInSubnet(srcSubnet);
-            dstHosts = getHostsNotInSubnet(srcSubnet);
-        } else {
-            srcHosts = getHostsInSubnet(srcSubnet);
-            dstHosts = getHostsInSubnet(dstSubnet);
-        }
-
-        for (Host srcHost : srcHosts)
-            for (Host dstHost : dstHosts)
-                protocols.addAll(getProtocols(srcHost, dstHost));
-        return protocols;
-    }
-
     public Map<Host, Long> getIncomingHostByteCounts(String subnet) {
         return getIncomingHostByteCountsInternal(subnet, null);
     }
@@ -474,6 +431,49 @@ public class AnalyticsManager implements IReadServiceListener, IAnalyticsManager
         return hosts;
     }
 
+    private Set<Byte> getProtocols(Host src, Host dst) {
+        if (this.hostsToStats.get(src) == null ||
+            this.hostsToStats.get(src).get(dst) == null)
+            return new HashSet<Byte>();
+        return this.hostsToStats.get(src).get(dst).getProtocols();
+    }
+
+    private Set<Byte> getProtocols(AffinityLink al) {
+        Set<Byte> protocols = new HashSet<Byte>();
+        for (Entry<Host, Host> flow : this.affinityManager.getAllFlowsByHost(al)) {
+            Host h1 = flow.getKey();
+            Host h2 = flow.getValue();
+            Set<Byte> thisProtocols = getProtocols(h1, h2);
+            protocols.addAll(thisProtocols);
+        }
+        return protocols;
+    }
+
+    private Set<Byte> getProtocols(String srcSubnet, String dstSubnet) {
+        if (srcSubnet == null && dstSubnet == null) {
+            log.debug("Source and destination subnets cannot both be null.");
+            return null;
+        }
+        Set<Byte> protocols = new HashSet<Byte>();
+        Set<Host> srcHosts;
+        Set<Host> dstHosts;
+        if (srcSubnet == null) {
+            dstHosts = getHostsInSubnet(dstSubnet);
+            srcHosts = getHostsNotInSubnet(dstSubnet);
+        } else if (dstSubnet == null) {
+            srcHosts = getHostsInSubnet(srcSubnet);
+            dstHosts = getHostsNotInSubnet(srcSubnet);
+        } else {
+            srcHosts = getHostsInSubnet(srcSubnet);
+            dstHosts = getHostsInSubnet(dstSubnet);
+        }
+
+        for (Host srcHost : srcHosts)
+            for (Host dstHost : dstHosts)
+                protocols.addAll(getProtocols(srcHost, dstHost));
+        return protocols;
+    }
+
     private Set<Host> getHostsNotInSubnet(String subnet) {
         Set<Host> hostsInSubnet = getHostsInSubnet(subnet);
         Set<HostNodeConnector> otherHosts = this.hostTracker.getAllHosts();
diff --git a/analytics/northbound/src/main/java/org/opendaylight/affinity/analytics/northbound/AllHostStatistics.java b/analytics/northbound/src/main/java/org/opendaylight/affinity/analytics/northbound/AllHostStatistics.java
new file mode 100644 (file)
index 0000000..78ef5e8
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.affinity.analytics.northbound;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class AllHostStatistics {
+    @XmlElement
+    private Map<Byte, HostStatistics> data;
+
+    public AllHostStatistics() {
+        super();
+        this.data = new HashMap<Byte, HostStatistics>();
+    }
+
+    public void addHostStat(Byte proto, HostStatistics stat) {
+        this.data.put(proto, stat);
+    }
+}
index 16a343f3cf01df5253c7dfc29f456f50ee12540d..b329e3eae7b554ffb4514a633d8c327e1dfdec19 100644 (file)
@@ -132,6 +132,83 @@ public class AnalyticsNorthbound {
         return new HostStatistics(srcHost, dstHost, byteCount, bitRate);
     }
 
+    /**
+     * Returns Host Statistics for a (src, dst) pair and a particular protocol
+     *
+     * @param containerName: Name of the Container
+     * @param srcIP: Source IP
+     * @param dstIP: Destination IP
+     * @param protocol: Protocol of interest
+     * @return Host Statistics for a given Node.
+     */
+    @Path("/{containerName}/hoststats/{srcIP}/{dstIP}/{protocol}")
+    @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") })
+    public HostStatistics getHostStatistics(
+        @PathParam("containerName") String containerName,
+        @PathParam("srcIP") String srcIP,
+        @PathParam("dstIP") String dstIP,
+        @PathParam("protocol") String protocol) {
+        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());
+
+        Host srcHost = handleHostAvailability(containerName, srcIP);
+        Host dstHost = handleHostAvailability(containerName, dstIP);
+        long byteCount = analyticsManager.getByteCount(srcHost, dstHost, IPProtocols.getProtocolNumberByte(protocol));
+        double bitRate = analyticsManager.getBitRate(srcHost, dstHost, IPProtocols.getProtocolNumberByte(protocol));
+
+        return new HostStatistics(srcHost, dstHost, byteCount, bitRate);
+    }
+
+    /**
+     * Returns all Host Statistics for a (src, dst) pair
+     *
+     * @param containerName: Name of the Container
+     * @param srcIP: Source IP
+     * @param dstIP: Destination IP
+     * @return Host Statistics for a given Node.
+     */
+    @Path("/{containerName}/hoststats/{srcIP}/{dstIP}/all")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+    @TypeHint(AllHostStatistics.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") })
+    public AllHostStatistics getAllHostStatistics(
+        @PathParam("containerName") String containerName,
+        @PathParam("srcIP") String srcIP,
+        @PathParam("dstIP") String dstIP) {
+        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());
+
+        Host srcHost = handleHostAvailability(containerName, srcIP);
+        Host dstHost = handleHostAvailability(containerName, dstIP);
+        Map<Byte, Long> byteCounts = analyticsManager.getAllByteCounts(srcHost, dstHost);
+        Map<Byte, Double> bitRates = analyticsManager.getAllBitRates(srcHost, dstHost);
+        AllHostStatistics allStats = new AllHostStatistics();
+        for (Byte protocol : byteCounts.keySet())
+            allStats.addHostStat(protocol, new HostStatistics(srcHost, dstHost, byteCounts.get(protocol), bitRates.get(protocol)));
+        System.out.println(">>> " + allStats);
+        return allStats;
+    }
+
     /**
      * Returns the affinity link statistics for a given link.
      *
@@ -228,6 +305,7 @@ public class AnalyticsNorthbound {
         @PathParam("containerName") String containerName,
         @PathParam("ip") String ip,
         @PathParam("mask") String mask) {
+        // TODO: Change AllHosts class name to something better
         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this))
             throw new UnauthorizedException("User is not authorized to perform this operation on container " + containerName);
         handleDefaultDisabled(containerName);
index 6ef2b9092f942f8f0cf119a6ec50f4c03e210913..0d77c2204cea98e3ec45a06f46c85f0eed6a808d 100644 (file)
@@ -9,20 +9,56 @@ from stats import Stats
 from subnet import SubnetControl
 from affinity_control import AffinityControl
 
-# 1. Start the controller
-# 2. On the local machine (e.g., your laptop), start this script.
-#    > python analytics.py
-# 3. On the mininet VM, run:
-#    > sudo mn --controller=remote,ip=192.168.56.1 --topo tree,2
-#    > h1 ping h3
-# 4. Give commands to analytics.py.  For instance:
-#    > host bytes 10.0.0.1 10.0.0.3
-#   (There is a usage prompt that prints at the beginning of analytics.py)
-# 5. Type 'quit' to exit analytics.py
+# Generic REST query
+def rest_method(url, rest_type):
+    h = httplib2.Http(".cache")
+    h.add_credentials('admin', 'admin')
+    resp, content = h.request(url, rest_type)
+    return json.loads(content)
+
+### Host Statistics
+
+def bytes_between_hosts(src, dst):
+    url = "http://localhost:8080/affinity/nb/v2/analytics/default/hoststats/%s/%s" % (src, dst)
+    data = rest_method(url, "GET")
+    print("%d bytes between %s and %s" % (int(data["byteCount"]), src, dst))
+
+def bytes_between_hosts_protocol(src, dst, protocol):
+    url = "http://localhost:8080/affinity/nb/v2/analytics/default/hoststats/%s/%s/%d" % (src, dst, protocol)
+    data = rest_method(url, "GET")
+    print("%d bytes between %s and %s for protocol %d" % (int(data["byteCount"]), src, dst, protocol))
+
+def rate_between_hosts(src, dst):
+    url = "http://localhost:8080/affinity/nb/v2/analytics/default/hoststats/%s/%s" % (src, dst)
+    data = rest_method(url, "GET")
+    print("%s bit/s between %s and %s" % (data["bitRate"], src, dst))
+
+def rate_between_hosts_protocol(src, dst, protocol):
+    url = "http://localhost:8080/affinity/nb/v2/analytics/default/hoststats/%s/%s/%d" % (src, dst, protocol)
+    data = rest_method(url, "GET")
+    print("%s bit/s between %s and %s on protocol %d" % (data["bitRate"], src, dst, protocol))
+
+def all_byte_counts_hosts(src, dst):
+    url = "http://localhost:8080/affinity/nb/v2/analytics/default/hoststats/%s/%s/all" % (src, dst)
+    data = rest_method(url, "GET")['data']['entry']
+    for entry in data:
+        protocol = entry['key']
+        byte_count = entry['value']['byteCount']
+        print("%s bytes from protocol %s" % (byte_count, protocol))
+
+def all_bit_rates_hosts(src, dst):
+    url = "http://localhost:8080/affinity/nb/v2/analytics/default/hoststats/%s/%s/all" % (src, dst)
+    data = rest_method(url, "GET")['data']['entry']
+    for entry in data:
+        protocol = entry['key']
+        bit_rate = entry['value']['bitRate']
+        print("%s bit/s from protocol %s" % (bit_rate, protocol))
+
+### Affinity link statistics
 
 def run_interactive_mode():
 
-    print "Usage: [host | link] [bytes | rate] [src dst | link-name]"
+    print "Usage: [host | link] [src dst | link-name] {protocol}"
 
     # Demo mode
     while True:
@@ -31,45 +67,26 @@ def run_interactive_mode():
             request = request.split()
             request_type = request[0]
 
-            if (request_type == "quit"):
+            if (request_type == "quit" or request_type == "exit"):
                 sys.exit()
 
             if (request_type == "host"):
-                action = request[1]
-                src, dst = request[2:4]
-                host_stat = Stats(Stats.TYPE_HOST, src=src, dst=dst)
-                if (action == "bytes"):
-                    print("%d bytes between %s and %s" % (host_stat.get_bytes(), src, dst))
-                elif (action == "rate"):
-                    print("%f bit/s between %s and %s" % (host_stat.get_bit_rate(), src, dst))
-                else:
-                    raise Exception
+                if (len(request) == 3):
+                    src, dst = request[1:3]
+                    bytes_between_hosts(src, dst)
+                    rate_between_hosts(src, dst)
+                    all_byte_counts_hosts(src, dst)
+                    all_bit_rates_hosts(src, dst)
+                elif (len(request) == 4):
+                    src, dst, protocol = request[1:4]
+                    bytes_between_hosts_protocol(src, dst, int(protocol))
+                    rate_between_hosts_protocol(src, dst, int(protocol))
 
             elif (request_type == "link"):
-                action = request[1]
-                link = request[2]
-                link_stat = Stats(Stats.TYPE_AL, al=link)
-                if (action == "bytes"):
-                    print("%d bytes on %s" % (link_stat.get_bytes(), link))
-                elif (action == "rate"):
-                    print("%f bit/s on %s" % (link_stat.get_bit_rate(), link))
-                else:
-                    raise Exception
-
-            elif (request_type == "prefix"):
-                prefix = request[1]
-                h = httplib2.Http(".cache")
-                h.add_credentials("admin", "admin")
-                url_prefix = "http://localhost:8080/affinity/nb/v2/analytics/default/prefixstats/"
-                resp, content = h.request(url_prefix + prefix, "GET")
-                if (resp.status == 200):
-                    data = json.loads(content)
-                    print data['byteCount'], "bytes"
-            else:
-                raise Exception
-        except Exception as e:
-            print "Error"
-            print e
+                link = request[1]
+
+            elif (request_type == "subnet"):
+                subnet = request[1]
 
 def main():
 
@@ -78,11 +95,11 @@ def main():
     subnet_control.add_subnet("defaultSubnet", "10.0.0.254/8")
 
     # Set up an affinity link
-    affinity_control = AffinityControl()
-    affinity_control.add_affinity_group("testAG1", ips=["10.0.0.1", "10.0.0.2"])
-    affinity_control.add_affinity_group("testAG2", ips=["10.0.0.3", "10.0.0.4"])
-    affinity_control.add_affinity_link("testAL", "testAG1", "testAG2")
-    raw_input("[Press enter to continue]" )
+#    affinity_control = AffinityControl()
+#    affinity_control.add_affinity_group("testAG1", ips=["10.0.0.1", "10.0.0.2"])
+#    affinity_control.add_affinity_group("testAG2", ips=["10.0.0.3", "10.0.0.4"])
+#    affinity_control.add_affinity_link("testAL", "testAG1", "testAG2")
+#    raw_input("[Press enter to continue]" )
 
     run_interactive_mode()