Merge remote-tracking branch 'upstream/master'
diff --git a/.gitignore b/.gitignore
index 51aa756..e59451b 100755
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,9 @@
 #IDE
 .idea/
 
+# virtualenv
+venv
+
 # vagrant
 .vagrant/
 
diff --git a/Vagrantfile b/Vagrantfile
index 30fd519..3ed9a3f 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -58,7 +58,10 @@
   # Create a forwarded port mapping which allows access to a specific port
   # within the machine from a port on the host machine. In the example below,
   # accessing "localhost:8080" will access port 80 on the guest machine.
-  config.vm.network "forwarded_port", guest: 5000, host: 5000
+  config.vm.network "forwarded_port", guest: 5000, host: 5000 # dummy gatekeeper
+  config.vm.network "forwarded_port", guest: 5001, host: 5001 # REST API
+  config.vm.network "forwarded_port", guest: 8080, host: 8080 # cAdvisor
+  config.vm.network "forwarded_port", guest: 9091, host: 9091 # push gateway
 
   # Create a private network, which allows host-only access to the machine
   # using a specific IP.
diff --git a/setup-cli.py b/setup-cli.py
new file mode 100644
index 0000000..78a212c
--- /dev/null
+++ b/setup-cli.py
@@ -0,0 +1,57 @@
+"""
+Copyright (c) 2015 SONATA-NFV
+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).
+"""
+"""
+Additional setup that installs 'son-emu-cli' in standalone mode.
+"""
+from setuptools import setup, find_packages
+
+setup(name='sonemucli',
+      version='0.9',
+      license='Apache 2.0',
+      description='CLI client for son-emu',
+      url='http://github.com/sonata-emu',
+      author_email='sonata-dev@sonata-nfv.eu',
+      package_dir={'': 'src'},
+      packages=find_packages('src'),
+      install_requires=[
+          'tabulate',
+          'argparse',
+          'pytest',
+          'requests',
+          'prometheus_client',
+          'urllib3'
+      ],
+      zip_safe=False,
+      entry_points={
+          'console_scripts': [
+              'son-emu-cli=emuvim.cli.son_emu_cli:main',
+          ],
+      },
+      setup_requires=['pytest-runner'],
+      tests_require=['pytest'],
+)
diff --git a/setup.py b/setup.py
index d23ea68..8770532 100755
--- a/setup.py
+++ b/setup.py
@@ -44,7 +44,7 @@
           'networkx',
           'six>=1.9',
           'ryu',
-          'ryu',
+          'oslo.config',
           'pytest',
           'Flask',
           'flask_restful',
diff --git a/src/emuvim/api/sonata/dummygatekeeper.py b/src/emuvim/api/sonata/dummygatekeeper.py
index 71fd7d5..2aa712e 100755
--- a/src/emuvim/api/sonata/dummygatekeeper.py
+++ b/src/emuvim/api/sonata/dummygatekeeper.py
@@ -129,7 +129,7 @@
         else:
             self._load_docker_urls()
             self._pull_predefined_dockerimages()
-        LOG.info("On-boarded service: %r" % self.manifest.get("package_name"))
+        LOG.info("On-boarded service: %r" % self.manifest.get("name"))
 
     def start_service(self):
         """
diff --git a/src/emuvim/cli/compute.py b/src/emuvim/cli/compute.py
deleted file mode 100755
index b5f775f..0000000
--- a/src/emuvim/cli/compute.py
+++ /dev/null
@@ -1,148 +0,0 @@
-"""
-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).
-"""
-
-import argparse
-import pprint
-from tabulate import tabulate
-import zerorpc
-
-
-pp = pprint.PrettyPrinter(indent=4)
-
-
-class ZeroRpcClient(object):
-
-    def __init__(self):
-        self.c = zerorpc.Client(heartbeat=None, timeout=120) #heartbeat=None, timeout=120
-        self.c.connect("tcp://127.0.0.1:4242")  # TODO hard coded for now. we'll change this later
-        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 start(self, args):
-        nw_list = list()
-        if args.get("network") is not None:
-            nw_list = self._parse_network(args.get("network"))
-        r = self.c.compute_action_start(
-            args.get("datacenter"),
-            args.get("name"),
-            args.get("image"),
-            nw_list,
-            args.get("docker_command")
-            )
-        pp.pprint(r)
-
-    def stop(self, args):
-        r = self.c.compute_action_stop(
-            args.get("datacenter"), args.get("name"))
-        pp.pprint(r)
-
-    def list(self, args):
-        r = self.c.compute_list(
-            args.get("datacenter"))
-        table = []
-        for c in r:
-            # for each container add a line to the output table
-            if len(c) > 1:
-                name = c[0]
-                status = c[1]
-                eth0ip = None
-                eth0status = "down"
-                if len(status.get("network")) > 0:
-                    eth0ip = status.get("network")[0].get("ip")
-                    eth0status = "up" if status.get(
-                        "network")[0].get("up") else "down"
-                table.append([status.get("datacenter"),
-                              name,
-                              status.get("image"),
-                              eth0ip,
-                              eth0status,
-                              status.get("state").get("Status")])
-        headers = ["Datacenter",
-                   "Container",
-                   "Image",
-                   "eth0 IP",
-                   "eth0 status",
-                   "Status"]
-        print(tabulate(table, headers=headers, tablefmt="grid"))
-
-    def status(self, args):
-        r = self.c.compute_status(
-            args.get("datacenter"), args.get("name"))
-        pp.pprint(r)
-
-    def _create_dict(self, **kwargs):
-        return kwargs
-
-    def _parse_network(self, network_str):
-        '''
-        parse the options for all network interfaces of the vnf
-        :param network_str: (id=x,ip=x.x.x.x/x), ...
-        :return: list of dicts [{"id":x,"ip":"x.x.x.x/x"}, ...]
-        '''
-        nw_list = list()
-        networks = network_str[1:-1].split('),(')
-        for nw in networks:
-            nw_dict = dict(tuple(e.split('=')) for e in nw.split(','))
-            nw_list.append(nw_dict)
-
-        return nw_list
-
-
-
-parser = argparse.ArgumentParser(description='son-emu compute')
-parser.add_argument(
-    "command",
-    choices=['start', 'stop', 'list', 'status'],
-    help="Action to be executed.")
-parser.add_argument(
-    "--datacenter", "-d", dest="datacenter",
-    help="Data center to in which the compute instance should be executed")
-parser.add_argument(
-    "--name", "-n", dest="name",
-    help="Name of compute instance e.g. 'vnf1'")
-parser.add_argument(
-    "--image","-i", dest="image",
-    help="Name of container image to be used e.g. 'ubuntu:trusty'")
-parser.add_argument(
-    "--dcmd", "-c", dest="docker_command",
-    help="Startup command of the container e.g. './start.sh'")
-parser.add_argument(
-    "--net", dest="network",
-    help="Network properties of a compute instance e.g. \
-          '(id=input,ip=10.0.10.3/24),(id=output,ip=10.0.10.4/24)' for multiple interfaces.")
-
-def main(argv):
-    args = vars(parser.parse_args(argv))
-    c = ZeroRpcClient()
-    c.execute_command(args)
diff --git a/src/emuvim/cli/datacenter.py b/src/emuvim/cli/datacenter.py
deleted file mode 100755
index e08a6c5..0000000
--- a/src/emuvim/cli/datacenter.py
+++ /dev/null
@@ -1,89 +0,0 @@
-"""
-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).
-"""
-
-import argparse
-import pprint
-from tabulate import tabulate
-import zerorpc
-
-
-pp = pprint.PrettyPrinter(indent=4)
-
-
-class ZeroRpcClient(object):
-
-    def __init__(self):
-        self.c = zerorpc.Client()
-        self.c.connect("tcp://127.0.0.1:4242")  # TODO hard coded for now. we'll change this later
-        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 list(self, args):
-        r = self.c.datacenter_list()
-        table = []
-        for d in r:
-            # for each dc add a line to the output table
-            if len(d) > 0:
-                table.append([d.get("label"),
-                              d.get("internalname"),
-                              d.get("switch"),
-                              d.get("n_running_containers"),
-                              len(d.get("metadata"))])
-        headers = ["Label",
-                   "Internal Name",
-                   "Switch",
-                   "# Containers",
-                   "# Metadata Items"]
-        print(tabulate(table, headers=headers, tablefmt="grid"))
-
-    def status(self, args):
-        r = self.c.datacenter_status(
-            args.get("datacenter"))
-        pp.pprint(r)
-
-
-parser = argparse.ArgumentParser(description='son-emu datacenter')
-parser.add_argument(
-    "command",
-    choices=['list', 'status'],
-    help="Action to be executed.")
-parser.add_argument(
-    "--datacenter", "-d", dest="datacenter",
-    help="Data center to which the command should be applied.")
-
-
-def main(argv):
-    args = vars(parser.parse_args(argv))
-    c = ZeroRpcClient()
-    c.execute_command(args)
diff --git a/src/emuvim/cli/monitor.py b/src/emuvim/cli/monitor.py
deleted file mode 100755
index 3e872d6..0000000
--- a/src/emuvim/cli/monitor.py
+++ /dev/null
@@ -1,149 +0,0 @@
-"""

-Copyright (c) 2015 SONATA-NFV

-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).

-"""

-

-import argparse

-import pprint

-import zerorpc

-from emuvim.cli import prometheus

-

-pp = pprint.PrettyPrinter(indent=4)

-

-class ZeroRpcClient(object):

-

-    def __init__(self):

-        # network zerorpc

-        self.c = zerorpc.Client()

-        # TODO connect to DCNetwork API

-        #self.c.connect("tcp://127.0.0.1:4242")  # TODO hard coded for now. we'll change this later

-        self.c.connect("tcp://127.0.0.1:5151")

-

-        # compute zerorpc

-        self.compute_api = zerorpc.Client(heartbeat=None, timeout=120)  # heartbeat=None, timeout=120

-        self.compute_api.connect("tcp://127.0.0.1:4242")  # TODO hard coded for now. we'll change this later

-

-        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"))

-        r = self.c.setup_metric(

-            vnf_name,

-            vnf_interface,

-            args.get("metric"))

-        pp.pprint(r)

-

-    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"))

-        r = self.c.stop_metric(

-            vnf_name,

-            vnf_interface,

-            args.get("metric"))

-        pp.pprint(r)

-

-    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"))

-        r = self.c.setup_flow(

-            vnf_name,

-            vnf_interface,

-            args.get("metric"),

-            args.get("cookie"))

-        pp.pprint(r)

-

-    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"))

-        r = self.c.stop_flow(

-            vnf_name,

-            vnf_interface,

-            args.get("metric"),

-            args.get("cookie"))

-        pp.pprint(r)

-

-    def prometheus(self, args):

-        # This functions makes it more user-friendly to create the correct prometheus query

-        # <uuid> is replaced by the correct uuid of the deployed vnf container

-        vnf_name = self._parse_vnf_name(args.get("vnf_name"))

-        vnf_interface = self._parse_vnf_interface(args.get("vnf_name"))

-        dc_label = args.get("datacenter")

-        query = args.get("query")

-        vnf_status = self.compute_api.compute_status(dc_label, vnf_name)

-        uuid = vnf_status['id']

-        query = query.replace('<uuid>', uuid)

-

-        r = prometheus.query_Prometheus(query)

-        pp.pprint(r)

-

-

-    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")

-

-def main(argv):

-    #print "This is the son-emu monitor CLI."

-    #print "Arguments: %s" % str(argv)

-    args = vars(parser.parse_args(argv))

-    c = ZeroRpcClient()

-    c.execute_command(args)

diff --git a/src/emuvim/cli/network.py b/src/emuvim/cli/network.py
deleted file mode 100755
index 960e387..0000000
--- a/src/emuvim/cli/network.py
+++ /dev/null
@@ -1,138 +0,0 @@
-"""

-Copyright (c) 2015 SONATA-NFV

-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).

-"""

-

-import argparse

-import pprint

-from tabulate import tabulate

-import zerorpc

-

-

-pp = pprint.PrettyPrinter(indent=4)

-

-class ZeroRpcClient(object):

-

-    def __init__(self):

-        self.c = zerorpc.Client()

-        # TODO connect to DCNetwork API

-        #self.c.connect("tcp://127.0.0.1:4242")  # TODO hard coded for now. we'll change this later

-        self.c.connect("tcp://127.0.0.1:5151")

-        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"))

-

-        # note zerorpc does not support named arguments

-        r = self.c.network_action_start(

-            #args.get("datacenter"),

-            vnf_src_name,

-            vnf_dst_name,

-            params)

-        pp.pprint(r)

-

-    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"))

-

-        r = self.c.network_action_stop(

-            #args.get("datacenter"),

-            vnf_src_name,

-            vnf_dst_name,

-            params)

-        pp.pprint(r)

-

-    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)")

-

-def main(argv):

-    args = vars(parser.parse_args(argv))

-    c = ZeroRpcClient()

-    c.execute_command(args)

diff --git a/src/emuvim/cli/son_emu_cli.py b/src/emuvim/cli/son_emu_cli.py
index edbd306..c45a5f1 100755
--- a/src/emuvim/cli/son_emu_cli.py
+++ b/src/emuvim/cli/son_emu_cli.py
@@ -38,11 +38,6 @@
 """
 
 import sys
-
-from emuvim.cli import compute
-from emuvim.cli import datacenter
-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
@@ -51,16 +46,8 @@
 
 def main():
     if len(sys.argv) < 2:
-        print("Usage: son-emu-cli <toolname> <arguments>")
+        print("Usage: son-emu-cli compute|datacenter|network|monitor <arguments>")
         exit(0)
-    if sys.argv[1] == "compute-zapi":
-        compute.main(sys.argv[2:])
-    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-zapi":
-        monitor.main(sys.argv[2:])
     elif sys.argv[1] == "monitor":
         restmon.main(sys.argv[2:])
     elif sys.argv[1] == "network":