Metadata for name, version, tags and type
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / ansible-awx-executor / src / test / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / functions / ansible / executor / ComponentRemoteAnsibleExecutorTest.kt
1 /*
2  *  Copyright © 2019 IBM.
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */
16
17 package org.onap.ccsdk.cds.blueprintsprocessor.functions.ansible.executor
18
19 import com.fasterxml.jackson.databind.JsonNode
20 import com.fasterxml.jackson.databind.ObjectMapper
21 import io.mockk.every
22 import io.mockk.mockk
23 import kotlinx.coroutines.runBlocking
24 import org.junit.Assert.assertEquals
25 import org.junit.Assert.assertTrue
26 import org.junit.Test
27 import org.junit.runner.RunWith
28 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
29 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.StepData
30 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BluePrintRestLibPropertyService
31 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService
32 import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService.WebClientResponse
33 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
34 import org.onap.ccsdk.cds.controllerblueprints.core.putJsonElement
35 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService
36 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
37 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
38 import org.springframework.test.context.TestPropertySource
39 import org.springframework.test.context.junit4.SpringRunner
40
41 @RunWith(SpringRunner::class)
42 @TestPropertySource(locations = ["classpath:application-test.properties"])
43 @Suppress("SameParameterValue")
44 class ComponentRemoteAnsibleExecutorTest {
45
46     private val webClientService = mockk<BlueprintWebClientService>()
47
48     companion object {
49         private const val jtId = 9
50         private const val jobId = 223
51
52         private val mapper = ObjectMapper()
53
54         // IMPORTANT: must match the corresponding properties blueprintsprocessor.restclient.awx.* on
55         // "application-test.properties"
56         private const val endpointSelector = """{
57             "type": "token-auth",
58             "url": "http://142.44.184.236",
59             "token": "Bearer J9gEtMDqf7P4YsJ7444fioY9VAhLDIs1"
60             }"""
61     }
62
63     @Test
64     fun testComponentRemoteAnsibleExecutor() {
65
66         every {
67             webClientService.exchangeResource("GET", "/api/v2/job_templates/hello_world_job_template/", "")
68         } returns WebClientResponse(200, getJobTemplates(jtId))
69         every {
70             webClientService.exchangeResource("GET", "/api/v2/job_templates/$jtId/launch/", "")
71         } returns WebClientResponse(200, getJobTemplateLaunch(jtId))
72         every {
73             webClientService.exchangeResource("GET", "/api/v2/inventories/?name=Demo+Inventory", "")
74         } returns WebClientResponse(200, getInventory())
75         every {
76             webClientService.exchangeResource(
77                 "POST", "/api/v2/job_templates/$jtId/launch/",
78                 """{"inventory":1,"extra_vars":{"site_id":"3 - Belmont","tor_group":"vEPC"}}"""
79             )
80         } returns WebClientResponse(201, newJobTemplateLaunch(jtId, jobId))
81         every {
82             webClientService.exchangeResource("GET", "/api/v2/jobs/$jobId/", "")
83         } returnsMany listOf(
84             WebClientResponse(200, getJobStatus1(jtId, jobId)),
85             WebClientResponse(200, getJobStatus2(jtId, jobId)),
86             WebClientResponse(200, getJobStatus3(jtId, jobId)),
87             WebClientResponse(200, getJobStatus4(jtId, jobId))
88         )
89         every {
90             webClientService.exchangeResource(
91                 "GET", "/api/v2/jobs/$jobId/stdout/?format=txt", "",
92                 mapOf("Accept" to "text/plain")
93             )
94         } returns WebClientResponse(200, getReport())
95         val selector = mapper.readTree(endpointSelector)
96         val bluePrintRestLibPropertyService = mockk<BluePrintRestLibPropertyService>()
97         every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService
98         val awxRemoteExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService, mapper)
99         awxRemoteExecutor.checkDelay = 1
100
101         val executionServiceInput = JacksonUtils.readValueFromClassPathFile(
102             "payload/requests/sample-remote-ansible-request.json",
103             ExecutionServiceInput::class.java
104         )!!
105
106         val bluePrintRuntimeService = createBlueprintRuntimeService(awxRemoteExecutor, executionServiceInput)
107
108         // when
109         runBlocking {
110             awxRemoteExecutor.applyNB(executionServiceInput)
111         }
112
113         // then
114         assertTrue(bluePrintRuntimeService.getBluePrintError().errors.isEmpty())
115     }
116
117     @Test
118     fun `handle unknown inventory`() {
119
120         every {
121             webClientService.exchangeResource("GET", "/api/v2/job_templates/hello_world_job_template/", "")
122         } returns WebClientResponse(200, getJobTemplates(jtId))
123         every {
124             webClientService.exchangeResource("GET", "/api/v2/job_templates/$jtId/launch/", "")
125         } returns WebClientResponse(200, getJobTemplateLaunch(jtId))
126         every {
127             webClientService.exchangeResource("GET", "/api/v2/inventories/?name=Demo+Inventory", "")
128         } returns WebClientResponse(404, "")
129         val selector = mapper.readTree(endpointSelector)
130         val bluePrintRestLibPropertyService = mockk<BluePrintRestLibPropertyService>()
131         every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService
132         val awxRemoteExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService, mapper)
133         awxRemoteExecutor.checkDelay = 1
134
135         val executionServiceInput = JacksonUtils.readValueFromClassPathFile(
136             "payload/requests/remote-ansible-request-full.json",
137             ExecutionServiceInput::class.java
138         )!!
139
140         val bluePrintRuntimeService = createBlueprintRuntimeService(awxRemoteExecutor, executionServiceInput)
141
142         // when
143         runBlocking {
144             awxRemoteExecutor.applyNB(executionServiceInput)
145         }
146
147         // then
148         val errors = bluePrintRuntimeService.getBluePrintError().errors
149         assertEquals(1, errors.size)
150     }
151
152     @Test
153     fun `handle failure on job submission`() {
154
155         every {
156             webClientService.exchangeResource("GET", "/api/v2/job_templates/hello_world_job_template/", "")
157         } returns WebClientResponse(200, getJobTemplates(jtId))
158         every {
159             webClientService.exchangeResource("GET", "/api/v2/job_templates/$jtId/launch/", "")
160         } returns WebClientResponse(200, getJobTemplateLaunch(jtId))
161         every {
162             webClientService.exchangeResource("GET", "/api/v2/inventories/?name=Demo+Inventory", "")
163         } returns WebClientResponse(200, getInventory())
164         every {
165             webClientService.exchangeResource(
166                 "POST", "/api/v2/job_templates/$jtId/launch/",
167                 """{"limit":"123","tags":"some-tag","skip_tags":"some-skip-tag","inventory":1,"extra_vars":{"site_id":"3 - Belmont","tor_group":"vEPC"}}"""
168             )
169         } returns WebClientResponse(500, "")
170         val selector = mapper.readTree(endpointSelector)
171         val bluePrintRestLibPropertyService = mockk<BluePrintRestLibPropertyService>()
172         every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService
173         val awxRemoteExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService, mapper)
174         awxRemoteExecutor.checkDelay = 1
175
176         val executionServiceInput = JacksonUtils.readValueFromClassPathFile(
177             "payload/requests/remote-ansible-request-full.json",
178             ExecutionServiceInput::class.java
179         )!!
180
181         val bluePrintRuntimeService = createBlueprintRuntimeService(awxRemoteExecutor, executionServiceInput)
182
183         // when
184         runBlocking {
185             awxRemoteExecutor.applyNB(executionServiceInput)
186         }
187
188         // then
189         val errors = bluePrintRuntimeService.getBluePrintError().errors
190         assertEquals(1, errors.size)
191     }
192
193     private fun createBlueprintRuntimeService(
194         awxRemoteExecutor: ComponentRemoteAnsibleExecutor,
195         executionServiceInput: ExecutionServiceInput
196     ): BluePrintRuntimeService<MutableMap<String, JsonNode>> {
197         val bluePrintRuntimeService = BluePrintMetadataUtils.bluePrintRuntime(
198             "123456-1000",
199             "./../../../../components/model-catalog/blueprint-model/test-blueprint/remote_ansible"
200         )
201         awxRemoteExecutor.bluePrintRuntimeService = bluePrintRuntimeService
202
203         val workflowName = executionServiceInput.actionIdentifiers.actionName
204
205         // Assign Workflow inputs
206         val input = executionServiceInput.payload.get("$workflowName-request")
207         bluePrintRuntimeService.assignWorkflowInputs(workflowName, input)
208
209         val stepMetaData: MutableMap<String, JsonNode> = hashMapOf()
210         stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE, "execute-remote-ansible")
211         stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_INTERFACE, "ComponentRemoteAnsibleExecutor")
212         stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_OPERATION, "process")
213
214         val stepInputData = StepData().apply {
215             name = "execute-remote-ansible"
216             properties = stepMetaData
217         }
218         executionServiceInput.stepData = stepInputData
219         return bluePrintRuntimeService
220     }
221
222     private fun getJobTemplates(jtId: Int) = """{
223       "id": $jtId,
224       "type": "job_template",
225       "url": "/api/v2/job_templates/$jtId/",
226       "related": {
227         "named_url": "/api/v2/job_templates/hello_world_job_template/",
228         "created_by": "/api/v2/users/1/",
229         "modified_by": "/api/v2/users/1/",
230         "labels": "/api/v2/job_templates/$jtId/labels/",
231         "inventory": "/api/v2/inventories/1/",
232         "project": "/api/v2/projects/8/",
233         "extra_credentials": "/api/v2/job_templates/$jtId/extra_credentials/",
234         "credentials": "/api/v2/job_templates/$jtId/credentials/",
235         "last_job": "/api/v2/jobs/222/",
236         "jobs": "/api/v2/job_templates/$jtId/jobs/",
237         "schedules": "/api/v2/job_templates/$jtId/schedules/",
238         "activity_stream": "/api/v2/job_templates/$jtId/activity_stream/",
239         "launch": "/api/v2/job_templates/$jtId/launch/",
240         "notification_templates_any": "/api/v2/job_templates/$jtId/notification_templates_any/",
241         "notification_templates_success": "/api/v2/job_templates/$jtId/notification_templates_success/",
242         "notification_templates_error": "/api/v2/job_templates/$jtId/notification_templates_error/",
243         "access_list": "/api/v2/job_templates/$jtId/access_list/",
244         "survey_spec": "/api/v2/job_templates/$jtId/survey_spec/",
245         "object_roles": "/api/v2/job_templates/$jtId/object_roles/",
246         "instance_groups": "/api/v2/job_templates/$jtId/instance_groups/",
247         "slice_workflow_jobs": "/api/v2/job_templates/$jtId/slice_workflow_jobs/",
248         "copy": "/api/v2/job_templates/$jtId/copy/"
249       },
250       "summary_fields": {
251         "inventory": {
252           "id": 1,
253           "name": "Demo Inventory",
254           "description": "",
255           "has_active_failures": false,
256           "total_hosts": 1,
257           "hosts_with_active_failures": 0,
258           "total_groups": 0,
259           "groups_with_active_failures": 0,
260           "has_inventory_sources": false,
261           "total_inventory_sources": 0,
262           "inventory_sources_with_failures": 0,
263           "organization_id": 1,
264           "kind": ""
265         },
266         "project": {
267           "id": 8,
268           "name": "cds_playbooks",
269           "description": "CDS - cds_playbooks Project",
270           "status": "ok",
271           "scm_type": ""
272         },
273         "last_job": {
274           "id": 222,
275           "name": "hello_world_job_template",
276           "description": "hello_world Runner Job Template",
277           "finished": "2019-06-12T11:20:27.892787Z",
278           "status": "successful",
279           "failed": false
280         },
281         "last_update": {
282           "id": 222,
283           "name": "hello_world_job_template",
284           "description": "hello_world Runner Job Template",
285           "status": "successful",
286           "failed": false
287         },
288         "created_by": {
289           "id": 1,
290           "username": "admin",
291           "first_name": "",
292           "last_name": ""
293         },
294         "modified_by": {
295           "id": 1,
296           "username": "admin",
297           "first_name": "",
298           "last_name": ""
299         },
300         "object_roles": {
301           "admin_role": {
302             "description": "Can manage all aspects of the job template",
303             "name": "Admin",
304             "id": 51
305           },
306           "execute_role": {
307             "description": "May run the job template",
308             "name": "Execute",
309             "id": 52
310           },
311           "read_role": {
312             "description": "May view settings for the job template",
313             "name": "Read",
314             "id": 53
315           }
316         },
317         "user_capabilities": {
318           "edit": true,
319           "delete": true,
320           "start": true,
321           "schedule": true,
322           "copy": true
323         },
324         "labels": {
325           "count": 0,
326           "results": []
327         },
328         "survey": {
329           "title": "",
330           "description": ""
331         },
332         "recent_jobs": [
333           {
334             "id": 222,
335             "status": "successful",
336             "finished": "2019-06-12T11:20:27.892787Z",
337             "type": "job"
338           },
339           {
340             "id": 65,
341             "status": "successful",
342             "finished": "2019-06-03T18:27:19.114796Z",
343             "type": "job"
344           },
345           {
346             "id": 64,
347             "status": "successful",
348             "finished": "2019-06-03T18:26:53.606618Z",
349             "type": "job"
350           },
351           {
352             "id": 63,
353             "status": "successful",
354             "finished": "2019-06-03T18:24:36.072943Z",
355             "type": "job"
356           },
357           {
358             "id": 62,
359             "status": "successful",
360             "finished": "2019-06-03T18:17:50.616528Z",
361             "type": "job"
362           },
363           {
364             "id": 61,
365             "status": "successful",
366             "finished": "2019-06-03T18:04:42.995611Z",
367             "type": "job"
368           },
369           {
370             "id": 60,
371             "status": "successful",
372             "finished": "2019-06-03T17:47:13.983951Z",
373             "type": "job"
374           },
375           {
376             "id": 50,
377             "status": "successful",
378             "finished": "2019-05-30T15:47:55.700161Z",
379             "type": "job"
380           },
381           {
382             "id": 49,
383             "status": "successful",
384             "finished": "2019-05-29T14:46:51.615926Z",
385             "type": "job"
386           },
387           {
388             "id": 47,
389             "status": "successful",
390             "finished": "2019-05-27T20:23:58.656709Z",
391             "type": "job"
392           }
393         ],
394         "extra_credentials": [],
395         "credentials": []
396       },
397       "created": "2019-05-21T19:28:05.953730Z",
398       "modified": "2019-05-21T20:06:55.728697Z",
399       "name": "hello_world_job_template",
400       "description": "hello_world Runner Job Template",
401       "job_type": "run",
402       "inventory": 1,
403       "project": 8,
404       "playbook": "hello_world.yml",
405       "forks": 0,
406       "limit": "",
407       "verbosity": 0,
408       "extra_vars": "",
409       "job_tags": "",
410       "force_handlers": false,
411       "skip_tags": "",
412       "start_at_task": "",
413       "timeout": 0,
414       "use_fact_cache": false,
415       "last_job_run": "2019-06-12T11:20:27.892787Z",
416       "last_job_failed": false,
417       "next_job_run": null,
418       "status": "successful",
419       "host_config_key": "",
420       "ask_diff_mode_on_launch": false,
421       "ask_variables_on_launch": true,
422       "ask_limit_on_launch": true,
423       "ask_tags_on_launch": true,
424       "ask_skip_tags_on_launch": true,
425       "ask_job_type_on_launch": false,
426       "ask_verbosity_on_launch": false,
427       "ask_inventory_on_launch": true,
428       "ask_credential_on_launch": true,
429       "survey_enabled": true,
430       "become_enabled": false,
431       "diff_mode": false,
432       "allow_simultaneous": false,
433       "custom_virtualenv": null,
434       "job_slice_count": 1,
435       "credential": null,
436       "vault_credential": null
437     }"""
438
439     private fun getJobTemplateLaunch(jtId: Int) = """{
440       "can_start_without_user_input": false,
441       "passwords_needed_to_start": [],
442       "ask_variables_on_launch": true,
443       "ask_tags_on_launch": true,
444       "ask_diff_mode_on_launch": false,
445       "ask_skip_tags_on_launch": true,
446       "ask_job_type_on_launch": false,
447       "ask_limit_on_launch": true,
448       "ask_verbosity_on_launch": false,
449       "ask_inventory_on_launch": true,
450       "ask_credential_on_launch": true,
451       "survey_enabled": true,
452       "variables_needed_to_start": [
453         "tor_group",
454         "site_id"
455       ],
456       "credential_needed_to_start": false,
457       "inventory_needed_to_start": false,
458       "job_template_data": {
459         "name": "hello_world_job_template",
460         "id": $jtId,
461         "description": "hello_world Runner Job Template"
462       },
463       "defaults": {
464         "extra_vars": "",
465         "diff_mode": false,
466         "limit": "",
467         "job_tags": "",
468         "skip_tags": "",
469         "job_type": "run",
470         "verbosity": 0,
471         "inventory": {
472           "name": "Demo Inventory",
473           "id": 1
474         }
475       }
476     }"""
477
478     private fun getInventory() = """{
479           "count": 1,
480           "next": null,
481           "previous": null,
482           "results": [
483             {
484               "id": 1,
485               "type": "inventory",
486               "url": "/api/v2/inventories/1/",
487               "related": {
488                 "created_by": "/api/v2/users/1/",
489                 "modified_by": "/api/v2/users/1/",
490                 "hosts": "/api/v2/inventories/1/hosts/",
491                 "groups": "/api/v2/inventories/1/groups/",
492                 "root_groups": "/api/v2/inventories/1/root_groups/",
493                 "variable_data": "/api/v2/inventories/1/variable_data/",
494                 "script": "/api/v2/inventories/1/script/",
495                 "tree": "/api/v2/inventories/1/tree/",
496                 "inventory_sources": "/api/v2/inventories/1/inventory_sources/",
497                 "update_inventory_sources": "/api/v2/inventories/1/update_inventory_sources/",
498                 "activity_stream": "/api/v2/inventories/1/activity_stream/",
499                 "job_templates": "/api/v2/inventories/1/job_templates/",
500                 "ad_hoc_commands": "/api/v2/inventories/1/ad_hoc_commands/",
501                 "access_list": "/api/v2/inventories/1/access_list/",
502                 "object_roles": "/api/v2/inventories/1/object_roles/",
503                 "instance_groups": "/api/v2/inventories/1/instance_groups/",
504                 "copy": "/api/v2/inventories/1/copy/",
505                 "organization": "/api/v2/organizations/1/"
506               },
507               "summary_fields": {
508                 "organization": {
509                   "id": 1,
510                   "name": "Default",
511                   "description": ""
512                 },
513                 "created_by": {
514                   "id": 1,
515                   "username": "admin",
516                   "first_name": "",
517                   "last_name": ""
518                 },
519                 "modified_by": {
520                   "id": 1,
521                   "username": "admin",
522                   "first_name": "",
523                   "last_name": ""
524                 },
525                 "object_roles": {
526                   "admin_role": {
527                     "description": "Can manage all aspects of the inventory",
528                     "name": "Admin",
529                     "id": 21
530                   },
531                   "update_role": {
532                     "description": "May update project or inventory or group using the configured source update system",
533                     "name": "Update",
534                     "id": 22
535                   },
536                   "adhoc_role": {
537                     "description": "May run ad hoc commands on an inventory",
538                     "name": "Ad Hoc",
539                     "id": 23
540                   },
541                   "use_role": {
542                     "description": "Can use the inventory in a job template",
543                     "name": "Use",
544                     "id": 24
545                   },
546                   "read_role": {
547                     "description": "May view settings for the inventory",
548                     "name": "Read",
549                     "id": 25
550                   }
551                 },
552                 "user_capabilities": {
553                   "edit": true,
554                   "delete": true,
555                   "copy": true,
556                   "adhoc": true
557                 }
558               },
559               "created": "2019-05-21T15:45:31.954359Z",
560               "modified": "2019-05-21T15:45:31.954378Z",
561               "name": "Demo Inventory",
562               "description": "",
563               "organization": 1,
564               "kind": "",
565               "host_filter": null,
566               "variables": "",
567               "has_active_failures": false,
568               "total_hosts": 1,
569               "hosts_with_active_failures": 0,
570               "total_groups": 0,
571               "groups_with_active_failures": 0,
572               "has_inventory_sources": false,
573               "total_inventory_sources": 0,
574               "inventory_sources_with_failures": 0,
575               "insights_credential": null,
576               "pending_deletion": false
577             }
578           ]
579         }"""
580
581     private fun newJobTemplateLaunch(jtId: Int, jobId: Int) = """{
582       "job": $jobId,
583       "ignored_fields": {},
584       "id": $jobId,
585       "type": "job",
586       "url": "/api/v2/jobs/$jobId/",
587       "related": {
588         "created_by": "/api/v2/users/1/",
589         "modified_by": "/api/v2/users/1/",
590         "labels": "/api/v2/jobs/$jobId/labels/",
591         "inventory": "/api/v2/inventories/1/",
592         "project": "/api/v2/projects/8/",
593         "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/",
594         "credentials": "/api/v2/jobs/$jobId/credentials/",
595         "unified_job_template": "/api/v2/job_templates/$jtId/",
596         "stdout": "/api/v2/jobs/$jobId/stdout/",
597         "job_events": "/api/v2/jobs/$jobId/job_events/",
598         "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/",
599         "activity_stream": "/api/v2/jobs/$jobId/activity_stream/",
600         "notifications": "/api/v2/jobs/$jobId/notifications/",
601         "job_template": "/api/v2/job_templates/$jtId/",
602         "cancel": "/api/v2/jobs/$jobId/cancel/",
603         "create_schedule": "/api/v2/jobs/$jobId/create_schedule/",
604         "relaunch": "/api/v2/jobs/$jobId/relaunch/"
605       },
606       "summary_fields": {
607         "inventory": {
608           "id": 1,
609           "name": "Demo Inventory",
610           "description": "",
611           "has_active_failures": false,
612           "total_hosts": 1,
613           "hosts_with_active_failures": 0,
614           "total_groups": 0,
615           "groups_with_active_failures": 0,
616           "has_inventory_sources": false,
617           "total_inventory_sources": 0,
618           "inventory_sources_with_failures": 0,
619           "organization_id": 1,
620           "kind": ""
621         },
622         "project": {
623           "id": 8,
624           "name": "cds_playbooks",
625           "description": "CDS - cds_playbooks Project",
626           "status": "ok",
627           "scm_type": ""
628         },
629         "job_template": {
630           "id": $jtId,
631           "name": "hello_world_job_template",
632           "description": "hello_world Runner Job Template"
633         },
634         "unified_job_template": {
635           "id": $jtId,
636           "name": "hello_world_job_template",
637           "description": "hello_world Runner Job Template",
638           "unified_job_type": "job"
639         },
640         "created_by": {
641           "id": 1,
642           "username": "admin",
643           "first_name": "",
644           "last_name": ""
645         },
646         "modified_by": {
647           "id": 1,
648           "username": "admin",
649           "first_name": "",
650           "last_name": ""
651         },
652         "user_capabilities": {
653           "delete": true,
654           "start": true
655         },
656         "labels": {
657           "count": 0,
658           "results": []
659         },
660         "extra_credentials": [],
661         "credentials": []
662       },
663       "created": "2019-06-12T11:21:26.891986Z",
664       "modified": "2019-06-12T11:21:27.016410Z",
665       "name": "hello_world_job_template",
666       "description": "hello_world Runner Job Template",
667       "job_type": "run",
668       "inventory": 1,
669       "project": 8,
670       "playbook": "hello_world.yml",
671       "forks": 0,
672       "limit": "",
673       "verbosity": 0,
674       "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}",
675       "job_tags": "",
676       "force_handlers": false,
677       "skip_tags": "",
678       "start_at_task": "",
679       "timeout": 0,
680       "use_fact_cache": false,
681       "unified_job_template": $jtId,
682       "launch_type": "manual",
683       "status": "pending",
684       "failed": false,
685       "started": null,
686       "finished": null,
687       "elapsed": 0,
688       "job_args": "",
689       "job_cwd": "",
690       "job_env": {},
691       "job_explanation": "",
692       "execution_node": "",
693       "controller_node": "",
694       "result_traceback": "",
695       "event_processing_finished": false,
696       "job_template": $jtId,
697       "passwords_needed_to_start": [],
698       "ask_diff_mode_on_launch": false,
699       "ask_variables_on_launch": true,
700       "ask_limit_on_launch": true,
701       "ask_tags_on_launch": true,
702       "ask_skip_tags_on_launch": true,
703       "ask_job_type_on_launch": false,
704       "ask_verbosity_on_launch": false,
705       "ask_inventory_on_launch": true,
706       "ask_credential_on_launch": true,
707       "allow_simultaneous": false,
708       "artifacts": {},
709       "scm_revision": "",
710       "instance_group": null,
711       "diff_mode": false,
712       "job_slice_number": 0,
713       "job_slice_count": 1,
714       "credential": null,
715       "vault_credential": null
716     }"""
717
718     private fun getJobStatus1(jtId: Int, jobId: Int) = """{
719       "id": $jobId,
720       "type": "job",
721       "url": "/api/v2/jobs/$jobId/",
722       "related": {
723         "created_by": "/api/v2/users/1/",
724         "labels": "/api/v2/jobs/$jobId/labels/",
725         "inventory": "/api/v2/inventories/1/",
726         "project": "/api/v2/projects/8/",
727         "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/",
728         "credentials": "/api/v2/jobs/$jobId/credentials/",
729         "unified_job_template": "/api/v2/job_templates/$jtId/",
730         "stdout": "/api/v2/jobs/$jobId/stdout/",
731         "job_events": "/api/v2/jobs/$jobId/job_events/",
732         "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/",
733         "activity_stream": "/api/v2/jobs/$jobId/activity_stream/",
734         "notifications": "/api/v2/jobs/$jobId/notifications/",
735         "job_template": "/api/v2/job_templates/$jtId/",
736         "cancel": "/api/v2/jobs/$jobId/cancel/",
737         "create_schedule": "/api/v2/jobs/$jobId/create_schedule/",
738         "relaunch": "/api/v2/jobs/$jobId/relaunch/"
739       },
740       "summary_fields": {
741         "inventory": {
742           "id": 1,
743           "name": "Demo Inventory",
744           "description": "",
745           "has_active_failures": false,
746           "total_hosts": 1,
747           "hosts_with_active_failures": 0,
748           "total_groups": 0,
749           "groups_with_active_failures": 0,
750           "has_inventory_sources": false,
751           "total_inventory_sources": 0,
752           "inventory_sources_with_failures": 0,
753           "organization_id": 1,
754           "kind": ""
755         },
756         "project": {
757           "id": 8,
758           "name": "cds_playbooks",
759           "description": "CDS - cds_playbooks Project",
760           "status": "ok",
761           "scm_type": ""
762         },
763         "job_template": {
764           "id": $jtId,
765           "name": "hello_world_job_template",
766           "description": "hello_world Runner Job Template"
767         },
768         "unified_job_template": {
769           "id": $jtId,
770           "name": "hello_world_job_template",
771           "description": "hello_world Runner Job Template",
772           "unified_job_type": "job"
773         },
774         "instance_group": {
775           "name": "tower",
776           "id": 1
777         },
778         "created_by": {
779           "id": 1,
780           "username": "admin",
781           "first_name": "",
782           "last_name": ""
783         },
784         "user_capabilities": {
785           "delete": true,
786           "start": true
787         },
788         "labels": {
789           "count": 0,
790           "results": []
791         },
792         "extra_credentials": [],
793         "credentials": []
794       },
795       "created": "2019-06-12T11:21:26.891986Z",
796       "modified": "2019-06-12T11:21:27.355185Z",
797       "name": "hello_world_job_template",
798       "description": "hello_world Runner Job Template",
799       "job_type": "run",
800       "inventory": 1,
801       "project": 8,
802       "playbook": "hello_world.yml",
803       "forks": 0,
804       "limit": "",
805       "verbosity": 0,
806       "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}",
807       "job_tags": "",
808       "force_handlers": false,
809       "skip_tags": "",
810       "start_at_task": "",
811       "timeout": 0,
812       "use_fact_cache": false,
813       "unified_job_template": $jtId,
814       "launch_type": "manual",
815       "status": "waiting",
816       "failed": false,
817       "started": null,
818       "finished": null,
819       "elapsed": 0,
820       "job_args": "",
821       "job_cwd": "",
822       "job_env": {},
823       "job_explanation": "",
824       "execution_node": "awx",
825       "controller_node": "",
826       "result_traceback": "",
827       "event_processing_finished": false,
828       "job_template": $jtId,
829       "passwords_needed_to_start": [],
830       "ask_diff_mode_on_launch": false,
831       "ask_variables_on_launch": true,
832       "ask_limit_on_launch": true,
833       "ask_tags_on_launch": true,
834       "ask_skip_tags_on_launch": true,
835       "ask_job_type_on_launch": false,
836       "ask_verbosity_on_launch": false,
837       "ask_inventory_on_launch": true,
838       "ask_credential_on_launch": true,
839       "allow_simultaneous": false,
840       "artifacts": {},
841       "scm_revision": "",
842       "instance_group": 1,
843       "diff_mode": false,
844       "job_slice_number": 0,
845       "job_slice_count": 1,
846       "host_status_counts": {},
847       "playbook_counts": {
848         "play_count": 0,
849         "task_count": 0
850       },
851       "custom_virtualenv": null,
852       "credential": null,
853       "vault_credential": null
854     }"""
855
856     private fun getJobStatus2(jtId: Int, jobId: Int) = """{
857       "id": $jobId,
858       "type": "job",
859       "url": "/api/v2/jobs/$jobId/",
860       "related": {
861         "created_by": "/api/v2/users/1/",
862         "labels": "/api/v2/jobs/$jobId/labels/",
863         "inventory": "/api/v2/inventories/1/",
864         "project": "/api/v2/projects/8/",
865         "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/",
866         "credentials": "/api/v2/jobs/$jobId/credentials/",
867         "unified_job_template": "/api/v2/job_templates/$jtId/",
868         "stdout": "/api/v2/jobs/$jobId/stdout/",
869         "job_events": "/api/v2/jobs/$jobId/job_events/",
870         "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/",
871         "activity_stream": "/api/v2/jobs/$jobId/activity_stream/",
872         "notifications": "/api/v2/jobs/$jobId/notifications/",
873         "job_template": "/api/v2/job_templates/$jtId/",
874         "cancel": "/api/v2/jobs/$jobId/cancel/",
875         "create_schedule": "/api/v2/jobs/$jobId/create_schedule/",
876         "relaunch": "/api/v2/jobs/$jobId/relaunch/"
877       },
878       "summary_fields": {
879         "inventory": {
880           "id": 1,
881           "name": "Demo Inventory",
882           "description": "",
883           "has_active_failures": false,
884           "total_hosts": 1,
885           "hosts_with_active_failures": 0,
886           "total_groups": 0,
887           "groups_with_active_failures": 0,
888           "has_inventory_sources": false,
889           "total_inventory_sources": 0,
890           "inventory_sources_with_failures": 0,
891           "organization_id": 1,
892           "kind": ""
893         },
894         "project": {
895           "id": 8,
896           "name": "cds_playbooks",
897           "description": "CDS - cds_playbooks Project",
898           "status": "ok",
899           "scm_type": ""
900         },
901         "job_template": {
902           "id": $jtId,
903           "name": "hello_world_job_template",
904           "description": "hello_world Runner Job Template"
905         },
906         "unified_job_template": {
907           "id": $jtId,
908           "name": "hello_world_job_template",
909           "description": "hello_world Runner Job Template",
910           "unified_job_type": "job"
911         },
912         "instance_group": {
913           "name": "tower",
914           "id": 1
915         },
916         "created_by": {
917           "id": 1,
918           "username": "admin",
919           "first_name": "",
920           "last_name": ""
921         },
922         "user_capabilities": {
923           "delete": true,
924           "start": true
925         },
926         "labels": {
927           "count": 0,
928           "results": []
929         },
930         "extra_credentials": [],
931         "credentials": []
932       },
933       "created": "2019-06-12T11:21:26.891986Z",
934       "modified": "2019-06-12T11:21:27.355185Z",
935       "name": "hello_world_job_template",
936       "description": "hello_world Runner Job Template",
937       "job_type": "run",
938       "inventory": 1,
939       "project": 8,
940       "playbook": "hello_world.yml",
941       "forks": 0,
942       "limit": "",
943       "verbosity": 0,
944       "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}",
945       "job_tags": "",
946       "force_handlers": false,
947       "skip_tags": "",
948       "start_at_task": "",
949       "timeout": 0,
950       "use_fact_cache": false,
951       "unified_job_template": $jtId,
952       "launch_type": "manual",
953       "status": "running",
954       "failed": false,
955       "started": "2019-06-12T11:21:27.510766Z",
956       "finished": null,
957       "elapsed": 10.862184,
958       "job_args": "[\"ansible-playbook\", \"-u\", \"root\", \"-i\", \"/tmp/awx_223_ft8hu4p4/tmptmtwllu4\", \"-e\", \"@/tmp/awx_223_ft8hu4p4/env/extravars\", \"hello_world.yml\"]",
959       "job_cwd": "/var/lib/awx/projects/cds_playbooks_folder",
960       "job_env": {
961         "HOSTNAME": "awx",
962         "LC_ALL": "en_US.UTF-8",
963         "VIRTUAL_ENV": "/var/lib/awx/venv/ansible",
964         "PATH": "/var/lib/awx/venv/ansible/bin:/var/lib/awx/venv/awx/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
965         "SUPERVISOR_GROUP_NAME": "tower-processes",
966         "PWD": "/var/lib/awx",
967         "LANG": "en_US.UTF-8",
968         "PS1": "(awx) ",
969         "SUPERVISOR_ENABLED": "1",
970         "HOME": "/var/lib/awx",
971         "SHLVL": "2",
972         "LANGUAGE": "en_US.UTF-8",
973         "LC_CTYPE": "en_US.UTF-8",
974         "SUPERVISOR_PROCESS_NAME": "dispatcher",
975         "SUPERVISOR_SERVER_URL": "unix:///tmp/supervisor.sock",
976         "DJANGO_SETTINGS_MODULE": "awx.settings.production",
977         "DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199",
978         "TZ": "UTC",
979         "ANSIBLE_FORCE_COLOR": "True",
980         "ANSIBLE_HOST_KEY_CHECKING": "False",
981         "ANSIBLE_INVENTORY_UNPARSED_FAILED": "True",
982         "ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False",
983         "ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible",
984         "AWX_PRIVATE_DATA_DIR": "/tmp/awx_223_ft8hu4p4",
985         "PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python2.7/site-packages:/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/lib:",
986         "JOB_ID": "$jobId",
987         "INVENTORY_ID": "1",
988         "PROJECT_REVISION": "",
989         "ANSIBLE_RETRY_FILES_ENABLED": "False",
990         "MAX_EVENT_RES": "700000",
991         "ANSIBLE_CALLBACK_PLUGINS": "/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/plugins/callback",
992         "AWX_HOST": "https://towerhost",
993         "ANSIBLE_SSH_CONTROL_PATH_DIR": "/tmp/awx_223_ft8hu4p4/cp",
994         "ANSIBLE_STDOUT_CALLBACK": "awx_display",
995         "AWX_ISOLATED_DATA_DIR": "/tmp/awx_223_ft8hu4p4/artifacts/$jobId"
996       },
997       "job_explanation": "",
998       "execution_node": "awx",
999       "controller_node": "",
1000       "result_traceback": "",
1001       "event_processing_finished": false,
1002       "job_template": $jtId,
1003       "passwords_needed_to_start": [],
1004       "ask_diff_mode_on_launch": false,
1005       "ask_variables_on_launch": true,
1006       "ask_limit_on_launch": true,
1007       "ask_tags_on_launch": true,
1008       "ask_skip_tags_on_launch": true,
1009       "ask_job_type_on_launch": false,
1010       "ask_verbosity_on_launch": false,
1011       "ask_inventory_on_launch": true,
1012       "ask_credential_on_launch": true,
1013       "allow_simultaneous": false,
1014       "artifacts": {},
1015       "scm_revision": "",
1016       "instance_group": 1,
1017       "diff_mode": false,
1018       "job_slice_number": 0,
1019       "job_slice_count": 1,
1020       "host_status_counts": {},
1021       "playbook_counts": {
1022         "play_count": 1,
1023         "task_count": 1
1024       },
1025       "custom_virtualenv": "/var/lib/awx/venv/ansible",
1026       "credential": null,
1027       "vault_credential": null
1028     }"""
1029
1030     private fun getJobStatus3(jtId: Int, jobId: Int) = """{
1031       "id": $jobId,
1032       "type": "job",
1033       "url": "/api/v2/jobs/$jobId/",
1034       "related": {
1035         "created_by": "/api/v2/users/1/",
1036         "labels": "/api/v2/jobs/$jobId/labels/",
1037         "inventory": "/api/v2/inventories/1/",
1038         "project": "/api/v2/projects/8/",
1039         "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/",
1040         "credentials": "/api/v2/jobs/$jobId/credentials/",
1041         "unified_job_template": "/api/v2/job_templates/$jtId/",
1042         "stdout": "/api/v2/jobs/$jobId/stdout/",
1043         "job_events": "/api/v2/jobs/$jobId/job_events/",
1044         "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/",
1045         "activity_stream": "/api/v2/jobs/$jobId/activity_stream/",
1046         "notifications": "/api/v2/jobs/$jobId/notifications/",
1047         "job_template": "/api/v2/job_templates/$jtId/",
1048         "cancel": "/api/v2/jobs/$jobId/cancel/",
1049         "create_schedule": "/api/v2/jobs/$jobId/create_schedule/",
1050         "relaunch": "/api/v2/jobs/$jobId/relaunch/"
1051       },
1052       "summary_fields": {
1053         "inventory": {
1054           "id": 1,
1055           "name": "Demo Inventory",
1056           "description": "",
1057           "has_active_failures": false,
1058           "total_hosts": 1,
1059           "hosts_with_active_failures": 0,
1060           "total_groups": 0,
1061           "groups_with_active_failures": 0,
1062           "has_inventory_sources": false,
1063           "total_inventory_sources": 0,
1064           "inventory_sources_with_failures": 0,
1065           "organization_id": 1,
1066           "kind": ""
1067         },
1068         "project": {
1069           "id": 8,
1070           "name": "cds_playbooks",
1071           "description": "CDS - cds_playbooks Project",
1072           "status": "ok",
1073           "scm_type": ""
1074         },
1075         "job_template": {
1076           "id": $jtId,
1077           "name": "hello_world_job_template",
1078           "description": "hello_world Runner Job Template"
1079         },
1080         "unified_job_template": {
1081           "id": $jtId,
1082           "name": "hello_world_job_template",
1083           "description": "hello_world Runner Job Template",
1084           "unified_job_type": "job"
1085         },
1086         "instance_group": {
1087           "name": "tower",
1088           "id": 1
1089         },
1090         "created_by": {
1091           "id": 1,
1092           "username": "admin",
1093           "first_name": "",
1094           "last_name": ""
1095         },
1096         "user_capabilities": {
1097           "delete": true,
1098           "start": true
1099         },
1100         "labels": {
1101           "count": 0,
1102           "results": []
1103         },
1104         "extra_credentials": [],
1105         "credentials": []
1106       },
1107       "created": "2019-06-12T11:21:26.891986Z",
1108       "modified": "2019-06-12T11:21:27.355185Z",
1109       "name": "hello_world_job_template",
1110       "description": "hello_world Runner Job Template",
1111       "job_type": "run",
1112       "inventory": 1,
1113       "project": 8,
1114       "playbook": "hello_world.yml",
1115       "forks": 0,
1116       "limit": "",
1117       "verbosity": 0,
1118       "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}",
1119       "job_tags": "",
1120       "force_handlers": false,
1121       "skip_tags": "",
1122       "start_at_task": "",
1123       "timeout": 0,
1124       "use_fact_cache": false,
1125       "unified_job_template": $jtId,
1126       "launch_type": "manual",
1127       "status": "running",
1128       "failed": false,
1129       "started": "2019-06-12T11:21:27.510766Z",
1130       "finished": null,
1131       "elapsed": 21.297881,
1132       "job_args": "[\"ansible-playbook\", \"-u\", \"root\", \"-i\", \"/tmp/awx_223_ft8hu4p4/tmptmtwllu4\", \"-e\", \"@/tmp/awx_223_ft8hu4p4/env/extravars\", \"hello_world.yml\"]",
1133       "job_cwd": "/var/lib/awx/projects/cds_playbooks_folder",
1134       "job_env": {
1135         "HOSTNAME": "awx",
1136         "LC_ALL": "en_US.UTF-8",
1137         "VIRTUAL_ENV": "/var/lib/awx/venv/ansible",
1138         "PATH": "/var/lib/awx/venv/ansible/bin:/var/lib/awx/venv/awx/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
1139         "SUPERVISOR_GROUP_NAME": "tower-processes",
1140         "PWD": "/var/lib/awx",
1141         "LANG": "en_US.UTF-8",
1142         "PS1": "(awx) ",
1143         "SUPERVISOR_ENABLED": "1",
1144         "HOME": "/var/lib/awx",
1145         "SHLVL": "2",
1146         "LANGUAGE": "en_US.UTF-8",
1147         "LC_CTYPE": "en_US.UTF-8",
1148         "SUPERVISOR_PROCESS_NAME": "dispatcher",
1149         "SUPERVISOR_SERVER_URL": "unix:///tmp/supervisor.sock",
1150         "DJANGO_SETTINGS_MODULE": "awx.settings.production",
1151         "DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199",
1152         "TZ": "UTC",
1153         "ANSIBLE_FORCE_COLOR": "True",
1154         "ANSIBLE_HOST_KEY_CHECKING": "False",
1155         "ANSIBLE_INVENTORY_UNPARSED_FAILED": "True",
1156         "ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False",
1157         "ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible",
1158         "AWX_PRIVATE_DATA_DIR": "/tmp/awx_223_ft8hu4p4",
1159         "PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python2.7/site-packages:/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/lib:",
1160         "JOB_ID": "$jobId",
1161         "INVENTORY_ID": "1",
1162         "PROJECT_REVISION": "",
1163         "ANSIBLE_RETRY_FILES_ENABLED": "False",
1164         "MAX_EVENT_RES": "700000",
1165         "ANSIBLE_CALLBACK_PLUGINS": "/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/plugins/callback",
1166         "AWX_HOST": "https://towerhost",
1167         "ANSIBLE_SSH_CONTROL_PATH_DIR": "/tmp/awx_223_ft8hu4p4/cp",
1168         "ANSIBLE_STDOUT_CALLBACK": "awx_display",
1169         "AWX_ISOLATED_DATA_DIR": "/tmp/awx_223_ft8hu4p4/artifacts/$jobId"
1170       },
1171       "job_explanation": "",
1172       "execution_node": "awx",
1173       "controller_node": "",
1174       "result_traceback": "",
1175       "event_processing_finished": false,
1176       "job_template": $jtId,
1177       "passwords_needed_to_start": [],
1178       "ask_diff_mode_on_launch": false,
1179       "ask_variables_on_launch": true,
1180       "ask_limit_on_launch": true,
1181       "ask_tags_on_launch": true,
1182       "ask_skip_tags_on_launch": true,
1183       "ask_job_type_on_launch": false,
1184       "ask_verbosity_on_launch": false,
1185       "ask_inventory_on_launch": true,
1186       "ask_credential_on_launch": true,
1187       "allow_simultaneous": false,
1188       "artifacts": {},
1189       "scm_revision": "",
1190       "instance_group": 1,
1191       "diff_mode": false,
1192       "job_slice_number": 0,
1193       "job_slice_count": 1,
1194       "host_status_counts": {},
1195       "playbook_counts": {
1196         "play_count": 1,
1197         "task_count": 2
1198       },
1199       "custom_virtualenv": "/var/lib/awx/venv/ansible",
1200       "credential": null,
1201       "vault_credential": null
1202     } """
1203
1204     private fun getJobStatus4(jtId: Int, jobId: Int) = """{
1205       "id": $jobId,
1206       "type": "job",
1207       "url": "/api/v2/jobs/$jobId/",
1208       "related": {
1209         "created_by": "/api/v2/users/1/",
1210         "labels": "/api/v2/jobs/$jobId/labels/",
1211         "inventory": "/api/v2/inventories/1/",
1212         "project": "/api/v2/projects/8/",
1213         "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/",
1214         "credentials": "/api/v2/jobs/$jobId/credentials/",
1215         "unified_job_template": "/api/v2/job_templates/$jtId/",
1216         "stdout": "/api/v2/jobs/$jobId/stdout/",
1217         "job_events": "/api/v2/jobs/$jobId/job_events/",
1218         "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/",
1219         "activity_stream": "/api/v2/jobs/$jobId/activity_stream/",
1220         "notifications": "/api/v2/jobs/$jobId/notifications/",
1221         "job_template": "/api/v2/job_templates/$jtId/",
1222         "cancel": "/api/v2/jobs/$jobId/cancel/",
1223         "create_schedule": "/api/v2/jobs/$jobId/create_schedule/",
1224         "relaunch": "/api/v2/jobs/$jobId/relaunch/"
1225       },
1226       "summary_fields": {
1227         "inventory": {
1228           "id": 1,
1229           "name": "Demo Inventory",
1230           "description": "",
1231           "has_active_failures": false,
1232           "total_hosts": 1,
1233           "hosts_with_active_failures": 0,
1234           "total_groups": 0,
1235           "groups_with_active_failures": 0,
1236           "has_inventory_sources": false,
1237           "total_inventory_sources": 0,
1238           "inventory_sources_with_failures": 0,
1239           "organization_id": 1,
1240           "kind": ""
1241         },
1242         "project": {
1243           "id": 8,
1244           "name": "cds_playbooks",
1245           "description": "CDS - cds_playbooks Project",
1246           "status": "ok",
1247           "scm_type": ""
1248         },
1249         "job_template": {
1250           "id": $jtId,
1251           "name": "hello_world_job_template",
1252           "description": "hello_world Runner Job Template"
1253         },
1254         "unified_job_template": {
1255           "id": $jtId,
1256           "name": "hello_world_job_template",
1257           "description": "hello_world Runner Job Template",
1258           "unified_job_type": "job"
1259         },
1260         "instance_group": {
1261           "name": "tower",
1262           "id": 1
1263         },
1264         "created_by": {
1265           "id": 1,
1266           "username": "admin",
1267           "first_name": "",
1268           "last_name": ""
1269         },
1270         "user_capabilities": {
1271           "delete": true,
1272           "start": true
1273         },
1274         "labels": {
1275           "count": 0,
1276           "results": []
1277         },
1278         "extra_credentials": [],
1279         "credentials": []
1280       },
1281       "created": "2019-06-12T11:21:26.891986Z",
1282       "modified": "2019-06-12T11:21:27.355185Z",
1283       "name": "hello_world_job_template",
1284       "description": "hello_world Runner Job Template",
1285       "job_type": "run",
1286       "inventory": 1,
1287       "project": 8,
1288       "playbook": "hello_world.yml",
1289       "forks": 0,
1290       "limit": "",
1291       "verbosity": 0,
1292       "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}",
1293       "job_tags": "",
1294       "force_handlers": false,
1295       "skip_tags": "",
1296       "start_at_task": "",
1297       "timeout": 0,
1298       "use_fact_cache": false,
1299       "unified_job_template": $jtId,
1300       "launch_type": "manual",
1301       "status": "successful",
1302       "failed": false,
1303       "started": "2019-06-12T11:21:27.510766Z",
1304       "finished": "2019-06-12T11:21:48.993385Z",
1305       "elapsed": 21.483,
1306       "job_args": "[\"ansible-playbook\", \"-u\", \"root\", \"-i\", \"/tmp/awx_223_ft8hu4p4/tmptmtwllu4\", \"-e\", \"@/tmp/awx_223_ft8hu4p4/env/extravars\", \"hello_world.yml\"]",
1307       "job_cwd": "/var/lib/awx/projects/cds_playbooks_folder",
1308       "job_env": {
1309         "HOSTNAME": "awx",
1310         "LC_ALL": "en_US.UTF-8",
1311         "VIRTUAL_ENV": "/var/lib/awx/venv/ansible",
1312         "PATH": "/var/lib/awx/venv/ansible/bin:/var/lib/awx/venv/awx/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
1313         "SUPERVISOR_GROUP_NAME": "tower-processes",
1314         "PWD": "/var/lib/awx",
1315         "LANG": "en_US.UTF-8",
1316         "PS1": "(awx) ",
1317         "SUPERVISOR_ENABLED": "1",
1318         "HOME": "/var/lib/awx",
1319         "SHLVL": "2",
1320         "LANGUAGE": "en_US.UTF-8",
1321         "LC_CTYPE": "en_US.UTF-8",
1322         "SUPERVISOR_PROCESS_NAME": "dispatcher",
1323         "SUPERVISOR_SERVER_URL": "unix:///tmp/supervisor.sock",
1324         "DJANGO_SETTINGS_MODULE": "awx.settings.production",
1325         "DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199",
1326         "TZ": "UTC",
1327         "ANSIBLE_FORCE_COLOR": "True",
1328         "ANSIBLE_HOST_KEY_CHECKING": "False",
1329         "ANSIBLE_INVENTORY_UNPARSED_FAILED": "True",
1330         "ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False",
1331         "ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible",
1332         "AWX_PRIVATE_DATA_DIR": "/tmp/awx_223_ft8hu4p4",
1333         "PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python2.7/site-packages:/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/lib:",
1334         "JOB_ID": "$jobId",
1335         "INVENTORY_ID": "1",
1336         "PROJECT_REVISION": "",
1337         "ANSIBLE_RETRY_FILES_ENABLED": "False",
1338         "MAX_EVENT_RES": "700000",
1339         "ANSIBLE_CALLBACK_PLUGINS": "/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/plugins/callback",
1340         "AWX_HOST": "https://towerhost",
1341         "ANSIBLE_SSH_CONTROL_PATH_DIR": "/tmp/awx_223_ft8hu4p4/cp",
1342         "ANSIBLE_STDOUT_CALLBACK": "awx_display",
1343         "AWX_ISOLATED_DATA_DIR": "/tmp/awx_223_ft8hu4p4/artifacts/$jobId"
1344       },
1345       "job_explanation": "",
1346       "execution_node": "awx",
1347       "controller_node": "",
1348       "result_traceback": "",
1349       "event_processing_finished": true,
1350       "job_template": $jtId,
1351       "passwords_needed_to_start": [],
1352       "ask_diff_mode_on_launch": false,
1353       "ask_variables_on_launch": true,
1354       "ask_limit_on_launch": true,
1355       "ask_tags_on_launch": true,
1356       "ask_skip_tags_on_launch": true,
1357       "ask_job_type_on_launch": false,
1358       "ask_verbosity_on_launch": false,
1359       "ask_inventory_on_launch": true,
1360       "ask_credential_on_launch": true,
1361       "allow_simultaneous": false,
1362       "artifacts": {},
1363       "scm_revision": "",
1364       "instance_group": 1,
1365       "diff_mode": false,
1366       "job_slice_number": 0,
1367       "job_slice_count": 1,
1368       "host_status_counts": {
1369         "ok": 1
1370       },
1371       "playbook_counts": {
1372         "play_count": 1,
1373         "task_count": 2
1374       },
1375       "custom_virtualenv": "/var/lib/awx/venv/ansible",
1376       "credential": null,
1377       "vault_credential": null
1378     }"""
1379
1380     private fun getReport() = """
1381
1382 PLAY [Hello World Sample] ******************************************************
1383
1384 TASK [Gathering Facts] *********************************************************
1385 ok: [localhost]
1386
1387 TASK [Hello Message] ***********************************************************
1388 ok: [localhost] => {
1389     "msg": "Hello World!"
1390 }
1391
1392 PLAY RECAP *********************************************************************
1393 localhost                  : ok=2    changed=0    unreachable=0    failed=0
1394
1395 """
1396 }