From: stevenvanrossem Date: Wed, 10 Aug 2016 14:51:02 +0000 (+0200) Subject: Merge pull request #154 from stevenvanrossem/master X-Git-Tag: v3.1~75^2 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=36afe6369a9b6178525057a524a27fde59398b00;hp=8de1f30034ca592d21b588bf6202e05f27659b3c;p=osm%2Fvim-emu.git Merge pull request #154 from stevenvanrossem/master fix some bugs in monitoring rest api --- diff --git a/src/emuvim/api/rest/compute.py b/src/emuvim/api/rest/compute.py index 78b49e3..c3680a0 100755 --- a/src/emuvim/api/rest/compute.py +++ b/src/emuvim/api/rest/compute.py @@ -113,10 +113,10 @@ class Compute(Resource): class ComputeList(Resource): global dcs - def get(self, dc_label): + def get(self, dc_label=None): logging.debug("API CALL: compute list") try: - if dc_label == 'None': + if dc_label is None or dc_label == 'None': # return list with all compute nodes in all DCs all_containers = [] for dc in dcs.itervalues(): diff --git a/src/emuvim/api/rest/network.py b/src/emuvim/api/rest/network.py index e3945b0..83fbde7 100755 --- a/src/emuvim/api/rest/network.py +++ b/src/emuvim/api/rest/network.py @@ -53,6 +53,7 @@ class NetworkAction(Resource): :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. + :param priority: integer indicating the priority of the flow entry :return: message string indicating if the chain action is succesful or not """ diff --git a/src/emuvim/api/rest/rest_api_endpoint.py b/src/emuvim/api/rest/rest_api_endpoint.py index b586915..e382f5a 100755 --- a/src/emuvim/api/rest/rest_api_endpoint.py +++ b/src/emuvim/api/rest/rest_api_endpoint.py @@ -60,8 +60,11 @@ class RestApiEndpoint(object): self.api = Api(self.app) # setup endpoints + self.api.add_resource(Compute, "/restapi/compute//") - self.api.add_resource(ComputeList, "/restapi/compute/") + self.api.add_resource(ComputeList, + "/restapi/compute", + "/restapi/compute/") self.api.add_resource(DatacenterStatus, "/restapi/datacenter/") self.api.add_resource(DatacenterList, "/restapi/datacenter") diff --git a/src/emuvim/api/sonata/dummygatekeeper.py b/src/emuvim/api/sonata/dummygatekeeper.py index 0fb3aa0..916e168 100755 --- a/src/emuvim/api/sonata/dummygatekeeper.py +++ b/src/emuvim/api/sonata/dummygatekeeper.py @@ -166,7 +166,9 @@ class Service(object): fwd_links = self.nsd["forwarding_graphs"][0]["constituent_virtual_links"] eline_fwd_links = [l for l in vlinks if (l["id"] in fwd_links) and (l["connectivity_type"] == "E-Line")] - cookie = 1 # not clear why this is needed - to check with Steven + # cookie is used as identifier for the flowrules installed by the dummygatekeeper + # eg. different services get a unique cookie for their flowrules + cookie = 1 for link in eline_fwd_links: src_id, src_if_name = link["connection_points_reference"][0].split(":") dst_id, dst_if_name = link["connection_points_reference"][1].split(":") @@ -187,7 +189,6 @@ class Service(object): src_docker_name, dst_docker_name, vnf_src_interface=src_if_name, vnf_dst_interface=dst_if_name, bidirectional=True, cmd="add-flow", cookie=cookie) - cookie += 1 # re-configure the VNFs IP assignment and ensure that a new subnet is used for each E-Link src_vnfi = self._get_vnf_instance(instance_uuid, src_name) diff --git a/src/emuvim/dcemulator/monitoring.py b/src/emuvim/dcemulator/monitoring.py index 80b139c..ba04771 100755 --- a/src/emuvim/dcemulator/monitoring.py +++ b/src/emuvim/dcemulator/monitoring.py @@ -27,6 +27,7 @@ partner consortium (www.sonata-nfv.eu). """ import logging +import sys from mininet.node import OVSSwitch import ast import time @@ -348,6 +349,7 @@ class DCNetworkMonitor(): data = {} data['cookie'] = flow_dict['cookie'] + data['cookie_mask'] = flow_dict['cookie'] if 'tx' in flow_dict['metric_key']: data['match'] = {'in_port':flow_dict['mon_port']} @@ -357,9 +359,15 @@ class DCNetworkMonitor(): # query Ryu ret = self.net.ryu_REST('stats/flow', dpid=flow_dict['switch_dpid'], data=data) - flow_stat_dict = ast.literal_eval(ret) + if isinstance(ret, dict): + flow_stat_dict = ret + elif isinstance(ret, basestring): + flow_stat_dict = ast.literal_eval(ret.rstrip()) + else: + flow_stat_dict = None logging.debug('received flow stat:{0} '.format(flow_stat_dict)) + self.set_flow_metric(flow_dict, flow_stat_dict) self.monitor_flow_lock.release() @@ -446,13 +454,6 @@ class DCNetworkMonitor(): previous_monitor_time = metric_dict['previous_monitor_time'] cookie = metric_dict['cookie'] - # TODO aggregate all found flow stats - #flow_stat = flow_stat_dict[str(switch_dpid)][0] - #if 'bytes' in metric_key: - # counter = flow_stat['byte_count'] - #elif 'packet' in metric_key: - # counter = flow_stat['packet_count'] - counter = 0 for flow_stat in flow_stat_dict[str(switch_dpid)]: if 'bytes' in metric_key: @@ -466,7 +467,10 @@ class DCNetworkMonitor(): self.prom_metrics[metric_dict['metric_key']]. \ labels({'vnf_name': vnf_name, 'vnf_interface': vnf_interface, 'flow_id': cookie}). \ set(counter) - pushadd_to_gateway(self.pushgateway, job='sonemu-SDNcontroller', registry=self.registry) + try: + pushadd_to_gateway(self.pushgateway, job='sonemu-SDNcontroller', registry=self.registry) + except Exception, e: + logging.warning("Pushgateway not reachable: {0} {1}".format(Exception, e)) def start_Prometheus(self, port=9090): diff --git a/src/emuvim/dcemulator/net.py b/src/emuvim/dcemulator/net.py index bca20b2..15bb6f1 100755 --- a/src/emuvim/dcemulator/net.py +++ b/src/emuvim/dcemulator/net.py @@ -30,10 +30,8 @@ import logging import site import time from subprocess import Popen -import os import re -import urllib2 -from functools import partial +import requests from mininet.net import Containernet from mininet.node import Controller, DefaultController, OVSSwitch, OVSKernelSwitch, Docker, RemoteController @@ -94,9 +92,10 @@ class DCNetwork(Containernet): self.vlans = range(4096)[::-1] # link to Ryu REST_API - ryu_ip = '0.0.0.0' + ryu_ip = 'localhost' ryu_port = '8080' self.ryu_REST_api = 'http://{0}:{1}'.format(ryu_ip, ryu_port) + self.RyuSession = requests.Session() # monitoring agent if monitor: @@ -261,8 +260,22 @@ class DCNetwork(Containernet): def CLI(self): CLI(self) - # to remove chain do setChain( src, dst, cmd='del-flows') def setChain(self, vnf_src_name, vnf_dst_name, vnf_src_interface=None, vnf_dst_interface=None, **kwargs): + """ + Chain 2 vnf interfaces together by installing the flowrules in the switches along their path. + Currently the path is found using the default networkx shortest path function. + Each chain gets a unique vlan id , so different chains wil not interfere. + + :param vnf_src_name: vnf name (string) + :param vnf_dst_name: vnf name (string) + :param vnf_src_interface: source interface name (string) + :param vnf_dst_interface: destination interface name (string) + :param cmd: 'add-flow' (default) to add a chain, 'del-flows' to remove a chain + :param cookie: cookie for the installed flowrules (can be used later as identifier for a set of installed chains) + :param match: custom match entry to be added to the flowrules (default: only in_port and vlan tag) + :param priority: custom flowrule priority + :return: output log string + """ cmd = kwargs.get('cmd') if cmd == 'add-flow': ret = self._chainAddFlow(vnf_src_name, vnf_dst_name, vnf_src_interface, vnf_dst_interface, **kwargs) @@ -533,22 +546,35 @@ class DCNetwork(Containernet): Popen(['pkill', '-f', 'ryu-manager']) def ryu_REST(self, prefix, dpid=None, data=None): - try: - if dpid: - url = self.ryu_REST_api + '/' + str(prefix) + '/' + str(dpid) - else: - url = self.ryu_REST_api + '/' + str(prefix) - if data: - #LOG.info('POST: {0}'.format(str(data))) - req = urllib2.Request(url, str(data)) - else: - req = urllib2.Request(url) - ret = urllib2.urlopen(req).read() + if dpid: + url = self.ryu_REST_api + '/' + str(prefix) + '/' + str(dpid) + else: + url = self.ryu_REST_api + '/' + str(prefix) + if data: + req = self.RyuSession.post(url, json=data) + else: + req = self.RyuSession.get(url) + + + # do extra logging if status code is not 200 (OK) + if req.status_code is not requests.codes.ok: + logging.info( + 'type {0} encoding: {1} text: {2} headers: {3} history: {4}'.format(req.headers['content-type'], + req.encoding, req.text, + req.headers, req.history)) + LOG.info('url: {0}'.format(str(url))) + if data: LOG.info('POST: {0}'.format(str(data))) + LOG.info('status: {0} reason: {1}'.format(req.status_code, req.reason)) + + + if 'json' in req.headers['content-type']: + ret = req.json() return ret - except: - LOG.info('error url: {0}'.format(str(url))) - if data: LOG.info('error POST: {0}'.format(str(data))) + + ret = req.text.rstrip() + return ret + # need to respect that some match fields must be integers # http://ryu.readthedocs.io/en/latest/app/ofctl_rest.html#description-of-match-and-actions