Skip to content

Commit

Permalink
Merge pull request #198 from stevenvanrossem/master
Browse files Browse the repository at this point in the history
son-emu updates regarding monitoring
  • Loading branch information
mpeuster authored Feb 10, 2017
2 parents 339da03 + a5c5d5d commit 5abdd34
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 35 deletions.
83 changes: 67 additions & 16 deletions src/emuvim/api/rest/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"""

import logging
from flask_restful import Resource
from flask_restful import Resource, reqparse
from flask import request
import json

Expand All @@ -55,8 +55,17 @@ class MonitorInterfaceAction(Resource):
"""
global net

def put(self, vnf_name, vnf_interface=None, metric='tx_packets', cookie=None):
def put(self):
logging.debug("REST CALL: start monitor VNF interface")
# get URL parameters
data = request.args
if data is None:
data = {}
vnf_name = data.get("vnf_name")
vnf_interface = data.get("vnf_interface", None)
metric = data.get("metric", 'tx_packets')
cookie = data.get("cookie")

try:
if cookie:
c = net.monitor_agent.setup_flow(vnf_name, vnf_interface, metric, cookie)
Expand All @@ -68,8 +77,17 @@ def put(self, vnf_name, vnf_interface=None, metric='tx_packets', cookie=None):
logging.exception("API error.")
return ex.message, 500, CORS_HEADER

def delete(self, vnf_name, vnf_interface=None, metric='tx_packets', cookie=None):
def delete(self):
logging.debug("REST CALL: stop monitor VNF interface")
# get URL parameters
data = request.args
if data is None:
data = {}
vnf_name = data.get("vnf_name")
vnf_interface = data.get("vnf_interface", None)
metric = data.get("metric", 'tx_packets')
cookie = data.get("cookie")

try:
if cookie:
c = net.monitor_agent.stop_flow(vnf_name, vnf_interface, metric, cookie)
Expand All @@ -93,8 +111,17 @@ class MonitorFlowAction(Resource):
"""
global net

def put(self, vnf_name, vnf_interface=None, metric='tx_packets', cookie=0):
def put(self):
logging.debug("REST CALL: start monitor VNF interface")
# get URL parameters
data = request.args
if data is None:
data = {}
vnf_name = data.get("vnf_name")
vnf_interface = data.get("vnf_interface", None)
metric = data.get("metric", 'tx_packets')
cookie = data.get("cookie", 0)

try:
c = net.monitor_agent.setup_flow(vnf_name, vnf_interface, metric, cookie)
# return monitor message response
Expand All @@ -103,8 +130,17 @@ def put(self, vnf_name, vnf_interface=None, metric='tx_packets', cookie=0):
logging.exception("API error.")
return ex.message, 500, CORS_HEADER

def delete(self, vnf_name, vnf_interface=None, metric='tx_packets', cookie=0):
def delete(self):
logging.debug("REST CALL: stop monitor VNF interface")
# get URL parameters
data = request.args
if data is None:
data = {}
vnf_name = data.get("vnf_name")
vnf_interface = data.get("vnf_interface", None)
metric = data.get("metric", 'tx_packets')
cookie = data.get("cookie", 0)

try:
c = net.monitor_agent.stop_flow(vnf_name, vnf_interface, metric, cookie)
# return monitor message response
Expand Down Expand Up @@ -138,37 +174,40 @@ class MonitorLinkAction(Resource):
# the global net is set from the topology file, and connected via connectDCNetwork function in rest_api_endpoint.py
global net

def put(self, vnf_src_name, vnf_dst_name):
def put(self):
logging.debug("REST CALL: monitor link flow add")

try:
command = 'add-flow'
return self._MonitorLinkAction(vnf_src_name, vnf_dst_name, command=command)
return self._MonitorLinkAction(command=command)
except Exception as ex:
logging.exception("API error.")
return ex.message, 500, CORS_HEADER

def delete(self, vnf_src_name, vnf_dst_name):
def delete(self):
logging.debug("REST CALL: monitor link flow remove")

try:
command = 'del-flows'
return self._MonitorLinkAction(vnf_src_name, vnf_dst_name, command=command)
return self._MonitorLinkAction(command=command)
except Exception as ex:
logging.exception("API error.")
return ex.message, 500, CORS_HEADER

def _MonitorLinkAction(self, vnf_src_name, vnf_dst_name, command=None):
def _MonitorLinkAction(self, command=None):
# call DCNetwork method, not really datacenter specific API for now...
# no check if vnfs are really connected to this datacenter...

try:
# check if json data is a dict
data = request.json
# get URL parameters
data = request.args
#then no data
if data is None:
data = {}
elif type(data) is not dict:
data = json.loads(request.json)


vnf_src_name = data.get("vnf_src_name")
vnf_dst_name = data.get("vnf_dst_name")
vnf_src_interface = data.get("vnf_src_interface")
vnf_dst_interface = data.get("vnf_dst_interface")
weight = data.get("weight")
Expand Down Expand Up @@ -225,8 +264,14 @@ class MonitorSkewAction(Resource):
"""
global net

def put(self, vnf_name, resource_name='cpu'):
def put(self):
logging.debug("REST CALL: start monitor skewness")
# get URL parameters
data = request.args
if data is None:
data = {}
vnf_name = data.get("vnf_name")
resource_name = data.get("resource_name", 'cpu')
try:
# configure skewmon
c = net.monitor_agent.update_skewmon(vnf_name, resource_name, action='start')
Expand All @@ -237,8 +282,14 @@ def put(self, vnf_name, resource_name='cpu'):
logging.exception("API error.")
return ex.message, 500

def delete(self, vnf_name, resource_name='cpu'):
def delete(self):
logging.debug("REST CALL: stop monitor skewness")
# get URL parameters
data = request.args
if data is None:
data = {}
vnf_name = data.get("vnf_name")
resource_name = data.get("resource_name", 'cpu')
try:
# configure skewmon
c = net.monitor_agent.update_skewmon(vnf_name, resource_name, action='stop')
Expand Down
18 changes: 12 additions & 6 deletions src/emuvim/api/rest/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,27 +65,33 @@ class NetworkAction(Resource):

global net

def put(self, vnf_src_name, vnf_dst_name):
def put(self):
logging.debug("REST CALL: network chain add")
command = 'add-flow'
return self._NetworkAction(vnf_src_name, vnf_dst_name, command=command)
return self._NetworkAction(command=command)

def delete(self, vnf_src_name, vnf_dst_name):
def delete(self):
logging.debug("REST CALL: network chain remove")
command = 'del-flows'
return self._NetworkAction(vnf_src_name, vnf_dst_name, command=command)
return self._NetworkAction(command=command)

def _NetworkAction(self, vnf_src_name, vnf_dst_name, command=None):
def _NetworkAction(self, command=None):
# call DCNetwork method, not really datacenter specific API for now...
# no check if vnfs are really connected to this datacenter...
try:
# check if json data is a dict
data = request.json
data = request.args
# try json payload
if data is None:
data = request.json
# then no data
if data is None:
data = {}
elif type(data) is not dict:
data = json.loads(request.json)

vnf_src_name = data.get("vnf_src_name")
vnf_dst_name = data.get("vnf_dst_name")
vnf_src_interface = data.get("vnf_src_interface")
vnf_dst_interface = data.get("vnf_dst_interface")
weight = data.get("weight")
Expand Down
13 changes: 5 additions & 8 deletions src/emuvim/api/rest/rest_api_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,27 +75,24 @@ def __init__(self, listenip, port):

# network related actions (setup chaining between VNFs)
self.api.add_resource(NetworkAction,
"/restapi/network/<vnf_src_name>/<vnf_dst_name>")
"/restapi/network")


# monitoring related actions
# export a network interface traffic rate counter
self.api.add_resource(MonitorInterfaceAction,
"/restapi/monitor/interface/<vnf_name>/<metric>",
"/restapi/monitor/interface/<vnf_name>/<vnf_interface>/<metric>",
"/restapi/monitor/interface/<vnf_name>/<vnf_interface>/<metric>/<cookie>")
"/restapi/monitor/interface")
# export flow traffic counter, of a manually pre-installed flow entry, specified by its cookie
self.api.add_resource(MonitorFlowAction,
"/restapi/monitor/flow/<vnf_name>/<metric>/<cookie>",
"/restapi/monitor/flow/<vnf_name>/<vnf_interface>/<metric>/<cookie>")
"/restapi/monitor/flow")
# install monitoring of a specific flow on a pre-existing link in the service.
# the traffic counters of the newly installed monitor flow are exported
self.api.add_resource(MonitorLinkAction,
"/restapi/monitor/link/<vnf_src_name>/<vnf_dst_name>")
"/restapi/monitor/link")
# install skewness monitor of resource usage disribution
# the skewness metric is exported
self.api.add_resource(MonitorSkewAction,
"/restapi/monitor/skewness/<vnf_name>/<resource_name>")
"/restapi/monitor/skewness")

logging.debug("Created API endpoint %s(%s:%d)" % (self.__class__.__name__, self.ip, self.port))

Expand Down
11 changes: 11 additions & 0 deletions src/emuvim/dcemulator/monitoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,17 @@ def update_skewmon(self, vnf_name, resource_name, action):
labels=['com.containernet'],
name='skewmon'
)
# Wait a while for containers to be completely started
started = False
wait_time = 0
while not started:
list1 = self.dockercli.containers.list(filters={'status': 'running', 'name': 'prometheus'})
if len(list1) >= 1:
started = True
if wait_time > 5:
return 'skewmon not started'
time.sleep(1)
wait_time += 1
return ret


Expand Down
8 changes: 3 additions & 5 deletions src/emuvim/dcemulator/net.py
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ def _addMonitorFlow(self, vnf_src_name, vnf_dst_name, vnf_src_interface=None, vn
kwargs['switch_inport_name'] = src_sw_inport_name
kwargs['switch_outport_name'] = dst_sw_outport_name
kwargs['skip_vlan_tag'] = True
kwargs['pathindex'] = i

monitor_placement = kwargs.get('monitor_placement').strip()
# put monitor flow at the dst switch
Expand Down Expand Up @@ -500,12 +501,10 @@ def setChain(self, vnf_src_name, vnf_dst_name, vnf_src_interface=None, vnf_dst_i
: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
<<<<<<< HEAD
:param monitor: boolean to indicate whether this chain is a monitoring chain
:param tag: vlan tag to be used for this chain (pre-defined or new one if none is specified)
=======
:param skip_vlan_tag: boolean to indicate if a vlan tag should be appointed to this flow or not
:param path: custom path between the two VNFs (list of switches)
>>>>>>> upstream/master
:return: output log string
"""

Expand Down Expand Up @@ -617,7 +616,6 @@ def _chainAddFlow(self, vnf_src_name, vnf_dst_name, vnf_src_interface=None, vnf_
switch_inport_nr = src_sw_inport_nr

# choose free vlan
## if path contains more than 1 switch
cmd = kwargs.get('cmd')
vlan = None
if cmd == 'add-flow':
Expand Down Expand Up @@ -661,7 +659,7 @@ def _chainAddFlow(self, vnf_src_name, vnf_dst_name, vnf_src_interface=None, vnf_
switch_outport_nr = self.DCNetwork_graph[current_hop][next_hop][index_edge_out]['src_port_nr']


# set of entry via ovs-ofctl
# set OpenFlow entry
if isinstance( current_node, OVSSwitch ):
kwargs['vlan'] = vlan
kwargs['path'] = path
Expand Down
65 changes: 65 additions & 0 deletions utils/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright (c) 2015 SONATA-NFV and Paderborn University
# ALL RIGHTS RESERVED.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Neither the name of the SONATA-NFV [, ANY ADDITIONAL AFFILIATION]
# nor the names of its contributors may be used to endorse or promote
# products derived from this software without specific prior written
# permission.
#
# This work has been performed in the framework of the SONATA project,
# funded by the European Commission under Grant number 671517 through
# the Horizon 2020 and 5G-PPP programmes. The authors would like to
# acknowledge the contributions of their colleagues of the SONATA
# partner consortium (www.sonata-nfv.eu).

FROM ubuntu:trusty
MAINTAINER [email protected]

ENV SON_EMU_IN_DOCKER 1

RUN apt-get clean
RUN apt-get update \
&& apt-get install -y git aptitude


# install containernet
RUN apt-get install -y curl python-pip
# install docker
RUN curl -fsSL https://get.docker.com/gpg | apt-key add -
RUN curl -fsSL https://get.docker.com/ | sh

RUN pip install -U urllib3 setuptools pyparsing docker
WORKDIR /
RUN git clone https://github.com/containernet/containernet.git
RUN containernet/util/install.sh
WORKDIR containernet/
RUN make develop

# install son-emu
RUN echo 'install son-emu'
RUN apt-get install -y python-dev python-zmq libzmq-dev libffi-dev libssl-dev
RUN pip install -U zerorpc tabulate argparse networkx six ryu oslo.config pytest Flask flask_restful requests prometheus_client pyaml
WORKDIR /
RUN git clone https://github.com/sonata-nfv/son-emu.git
WORKDIR son-emu/
RUN python setup.py develop
WORKDIR /
RUN echo 'Done'


ENTRYPOINT ["/son-emu/utils/docker/entrypoint.sh"]

# dummy GK, cAdvisor, Prometheus Push Gateway, son-emu REST API
EXPOSE 5000 8081 9091 5001
23 changes: 23 additions & 0 deletions utils/docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Docker build scripts for son-emu

This directory holds the Dockerfile to build son-emu as a docker container.
This is an easy way to deploy son-emu.
To build this container:

(container tag can be freely chosen)
```
docker build -t registry.sonata-nfv.eu:5000/son-emu .
```

To deploy this container:

(choose an example topology to start in the emulator)
```
docker run -d -i --net='host' --pid='host' --privileged='true' --name 'son-emu' \
-v '/var/run/docker.sock:/var/run/docker.sock' \
-p 5000:5000 \
-p 9091:9091 \
-p 8081:8081 \
-p 5001:5001 \
registry.sonata-nfv.eu:5000/son-emu 'python src/emuvim/examples/sonata_simple_topology.py'
```
Loading

0 comments on commit 5abdd34

Please sign in to comment.