From 9c15bd683ccd0bf11d79ee0934a4cc3f78be521f Mon Sep 17 00:00:00 2001
From: Manuel Buil Mur <manuel.buil@ericsson.com>
Date: Fri, 9 Oct 2015 16:48:36 +0200
Subject: First version of VNF manager simulator

This simulator contacts Openstack to create the SF VMs and then contacts ODL to create the SFC.
It is not intended to be a replacement of other VNF Managers such as Tacker or OpenMANO, just a
simple simulation for testing and development purposes.

Change-Id: Iaf691035d1b8435f5fccf559aebf6f3ed1afd066
Signed-off-by: mbuil <manuel.buil@ericsson.com>
---
 vnfmgr/vnfmgr_main.py                              |  72 ++++
 vnfmgr/vnfmgr_odl/__init__.py                      |   0
 .../sample_config/RestConf-RSP-HttpPost.json       |   7 +
 .../sample_config/RestConf-SFCs-HttpPut.json       |  22 ++
 .../sample_config/RestConf-SFFs-HttpPut.json       |  75 ++++
 .../sample_config/RestConf-SFPs-HttpPut.json       |  12 +
 .../sample_config/RestConf-SFs-HttpPut.json        |  38 ++
 vnfmgr/vnfmgr_odl/vnfmgr_odl.py                    | 440 +++++++++++++++++++++
 vnfmgr/vnfmgr_os/__init__.py                       |   0
 vnfmgr/vnfmgr_os/vnfmgr_os.py                      |  68 ++++
 10 files changed, 734 insertions(+)
 create mode 100755 vnfmgr/vnfmgr_main.py
 create mode 100644 vnfmgr/vnfmgr_odl/__init__.py
 create mode 100755 vnfmgr/vnfmgr_odl/sample_config/RestConf-RSP-HttpPost.json
 create mode 100755 vnfmgr/vnfmgr_odl/sample_config/RestConf-SFCs-HttpPut.json
 create mode 100755 vnfmgr/vnfmgr_odl/sample_config/RestConf-SFFs-HttpPut.json
 create mode 100755 vnfmgr/vnfmgr_odl/sample_config/RestConf-SFPs-HttpPut.json
 create mode 100755 vnfmgr/vnfmgr_odl/sample_config/RestConf-SFs-HttpPut.json
 create mode 100755 vnfmgr/vnfmgr_odl/vnfmgr_odl.py
 create mode 100644 vnfmgr/vnfmgr_os/__init__.py
 create mode 100755 vnfmgr/vnfmgr_os/vnfmgr_os.py

(limited to 'vnfmgr')

diff --git a/vnfmgr/vnfmgr_main.py b/vnfmgr/vnfmgr_main.py
new file mode 100755
index 00000000..b5ab8be1
--- /dev/null
+++ b/vnfmgr/vnfmgr_main.py
@@ -0,0 +1,72 @@
+#################################################################
+#								#
+# Copyright 2015 Ericsson AB					#
+# All Rights Reserved						#
+#								#
+#	Author: Manuel Buil <Manuel.Buil@ericsson.com>		#
+#	Version: 0.1						#
+#								#
+#################################################################
+
+import pdb
+from vnfmgr_os.vnfmgr_os import OpenStack_API
+import vnfmgr_odl.vnfmgr_odl as odlscript
+import time
+import json
+
+if __name__ == "__main__":
+    #OpenStack environment information
+    authurl = "http://localhost:5000/v2.0"
+    adminTenantName = 'admin'
+    adminTenantUser = 'admin'
+    adminTenantPass = 'abc123'
+    tenantName = adminTenantName
+    tenantUser = adminTenantUser
+    tenantPass = adminTenantPass
+
+    openstack = OpenStack_API(authurl, tenantName, tenantUser, tenantPass)
+
+    # 1 - Get the SF type
+    # Provide the file with the SFC configuration
+    file_json = "vnfmgr_odl/sample_config/RestConf-SFCs-HttpPut.json"
+    # Read the config files which refer to SF
+    json_data=open(file_json).read()
+    data = json.loads(json_data)
+    pdb.set_trace()
+
+    # Grab the SF type
+    chains = data['service-function-chains']['service-function-chain']
+    for chain in chains:
+        SFs = chain['sfc-service-function']
+        for SF in SFs:
+            sf_type = SF['type']
+            name = SF['name']
+            #2 - Search the image in glance with that SF type
+            image = openstack.find_image(sf_type)
+            if image == None:
+                print("There is no image with that sf_name")
+                exit(1)
+                # 3 - Boot the VM without network
+                flavor = 1
+                print("About to deploy")
+                vm = openstack.create_vm(name,image,flavor)
+                if vm == None:
+                    print("Problems to deploy the VM")
+                    exit(1)
+	
+    #Make the call to ODL to deploy SFC
+    context = odlscript.Context()
+    context.set_path_prefix_paths("vnfmgr_odl/sample_config")
+    pdb.set_trace()
+    odlscript.send_rest(context, "PUT", context.rest_url_sf_sel,  context.rest_path_sf_sel)
+    odlscript.send_rest(context, "PUT", context.rest_url_sf,  context.rest_path_sf)
+    odlscript.send_rest(context, "PUT", context.rest_url_sff, context.rest_path_sff)
+    odlscript.send_rest(context, "PUT", context.rest_url_sfc, context.rest_path_sfc)
+    odlscript.send_rest(context, "PUT", context.rest_url_sfp, context.rest_path_sfp)
+    time.sleep(1);
+    odlscript.send_rest(context, "POST", context.rest_url_rsp_rpc, context.rest_path_rsp)
+
+
+	#TO DO
+	# Check if the SF_VM already exists before creating it
+	# Network of the VM
diff --git a/vnfmgr/vnfmgr_odl/__init__.py b/vnfmgr/vnfmgr_odl/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/vnfmgr/vnfmgr_odl/sample_config/RestConf-RSP-HttpPost.json b/vnfmgr/vnfmgr_odl/sample_config/RestConf-RSP-HttpPost.json
new file mode 100755
index 00000000..998d1e07
--- /dev/null
+++ b/vnfmgr/vnfmgr_odl/sample_config/RestConf-RSP-HttpPost.json
@@ -0,0 +1,7 @@
+{
+  "input": {
+      "name": "sfc-path-1",
+      "parent-service-function-path": "sfc-path-1",
+      "symmetric": true
+  }
+}
diff --git a/vnfmgr/vnfmgr_odl/sample_config/RestConf-SFCs-HttpPut.json b/vnfmgr/vnfmgr_odl/sample_config/RestConf-SFCs-HttpPut.json
new file mode 100755
index 00000000..34449647
--- /dev/null
+++ b/vnfmgr/vnfmgr_odl/sample_config/RestConf-SFCs-HttpPut.json
@@ -0,0 +1,22 @@
+{
+  "service-function-chains": {
+    "service-function-chain": [
+      {
+        "name": "sfc-chain-1",
+        "symmetric": true,
+        "sfc-service-function": [
+          {
+            "name": "firewall-abstract1",
+            "type": "service-function-type:firewall"
+          },
+          {
+            "name": "firewall-abstract2",
+            "type": "service-function-type:firewall"
+          }
+        ]
+      }
+ 
+    ]
+  }
+}
+ 
diff --git a/vnfmgr/vnfmgr_odl/sample_config/RestConf-SFFs-HttpPut.json b/vnfmgr/vnfmgr_odl/sample_config/RestConf-SFFs-HttpPut.json
new file mode 100755
index 00000000..191fd540
--- /dev/null
+++ b/vnfmgr/vnfmgr_odl/sample_config/RestConf-SFFs-HttpPut.json
@@ -0,0 +1,75 @@
+{
+  "service-function-forwarders": {
+    "service-function-forwarder": [
+    {
+        "name": "SFF2",
+        "sff-data-plane-locator": [
+        {
+            "name": "sff2-dp1",
+            "service-function-forwarder-ovs:ovs-bridge": {},
+            "data-plane-locator": {
+                "transport": "service-locator:vxlan-gpe",
+                "port": 6633,
+                "ip": "192.168.1.100"
+            },
+            "service-function-forwarder-ovs:ovs-options": {
+                "nshc1": "flow",
+                "nsp": "flow",
+                "key": "flow",
+                "remote-ip": "flow",
+                "nsi": "flow",
+                "nshc2": "flow",
+                "nshc3": "flow",
+                "dst-port": "6633",
+                "nshc4": "flow"
+            }
+        }
+        ],
+        "service-function-forwarder-ovs:ovs-bridge": {
+            "bridge-name": "ovs-br2"
+        },
+        "service-function-dictionary": [
+        {
+            "name": "firewall-2",
+            "type": "service-function-type:firewall",
+            "sff-sf-data-plane-locator": {
+                "service-function-forwarder-ovs:ovs-bridge": {},
+                "transport": "service-locator:vxlan-gpe",
+                "port": 6633,
+                "ip": "192.168.1.11"
+            }
+        },
+           {
+            "name": "firewall-3",
+            "type": "service-function-type:firewall",
+            "sff-sf-data-plane-locator": {
+                "service-function-forwarder-ovs:ovs-bridge": {},
+                "transport": "service-locator:vxlan-gpe",
+                "port": 6633,
+                "ip": "192.168.1.12"
+            }
+        }
+        ],
+        "ip-mgmt-address": "192.168.1.100",
+        "service-node": ""
+    },
+    {
+        "name": "SFF-CL",
+        "sff-data-plane-locator": [
+          {
+            "name": "ovs-br1",
+            "service-function-forwarder-ovs:ovs-bridge": {},
+            "data-plane-locator": {
+              "transport": "service-locator:vxlan-gpe",
+              "port": 30001,
+              "ip": "192.168.1.50"
+            }
+          }
+        ],
+        "rest-uri": "http://192.168.1.50:5000",
+        "ip-mgmt-address": "192.168.1.50",
+        "service-node": ""
+    }
+   ]
+  }
+}
diff --git a/vnfmgr/vnfmgr_odl/sample_config/RestConf-SFPs-HttpPut.json b/vnfmgr/vnfmgr_odl/sample_config/RestConf-SFPs-HttpPut.json
new file mode 100755
index 00000000..da1f2c45
--- /dev/null
+++ b/vnfmgr/vnfmgr_odl/sample_config/RestConf-SFPs-HttpPut.json
@@ -0,0 +1,12 @@
+{
+   "service-function-paths": {
+     "service-function-path": [
+       {
+         "name": "sfc-path-1",
+         "service-chain-name": "sfc-chain-1",
+         "transport-type": "service-locator:vxlan-gpe",
+         "symmetric": true
+       }
+     ]
+   }
+}
diff --git a/vnfmgr/vnfmgr_odl/sample_config/RestConf-SFs-HttpPut.json b/vnfmgr/vnfmgr_odl/sample_config/RestConf-SFs-HttpPut.json
new file mode 100755
index 00000000..1ea27e79
--- /dev/null
+++ b/vnfmgr/vnfmgr_odl/sample_config/RestConf-SFs-HttpPut.json
@@ -0,0 +1,38 @@
+{
+ "service-functions": {
+   "service-function": [
+     {
+       "name": "firewall-2",
+       "sf-data-plane-locator": [
+         {
+           "name": "firewall-2-dp1",
+           "ip": "192.168.1.11",
+           "port": 6633,
+           "transport": "service-locator:vxlan-gpe",
+           "service-function-forwarder": "SFF2"
+         }
+       ],
+       "rest-uri": "http://192.168.1.11:5000",
+       "nsh-aware": true,
+       "ip-mgmt-address": "192.168.1.11",
+       "type": "service-function-type:firewall"
+     },
+     {
+       "name": "firewall-3",
+       "sf-data-plane-locator": [
+         {
+           "name": "firewall-3-dp1",
+           "ip": "192.168.1.12",
+           "port": 6633,
+           "transport": "service-locator:vxlan-gpe",
+           "service-function-forwarder": "SFF2"
+         }
+       ],
+       "rest-uri": "http://192.168.1.12:5000",
+       "nsh-aware": true,
+       "ip-mgmt-address": "192.168.1.12",
+       "type": "service-function-type:firewall"
+     }
+   ]
+ }
+}
diff --git a/vnfmgr/vnfmgr_odl/vnfmgr_odl.py b/vnfmgr/vnfmgr_odl/vnfmgr_odl.py
new file mode 100755
index 00000000..4d35aebb
--- /dev/null
+++ b/vnfmgr/vnfmgr_odl/vnfmgr_odl.py
@@ -0,0 +1,440 @@
+#! /usr/bin/env python
+
+__author__ = "Brady Johnson"
+__copyright__ = "Copyright(c) 2015, Ericsson, Inc."
+__license__ = "Apache License version 2.0"
+__version__ = "0.1"
+__email__ = "brady.allen.johnson@ericsson.com"
+__status__ = "beta"
+import pdb
+import os
+import time
+import requests
+import json
+import argparse
+
+PUT  = 'PUT'
+GET  = 'GET'
+POST = 'POST'
+
+class Context(object):
+    """
+    Context class to hold the configuration as specified on the command line
+    """
+    def __init__(self):
+        self.rest_path_prefix =  'sampleConfig'
+        self.rest_path_sf     =  'RestConf-SFs-HttpPut.json'
+        self.rest_path_sf_sel =  'RestConf-SFselect-HttpPut.json'
+        self.rest_path_sfc    =  'RestConf-SFCs-HttpPut.json'
+        self.rest_path_sff    =  'RestConf-SFFs-HttpPut.json'
+        self.rest_path_sfp    =  'RestConf-SFPs-HttpPut.json'
+        self.rest_path_acl    =  'RestConf-ACLs-HttpPut.json'
+        self.rest_path_rsp    =  'RestConf-RSP-HttpPost.json'
+
+        self.rest_url_sf      =  'config/service-function:service-functions/'
+        self.rest_url_sf_sel  =  'config/service-function-scheduler-type:service-function-scheduler-types/'
+        self.rest_url_sfc     =  'config/service-function-chain:service-function-chains/'
+        self.rest_url_sff     =  'config/service-function-forwarder:service-function-forwarders/'
+        self.rest_url_sfp     =  'config/service-function-path:service-function-paths/'
+        self.rest_url_rsp     =  'operational/rendered-service-path:rendered-service-paths/'
+        self.rest_url_rsp_rpc =  'operations/rendered-service-path:create-rendered-path'
+        self.rest_url_acl     =  'config/ietf-acl:access-lists/'
+
+        self.http_headers   =  {'Content-Type' : 'application/json', 'Cache-Control' : 'no-cache'}
+        self.http_server    =  'localhost'
+        self.url_base       =  ''
+        self.http_port      =  '8181'
+        self.interractive   =  True
+        self.user           =  'admin'
+        self.pw             =  'admin'
+        self.batch_sf       =  False
+        self.batch_sf_sel   =  False
+        self.batch_sfc      =  False
+        self.batch_sff      =  False
+        self.batch_sfp      =  False
+        self.batch_acl      =  False
+        self.batch_rsp      =  False
+        self.batch_query    =  False
+
+    def set_path_prefix_paths(self, path_prefix):
+        self.rest_path_prefix = path_prefix
+        self.rest_path_sf     =  os.path.join(self.rest_path_prefix, self.rest_path_sf)
+        self.rest_path_sf_sel =  os.path.join(self.rest_path_prefix, self.rest_path_sf_sel)
+        self.rest_path_sfc    =  os.path.join(self.rest_path_prefix, self.rest_path_sfc)
+        self.rest_path_sff    =  os.path.join(self.rest_path_prefix, self.rest_path_sff)
+        self.rest_path_sfp    =  os.path.join(self.rest_path_prefix, self.rest_path_sfp)
+        self.rest_path_acl    =  os.path.join(self.rest_path_prefix, self.rest_path_acl)
+        self.rest_path_rsp    =  os.path.join(self.rest_path_prefix, self.rest_path_rsp)
+
+
+def get_cmd_line(context):
+    """
+    Create a command-line parser, parse the command line args, and process them.
+    Populate the Context object with the processed command-line args.
+    """
+
+    opts = argparse.ArgumentParser()
+
+    # Batch or Interractive mode
+    opts.add_argument('--interractive', '-i',
+                      dest='interractive',
+                      action='store_true',
+                      help='Interractive mode, default')
+    opts.add_argument('--batch', '-b',
+                      dest='batch',
+                      action='store_true',
+                      help='Batch mode, overrides interractive mode')
+
+    # Where to send the messages
+    opts.add_argument('--http-server', '-s',
+                      default=context.http_server,
+                      dest='http_server',
+                      help='HTTP server address')
+    opts.add_argument('--http-port',
+                      default=context.http_port,
+                      dest='http_port',
+                      help='HTTP server port')
+
+    # Batch mode, which message(s) to send
+    opts.add_argument('--send-sf', '-1',
+                      dest='send_sf',
+                      action='store_true',
+                      help='Send an SF REST JSON PUT message')
+    opts.add_argument('--send-sf-sel',
+                      dest='send_sf_sel',
+                      action='store_true',
+                      help='Send an SF Selection REST JSON PUT message')
+    opts.add_argument('--send-sfc', '-2',
+                      dest='send_sfc',
+                      action='store_true',
+                      help='Send an SFC REST JSON PUT message')
+    opts.add_argument('--send-sff', '-3',
+                      dest='send_sff',
+                      action='store_true',
+                      help='Send an SFF REST JSON PUT message')
+    opts.add_argument('--send-sfp', '-4',
+                      dest='send_sfp',
+                      action='store_true',
+                      help='Send an SFP REST JSON PUT message')
+    opts.add_argument('--send-acl', '-5',
+                      dest='send_acl',
+                      action='store_true',
+                      help='Send an ACL REST JSON PUT message')
+    opts.add_argument('--send-rsp', '-6',
+                      dest='send_rsp',
+                      action='store_true',
+                      help='Send an RSP REST JSON POST RPC message')
+    opts.add_argument('--send-all', '-7',
+                      dest='send_all',
+                      action='store_true',
+                      help='Send all (SF, SFF, SFC, SFP, RSP, ACL) REST JSON messages')
+    opts.add_argument('--query-sfc', '-q',
+                      dest='query_sfc',
+                      action='store_true',
+                      help='Query all SFC objects')
+
+    # Paths to the rest JSON files
+    opts.add_argument('--rest-path-prefix', '-prefix',
+                      default=context.rest_path_prefix,
+                      dest='rest_path_prefix',
+                      help='Path prefix where the REST JSON files are located')
+    opts.add_argument('--rest-path-sf-sel',
+                      default=context.rest_path_sf_sel,
+                      dest='rest_path_sf_sel',
+                      help='Name of the SF Selection REST JSON file, relative to configured prefix')
+    opts.add_argument('--rest-path-sf', '-n',
+                      default=context.rest_path_sf,
+                      dest='rest_path_sf',
+                      help='Name of the SF REST JSON file, relative to configured prefix')
+    opts.add_argument('--rest-path-sfc', '-c',
+                      default=context.rest_path_sfc,
+                      dest='rest_path_sfc',
+                      help='Name of the SFC REST JSON file, relative to configured prefix')
+    opts.add_argument('--rest-path-sff', '-f',
+                      default=context.rest_path_sff,
+                      dest='rest_path_sff',
+                      help='Name of the SFF REST JSON file, relative toconfigured  prefix')
+    opts.add_argument('--rest-path-sfp', '-p',
+                      default=context.rest_path_sfp,
+                      dest='rest_path_sfp',
+                      help='Name of the SFP REST JSON file, relative to configured prefix')
+    opts.add_argument('--rest-path-rsp', '-r',
+                      default=context.rest_path_rsp,
+                      dest='rest_path_rsp',
+                      help='Name of the RSP REST JSON file, relative to configured prefix')
+    opts.add_argument('--rest-path-acl', '-a',
+                      default=context.rest_path_acl,
+                      dest='rest_path_acl',
+                      help='Name of the ACL REST JSON file, relative to configured prefix')
+
+    args = opts.parse_args()
+
+    context.http_server      = args.http_server
+    context.http_port        = args.http_port
+    context.url_base         = 'http://%s:%s/restconf/' % (context.http_server, context.http_port)
+
+    context.rest_path_prefix = args.rest_path_prefix
+    context.rest_path_sf     = args.rest_path_sf
+    context.rest_path_sf_sel = args.rest_path_sf_sel
+    context.rest_path_sfc    = args.rest_path_sfc
+    context.rest_path_sff    = args.rest_path_sff
+    context.rest_path_sfp    = args.rest_path_sfp
+    context.rest_path_acl    = args.rest_path_acl
+    context.rest_path_rsp    = args.rest_path_rsp
+    context.set_path_prefix_paths(context.rest_path_prefix)
+
+    for path in [context.rest_path_sf, context.rest_path_sfc, context.rest_path_sff, context.rest_path_sfp]:
+        print '\tUsing REST file: %s' % path
+
+    if args.batch:
+        context.interractive = False
+        if args.send_all:
+            context.batch_sf       =  True
+            context.batch_sf_sel   =  True
+            context.batch_sfc      =  True
+            context.batch_sff      =  True
+            context.batch_sfp      =  True
+            context.batch_rsp      =  True
+            # TODO deactivated for now
+            #context.batch_acl      =  True
+        else:
+            context.batch_sf       =  args.send_sf
+            context.batch_sf_sel   =  args.send_sf_sel
+            context.batch_sfc      =  args.send_sfc
+            context.batch_sff      =  args.send_sff
+            context.batch_sfp      =  args.send_sfp
+            context.batch_rsp      =  args.send_rsp
+            # TODO deactivated for now
+            #context.batch_acl      =  args.send_acl
+            context.batch_query    =  args.query_sfc
+
+    return True
+
+
+def send_rest(context, operation, rest_url, rest_file=None):
+    """
+    Send an HTTP REST message
+    Keyword arguments:
+    context -- specifies the destination IP/Port and user/pw
+    operation -- specifies if the HTTP OP is one of: GET, PUT, or POST
+    rest_url -- the operation URL
+    rest_file -- for PUT and POST operations, specifies where the JSON input is found
+    """
+
+    complete_url = '%s%s' % (context.url_base, rest_url)
+
+    if rest_file:
+        if not os.path.exists(rest_file):
+            print 'REST file [%s] does not exists' % rest_file
+            return False
+
+    try:
+        if operation == GET:
+            r = requests.get(url = complete_url,
+                             headers = context.http_headers,
+                             auth=(context.user, context.pw))
+
+            print '\nHTTP GET %s\nresult: %s' % (rest_url, r.status_code)
+            #if len(r.text) > 1:
+            if r.status_code >= 200 and r.status_code <= 299:
+                print json.dumps(json.loads(r.text), indent=4, separators=(',', ': '))
+
+        elif operation == PUT:
+            if not rest_file:
+                print 'ERROR trying to PUT with empty REST file'
+                return False
+
+            r = requests.put(url = complete_url,
+                             auth=(context.user, context.pw),
+                             data = json.dumps(json.load(open(rest_file, 'r'))),
+                             headers = context.http_headers)
+            print '\nHTTP PUT %s\nresult: %s' % (rest_url, r.status_code)
+
+        elif operation == POST:
+            if not rest_file:
+                print 'ERROR trying to POST with empty REST file'
+                return False
+
+            post_list = json.load(open(rest_file, 'r'))
+            if len(post_list) > 1:
+                # This allows for multiple RSPs to be sent from one JSON file
+                for entry in post_list:
+                    r = requests.post(url = complete_url,
+                                      auth=(context.user, context.pw),
+                                      data = json.dumps(entry),
+                                      headers = context.http_headers)
+                    print '\nHTTP POST %s\nresult: %s' % (rest_url, r.status_code)
+            else:
+                r = requests.post(url = complete_url,
+                                  auth=(context.user, context.pw),
+                                  data = json.dumps(post_list),
+                                  headers = context.http_headers)
+                print '\nHTTP POST %s\nresult: %s' % (rest_url, r.status_code)
+        else:
+            print 'ERROR: Invalid Operation: %s' % (operation)
+
+    except requests.exceptions.ConnectionError as ce:
+        print 'ERROR connecting: %s' % (ce)
+        return False
+    except Exception as e:
+        print 'ERROR Exception: %s' % (e)
+        return False
+    except:
+        print 'ERROR unkown exception raised'
+        return False
+
+    return True
+
+def validate_rest(context):
+    """
+    For each JSON input file in context, validate the JSON syntax.
+    No validation checking is made on parameter names or types.
+    """
+
+    print ''
+    for path in [context.rest_path_sf,
+                 context.rest_path_sfc,
+                 context.rest_path_sff,
+                 context.rest_path_sfp,
+                 context.rest_path_rsp,
+                 context.rest_path_sf_sel]:
+        if os.path.exists(path):
+            print 'Validating JSON file: %s' % path
+            try:
+                json.load(open(path, 'r'))
+            except ValueError as ve:
+                print '\tValidation error [%s]' % ve
+                return False
+
+    return True
+
+def batch(context):
+    """
+    Launch the application in batch mode and perform
+    the operations as specified in the Context object.
+    """
+
+    # The order of these if's is important
+    # If send-all was set, then each of these needs to be sent, in order
+    if context.batch_sf_sel:
+        send_rest(context, PUT, context.rest_url_sf_sel,  context.rest_path_sf_sel)
+    if context.batch_sf:
+        send_rest(context, PUT, context.rest_url_sf,  context.rest_path_sf)
+    if context.batch_sff:
+        send_rest(context, PUT, context.rest_url_sff, context.rest_path_sff)
+    if context.batch_sfc:
+        send_rest(context, PUT, context.rest_url_sfc, context.rest_path_sfc)
+    if context.batch_sfp:
+        send_rest(context, PUT, context.rest_url_sfp, context.rest_path_sfp)
+    if context.batch_rsp:
+        send_rest(context, POST, context.rest_url_rsp_rpc, context.rest_path_rsp)
+    if context.batch_acl:
+        send_rest(context, PUT, context.rest_url_acl, context.rest_path_acl)
+
+    if context.batch_query:
+        send_rest(context, GET, context.rest_url_sf_sel)
+        send_rest(context, GET, context.rest_url_sf)
+        send_rest(context, GET, context.rest_url_sff)
+        send_rest(context, GET, context.rest_url_sfc)
+        send_rest(context, GET, context.rest_url_sfp)
+        send_rest(context, GET, context.rest_url_rsp)
+        # TODO deactivated for now
+        #send_rest(context, GET, context.rest_url_acl)
+
+
+def CLI(context):
+    """
+    Run a simple Command Line Interface.
+    The Context object is used for sending rest messages
+    """
+
+    option = '1'
+    while option != '0':
+        print '\n\nChoose Option to perform:'
+        print ' 0) Quit'
+        print ' 1) Send SF  REST'
+        print ' 2) Send SFC REST'
+        print ' 3) Send SFF REST'
+        print ' 4) Send SFP REST'
+        print ' 5) Send RSP REST'
+        print ' 6) Send ACL REST'
+        print ' 7) Send all ordered: (SFsel, SF, SFF, SFC, SFP, RSP)'
+        print ' 8) Query all: (SFsel, SF, SFF, SFC, SFP, RSP)'
+        print ' 9) Change config file path, currently [%s]' % (context.rest_path_prefix)
+        print '10) Validate config files JSON syntax'
+
+        option = raw_input('=> ')
+
+        if option == '1':
+            send_rest(context, PUT, context.rest_url_sf,  context.rest_path_sf)
+        elif option == '2':
+            send_rest(context, PUT, context.rest_url_sfc, context.rest_path_sfc)
+        elif option == '3':
+            send_rest(context, PUT, context.rest_url_sff, context.rest_path_sff)
+        elif option == '4':
+            send_rest(context, PUT, context.rest_url_sfp, context.rest_path_sfp)
+        elif option == '5':
+            send_rest(context, POST, context.rest_url_rsp_rpc, context.rest_path_rsp)
+        elif option == '6':
+            send_rest(context, PUT, context.rest_url_acl, context.rest_path_acl)
+        elif option == '7':
+            pdb.set_trace()
+	    send_rest(context, PUT, context.rest_url_sf_sel,  context.rest_path_sf_sel)
+            send_rest(context, PUT, context.rest_url_sf,  context.rest_path_sf)
+            send_rest(context, PUT, context.rest_url_sff, context.rest_path_sff)
+            send_rest(context, PUT, context.rest_url_sfc, context.rest_path_sfc)
+            send_rest(context, PUT, context.rest_url_sfp, context.rest_path_sfp)
+            time.sleep(1);
+            send_rest(context, POST, context.rest_url_rsp_rpc, context.rest_path_rsp)
+            # TODO ACL deactivated for now
+            # Need to wait until the SFC creates the RSP internally before sending the ACL
+            #print 'Sleeping 2 seconds while RSP being created'
+            #time.sleep(2);
+            #send_rest(context, PUT, context.rest_url_acl, context.rest_path_acl)
+        elif option == '8':
+            send_rest(context, GET, context.rest_url_sf_sel)
+            send_rest(context, GET, context.rest_url_sf)
+            send_rest(context, GET, context.rest_url_sff)
+            send_rest(context, GET, context.rest_url_sfc)
+            send_rest(context, GET, context.rest_url_sfp)
+            send_rest(context, GET, context.rest_url_rsp)
+            send_rest(context, GET, context.rest_url_acl)
+        elif option == '9':
+            path_prefix = raw_input('Enter path => ')
+            if not os.path.exists(path_prefix):
+                print 'ERROR: path does not exist: [%s]' % (path_prefix)
+            else:
+                context.set_path_prefix_paths(path_prefix)
+        elif option == '10':
+            validate_rest(context)
+        elif option != '0':
+            print 'ERROR: Invalid option %s' % (option)
+
+
+def main():
+    """
+    Main entry point into the VnfMgrSim application.
+    Command line arguments are expected.
+    Example invocations:
+    To display application command-line help:
+        vnfmgr_odl.py --help
+    To start the application in interractive mode:
+        vnfmgr_odl.py -prefix <input json dir>
+    To start the application in batch mode and send an SF JSON REST message:
+        vnfmgr_odl.py -b -prefix <input json dir> --send-sf
+    """
+
+    context = Context()
+    if not get_cmd_line(context):
+        return 1
+
+    if context.interractive:
+        CLI(context)
+    else:
+        batch(context)
+
+    return 0
+
+if __name__ == '__main__':
+    main()
+
diff --git a/vnfmgr/vnfmgr_os/__init__.py b/vnfmgr/vnfmgr_os/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/vnfmgr/vnfmgr_os/vnfmgr_os.py b/vnfmgr/vnfmgr_os/vnfmgr_os.py
new file mode 100755
index 00000000..00678503
--- /dev/null
+++ b/vnfmgr/vnfmgr_os/vnfmgr_os.py
@@ -0,0 +1,68 @@
+#################################################################
+#								#
+# Copyright 2015 Ericsson AB					#
+# All Rights Reserved						#
+#								#
+#	Author: Manuel Buil <Manuel.Buil@ericsson.com>		#
+#	Version: 0.1						#
+#								#
+#################################################################
+
+import pdb
+
+from novaclient.v2 import client as nova
+from novaclient import exceptions as novaexceptions
+from keystoneclient.v2_0 import client as keystone
+from glanceclient import client as glance
+
+
+class OpenStack_API:
+    def __init__(self, authurl, tenantName, tenantUser, tenantPass):
+        self.authurl=authurl
+        self.tenantName=tenantName
+        self.tenantUser=tenantUser
+        self.tenantPass=tenantPass
+
+    def get_token(self):
+        # Establish connection to Openstack controller
+        osconn = keystone.Client(username=self.tenantUser, password=self.tenantPass, tenant_name=self.tenantName, auth_url=self.authurl)
+        token = osconn.auth_token
+        return token
+
+    def get_endpoint(self,service_type, endpoint_type):
+        # Establish connection to Openstack controller
+        osconn = keystone.Client(username=self.tenantUser, password=self.tenantPass, tenant_name=self.tenantName, auth_url=self.authurl)
+        endpoint = osconn.service_catalog.url_for(service_type=service_type, endpoint_type=endpoint_type)
+        return endpoint
+	
+    def find_image(self,SF_type):
+    # Find in glance the image that matches the SF we want to deploy
+        token = self.get_token()
+        endpoint = self.get_endpoint('image','publicURL')
+        osconn = glance.Client('1',endpoint=endpoint,token=token)
+        image_list = osconn.images.list()
+        for item in image_list:
+            try:
+                image_type = item.properties.get('image_type', None)
+                image_id=None
+                if (image_type == SF_type):
+                    image_id = item.id
+                    break
+            except:
+                print("Errrorr")
+
+        #Search image which matches the SF type
+        return image_id
+
+    def create_vm(self, name, image, flavor, nics=None):
+        # Establish connection to Openstack controller
+        osconn = nova.Client(self.tenantUser, self.tenantPass, self.tenantName, self.authurl, service_type="compute")
+        try:
+            if nics is None:
+                vm = osconn.servers.create(name,image,flavor)
+            else:
+                vm = osconn.servers.create(name,image,flavor,nics)
+        except:
+            print("Something wrong happened while creating the VM")
+            vm = None
+        return vm
-- 
cgit