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 threading
-from flask import Flask, request
-from flask_restful import Resource,Api
+from flask_restful import Resource
+from flask import request
 import json
 
-
-
 logging.basicConfig(level=logging.INFO)
 
-
 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)
@@ -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),...
-    :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
 
@@ -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
-            return  c. getStatus(), 200
+            return c.getStatus(), 200
         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
+#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)
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}
 
-        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))
-        pp.pprint(responce.json())
+        pp.pprint(response.json())
+
     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")))
-        pp.pprint(responce.json())
+        pp.pprint(response.json())
 
     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.rest import monitor as restmon
+from emuvim.cli.rest import network as restnetw
 
 
 def main():
@@ -29,12 +30,16 @@ def main():
         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:])
-    elif sys.argv[1] == "monitor":
+    elif sys.argv[1] == "monitor-zapi":
         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":
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:
-            # 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)
 
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
-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)
@@ -30,11 +31,12 @@ def create_topology1():
     """
     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
     """
+    #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()
@@ -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.
     """
+    # 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
@@ -83,6 +93,8 @@ def create_topology1():
     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()
 
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
-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
 
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
 
-
 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('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)
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
-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
-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 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)
-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
@@ -32,7 +34,7 @@ fi
 
 
 # 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