add rest api for network and monitoring
authorstevenvanrossem <steven.vanrossem@intec.ugent.be>
Tue, 28 Jun 2016 23:44:07 +0000 (01:44 +0200)
committerstevenvanrossem <steven.vanrossem@intec.ugent.be>
Tue, 28 Jun 2016 23:44:07 +0000 (01:44 +0200)
19 files changed:
src/emuvim/api/rest/__init__.py [changed mode: 0644->0755]
src/emuvim/api/rest/compute.py [changed mode: 0644->0755]
src/emuvim/api/rest/monitor.py [new file with mode: 0755]
src/emuvim/api/rest/network.py [new file with mode: 0755]
src/emuvim/api/rest/rest_api_endpoint.py [new file with mode: 0755]
src/emuvim/cli/prometheus.py
src/emuvim/cli/rest/__init__.py [changed mode: 0644->0755]
src/emuvim/cli/rest/compute.py [changed mode: 0644->0755]
src/emuvim/cli/rest/datacenter.py [changed mode: 0644->0755]
src/emuvim/cli/rest/monitor.py [new file with mode: 0755]
src/emuvim/cli/rest/network.py [new file with mode: 0755]
src/emuvim/cli/son_emu_cli.py
src/emuvim/dcemulator/net.py
src/emuvim/examples/simple_topology_restapi.py [changed mode: 0644->0755]
src/emuvim/test/api_base.py [changed mode: 0644->0755]
src/emuvim/test/unittests/test_restapi.py [changed mode: 0644->0755]
utils/ci/son-analyze_test.sh [new file with mode: 0755]
utils/ci/stop_sdk_monitor.sh
utils/ci/test_sdk_monitor.sh

old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 02ca9f2..1c9c892
@@ -1,59 +1,12 @@
 import logging
 import logging
-import threading
-from flask import Flask, request
-from flask_restful import Resource,Api
+from flask_restful import Resource
+from flask import request
 import json
 
 import json
 
-
-
 logging.basicConfig(level=logging.INFO)
 
 logging.basicConfig(level=logging.INFO)
 
-
 dcs = {}
 
 dcs = {}
 
-class RestApiEndpoint(object):
-
-    """
-    Simple API endpoint that offers a REST
-    interface. This interface will be used by the
-    default command line client.
-    """
-    global dcs
-
-    def __init__(self, listenip, port):
-        self.ip = listenip
-        self.port = port
-
-        # setup Flask
-        self.app = Flask(__name__)
-        self.api = Api(self.app)
-
-        # setup endpoints
-        self.api.add_resource(ComputeList, "/restapi/compute/<dc_label>")
-        self.api.add_resource(ComputeStart, "/restapi/compute/<dc_label>/<compute_name>/start")
-        self.api.add_resource(ComputeStop, "/restapi/compute/<dc_label>/<compute_name>/stop")
-        self.api.add_resource(ComputeStatus, "/restapi/compute/<dc_label>/<compute_name>")
-        self.api.add_resource(DatacenterList, "/restapi/datacenter")
-        self.api.add_resource(DatacenterStatus, "/restapi/datacenter/<dc_label>")
-
-        logging.debug("Created API endpoint %s(%s:%d)" % (self.__class__.__name__, self.ip, self.port))
-
-
-    def connectDatacenter(self, dc):
-        dcs[dc.label] = dc
-        logging.info("Connected DC(%s) to API endpoint %s(%s:%d)" % (dc.label, self.__class__.__name__, self.ip, self.port))
-
-    def start(self):
-        thread = threading.Thread(target= self._start_flask, args=())
-        thread.daemon = True
-        thread.start()
-        logging.info("Started API endpoint @ http://%s:%d" % (self.ip, self.port))
-
-
-    def _start_flask(self):
-        self.app.run(self.ip, self.port, debug=True, use_reloader=False)
-
-
 class ComputeStart(Resource):
     """
     Start a new compute instance: A docker container (note: zerorpc does not support keyword arguments)
 class ComputeStart(Resource):
     """
     Start a new compute instance: A docker container (note: zerorpc does not support keyword arguments)
@@ -62,7 +15,8 @@ class ComputeStart(Resource):
     :param image: image name
     :param command: command to execute
     :param network: list of all interface of the vnf, with their parameters (id=id1,ip=x.x.x.x/x),...
     :param image: image name
     :param command: command to execute
     :param network: list of all interface of the vnf, with their parameters (id=id1,ip=x.x.x.x/x),...
-    :return: networks list({"id":"input","ip": "10.0.0.254/8"}, {"id":"output","ip": "11.0.0.254/24"})
+    example networks list({"id":"input","ip": "10.0.0.254/8"}, {"id":"output","ip": "11.0.0.254/24"})
+    :return: docker inspect dict of deployed docker
     """
     global dcs
 
     """
     global dcs
 
@@ -76,7 +30,7 @@ class ComputeStart(Resource):
             c = dcs.get(dc_label).startCompute(
                 compute_name, image= image, command= command, network= network)
             # return docker inspect dict
             c = dcs.get(dc_label).startCompute(
                 compute_name, image= image, command= command, network= network)
             # return docker inspect dict
-            return  c. getStatus(), 200
+            return c.getStatus(), 200
         except Exception as ex:
             logging.exception("API error.")
             return ex.message, 500
         except Exception as ex:
             logging.exception("API error.")
             return ex.message, 500
diff --git a/src/emuvim/api/rest/monitor.py b/src/emuvim/api/rest/monitor.py
new file mode 100755 (executable)
index 0000000..b1edbc3
--- /dev/null
@@ -0,0 +1,72 @@
+import logging
+from flask_restful import Resource
+from flask import request
+import json
+
+logging.basicConfig(level=logging.INFO)
+
+net = None
+
+
+
+class MonitorInterfaceAction(Resource):
+    """
+    Monitor the counters of a VNF interface
+    :param vnf_name: name of the VNF to be monitored
+    :param vnf_interface: name of the VNF interface to be monitored
+    :param metric: tx_bytes, rx_bytes, tx_packets, rx_packets
+    :return: message string indicating if the monitor action is succesful or not
+    """
+    global net
+
+    def put(self, vnf_name, vnf_interface, metric):
+        logging.debug("REST CALL: start monitor VNF interface")
+        try:
+            c = net.monitor_agent.setup_metric(vnf_name, vnf_interface, metric)
+            # return monitor message response
+            return  str(c), 200
+        except Exception as ex:
+            logging.exception("API error.")
+            return ex.message, 500
+
+    def delete(self, vnf_name, vnf_interface, metric):
+        logging.debug("REST CALL: stop monitor VNF interface")
+        try:
+            c = net.monitor_agent.stop_metric(vnf_name, vnf_interface, metric)
+            # return monitor message response
+            return str(c), 200
+        except Exception as ex:
+            logging.exception("API error.")
+            return ex.message, 500
+
+
+class MonitorFlowAction(Resource):
+    """
+    Monitor the counters of a specific flow
+    :param vnf_name: name of the VNF to be monitored
+    :param vnf_interface: name of the VNF interface to be monitored
+    :param metric: tx_bytes, rx_bytes, tx_packets, rx_packets
+    :param cookie: specific identifier of flows to monitor
+    :return: message string indicating if the monitor action is succesful or not
+    """
+    global net
+
+    def put(self, vnf_name, vnf_interface, metric, cookie):
+        logging.debug("REST CALL: start monitor VNF interface")
+        try:
+            c = net.monitor_agent.setup_flow(vnf_name, vnf_interface, metric, cookie)
+            # return monitor message response
+            return str(c), 200
+        except Exception as ex:
+            logging.exception("API error.")
+            return ex.message, 500
+
+    def delete(self, vnf_name, vnf_interface, metric, cookie):
+        logging.debug("REST CALL: stop monitor VNF interface")
+        try:
+            c = net.monitor_agent.stop_flow(vnf_name, vnf_interface, metric, cookie)
+            # return monitor message response
+            return str(c), 200
+        except Exception as ex:
+            logging.exception("API error.")
+            return ex.message, 500
\ No newline at end of file
diff --git a/src/emuvim/api/rest/network.py b/src/emuvim/api/rest/network.py
new file mode 100755 (executable)
index 0000000..4a0214f
--- /dev/null
@@ -0,0 +1,60 @@
+import logging
+from flask_restful import Resource
+from flask import request
+import json
+
+logging.basicConfig(level=logging.INFO)
+
+net = None
+
+
+class NetworkAction(Resource):
+    """
+    Add or remove chains between VNFs. These chain links are implemented as flow entries in the networks' SDN switches.
+    :param vnf_src_name: VNF name of the source of the link
+    :param vnf_dst_name: VNF name of the destination of the link
+    :param vnf_src_interface: VNF interface name of the source of the link
+    :param vnf_dst_interface: VNF interface name of the destination of the link
+    :param weight: weight of the link (can be useful for routing calculations)
+    :param match: OpenFlow match format of the flow entry
+    :param bidirectional: boolean value if the link needs to be implemented from src to dst and back
+    :param cookie: cookie value, identifier of the flow entry to be installed.
+    :return: message string indicating if the chain action is succesful or not
+    """
+
+    global net
+
+    def put(self, vnf_src_name, vnf_dst_name):
+        logging.debug("REST CALL: network chain add")
+        command = 'add-flow'
+        return self._NetworkAction(vnf_src_name, vnf_dst_name, command=command)
+
+    def delete(self, vnf_src_name, vnf_dst_name):
+        logging.debug("REST CALL: network chain remove")
+        command = 'del-flows'
+        return self._NetworkAction(vnf_src_name, vnf_dst_name, command=command)
+
+    def _NetworkAction(self, vnf_src_name, vnf_dst_name, command=None):
+        # call DCNetwork method, not really datacenter specific API for now...
+        # no check if vnfs are really connected to this datacenter...
+        try:
+            vnf_src_interface = json.loads(request.json).get("vnf_src_interface")
+            vnf_dst_interface = json.loads(request.json).get("vnf_dst_interface")
+            weight = json.loads(request.json).get("weight")
+            match = json.loads(request.json).get("match")
+            bidirectional = json.loads(request.json).get("bidirectional")
+            cookie = json.loads(request.json).get("cookie")
+            c = net.setChain(
+                vnf_src_name, vnf_dst_name,
+                vnf_src_interface=vnf_src_interface,
+                vnf_dst_interface=vnf_dst_interface,
+                cmd=command,
+                weight=weight,
+                match=match,
+                bidirectional=bidirectional,
+                cookie=cookie)
+            # return setChain response
+            return str(c), 200
+        except Exception as ex:
+            logging.exception("API error.")
+            return ex.message, 500
\ No newline at end of file
diff --git a/src/emuvim/api/rest/rest_api_endpoint.py b/src/emuvim/api/rest/rest_api_endpoint.py
new file mode 100755 (executable)
index 0000000..6c69a03
--- /dev/null
@@ -0,0 +1,73 @@
+import logging
+import threading
+from flask import Flask
+from flask_restful import Api
+
+# need to import total module to set its global variable dcs
+import compute
+from compute import dcs, ComputeList, ComputeStart, ComputeStatus, ComputeStop, DatacenterList, DatacenterStatus
+
+# need to import total module to set its global variable net
+import network
+from network import NetworkAction
+
+import monitor
+from monitor import MonitorInterfaceAction, MonitorFlowAction
+
+logging.basicConfig(level=logging.INFO)
+
+
+
+class RestApiEndpoint(object):
+
+    """
+    Simple API endpoint that offers a REST
+    interface. This interface will be used by the
+    default command line client.
+    """
+
+    def __init__(self, listenip, port):
+        self.ip = listenip
+        self.port = port
+
+        # setup Flask
+        self.app = Flask(__name__)
+        self.api = Api(self.app)
+
+        # setup endpoints
+        self.api.add_resource(ComputeList, "/restapi/compute/<dc_label>")
+        self.api.add_resource(ComputeStart, "/restapi/compute/<dc_label>/<compute_name>/start")
+        self.api.add_resource(ComputeStop, "/restapi/compute/<dc_label>/<compute_name>/stop")
+        self.api.add_resource(ComputeStatus, "/restapi/compute/<dc_label>/<compute_name>")
+        self.api.add_resource(DatacenterList, "/restapi/datacenter")
+        self.api.add_resource(DatacenterStatus, "/restapi/datacenter/<dc_label>")
+
+        self.api.add_resource(NetworkAction, "/restapi/network/<vnf_src_name>/<vnf_dst_name>")
+
+        self.api.add_resource(MonitorInterfaceAction, "/restapi/monitor/<vnf_name>/<vnf_interface>/<metric>")
+        self.api.add_resource(MonitorFlowAction, "/restapi/monitor/<vnf_name>/<vnf_interface>/<metric>/<cookie>")
+
+        logging.debug("Created API endpoint %s(%s:%d)" % (self.__class__.__name__, self.ip, self.port))
+
+
+    def connectDatacenter(self, dc):
+        compute.dcs[dc.label] = dc
+        logging.info("Connected DC(%s) to API endpoint %s(%s:%d)" % (dc.label, self.__class__.__name__, self.ip, self.port))
+
+    def connectDCNetwork(self, DCnetwork):
+
+        network.net = DCnetwork
+        monitor.net = DCnetwork
+
+        logging.info("Connected DCNetwork to API endpoint %s(%s:%d)" % (
+            self.__class__.__name__, self.ip, self.port))
+
+    def start(self):
+        thread = threading.Thread(target= self._start_flask, args=())
+        thread.daemon = True
+        thread.start()
+        logging.info("Started API endpoint @ http://%s:%d" % (self.ip, self.port))
+
+
+    def _start_flask(self):
+        self.app.run(self.ip, self.port, debug=True, use_reloader=False)
\ No newline at end of file
index 9432408..6250fb2 100755 (executable)
@@ -9,6 +9,7 @@ import requests
 
 # set this to localhost for now
 # this is correct for son-emu started outside of a container or as a container with net=host
 
 # set this to localhost for now
 # this is correct for son-emu started outside of a container or as a container with net=host
+#TODO prometheus sdk DB is started outside of emulator, place these globals in an external SDK config file?
 prometheus_ip = '127.0.0.1'
 prometheus_port = '9090'
 prometheus_REST_api = 'http://{0}:{1}'.format(prometheus_ip, prometheus_port)
 prometheus_ip = '127.0.0.1'
 prometheus_port = '9090'
 prometheus_REST_api = 'http://{0}:{1}'.format(prometheus_ip, prometheus_port)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index bdef0ec..29e65dc
@@ -27,19 +27,20 @@ class RestApiClient():
                'command':args.get("docker_command"),
                'network':nw_list}
 
                'command':args.get("docker_command"),
                'network':nw_list}
 
-        responce = put("%s/restapi/compute/%s/%s/start" %
+        response = put("%s/restapi/compute/%s/%s/start" %
                        (args.get("endpoint"),
                         args.get("datacenter"),
                         args.get("name")),
                        json = json.dumps(req))
                        (args.get("endpoint"),
                         args.get("datacenter"),
                         args.get("name")),
                        json = json.dumps(req))
-        pp.pprint(responce.json())
+        pp.pprint(response.json())
+
     def stop(self, args):
 
     def stop(self, args):
 
-        responce = get("%s/restapi/compute/%s/%s/stop" %
+        response = get("%s/restapi/compute/%s/%s/stop" %
                        (args.get("endpoint"),
                         args.get("datacenter"),
                         args.get("name")))
                        (args.get("endpoint"),
                         args.get("datacenter"),
                         args.get("name")))
-        pp.pprint(responce.json())
+        pp.pprint(response.json())
 
     def list(self,args):
 
 
     def list(self,args):
 
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/src/emuvim/cli/rest/monitor.py b/src/emuvim/cli/rest/monitor.py
new file mode 100755 (executable)
index 0000000..2ed1402
--- /dev/null
@@ -0,0 +1,110 @@
+from requests import get, put, delete
+from tabulate import tabulate
+import pprint
+import argparse
+import json
+from emuvim.cli import prometheus
+
+pp = pprint.PrettyPrinter(indent=4)
+
+class RestApiClient():
+
+    def __init__(self):
+        self.cmds = {}
+
+    def execute_command(self, args):
+        if getattr(self, args["command"]) is not None:
+            # call the local method with the same name as the command arg
+            getattr(self, args["command"])(args)
+        else:
+            print("Command not implemented.")
+
+    def setup_metric(self, args):
+        vnf_name = self._parse_vnf_name(args.get("vnf_name"))
+        vnf_interface = self._parse_vnf_interface(args.get("vnf_name"))
+
+        response = put("%s/restapi/monitor/%s/%s/%s" %
+                       (args.get("endpoint"),
+                        vnf_name,
+                        vnf_interface,
+                        args.get("metric")))
+        pp.pprint(response.json())
+
+    def stop_metric(self, args):
+        vnf_name = self._parse_vnf_name(args.get("vnf_name"))
+        vnf_interface = self._parse_vnf_interface(args.get("vnf_name"))
+
+        response = delete("%s/restapi/monitor/%s/%s/%s" %
+                       (args.get("endpoint"),
+                        vnf_name,
+                        vnf_interface,
+                        args.get("metric")))
+        pp.pprint(response.json())
+
+    def setup_flow(self, args):
+        vnf_name = self._parse_vnf_name(args.get("vnf_name"))
+        vnf_interface = self._parse_vnf_interface(args.get("vnf_name"))
+
+        response = put("%s/restapi/monitor/%s/%s/%s/%s" %
+                       (args.get("endpoint"),
+                        vnf_name,
+                        vnf_interface,
+                        args.get("metric"),
+                        args.get("cookie")))
+
+        pp.pprint(response.json())
+
+    def stop_flow(self, args):
+        vnf_name = self._parse_vnf_name(args.get("vnf_name"))
+        vnf_interface = self._parse_vnf_interface(args.get("vnf_name"))
+
+        response = delete("%s/restapi/monitor/%s/%s/%s/%s" %
+                       (args.get("endpoint"),
+                        vnf_name,
+                        vnf_interface,
+                        args.get("metric"),
+                        args.get("cookie")))
+
+        pp.pprint(response.json())
+
+    def _parse_vnf_name(self, vnf_name_str):
+        vnf_name = vnf_name_str.split(':')[0]
+        return vnf_name
+
+    def _parse_vnf_interface(self, vnf_name_str):
+        try:
+            vnf_interface = vnf_name_str.split(':')[1]
+        except:
+            vnf_interface = None
+
+        return vnf_interface
+
+parser = argparse.ArgumentParser(description='son-emu monitor')
+parser.add_argument(
+    "command",
+    choices=['setup_metric', 'stop_metric', 'setup_flow', 'stop_flow','prometheus'],
+    help="setup/stop a metric/flow to be monitored or query Prometheus")
+parser.add_argument(
+    "--vnf_name", "-vnf", dest="vnf_name",
+    help="vnf name:interface to be monitored")
+parser.add_argument(
+    "--metric", "-m", dest="metric",
+    help="tx_bytes, rx_bytes, tx_packets, rx_packets")
+parser.add_argument(
+    "--cookie", "-c", dest="cookie",
+    help="flow cookie to monitor")
+parser.add_argument(
+    "--query", "-q", dest="query",
+    help="prometheus query")
+parser.add_argument(
+    "--datacenter", "-d", dest="datacenter",
+    help="Data center where the vnf is deployed")
+parser.add_argument(
+    "--endpoint", "-e", dest="endpoint",
+    default="http://127.0.0.1:5000",
+    help="UUID of the plugin to be manipulated.")
+
+def main(argv):
+    args = vars(parser.parse_args(argv))
+    c = RestApiClient()
+    c.execute_command(args)
\ No newline at end of file
diff --git a/src/emuvim/cli/rest/network.py b/src/emuvim/cli/rest/network.py
new file mode 100755 (executable)
index 0000000..e7687f6
--- /dev/null
@@ -0,0 +1,109 @@
+from requests import get,put, delete
+from tabulate import tabulate
+import pprint
+import argparse
+import json
+
+pp = pprint.PrettyPrinter(indent=4)
+
+class RestApiClient():
+
+    def __init__(self):
+        self.cmds = {}
+
+    def execute_command(self, args):
+        if getattr(self, args["command"]) is not None:
+            # call the local method with the same name as the command arg
+            getattr(self, args["command"])(args)
+        else:
+            print("Command not implemented.")
+
+    def add(self, args):
+        vnf_src_name = self._parse_vnf_name(args.get("source"))
+        vnf_dst_name = self._parse_vnf_name(args.get("destination"))
+
+        params = self._create_dict(
+            vnf_src_interface=self._parse_vnf_interface(args.get("source")),
+            vnf_dst_interface=self._parse_vnf_interface(args.get("destination")),
+            weight=args.get("weight"),
+            match=args.get("match"),
+            bidirectional=args.get("bidirectional"),
+            cookie=args.get("cookie"))
+
+        response = put("%s/restapi/network/%s/%s" %
+                       (args.get("endpoint"),
+                        vnf_src_name,
+                        vnf_dst_name),
+                       json=json.dumps(params))
+        pp.pprint(response.json())
+
+    def remove(self, args):
+        vnf_src_name = self._parse_vnf_name(args.get("source"))
+        vnf_dst_name = self._parse_vnf_name(args.get("destination"))
+
+        params = self._create_dict(
+            vnf_src_interface=self._parse_vnf_interface(args.get("source")),
+            vnf_dst_interface=self._parse_vnf_interface(args.get("destination")),
+            weight=args.get("weight"),
+            match=args.get("match"),
+            bidirectional=args.get("bidirectional"),
+            cookie=args.get("cookie"))
+
+        response = delete("%s/restapi/network/%s/%s" %
+                       (args.get("endpoint"),
+                        vnf_src_name,
+                        vnf_dst_name),
+                       json=json.dumps(params))
+        pp.pprint(response.json())
+
+    def _parse_vnf_name(self, vnf_name_str):
+        vnf_name = vnf_name_str.split(':')[0]
+        return vnf_name
+
+    def _parse_vnf_interface(self, vnf_name_str):
+        try:
+            vnf_interface = vnf_name_str.split(':')[1]
+        except:
+            vnf_interface = None
+
+        return vnf_interface
+
+    def _create_dict(self, **kwargs):
+        return kwargs
+
+parser = argparse.ArgumentParser(description='son-emu network')
+parser.add_argument(
+    "command",
+    choices=['add', 'remove'],
+    help="Action to be executed.")
+parser.add_argument(
+    "--datacenter", "-d", dest="datacenter",
+    help="Data center to in which the network action should be initiated")
+parser.add_argument(
+    "--source", "-src", dest="source",
+    help="vnf name of the source of the chain")
+parser.add_argument(
+    "--destination", "-dst", dest="destination",
+    help="vnf name of the destination of the chain")
+parser.add_argument(
+    "--weight", "-w", dest="weight",
+    help="weight metric to calculate the path")
+parser.add_argument(
+    "--match", "-m", dest="match",
+    help="string holding extra matches for the flow entries")
+parser.add_argument(
+    "--bidirectional", "-b", dest="bidirectional",
+    action='store_true',
+    help="add/remove the flow entries from src to dst and back")
+parser.add_argument(
+    "--cookie", "-c", dest="cookie",
+    help="cookie for this flow, as easy to use identifier (eg. per tenant/service)")
+parser.add_argument(
+    "--endpoint", "-e", dest="endpoint",
+    default="http://127.0.0.1:5000",
+    help="UUID of the plugin to be manipulated.")
+
+def main(argv):
+    args = vars(parser.parse_args(argv))
+    c = RestApiClient()
+    c.execute_command(args)
\ No newline at end of file
index dc3e73a..5c0ae72 100755 (executable)
@@ -20,7 +20,8 @@ from emuvim.cli import monitor
 from emuvim.cli import network
 from emuvim.cli.rest import compute as restcom
 from emuvim.cli.rest import datacenter as restdc
 from emuvim.cli import network
 from emuvim.cli.rest import compute as restcom
 from emuvim.cli.rest import datacenter as restdc
-
+from emuvim.cli.rest import monitor as restmon
+from emuvim.cli.rest import network as restnetw
 
 
 def main():
 
 
 def main():
@@ -29,12 +30,16 @@ def main():
         exit(0)
     if sys.argv[1] == "compute-zapi":
         compute.main(sys.argv[2:])
         exit(0)
     if sys.argv[1] == "compute-zapi":
         compute.main(sys.argv[2:])
-    elif sys.argv[1] == "network":
+    elif sys.argv[1] == "network-zapi":
         network.main(sys.argv[2:])
     elif sys.argv[1] == "datacenter-zapi":
         datacenter.main(sys.argv[2:])
         network.main(sys.argv[2:])
     elif sys.argv[1] == "datacenter-zapi":
         datacenter.main(sys.argv[2:])
-    elif sys.argv[1] == "monitor":
+    elif sys.argv[1] == "monitor-zapi":
         monitor.main(sys.argv[2:])
         monitor.main(sys.argv[2:])
+    elif sys.argv[1] == "monitor":
+        restmon.main(sys.argv[2:])
+    elif sys.argv[1] == "network":
+        restnetw.main(sys.argv[2:])
     elif sys.argv[1] == "compute":
         restcom.main(sys.argv[2:])
     elif sys.argv[1] == "datacenter":
     elif sys.argv[1] == "compute":
         restcom.main(sys.argv[2:])
     elif sys.argv[1] == "datacenter":
index 39c4a96..1adc8bc 100755 (executable)
@@ -470,7 +470,7 @@ class DCNetwork(Containernet):
         if learning_switch:
             self.ryu_process = Popen([ryu_cmd, ryu_path, ryu_path2, ryu_option, ryu_of_port], stdout=FNULL, stderr=FNULL)
         else:
         if learning_switch:
             self.ryu_process = Popen([ryu_cmd, ryu_path, ryu_path2, ryu_option, ryu_of_port], stdout=FNULL, stderr=FNULL)
         else:
-            # no learning switch
+            # no learning switch, but with rest api
             self.ryu_process = Popen([ryu_cmd, ryu_path2, ryu_option, ryu_of_port], stdout=FNULL, stderr=FNULL)
         time.sleep(1)
 
             self.ryu_process = Popen([ryu_cmd, ryu_path2, ryu_option, ryu_of_port], stdout=FNULL, stderr=FNULL)
         time.sleep(1)
 
old mode 100644 (file)
new mode 100755 (executable)
index 121e2ef..f3125f1
@@ -19,8 +19,9 @@ script.
 import logging
 from mininet.log import setLogLevel
 from emuvim.dcemulator.net import DCNetwork
 import logging
 from mininet.log import setLogLevel
 from emuvim.dcemulator.net import DCNetwork
-from emuvim.api.rest.compute import RestApiEndpoint
-#from emuvim.api.zerorpc.compute import ZeroRpcApiEndpoint
+from emuvim.api.rest.rest_api_endpoint import RestApiEndpoint
+
+from emuvim.api.zerorpc.compute import ZeroRpcApiEndpoint
 from emuvim.api.zerorpc.network import ZeroRpcApiEndpointDCNetwork
 
 logging.basicConfig(level=logging.INFO)
 from emuvim.api.zerorpc.network import ZeroRpcApiEndpointDCNetwork
 
 logging.basicConfig(level=logging.INFO)
@@ -30,11 +31,12 @@ def create_topology1():
     """
     1. Create a data center network object (DCNetwork)
     """
     """
     1. Create a data center network object (DCNetwork)
     """
-    net = DCNetwork()
+    net = DCNetwork(monitor=True, enable_learning=False)
 
     """
     1b. add a monitoring agent to the DCNetwork
     """
 
     """
     1b. add a monitoring agent to the DCNetwork
     """
+    #keep old zeroRPC interface to test the prometheus metric query
     mon_api = ZeroRpcApiEndpointDCNetwork("0.0.0.0", 5151)
     mon_api.connectDCNetwork(net)
     mon_api.start()
     mon_api = ZeroRpcApiEndpointDCNetwork("0.0.0.0", 5151)
     mon_api.connectDCNetwork(net)
     mon_api.start()
@@ -76,6 +78,14 @@ def create_topology1():
        one or more data centers to it, which can then be controlled through
        this API, e.g., start/stop/list compute instances.
     """
        one or more data centers to it, which can then be controlled through
        this API, e.g., start/stop/list compute instances.
     """
+    # keep the old zeroRPC interface for the prometheus metric query test
+    zapi1 = ZeroRpcApiEndpoint("0.0.0.0", 4242)
+    # connect data centers to this endpoint
+    zapi1.connectDatacenter(dc1)
+    zapi1.connectDatacenter(dc2)
+    # run API endpoint server (in another thread, don't block)
+    zapi1.start()
+
     # create a new instance of a endpoint implementation
     api1 = RestApiEndpoint("127.0.0.1", 5000)
     # connect data centers to this endpoint
     # create a new instance of a endpoint implementation
     api1 = RestApiEndpoint("127.0.0.1", 5000)
     # connect data centers to this endpoint
@@ -83,6 +93,8 @@ def create_topology1():
     api1.connectDatacenter(dc2)
     api1.connectDatacenter(dc3)
     api1.connectDatacenter(dc4)
     api1.connectDatacenter(dc2)
     api1.connectDatacenter(dc3)
     api1.connectDatacenter(dc4)
+    # connect total network also, needed to do the chaining and monitoring
+    api1.connectDCNetwork(net)
     # run API endpoint server (in another thread, don't block)
     api1.start()
 
     # run API endpoint server (in another thread, don't block)
     api1.start()
 
old mode 100644 (file)
new mode 100755 (executable)
index 54ffde9..e7ab297
@@ -7,7 +7,7 @@ import os
 import subprocess
 import docker
 from emuvim.dcemulator.net import DCNetwork
 import subprocess
 import docker
 from emuvim.dcemulator.net import DCNetwork
-from emuvim.api.rest.compute import RestApiEndpoint
+from emuvim.api.rest.rest_api_endpoint import RestApiEndpoint
 from mininet.clean import cleanup
 from mininet.node import Controller
 
 from mininet.clean import cleanup
 from mininet.node import Controller
 
old mode 100644 (file)
new mode 100755 (executable)
index c395220..67e97f2
@@ -7,7 +7,6 @@ import unittest
 from emuvim.test.api_base import SimpleTestTopology
 import subprocess
 
 from emuvim.test.api_base import SimpleTestTopology
 import subprocess
 
-
 class testRestApi( SimpleTestTopology ):
     """
     Tests to check the REST API endpoints of the emulator.
 class testRestApi( SimpleTestTopology ):
     """
     Tests to check the REST API endpoints of the emulator.
@@ -37,6 +36,14 @@ class testRestApi( SimpleTestTopology ):
         print('compute list ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
         print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
         subprocess.call("son-emu-cli compute list", shell=True)
         print('compute list ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
         print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
         subprocess.call("son-emu-cli compute list", shell=True)
+
+        print('network add vnf1 vnf2->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        subprocess.call("son-emu-cli network add -src vnf1 -dst vnf2 -b -c 10", shell=True)
+        print('network remove vnf1 vnf2->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        subprocess.call("son-emu-cli network remove -src vnf1 -dst vnf2 -b", shell=True)
+
         print('compute stop datacenter0, vnf2 ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
         print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
         subprocess.call("son-emu-cli compute stop -d datacenter0 -n vnf2", shell=True)
         print('compute stop datacenter0, vnf2 ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
         print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
         subprocess.call("son-emu-cli compute stop -d datacenter0 -n vnf2", shell=True)
diff --git a/utils/ci/son-analyze_test.sh b/utils/ci/son-analyze_test.sh
new file mode 100755 (executable)
index 0000000..45aafad
--- /dev/null
@@ -0,0 +1,3 @@
+vnf1_uuid=$(docker inspect --format="{{.Id}}" mn.vnf1)
+
+
index b162f20..c61e3f6 100755 (executable)
@@ -6,6 +6,6 @@ son-emu-cli monitor stop_metric -vnf vnf1:output --metric tx_packets
 sleep 1
 
 #stop the vnf
 sleep 1
 
 #stop the vnf
-son-emu-cli compute-zapi stop -d datacenter1 -n vnf1
+son-emu-cli compute stop -d datacenter1 -n vnf1
 
 
 
 
index 08e52e5..e5cd13b 100755 (executable)
@@ -5,18 +5,20 @@
 #python src/emuvim/examples/monitoring_demo_topology.py &
 
 # start a vnf
 #python src/emuvim/examples/monitoring_demo_topology.py &
 
 # start a vnf
-son-emu-cli compute-zapi start -d datacenter1 -n vnf1  --net '(id=input,ip=10.0.10.3/24),(id=output,ip=10.0.10.4/24)'
+son-emu-cli compute start -d datacenter1 -n vnf1  --net '(id=input,ip=10.0.10.3/24),(id=output,ip=10.0.10.4/24)'
 
 sleep 1
 
 # monitor a metric
 son-emu-cli monitor setup_metric -vnf vnf1:output --metric tx_packets
 
 
 sleep 1
 
 # monitor a metric
 son-emu-cli monitor setup_metric -vnf vnf1:output --metric tx_packets
 
-sleep 5
+# allow some time to gather metrics
+sleep 20
 
 # check if metric is monitored as expected (exported by son-emu, has vnf name as metric id)
 
 # check if metric is monitored as expected (exported by son-emu, has vnf name as metric id)
-tx_rate=$(son-emu-cli monitor prometheus -d datacenter1 -vnf vnf1 -q 'rate(sonemu_tx_count_packets{vnf_name="vnf1"}[1m])')
+tx_rate=$(son-emu-cli monitor-zapi prometheus -d datacenter1 -vnf vnf1 -q 'rate(sonemu_tx_count_packets{vnf_name="vnf1"}[10s])')
 
 
+sleep 1
 
 # test if prometheus query worked
 echo $tx_rate
 
 # test if prometheus query worked
 echo $tx_rate
@@ -32,7 +34,7 @@ fi
 
 
 # check if cpu load can be monitored (exported by cAdvisor, needs uuid)
 
 
 # check if cpu load can be monitored (exported by cAdvisor, needs uuid)
-cpu_load=$(son-emu-cli monitor prometheus -d datacenter1 -vnf vnf1 -q 'sum(rate(container_cpu_usage_seconds_total{id="/docker/<uuid>"}[10s]))')
+cpu_load=$(son-emu-cli monitor-zapi prometheus -d datacenter1 -vnf vnf1 -q 'sum(rate(container_cpu_usage_seconds_total{id="/docker/<uuid>"}[10s]))')
 
 sleep 1
 
 
 sleep 1