Support to specify jvm_heap_size option for ONOS container.
This allows to override the inferred defaults based on system memory.
manifest.json option is jvm_heap_size and defaults to 1 gig.
Run time command line setup/run option defaults to inferred mode as earlier done based on half of available system memory(capped to 16 gig)

Change-Id: I80a9180ad3a690fcef79d3c2979348965cda38b5
diff --git a/src/test/setup/cord-test.py b/src/test/setup/cord-test.py
index b0b2f2f..369de0a 100755
--- a/src/test/setup/cord-test.py
+++ b/src/test/setup/cord-test.py
@@ -409,6 +409,7 @@
 
     Container.IMAGE_PREFIX = test_manifest.image_prefix
     Onos.MAX_INSTANCES = test_manifest.onos_instances
+    Onos.JVM_HEAP_SIZE = test_manifest.jvm_heap_size
     cluster_mode = True if test_manifest.onos_instances > 1 else False
     async_mode = cluster_mode and test_manifest.async_mode
     existing_list = [ c['Names'][0][1:] for c in Container.dckr.containers() if c['Image'] == test_manifest.onos_image ]
@@ -671,6 +672,7 @@
     Onos.PREFIX = test_manifest.image_prefix
     Onos.TAG = onos_cnt['tag']
     Onos.MAX_INSTANCES = test_manifest.onos_instances
+    Onos.JVM_HEAP_SIZE = test_manifest.jvm_heap_size
     cluster_mode = True if test_manifest.onos_instances > 1 else False
     async_mode = cluster_mode and test_manifest.async_mode
     existing_list = [ c['Names'][0][1:] for c in Container.dckr.containers() if c['Image'] == test_manifest.onos_image ]
@@ -1033,9 +1035,9 @@
                             choices=['DEBUG','TRACE','ERROR','WARN','INFO'],
                             type=str,
                             help='Specify the log level for the test cases')
+    parser_run.add_argument('-jvm-heap-size', '--jvm-heap-size', default='', type=str, help='ONOS JVM heap size')
     parser_run.set_defaults(func=runTest)
 
-
     parser_setup = subparser.add_parser('setup', help='Setup cord tester environment')
     parser_setup.add_argument('-o', '--onos', default=onos_image_default, type=str, help='ONOS container image')
     parser_setup.add_argument('-r', '--server', default=cord_test_server_address, type=str,
@@ -1067,6 +1069,7 @@
     parser_setup.add_argument('-async', '--async-mode', action='store_true',
                               help='Start ONOS cluster instances in async mode')
     parser_setup.add_argument('-f', '--foreground', action='store_true', help='Run in foreground')
+    parser_setup.add_argument('-jvm-heap-size', '--jvm-heap-size', default='', type=str, help='ONOS JVM heap size')
     parser_setup.set_defaults(func=setupCordTester)
 
     parser_xos = subparser.add_parser('xos', help='Building xos into cord tester environment')
diff --git a/src/test/setup/manifest.json b/src/test/setup/manifest.json
index 8ac08e3..862662d 100644
--- a/src/test/setup/manifest.json
+++ b/src/test/setup/manifest.json
@@ -3,5 +3,6 @@
     "olt": true,
     "start_switch": true,
     "onos_image": "onosproject/onos:latest",
-    "log_level" : "INFO"
+    "log_level" : "INFO",
+    "jvm_heap_size" : "1G"
 }
diff --git a/src/test/utils/CordContainer.py b/src/test/utils/CordContainer.py
index 80d8f75..2c57823 100644
--- a/src/test/utils/CordContainer.py
+++ b/src/test/utils/CordContainer.py
@@ -234,9 +234,25 @@
     def restart(self, timeout =10):
         return self.dckr.restart(self.name, timeout)
 
-def get_mem(instances = 1):
+def get_mem(jvm_heap_size = None, instances = 1):
     if instances <= 0:
         instances = 1
+    heap_size = jvm_heap_size
+    heap_size_i = 0
+    #sanitize the heap size config
+    if heap_size is not None:
+        if not heap_size.isdigit():
+            try:
+                heap_size_i = int(heap_size[:-1])
+                suffix = heap_size[-1]
+                if suffix == 'M':
+                    heap_size_i /= 1024 #convert to gigs
+            except:
+                ##invalid suffix length probably. Fall back to default
+                heap_size = None
+        else:
+            heap_size_i = int(heap_size)
+
     with open('/proc/meminfo', 'r') as fd:
         meminfo = fd.readlines()
         mem = 0
@@ -246,7 +262,14 @@
 
         mem = max(mem/1024/1024/2/instances, 1)
         mem = min(mem, 16)
-        return str(mem) + 'G'
+
+    if heap_size_i:
+        #we take the minimum of the provided heap size and max allowed heap size
+        heap_size_i = min(heap_size_i, mem)
+    else:
+        heap_size_i = mem
+
+    return '{}G'.format(heap_size_i)
 
 class OnosCord(Container):
     """Use this when running the cord tester agent on the onos compute node"""
@@ -333,11 +356,13 @@
 class Onos(Container):
     QUAGGA_CONFIG = [ { 'bridge' : 'quagga-br', 'ip': '10.10.0.4', 'mask' : 16 }, ]
     MAX_INSTANCES = 3
+    JVM_HEAP_SIZE = None
     SYSTEM_MEMORY = (get_mem(),) * 2
     INSTANCE_MEMORY = (get_mem(instances=MAX_INSTANCES),) * 2
-    JAVA_OPTS = '-Xms{} -Xmx{} -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode'.format(*SYSTEM_MEMORY)#-XX:+PrintGCDetails -XX:+PrintGCTimeStamps'
-    JAVA_OPTS_CLUSTER = '-Xms{} -Xmx{} -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode'.format(*INSTANCE_MEMORY)
-    env = { 'ONOS_APPS' : 'drivers,openflow,proxyarp,vrouter', 'JAVA_OPTS' : JAVA_OPTS }
+    JAVA_OPTS_FORMAT = '-Xms{} -Xmx{} -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode'
+    JAVA_OPTS_DEFAULT = JAVA_OPTS_FORMAT.format(*SYSTEM_MEMORY) #-XX:+PrintGCDetails -XX:+PrintGCTimeStamps'
+    JAVA_OPTS_CLUSTER_DEFAULT = JAVA_OPTS_FORMAT.format(*INSTANCE_MEMORY)
+    env = { 'ONOS_APPS' : 'drivers,openflow,proxyarp,vrouter', 'JAVA_OPTS' : JAVA_OPTS_DEFAULT }
     onos_cord_apps = ( ('cord-config', '1.1-SNAPSHOT'),
                        ('aaa', '1.1-SNAPSHOT'),
                        ('igmp', '1.1-SNAPSHOT'),
@@ -426,15 +451,10 @@
         super(Onos, self).__init__(name, image, prefix = prefix, tag = tag, quagga_config = quagga_config)
         self.boot_delay = boot_delay
         self.data_map = None
+        instance_memory = (get_mem(jvm_heap_size = Onos.JVM_HEAP_SIZE, instances = Onos.MAX_INSTANCES),) * 2
+        self.env['JAVA_OPTS'] = self.JAVA_OPTS_FORMAT.format(*instance_memory)
         if cluster is True:
             self.ports = []
-            if Onos.MAX_INSTANCES <= 3:
-                java_opts = self.JAVA_OPTS_CLUSTER
-            else:
-                instance_memory = (get_mem(instances=Onos.MAX_INSTANCES),) * 2
-                java_opts = '-Xms{} -Xmx{} -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode'.format(*instance_memory)
-
-            self.env['JAVA_OPTS'] = java_opts
             if data_volume is not None:
                 self.data_map = self.get_data_map(data_volume, self.guest_data_dir)
                 self.host_guest_map = self.host_guest_map + self.data_map
diff --git a/src/test/utils/TestManifest.py b/src/test/utils/TestManifest.py
index b56300d..78b01e1 100644
--- a/src/test/utils/TestManifest.py
+++ b/src/test/utils/TestManifest.py
@@ -37,6 +37,7 @@
             self.onos_image = args.onos
             self.iterations = None
             self.server = '{}:{}'.format(CORD_TEST_HOST, CORD_TEST_PORT)
+            self.jvm_heap_size = args.jvm_heap_size if args.jvm_heap_size else None
         else:
             with open(self.manifest, 'r') as fd:
                 data = json.load(fd)
@@ -53,3 +54,4 @@
             self.onos_image = data.get('onos_image', 'onosproject/onos:latest')
             self.server = data.get('test_server', '{}:{}'.format(CORD_TEST_HOST, CORD_TEST_PORT))
             self.iterations = data.get('iterations', None)
+            self.jvm_heap_size = data.get('jvm_heap_size', None)