add rest api for network and monitoring
diff --git a/src/emuvim/api/rest/__init__.py b/src/emuvim/api/rest/__init__.py
old mode 100644
new mode 100755
diff --git a/src/emuvim/api/rest/compute.py b/src/emuvim/api/rest/compute.py
old mode 100644
new mode 100755
index 02ca9f2..1c9c892
--- a/src/emuvim/api/rest/compute.py
+++ b/src/emuvim/api/rest/compute.py
@@ -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 @@
: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 @@
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
index 0000000..b1edbc3
--- /dev/null
+++ b/src/emuvim/api/rest/monitor.py
@@ -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
index 0000000..4a0214f
--- /dev/null
+++ b/src/emuvim/api/rest/network.py
@@ -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
index 0000000..6c69a03
--- /dev/null
+++ b/src/emuvim/api/rest/rest_api_endpoint.py
@@ -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