Repository: Duke-GCB/lando

Issue:
k8s lando should pass cpu/memory from job_flavor to calrissian
Currently the flavor settings are not being used by the k8s run workflow job.
These values need to be passed via "--max-ram" and "--max-cores" flags for the `run_workflow` step.
https://github.com/Duke-GCB/lando/blob/9294aabdb06947677d36dd738a3c927951bae7ec/lando/k8s/jobmanager.py#L170-L172

Discussion:

Patch:
diff --git a/lando/k8s/jobmanager.py b/lando/k8s/jobmanager.py
index b0c2095..456a8f2 100644
--- a/lando/k8s/jobmanager.py
+++ b/lando/k8s/jobmanager.py
@@ -169,7 +169,10 @@ class JobManager(object):
                 read_only=True))
         command_parts = run_workflow_config.command
         command_parts.extend(["--tmp-outdir-prefix", Paths.TMPOUT_DATA + "/",
-                              "--outdir", Paths.OUTPUT_RESULTS_DIR + "/"])
+                              "--outdir", Paths.OUTPUT_RESULTS_DIR + "/",
+                              "--max-ram", self.job.job_flavor_memory,
+                              "--max-cores", str(self.job.job_flavor_cpus)
+                              ])
         command_parts.extend([
             self.names.workflow_path,
             self.names.job_order_path,
diff --git a/lando/server/jobapi.py b/lando/server/jobapi.py
index bcf596d..a049cd0 100644
--- a/lando/server/jobapi.py
+++ b/lando/server/jobapi.py
@@ -302,6 +302,8 @@ class Job(object):
         self.state = data['state']
         self.step = data['step']
         self.job_flavor_name = data['job_flavor']['name']
+        self.job_flavor_cpus = data['job_flavor']['cpus']
+        self.job_flavor_memory = data['job_flavor']['memory']
         self.vm_instance_name = data['vm_instance_name']
         self.vm_volume_name = data['vm_volume_name']
         self.stage_group = data['stage_group']


Test patch:
diff --git a/lando/k8s/tests/test_jobmanager.py b/lando/k8s/tests/test_jobmanager.py
index fa1c304..e98c2a4 100644
--- a/lando/k8s/tests/test_jobmanager.py
+++ b/lando/k8s/tests/test_jobmanager.py
@@ -10,7 +10,13 @@ class TestJobManager(TestCase):
         mock_job_order = {
             'threads': 2
         }
-        self.mock_job = Mock(username='jpb', workflow=Mock(url='someurl', job_order=mock_job_order), volume_size=3)
+        self.mock_job = Mock(
+            username='jpb',
+            workflow=Mock(url='someurl', job_order=mock_job_order),
+            volume_size=3,
+            job_flavor_cpus=2,
+            job_flavor_memory='1G',
+        )
         self.mock_job.id = '51'
         self.mock_job.vm_settings = None
         self.mock_job.k8s_settings.stage_data = Mock(
@@ -184,14 +190,14 @@ class TestJobManager(TestCase):
         self.assertEqual(job_container.name, 'run-workflow-51-jpb')  # container name
         self.assertEqual(job_container.image_name, self.mock_job.k8s_settings.run_workflow.image_name,
                          'run workflow image name is based on job settings')
-
-        self.assertEqual(job_container.command, ['bash', '-c', 'cwltool --tmp-outdir-prefix /bespin/tmpout/ '
-                                                               '--outdir /bespin/output-data/results/ '
-                                                               '/bespin/job-data/workflow/someurl '
-                                                               '/bespin/job-data/job-order.json '
-                                                               '>/bespin/output-data/bespin-workflow-output.json '
-                                                               '2>/bespin/output-data/bespin-workflow-output.log'
-                                                ],
+        expected_bash_command = 'cwltool --tmp-outdir-prefix /bespin/tmpout/ ' \
+                                '--outdir /bespin/output-data/results/ ' \
+                                '--max-ram 1G --max-cores 2 ' \
+                                '/bespin/job-data/workflow/someurl ' \
+                                '/bespin/job-data/job-order.json ' \
+                                '>/bespin/output-data/bespin-workflow-output.json ' \
+                                '2>/bespin/output-data/bespin-workflow-output.log'
+        self.assertEqual(job_container.command, ['bash', '-c', expected_bash_command],
                          'run workflow command combines job settings and staged files')
         self.assertEqual(job_container.env_dict['CALRISSIAN_POD_NAME'].field_path, 'metadata.name',
                          'We should store the pod name in a CALRISSIAN_POD_NAME environment variable')
diff --git a/lando/server/tests/test_jobapi.py b/lando/server/tests/test_jobapi.py
index 32d48c5..4ef4c84 100644
--- a/lando/server/tests/test_jobapi.py
+++ b/lando/server/tests/test_jobapi.py
@@ -23,6 +23,8 @@ class TestJobApi(TestCase):
             'created': '2017-03-21T13:29:09.123603Z',
             'job_flavor': {
                 'name': 'm1.tiny',
+                'cpus': 1,
+                'memory': '200MB',
             },
             'vm_instance_name': '',
             'vm_volume_name': '',
@@ -76,6 +78,8 @@ class TestJobApi(TestCase):
         self.assertEqual('joe@joe.com', job.username)
         self.assertEqual('N', job.state)
         self.assertEqual('m1.tiny', job.job_flavor_name)
+        self.assertEqual(1, job.job_flavor_cpus)
+        self.assertEqual('200MB', job.job_flavor_memory)
         self.assertEqual('', job.vm_instance_name)
         self.assertEqual('', job.vm_volume_name)
         self.assertEqual(True, job.cleanup_vm)
@@ -180,6 +184,8 @@ class TestJobApi(TestCase):
             'step': '',
             'job_flavor': {
                 'name': 'm1.tiny',
+                'cpus': 8,
+                'memory': '1G',
             },
             'vm_instance_name': '',
             'vm_volume_name': '',
@@ -246,6 +252,8 @@ class TestJobApi(TestCase):
                 'created': '2017-03-21T13:29:09.123603Z',
                 'job_flavor': {
                     'name': 'm1.tiny',
+                    'cpus': 2,
+                    'memory': '1G',
                 },
                 'vm_instance_name': '',
                 'vm_volume_name': '',
@@ -396,6 +404,8 @@ class TestJob(TestCase):
             'created': '2017-03-21T13:29:09.123603Z',
             'job_flavor': {
                 'name': 'm1.tiny',
+                'cpus': 1,
+                'memory': '200MB',
             },
             'vm_instance_name': '',
             'vm_volume_name': '',
@@ -432,7 +442,7 @@ class TestJob(TestCase):
             ],
             "cwl_pre_process_command": [
                 "prep.sh"
-            ]
+            ],
         }
         self.k8s_job_data = copy.deepcopy(job_data)
         self.k8s_job_data['job_settings']['name'] = 'k8s'