add NorthBound load generator script
diff --git a/TestON/dependencies/loadgen_NB.py b/TestON/dependencies/loadgen_NB.py
new file mode 100755
index 0000000..bbbec3e
--- /dev/null
+++ b/TestON/dependencies/loadgen_NB.py
@@ -0,0 +1,257 @@
+#! /usr/bin/env python
+from time import time, sleep
+import time
+import json
+import requests
+import urllib2
+from urllib2 import URLError, HTTPError
+
+
+class Loadgen_SB_thread:
+    '''
+    This script is for Intent Throughput testing. Use linear 7-switch topo. Intents are from S1P1 to/from S7/P1, with incrementing src/dst Mac addresses'''
+
+    '''response
+    [{'intent_id':'5','status':'CREATED','log':['created, time:73268214932534']}]
+    '''
+
+    def __init__(self, urls, intPerGroup, groups, addrate, delrate, pause):
+        self.intPerGroup = intPerGroup
+        self.groups = groups
+        self.urls = urls
+        self.addrate = addrate
+        self.delrate = delrate
+        self.pause = pause
+        
+        intents = [[0 for group in range(self.groups)] for i in range(self.intPerGroup)]
+
+    def setIntJSN(self, node_id, intPerGroup, groups):
+        intents = [[None for a in range(self.intPerGroup)] for g in range(self.groups)]
+        id = 0
+        oper = {}
+        for group in range(groups):
+            index = 0
+            for i in range(intPerGroup / 2):
+                smac = str("%x" %(node_id * 0x100000000000 + 0x010000000000 + (group * 0x000001000000) +i + 1))
+                dmac = str("%x" %(node_id * 0x100000000000 + 0x070000000000 + (group * 0x000001000000) +i + 1))
+                srcMac = ':'.join(smac[i:i+2] for i in range(0, len(smac), 2))
+                dstMac = ':'.join(dmac[i:i+2] for i in range(0, len(dmac), 2))
+                srcSwitch = "00:00:00:00:00:00:00:01"
+                dstSwitch = "00:00:00:00:00:00:00:07"
+                srcPort = 1
+                dstPort = 1
+
+                oper['intentId'] = id
+                oper['intentType'] = 'SHORTEST_PATH'    # XXX: Hardcoded
+                oper['staticPath'] = False              # XXX: Hardcoded
+                oper['srcSwitchDpid'] = srcSwitch
+                oper['srcSwitchPort'] = srcPort
+                oper['dstSwitchDpid'] = dstSwitch
+                oper['dstSwitchPort'] = dstPort
+                oper['matchSrcMac'] = srcMac
+                oper['matchDstMac'] = dstMac
+                intents[group][index] = oper
+                #print ("perGroup Intents-0 are: " + json.dumps(intents) + "\n\n\n" )
+                index =index + 1
+                id =id+1
+                oper = {}
+                #print ("ID:" + str(id))
+
+                oper['intentId'] = id
+                oper['intentType'] = 'SHORTEST_PATH'    # XXX: Hardcoded
+                oper['staticPath'] = False              # XXX: Hardcoded
+                oper['srcSwitchDpid'] = dstSwitch
+                oper['srcSwitchPort'] = dstPort
+                oper['dstSwitchDpid'] = srcSwitch
+                oper['dstSwitchPort'] = srcPort
+                oper['matchSrcMac'] = dstMac
+                oper['matchDstMac'] = srcMac
+                intents[group][index] = oper
+                index = index + 1 
+                id = id + 1
+                oper = {}
+                #print ("ID: " + str(id))
+                #print ("perGroup Intents-1 are: " + json.dumps(intents) + "\n\n\n" )
+        #print ("contructed intents are: " + json.dumps(intents) + "\n\n\n")
+        return intents, id
+
+    def post_json(self, url, data):
+        """Make a REST POST call and return the JSON result
+           url: the URL to call
+           data: the data to POST"""
+        posturl = "http://%s/wm/onos/intent/high" %(url)
+        print ("\nPost url is : " + posturl + "\n")
+        parsed_result = []
+        data_json = json.dumps(data)
+        try:
+            request = urllib2.Request(posturl, data_json)
+            request.add_header("Content-Type", "application/json")
+            response = urllib2.urlopen(request)
+            result = response.read()
+            response.close()
+            if len(result) != 0:
+                parsed_result = json.loads(result)
+        except HTTPError as exc:
+            print "ERROR:"
+            print "  REST POST URL: %s" % posturl
+            # NOTE: exc.fp contains the object with the response payload
+            error_payload = json.loads(exc.fp.read())
+            print "  REST Error Code: %s" % (error_payload['code'])
+            print "  REST Error Summary: %s" % (error_payload['summary'])
+            print "  REST Error Description: %s" % (error_payload['formattedDescription'])
+            print "  HTTP Error Code: %s" % exc.code
+            print "  HTTP Error Reason: %s" % exc.reason
+        except URLError as exc:
+            print "ERROR:"
+            print "  REST POST URL: %s" % posturl
+            print "  URL Error Reason: %s" % exc.reason
+        return parsed_result
+
+    def delete_json(self, url, startID):
+        """Make a REST DELETE call and return the JSON result
+           url: the URL to call"""
+        #url = "localhost:8080"
+        for i in range(self.intPerGroup):
+            posturl = "http://%s/wm/onos/intent/high/%s" %(url, str(i + startID))
+            parsed_result = []
+            try:
+                request = urllib2.Request(posturl)
+                request.get_method = lambda: 'DELETE'
+                response = urllib2.urlopen(request)
+                result = response.read()
+                response.close()
+                #if len(result) != 0:
+                #    parsed_result = json.loads(result)
+            except HTTPError as exc:
+                print "ERROR:"
+                print "  REST DELETE URL: %s" % posturl
+                # NOTE: exc.fp contains the object with the response payload
+                error_payload = json.loads(exc.fp.read())
+                print "  REST Error Code: %s" % (error_payload['code'])
+                print "  REST Error Summary: %s" % (error_payload['summary'])
+                print "  REST Error Description: %s" % (error_payload['formattedDescription'])
+                print "  HTTP Error Code: %s" % exc.code
+                print "  HTTP Error Reason: %s" % exc.reason
+            except URLError as exc:
+                print "ERROR:"
+                print "  REST DELETE URL: %s" % posturl
+                print "  URL Error Reason: %s" % exc.reason
+        return parsed_result
+
+    def delete_all_json(self, url):
+        """Make a REST DELETE call and return the JSON result
+           url: the URL to call"""
+        #url = "localhost:8080"
+        posturl = "http://%s/wm/onos/intent/high" %(url)
+        parsed_result = []
+        try:
+            request = urllib2.Request(posturl)
+            request.get_method = lambda: 'DELETE'
+            response = urllib2.urlopen(request)
+            result = response.read()
+            response.close()
+            if len(result) != 0:
+                parsed_result = json.loads(result)
+        except HTTPError as exc:
+            print "ERROR:"
+            print "  REST DELETE URL: %s" % posturl
+            # NOTE: exc.fp contains the object with the response payload
+            error_payload = json.loads(exc.fp.read())
+            print "  REST Error Code: %s" % (error_payload['code'])
+            print "  REST Error Summary: %s" % (error_payload['summary'])
+            print "  REST Error Description: %s" % (error_payload['formattedDescription'])
+            print "  HTTP Error Code: %s" % exc.code
+            print "  HTTP Error Reason: %s" % exc.reason
+        except URLError as exc:
+            print "ERROR:"
+            print "  REST DELETE URL: %s" % posturl
+            print "  URL Error Reason: %s" % exc.reason
+        return parsed_result
+
+
+if __name__ == '__main__':
+    import argparse
+    import threading
+    from threading import Thread
+
+    parser = argparse.ArgumentParser(description="less script")
+    parser.add_argument("-u", "--urls", dest="urls", default="10.128.10.1", type=str, help="a string to show urls to post intents to separated by space, ex. '10.128.10.1:8080 10.128.10.2:80080' ")
+    parser.add_argument("-i", "--intentsPerGroup", dest="intPerGroup", default=100, type=int, help="number of intents in one restcall group")
+    parser.add_argument("-g", "--groups", dest="groups", default=1, type=int, help="number of groups")
+    parser.add_argument("-a", "--addrate", dest="addrate", default=10, type=int, help="rate to add intents groups, groups per second")
+    parser.add_argument("-d", "--delrate", dest="delrate", default=100, type=int, help= "rate to delete intents, intents/second")
+    parser.add_argument("-p", "--pause", dest="pause", default=0, type=int, help= "pausing time between add and delete of intents")
+    args = parser.parse_args()
+
+    myloadgen = Loadgen_SB_thread(args.urls, args.intPerGroup, args.groups, args.addrate, args.delrate, args.pause) 
+    print ("Intent posting urls are: " + args.urls)
+    print ("Number of Intents per group: " + str(args.intPerGroup))
+    print ("Number of Intent Groups: " + str(args.groups))
+    print ("Intent group add rate: " + str(args.addrate) )
+    print ("Intent delete rate:" + str(args.delrate) )
+    addsleeptimer = (1.000/args.addrate)
+    print ("Add Sleep timer: " + str(addsleeptimer) )
+    delsleeptimer = (1.000/args.delrate)
+    print ("Del Sleep timer: " + str(delsleeptimer) )
+    print ("Pause between add and delete: " + str(args.pause))
+ 
+    urllist = args.urls.split()
+    urlindex = 0
+
+    intents,id = myloadgen.setIntJSN(7, args.intPerGroup, args.groups)
+    print json.dumps(intents)
+    print ("Number of intents: " + str(id) )    
+    print ("Number of url: " + str(len(urllist)) )
+    
+    tstart = time.time()
+    for group in range(args.groups):
+        if urlindex < len(urllist):
+            realurlind = urlindex
+        else:
+            realurlind = 0
+            urlindex = 0
+        
+        u = str(urllist[realurlind])
+        gstart = time.time()
+        #print json.dumps(intents[group])
+        print ("urlindex is : " + str(urlindex) + "realurlindex is: " + str(realurlind))
+        print ("post url is: " + str(urllist[realurlind]) )
+        print ("intent group is : " + str(group))
+        result = myloadgen.post_json(u,intents[group])
+        #print ("post result: " + str(result))
+        gelapse = time.time() - gstart
+        print ("Group: " + str(group) + " of " + str(args.groups) + " with " +str(args.intPerGroup) + " intents were added in " + str(gelapse) + " seconds.")
+        sleep(1.000/myloadgen.addrate)
+        urlindex = urlindex + 1
+    
+    telapse = time.time() - tstart
+    print ( str(args.groups * args.intPerGroup) + " intents were added in " + str(telapse) + " seconds.")
+
+    sleep(myloadgen.pause)
+ 
+    urlindex = 0 
+    inID = 0
+    tstart = time.time()
+    for group in range(args.groups):
+        if urlindex < len(urllist):
+            realurlind = urlindex
+        else:
+            realurlind = 0
+            urlindex = 0
+        
+        inID = group * args.intPerGroup
+        gstart = time.time()
+        u = str(urllist[realurlind])
+        for i in range(args.intPerGroup):
+            result = myloadgen.delete_json(u, inID)
+            #print ("post result: " + str(result))
+        gelapse = time.time() - gstart
+        print ("Group: " + str(group) + " of " + str(args.groups) " with " + str(args.intPerGroup) + " intents were deleted in " + str(gelapse) + " seconds.")
+        sleep(1.000/myloadgen.delrate)
+        urlindex = urlindex +1
+    telapse = time.time() - tstart
+    print ( str(args.groups * args.intPerGroup) + " intents were deleted in " + str(telapse) + " seconds.")
+
+    print ("Final cleanup to delete all intents on nodes."
+    for u in urllist:
+        myloadgen.delete_all(u)