From 51d4ae7cfe58f87a4a993e5c503ed52736fd72e2 Mon Sep 17 00:00:00 2001 From: stevenvanrossem Date: Wed, 10 Aug 2016 13:22:53 +0200 Subject: [PATCH] fix ryu rest api, use requests iso urllib2 --- src/emuvim/dcemulator/monitoring.py | 21 ++++++---- src/emuvim/dcemulator/net.py | 64 ++++++++++++++++++++--------- 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/src/emuvim/dcemulator/monitoring.py b/src/emuvim/dcemulator/monitoring.py index 2c07ab5..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 @@ -358,7 +359,13 @@ 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) @@ -447,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: @@ -467,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 4503e1c..15bb6f1 100755 --- a/src/emuvim/dcemulator/net.py +++ b/src/emuvim/dcemulator/net.py @@ -30,7 +30,6 @@ import logging import site import time from subprocess import Popen -import os import re import requests @@ -93,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: @@ -260,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) @@ -532,25 +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)) - req = requests.post(url, data=str(data)) - else: - #req = urllib2.Request(url) - req = requests.get(url) - #ret = urllib2.urlopen(req).read() - ret = req.text + 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 -- 2.25.1