Merge pull request #122 from hadik3r/master
authorstevenvanrossem <steven.vanrossem@intec.ugent.be>
Tue, 28 Jun 2016 09:31:24 +0000 (11:31 +0200)
committerpeusterm <manuel.peuster@uni-paderborn.de>
Tue, 28 Jun 2016 09:31:24 +0000 (11:31 +0200)
rest api

src/emuvim/api/rest/__init__.py [new file with mode: 0644]
src/emuvim/api/rest/compute.py [new file with mode: 0644]
src/emuvim/cli/rest/__init__.py [new file with mode: 0644]
src/emuvim/cli/rest/compute.py [new file with mode: 0644]
src/emuvim/cli/rest/datacenter.py [new file with mode: 0644]
src/emuvim/cli/son_emu_cli.py
src/emuvim/examples/simple_topology_restapi.py [new file with mode: 0644]
src/emuvim/test/api_base.py [new file with mode: 0644]
src/emuvim/test/unittests/test_restapi.py [new file with mode: 0644]

diff --git a/src/emuvim/api/rest/__init__.py b/src/emuvim/api/rest/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/emuvim/api/rest/compute.py b/src/emuvim/api/rest/compute.py
new file mode 100644 (file)
index 0000000..02ca9f2
--- /dev/null
@@ -0,0 +1,155 @@
+import logging
+import threading
+from flask import Flask, request
+from flask_restful import Resource,Api
+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)
+    :param dc_label: name of the DC
+    :param compute_name: compute container name
+    :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"})
+    """
+    global dcs
+
+    def put(self, dc_label, compute_name):
+        logging.debug("API CALL: compute start")
+        try:
+
+            image = json.loads(request.json).get("image")
+            network = json.loads(request.json).get("network")
+            command = json.loads(request.json).get("docker_command")
+            c = dcs.get(dc_label).startCompute(
+                compute_name, image= image, command= command, network= network)
+            # return docker inspect dict
+            return  c. getStatus(), 200
+        except Exception as ex:
+            logging.exception("API error.")
+            return ex.message, 500
+
+class ComputeStop(Resource):
+
+    global dcs
+
+    def get(self, dc_label, compute_name):
+        logging.debug("API CALL: compute stop")
+        try:
+            return dcs.get(dc_label).stopCompute(compute_name), 200
+        except Exception as ex:
+            logging.exception("API error.")
+            return ex.message,500
+
+
+class ComputeList(Resource):
+
+    global dcs
+
+    def get(self, dc_label):
+        logging.debug("API CALL: compute list")
+        try:
+            if dc_label == 'None':
+                # return list with all compute nodes in all DCs
+                all_containers = []
+                for dc in dcs.itervalues():
+                    all_containers += dc.listCompute()
+                return [(c.name, c.getStatus()) for c in all_containers], 200
+            else:
+                # return list of compute nodes for specified DC
+                return [(c.name, c.getStatus())
+                    for c in dcs.get(dc_label).listCompute()], 200
+        except Exception as ex:
+            logging.exception("API error.")
+            return ex.message, 500
+
+
+class ComputeStatus(Resource):
+
+    global dcs
+
+    def get(self, dc_label, compute_name):
+
+        logging.debug("API CALL: compute list")
+
+        try:
+            return dcs.get(dc_label).containers.get(compute_name).getStatus(), 200
+        except Exception as ex:
+            logging.exception("API error.")
+            return ex.message, 500
+
+class DatacenterList(Resource):
+
+    global dcs
+
+    def get(self):
+        logging.debug("API CALL: datacenter list")
+        try:
+            return [d.getStatus() for d in dcs.itervalues()], 200
+        except Exception as ex:
+            logging.exception("API error.")
+            return ex.message, 500
+
+class DatacenterStatus(Resource):
+
+    global dcs
+
+    def get(self, dc_label):
+        logging.debug("API CALL: datacenter status")
+        try:
+            return dcs.get(dc_label).getStatus(), 200
+        except Exception as ex:
+            logging.exception("API error.")
+            return ex.message, 500
diff --git a/src/emuvim/cli/rest/__init__.py b/src/emuvim/cli/rest/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/emuvim/cli/rest/compute.py b/src/emuvim/cli/rest/compute.py
new file mode 100644 (file)
index 0000000..bdef0ec
--- /dev/null
@@ -0,0 +1,129 @@
+from requests import get,put
+from tabulate import tabulate
+import pprint
+import argparse
+import json
+
+pp = pprint.PrettyPrinter(indent=4)
+
+class RestApiClient():
+
+    def __init__(self):
+        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"))
+        req = {'image':args.get("image"),
+               'command':args.get("docker_command"),
+               'network':nw_list}
+
+        responce = put("%s/restapi/compute/%s/%s/start" %
+                       (args.get("endpoint"),
+                        args.get("datacenter"),
+                        args.get("name")),
+                       json = json.dumps(req))
+        pp.pprint(responce.json())
+    def stop(self, args):
+
+        responce = get("%s/restapi/compute/%s/%s/stop" %
+                       (args.get("endpoint"),
+                        args.get("datacenter"),
+                        args.get("name")))
+        pp.pprint(responce.json())
+
+    def list(self,args):
+
+        list = get('%s/restapi/compute/%s' % (args.get("endpoint"),args.get('datacenter'))).json()
+
+        table = []
+        for c in list:
+            # 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):
+
+        list = get("%s/restapi/compute/%s/%s" %
+                   (args.get("endpoint"),
+                    args.get("datacenter"),
+                    args.get("name"))).json()
+        pp.pprint(list)
+
+
+
+    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 datacenter')
+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 which the command should be applied.")
+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.")
+parser.add_argument(
+    "--endpoint", "-e", dest="endpoint",
+    default="http://127.0.0.1:5000",
+    help="UUID of the plugin to be manipulated.")
+
+def main(argv):
+    args = vars(parser.parse_args(argv))
+    c = RestApiClient()
+    c.execute_command(args)
\ No newline at end of file
diff --git a/src/emuvim/cli/rest/datacenter.py b/src/emuvim/cli/rest/datacenter.py
new file mode 100644 (file)
index 0000000..b43a445
--- /dev/null
@@ -0,0 +1,74 @@
+from requests import get
+from tabulate import tabulate
+import pprint
+import argparse
+
+pp = pprint.PrettyPrinter(indent=4)
+
+class RestApiClient():
+
+    def __init__(self):
+        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):
+        list = get('%s/restapi/datacenter' % args.get('endpoint')).json()
+        table = []
+        for d in list:
+            # 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):
+        list = get('%s/restapi/datacenter/%s' % ( args.get("endpoint"), args.get("datacenter"))).json()
+        table = []
+        table.append([list.get('label'),
+                  list.get('internalname'),
+                  list.get('switch'),
+                  list.get('n_running_containers'),
+                  len(list.get('metadata'))])
+
+        headers = ["Label",
+               "Internal Name",
+               "Switch",
+               "# Containers",
+               "# Metadata Items"]
+
+        print (tabulate(table, headers=headers, tablefmt="grid"))
+
+
+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.")
+parser.add_argument(
+    "--endpoint", "-e", dest="endpoint",
+    default="http://127.0.0.1:5000",
+    help="UUID of the plugin to be manipulated.")
+
+
+def main(argv):
+    args = vars(parser.parse_args(argv))
+    c = RestApiClient()
+    c.execute_command(args)
+
index 842d0a1..dc3e73a 100755 (executable)
 """
 
 import sys
+
 from emuvim.cli import compute
-from emuvim.cli import network
 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
+
+
 
 def main():
     if len(sys.argv) < 2:
         print("Usage: son-emu-cli <toolname> <arguments>")
         exit(0)
-    if sys.argv[1] == "compute":
+    if sys.argv[1] == "compute-zapi":
         compute.main(sys.argv[2:])
     elif sys.argv[1] == "network":
         network.main(sys.argv[2:])
-    elif sys.argv[1] == "datacenter":
+    elif sys.argv[1] == "datacenter-zapi":
         datacenter.main(sys.argv[2:])
     elif sys.argv[1] == "monitor":
         monitor.main(sys.argv[2:])
+    elif sys.argv[1] == "compute":
+        restcom.main(sys.argv[2:])
+    elif sys.argv[1] == "datacenter":
+        restdc.main(sys.argv[2:])
+
 
 if __name__ == '__main__':
     main()
diff --git a/src/emuvim/examples/simple_topology_restapi.py b/src/emuvim/examples/simple_topology_restapi.py
new file mode 100644 (file)
index 0000000..121e2ef
--- /dev/null
@@ -0,0 +1,108 @@
+"""
+This is an example topology for the distributed cloud emulator (dcemulator).
+(c) 2015 by Manuel Peuster <manuel.peuster@upb.de>
+
+
+This is an example that shows how a user of the emulation tool can
+define network topologies with multiple emulated cloud data centers.
+
+The definition is done with a Python API which looks very similar to the
+Mininet API (in fact it is a wrapper for it).
+
+We only specify the topology *between* data centers not within a single
+data center (data center internal setups or placements are not of interest,
+we want to experiment with VNF chains deployed across multiple PoPs).
+
+The original Mininet API has to be completely hidden and not be used by this
+script.
+"""
+import logging
+from mininet.log import setLogLevel
+from emuvim.dcemulator.net import DCNetwork
+from emuvim.api.rest.compute import RestApiEndpoint
+#from emuvim.api.zerorpc.compute import ZeroRpcApiEndpoint
+from emuvim.api.zerorpc.network import ZeroRpcApiEndpointDCNetwork
+
+logging.basicConfig(level=logging.INFO)
+
+
+def create_topology1():
+    """
+    1. Create a data center network object (DCNetwork)
+    """
+    net = DCNetwork()
+
+    """
+    1b. add a monitoring agent to the DCNetwork
+    """
+    mon_api = ZeroRpcApiEndpointDCNetwork("0.0.0.0", 5151)
+    mon_api.connectDCNetwork(net)
+    mon_api.start()
+    """
+    2. Add (logical) data centers to the topology
+       (each data center is one "bigswitch" in our simplified
+        first prototype)
+    """
+    dc1 = net.addDatacenter("datacenter1")
+    dc2 = net.addDatacenter("datacenter2")
+    dc3 = net.addDatacenter("long_data_center_name3")
+    dc4 = net.addDatacenter(
+        "datacenter4",
+        metadata={"mydata": "we can also add arbitrary metadata to each DC"})
+
+    """
+    3. You can add additional SDN switches for data center
+       interconnections to the network.
+    """
+    s1 = net.addSwitch("s1")
+
+    """
+    4. Add links between your data centers and additional switches
+       to define you topology.
+       These links can use Mininet's features to limit bw, add delay or jitter.
+    """
+    net.addLink(dc1, dc2)
+    net.addLink("datacenter1", s1)
+    net.addLink(s1, dc3)
+    net.addLink(s1, "datacenter4")
+
+    """
+    5. We want to access and control our data centers from the outside,
+       e.g., we want to connect an orchestrator to start/stop compute
+       resources aka. VNFs (represented by Docker containers in the emulated)
+
+       So we need to instantiate API endpoints (e.g. a zerorpc or REST
+       interface). Depending on the endpoint implementations, we can connect
+       one or more data centers to it, which can then be controlled through
+       this API, e.g., start/stop/list compute instances.
+    """
+    # create a new instance of a endpoint implementation
+    api1 = RestApiEndpoint("127.0.0.1", 5000)
+    # connect data centers to this endpoint
+    api1.connectDatacenter(dc1)
+    api1.connectDatacenter(dc2)
+    api1.connectDatacenter(dc3)
+    api1.connectDatacenter(dc4)
+    # run API endpoint server (in another thread, don't block)
+    api1.start()
+
+    """
+    6. Finally we are done and can start our network (the emulator).
+       We can also enter the Mininet CLI to interactively interact
+       with our compute resources (just like in default Mininet).
+       But we can also implement fully automated experiments that
+       can be executed again and again.
+    """
+    net.start()
+    net.CLI()
+    # when the user types exit in the CLI, we stop the emulator
+    net.stop()
+
+
+def main():
+    setLogLevel('info')  # set Mininet loglevel
+    create_topology1()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/src/emuvim/test/api_base.py b/src/emuvim/test/api_base.py
new file mode 100644 (file)
index 0000000..54ffde9
--- /dev/null
@@ -0,0 +1,106 @@
+"""
+Helper module that implements helpers for test implementations.
+"""
+
+import unittest
+import os
+import subprocess
+import docker
+from emuvim.dcemulator.net import DCNetwork
+from emuvim.api.rest.compute import RestApiEndpoint
+from mininet.clean import cleanup
+from mininet.node import Controller
+
+class SimpleTestTopology(unittest.TestCase):
+    """
+        Helper class to do basic test setups.
+        s1 -- s2 -- s3 -- ... -- sN
+    """
+
+    def __init__(self, *args, **kwargs):
+        self.net = None
+        self.api = None
+        self.s = []   # list of switches
+        self.h = []   # list of hosts
+        self.d = []   # list of docker containers
+        self.dc = []  # list of data centers
+        self.docker_cli = None
+        super(SimpleTestTopology, self).__init__(*args, **kwargs)
+
+    def createNet(
+            self,
+            nswitches=0, ndatacenter=0, nhosts=0, ndockers=0,
+            autolinkswitches=False, controller=Controller, **kwargs):
+        """
+        Creates a Mininet instance and automatically adds some
+        nodes to it.
+
+        Attention, we should always use Mininet's default controller
+        for our tests. Only use other controllers if you want to test
+        specific controller functionality.
+        """
+        self.net = DCNetwork(controller=controller, **kwargs)
+        self.api = RestApiEndpoint("127.0.0.1",5000)
+        # add some switches
+        # start from s1 because ovs does not like to have dpid = 0
+        # and switch name-number is being used by mininet to set the dpid
+        for i in range(1, nswitches+1):
+            self.s.append(self.net.addSwitch('s%d' % i))
+        # if specified, chain all switches
+        if autolinkswitches:
+            for i in range(0, len(self.s) - 1):
+                self.net.addLink(self.s[i], self.s[i + 1])
+        # add some data centers
+        for i in range(0, ndatacenter):
+            self.dc.append(
+                self.net.addDatacenter(
+                    'datacenter%d' % i,
+                    metadata={"unittest_dc": i}))
+        # connect data centers to the endpoint
+        for i in range(0, ndatacenter):
+            self.api.connectDatacenter(self.dc[i])
+        # add some hosts
+        for i in range(0, nhosts):
+            self.h.append(self.net.addHost('h%d' % i))
+        # add some dockers
+        for i in range(0, ndockers):
+            self.d.append(self.net.addDocker('d%d' % i, dimage="ubuntu:trusty"))
+
+    def startApi(self):
+        self.api.start()
+
+    def startNet(self):
+        self.net.start()
+
+    def stopNet(self):
+        self.net.stop()
+
+    def getDockerCli(self):
+        """
+        Helper to interact with local docker instance.
+        """
+        if self.docker_cli is None:
+            self.docker_cli = docker.Client(
+                base_url='unix://var/run/docker.sock')
+        return self.docker_cli
+
+    def getContainernetContainers(self):
+        """
+        List the containers managed by containernet
+        """
+        return self.getDockerCli().containers(filters={"label": "com.containernet"})
+
+    @staticmethod
+    def setUp():
+        pass
+
+    @staticmethod
+    def tearDown():
+        cleanup()
+        # make sure that all pending docker containers are killed
+        with open(os.devnull, 'w') as devnull:
+            subprocess.call(
+                "sudo docker rm -f $(sudo docker ps --filter 'label=com.containernet' -a -q)",
+                stdout=devnull,
+                stderr=devnull,
+                shell=True)
\ No newline at end of file
diff --git a/src/emuvim/test/unittests/test_restapi.py b/src/emuvim/test/unittests/test_restapi.py
new file mode 100644 (file)
index 0000000..c395220
--- /dev/null
@@ -0,0 +1,59 @@
+"""
+Test suite to automatically test emulator REST API endpoints.
+"""
+
+import time
+import unittest
+from emuvim.test.api_base import SimpleTestTopology
+import subprocess
+
+
+class testRestApi( SimpleTestTopology ):
+    """
+    Tests to check the REST API endpoints of the emulator.
+    """
+
+    def testRestApi(self):
+
+        # create network
+        self.createNet(nswitches=0, ndatacenter=2, nhosts=2, ndockers=0)
+        # setup links
+        self.net.addLink(self.dc[0], self.h[0])
+        self.net.addLink(self.h[1], self.dc[1])
+        self.net.addLink(self.dc[0], self.dc[1])
+        # start api
+        self.startApi()
+        # start Mininet network
+        self.startNet()
+        print('compute start datacenter0, vnf1 ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        subprocess.call("son-emu-cli compute start -d datacenter0 -n vnf1", shell=True)
+        print('compute start datacenter0, vnf2 ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        subprocess.call("son-emu-cli compute start -d datacenter0 -n vnf2", shell=True)
+        print('compute start datacenter1, vnf3 ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        subprocess.call("son-emu-cli compute start -d datacenter1 -n vnf3", shell=True)
+        print('compute list ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        subprocess.call("son-emu-cli compute list", shell=True)
+        print('compute stop datacenter0, vnf2 ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        subprocess.call("son-emu-cli compute stop -d datacenter0 -n vnf2", shell=True)
+        print('compute list ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        subprocess.call("son-emu-cli compute list", shell=True)
+        print('compute status datacenter0, vnf1 ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        subprocess.call("son-emu-cli compute status -d datacenter0 -n vnf1", shell=True)
+        print('datacenter list ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        subprocess.call("son-emu-cli datacenter list", shell=True)
+        print('datacenter status datacenter0 ->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        print('->>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
+        subprocess.call("son-emu-cli datacenter status -d datacenter0", shell=True)
+        self.stopNet()
+
+
+if __name__ == '__main__':
+    unittest.main()