diff options
Diffstat (limited to 'ms/blueprintsprocessor')
5 files changed, 1381 insertions, 189 deletions
diff --git a/ms/blueprintsprocessor/functions/ansible-awx-executor/pom.xml b/ms/blueprintsprocessor/functions/ansible-awx-executor/pom.xml index 8eafc4abf..828ff2ef2 100644 --- a/ms/blueprintsprocessor/functions/ansible-awx-executor/pom.xml +++ b/ms/blueprintsprocessor/functions/ansible-awx-executor/pom.xml @@ -49,16 +49,6 @@ <artifactId>httpclient</artifactId> <version>${apache.httpcomponents.client.version}</version> </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-web</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-security</artifactId> - <scope>test</scope> - </dependency> </dependencies> </project> diff --git a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutor.kt b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutor.kt index f145d9677..63998dd29 100644 --- a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutor.kt +++ b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutor.kt @@ -47,17 +47,20 @@ import org.springframework.stereotype.Component */ @Component("component-remote-ansible-executor") @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) -open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertyService: BluePrintRestLibPropertyService) +open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertyService: BluePrintRestLibPropertyService, + private val mapper: ObjectMapper) : AbstractComponentFunction() { - private val log = LoggerFactory.getLogger(ComponentRemoteAnsibleExecutor::class.java)!! - // HTTP related constants private val HTTP_SUCCESS = 200..202 private val GET = HttpMethod.GET.name private val POST = HttpMethod.POST.name + var checkDelay: Long = 1_000 + companion object { + private val log = LoggerFactory.getLogger(ComponentRemoteAnsibleExecutor::class.java) + // input fields names accepted by this executor const val INPUT_ENDPOINT_SELECTOR = "endpoint-selector" const val INPUT_JOB_TEMPLATE_NAME = "job-template-name" @@ -71,8 +74,6 @@ open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertySe const val ATTRIBUTE_EXEC_CMD_STATUS = "ansible-command-status" const val ATTRIBUTE_EXEC_CMD_LOG = "ansible-command-logs" const val ATTRIBUTE_EXEC_CMD_STATUS_ERROR = "error" - - const val CHECKDELAY: Long = 10000 } override suspend fun processNB(executionRequest: ExecutionServiceInput) { @@ -131,8 +132,6 @@ open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertySe * Finds the job template ID based on the job template name provided in the request */ private fun lookupJobTemplateIDByName(awxClient : BlueprintWebClientService, job_template_name: String?): String { - val mapper = ObjectMapper() - val encodedJTName = URI(null,null, "/api/v2/job_templates/${job_template_name}/", null,null).rawPath @@ -150,12 +149,11 @@ open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertySe * The status and output attributes are populated in the process. */ private fun runJobTemplateOnAWX(awxClient : BlueprintWebClientService, job_template_name: String?, jtId: String) { - val mapper = ObjectMapper() - setNodeOutputProperties( "preparing".asJsonPrimitive(), "".asJsonPrimitive()) // Get Job Template requirements var response = awxClient.exchangeResource(GET, "/api/v2/job_templates/${jtId}/launch/","") + // FIXME: handle non-successful SC val jtLaunchReqs: JsonNode = mapper.readTree(response.body) var payload = prepareLaunchPayload(awxClient, jtLaunchReqs) log.info("Running job with $payload, for requestId $processId.") @@ -182,7 +180,7 @@ open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertySe val jobLaunched: JsonNode = mapper.readTree(response.body) jobStatus = jobLaunched.at("/status").asText() jobEndTime = jobLaunched.at("/finished").asText() - Thread.sleep(CHECKDELAY) + Thread.sleep(checkDelay) } log.info("Execution of job template $job_template_name in job #$jobId finished with status ($jobStatus) for requestId $processId") @@ -255,8 +253,6 @@ open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertySe val encoded = URLEncoder.encode(inventoryProp) val response = awxClient.exchangeResource(GET,"/api/v2/inventories/?name=$encoded","") if (response.status in HTTP_SUCCESS) { - val mapper = ObjectMapper() - // Extract the inventory ID from response val invDetails = mapper.readTree(response.body) val nbInvFound = invDetails.at("/count").asInt() diff --git a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt index b7f1ed5f9..b60290268 100644 --- a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt +++ b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt @@ -21,223 +21,1362 @@ import com.fasterxml.jackson.databind.ObjectMapper import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.runBlocking -import org.junit.Ignore +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith -import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintProperties -import org.onap.ccsdk.cds.blueprintsprocessor.core.BlueprintPropertyConfiguration import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.StepData -import org.onap.ccsdk.cds.blueprintsprocessor.rest.BluePrintRestLibConfiguration import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BluePrintRestLibPropertyService +import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService +import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService.WebClientResponse import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants -import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive import org.onap.ccsdk.cds.controllerblueprints.core.putJsonElement -import org.onap.ccsdk.cds.controllerblueprints.core.service.DefaultBluePrintRuntimeService +import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils -import org.slf4j.LoggerFactory -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.TestPropertySource import org.springframework.test.context.junit4.SpringRunner @RunWith(SpringRunner::class) -@EnableAutoConfiguration(exclude = [DataSourceAutoConfiguration::class]) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) -@ContextConfiguration(classes = [BluePrintRestLibConfiguration::class, - BlueprintPropertyConfiguration::class, - BluePrintProperties::class, - BluePrintProperties::class]) -@TestPropertySource(properties = -[ - "server.port=8443", - "server.ssl.enabled=true", - "server.ssl.key-store=classpath:keystore.p12", - "server.ssl.key-store-password=changeit", - "server.ssl.keyStoreType=PKCS12", - "server.ssl.keyAlias=tomcat", - "blueprintsprocessor.restclient.awx.type=token-auth", - "blueprintsprocessor.restclient.awx.url=http://142.44.184.236", - "blueprintsprocessor.restclient.awx.token=Bearer J9gEtMDqf7P4YsJ74fioY9VAhLDIs1", - "blueprintsprocessor.restclient.future.keyStoreInstance=PKCS12", - "blueprintsprocessor.restclient.future.sslTrust=src/test/resources/keystore.p12", - "blueprintsprocessor.restclient.future.sslTrustPassword=changeit" -]) +@TestPropertySource(locations = ["classpath:application-test.properties"]) +@Suppress("SameParameterValue") class ComponentRemoteAnsibleExecutorTest { - @Autowired - lateinit var bluePrintRestLibPropertyService: BluePrintRestLibPropertyService + private val webClientService = mockk<BlueprintWebClientService>() - @Transient - private val log = LoggerFactory.getLogger(ComponentRemoteAnsibleExecutorTest::class.java) + companion object { + private const val jtId = 9 + private const val jobId = 223 + + private val mapper = ObjectMapper() + + // IMPORTANT: must match the corresponding properties blueprintsprocessor.restclient.awx.* on + // "application-test.properties" + private const val endpointSelector = """{ + "type": "token-auth", + "url": "http://142.44.184.236", + "token": "Bearer J9gEtMDqf7P4YsJ7444fioY9VAhLDIs1" + }""" + } @Test - @Ignore fun testComponentRemoteAnsibleExecutor() { - runBlocking { - val awxRemoteExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService) + every { + webClientService.exchangeResource("GET", "/api/v2/job_templates/hello_world_job_template/", "") + } returns WebClientResponse(200, getJobTemplates(jtId)) + every { + webClientService.exchangeResource("GET", "/api/v2/job_templates/$jtId/launch/", "") + } returns WebClientResponse(200, getJobTemplateLaunch(jtId)) + every { + webClientService.exchangeResource("GET", "/api/v2/inventories/?name=Demo+Inventory", "") + } returns WebClientResponse(200, getInventory()) + every { + webClientService.exchangeResource("POST", "/api/v2/job_templates/$jtId/launch/", + """{"inventory":1,"extra_vars":{"site_id":"3 - Belmont","tor_group":"vEPC"}}""") + } returns WebClientResponse(201, newJobTemplateLaunch(jtId, jobId)) + every { + webClientService.exchangeResource("GET", "/api/v2/jobs/$jobId/", "") + } returnsMany listOf( + WebClientResponse(200, getJobStatus1(jtId, jobId)), + WebClientResponse(200, getJobStatus2(jtId, jobId)), + WebClientResponse(200, getJobStatus3(jtId, jobId)), + WebClientResponse(200, getJobStatus4(jtId, jobId)) + ) + every { + webClientService.exchangeResource("GET", "/api/v2/jobs/$jobId/stdout/?format=txt", "", + mapOf("Content-Type" to "text/plain ;utf-8")) + } returns WebClientResponse(200, getReport()) + val selector = mapper.readTree(endpointSelector) + val bluePrintRestLibPropertyService = mockk<BluePrintRestLibPropertyService>() + every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService + val awxRemoteExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService, mapper) + awxRemoteExecutor.checkDelay = 1 - val executionServiceInput = JacksonUtils.readValueFromClassPathFile( - "payload/requests/sample-remote-ansible-request.json", - ExecutionServiceInput::class.java)!! + val executionServiceInput = JacksonUtils.readValueFromClassPathFile( + "payload/requests/sample-remote-ansible-request.json", + ExecutionServiceInput::class.java)!! - log.info("Request Inputs : " + executionServiceInput.payload) + val bluePrintRuntimeService = createBlueprintRuntimeService(awxRemoteExecutor, executionServiceInput) - val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime("123456-1000", - "./../../../../components/model-catalog/blueprint-model/test-blueprint/remote_ansible") - awxRemoteExecutor.bluePrintRuntimeService = bluePrintRuntimeService + // when + runBlocking { + awxRemoteExecutor.applyNB(executionServiceInput) + } + + // then + assertTrue(bluePrintRuntimeService.getBluePrintError().errors.isEmpty()) + } - val workflowName = executionServiceInput.actionIdentifiers.actionName + @Test + fun `handle unknown inventory`() { - // Assign Workflow inputs - val input = executionServiceInput.payload.get("$workflowName-request") - bluePrintRuntimeService.assignWorkflowInputs(workflowName, input) + every { + webClientService.exchangeResource("GET", "/api/v2/job_templates/hello_world_job_template/", "") + } returns WebClientResponse(200, getJobTemplates(jtId)) + every { + webClientService.exchangeResource("GET", "/api/v2/job_templates/$jtId/launch/", "") + } returns WebClientResponse(200, getJobTemplateLaunch(jtId)) + every { + webClientService.exchangeResource("GET", "/api/v2/inventories/?name=Demo+Inventory", "") + } returns WebClientResponse(404, "") + val selector = mapper.readTree(endpointSelector) + val bluePrintRestLibPropertyService = mockk<BluePrintRestLibPropertyService>() + every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService + val awxRemoteExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService, mapper) + awxRemoteExecutor.checkDelay = 1 - val stepMetaData: MutableMap<String, JsonNode> = hashMapOf() - stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE, "execute-remote-ansible") - stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_INTERFACE, "ComponentRemoteAnsibleExecutor") - stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_OPERATION, "process") + val executionServiceInput = JacksonUtils.readValueFromClassPathFile( + "payload/requests/remote-ansible-request-full.json", + ExecutionServiceInput::class.java)!! - val stepInputData = StepData().apply { - name = "execute-remote-ansible" - properties = stepMetaData - } - executionServiceInput.stepData = stepInputData + val bluePrintRuntimeService = createBlueprintRuntimeService(awxRemoteExecutor, executionServiceInput) + // when + runBlocking { awxRemoteExecutor.applyNB(executionServiceInput) } + + // then + val errors = bluePrintRuntimeService.getBluePrintError().errors + assertEquals(1, errors.size) } - /** - * Test cases for Ansible executor to work with the process NB of remote - * executor. - */ @Test - @Ignore - fun testComponentRemoteAnsibleExecutorProcessNB() { + fun `handle failure on job submission`() { + + every { + webClientService.exchangeResource("GET", "/api/v2/job_templates/hello_world_job_template/", "") + } returns WebClientResponse(200, getJobTemplates(jtId)) + every { + webClientService.exchangeResource("GET", "/api/v2/job_templates/$jtId/launch/", "") + } returns WebClientResponse(200, getJobTemplateLaunch(jtId)) + every { + webClientService.exchangeResource("GET", "/api/v2/inventories/?name=Demo+Inventory", "") + } returns WebClientResponse(200, getInventory()) + every { + webClientService.exchangeResource("POST", "/api/v2/job_templates/$jtId/launch/", + """{"limit":"123","tags":"some-tag","skip_tags":"some-skip-tag","inventory":1,"extra_vars":{"site_id":"3 - Belmont","tor_group":"vEPC"}}""") + } returns WebClientResponse(500, "") + val selector = mapper.readTree(endpointSelector) + val bluePrintRestLibPropertyService = mockk<BluePrintRestLibPropertyService>() + every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService + val awxRemoteExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService, mapper) + awxRemoteExecutor.checkDelay = 1 + + val executionServiceInput = JacksonUtils.readValueFromClassPathFile( + "payload/requests/remote-ansible-request-full.json", + ExecutionServiceInput::class.java)!! + + val bluePrintRuntimeService = createBlueprintRuntimeService(awxRemoteExecutor, executionServiceInput) + + // when runBlocking { - // val remoteScriptExecutionService = MockRemoteScriptExecutionService(bluePrintRestLibPropertyService) - val componentRemoteAnsibleExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService) - val bluePrintRuntime = mockk<DefaultBluePrintRuntimeService>("123456-1000") - val input = getMockedOutput(bluePrintRuntime) - componentRemoteAnsibleExecutor.bluePrintRuntimeService = bluePrintRuntime - componentRemoteAnsibleExecutor.applyNB(input) + awxRemoteExecutor.applyNB(executionServiceInput) } + + // then + val errors = bluePrintRuntimeService.getBluePrintError().errors + assertEquals(1, errors.size) } - /** - * Mocked input information for remote Ansible executor. - */ - fun getMockedOutput(svc: DefaultBluePrintRuntimeService): - ExecutionServiceInput { - val stepMetaData: MutableMap<String, JsonNode> = hashMapOf() + private fun createBlueprintRuntimeService(awxRemoteExecutor: ComponentRemoteAnsibleExecutor, executionServiceInput: ExecutionServiceInput): BluePrintRuntimeService<MutableMap<String, JsonNode>> { + val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime("123456-1000", + "./../../../../components/model-catalog/blueprint-model/test-blueprint/remote_ansible") + awxRemoteExecutor.bluePrintRuntimeService = bluePrintRuntimeService + + val workflowName = executionServiceInput.actionIdentifiers.actionName + // Assign Workflow inputs + val input = executionServiceInput.payload.get("$workflowName-request") + bluePrintRuntimeService.assignWorkflowInputs(workflowName, input) + + val stepMetaData: MutableMap<String, JsonNode> = hashMapOf() stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE, "execute-remote-ansible") stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_INTERFACE, "ComponentRemoteAnsibleExecutor") stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_OPERATION, "process") - val mapper = ObjectMapper() - val rootNode = mapper.createObjectNode() - rootNode.put("ip-address", "0.0.0.0") - rootNode.put("type", "rest") - - val operationalInputs: MutableMap<String, JsonNode> = hashMapOf() - operationalInputs.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE, "execute-remote-ansible") - operationalInputs.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_INTERFACE, "ComponentRemoteAnsibleExecutor") - operationalInputs.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_OPERATION, "process") - operationalInputs.putJsonElement("endpoint-selector", "aai") -// operationalInputs.putJsonElement("dynamic-properties", rootNode) -// operationalInputs.putJsonElement("command", "./run.sh") - operationalInputs.putJsonElement("job-template-name", "CDS_job_template2") - - every { - svc.resolveNodeTemplateInterfaceOperationInputs( - "execute-remote-ansible", - "ComponentRemoteAnsibleExecutor", "process") - } returns operationalInputs - val stepInputData = StepData().apply { name = "execute-remote-ansible" properties = stepMetaData } - - val executionServiceInput = JacksonUtils - .readValueFromClassPathFile( - "payload/requests/sample-remote-ansible-request.json", - ExecutionServiceInput::class.java)!! executionServiceInput.stepData = stepInputData + return bluePrintRuntimeService + } - val operationOutputs = hashMapOf<String, JsonNode>() - every { - svc.resolveNodeTemplateInterfaceOperationOutputs( - "execute-remote-ansible", - "ComponentRemoteAnsibleExecutor", "process") - } returns operationOutputs - val bluePrintRuntimeService = BluePrintMetadataUtils - .getBluePrintRuntime("123456-1000", - "./../../../../components/model-" + - "catalog/blueprint-model/test-blueprint/" + - "remote_ansible") -// every { -// svc.resolveNodeTemplateArtifactDefinition("execute-remote-ansible", "component-script") -// } returns bluePrintRuntimeService.resolveNodeTemplateArtifactDefinition("execute-remote-ansible", -// "component-script") - every { - svc.setNodeTemplateAttributeValue( - "execute-remote-ansible", - "execute-command-status", - "successful".asJsonPrimitive()) - } returns Unit + private fun getJobTemplates(jtId: Int) = """{ + "id": $jtId, + "type": "job_template", + "url": "/api/v2/job_templates/$jtId/", + "related": { + "named_url": "/api/v2/job_templates/hello_world_job_template/", + "created_by": "/api/v2/users/1/", + "modified_by": "/api/v2/users/1/", + "labels": "/api/v2/job_templates/$jtId/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/8/", + "extra_credentials": "/api/v2/job_templates/$jtId/extra_credentials/", + "credentials": "/api/v2/job_templates/$jtId/credentials/", + "last_job": "/api/v2/jobs/222/", + "jobs": "/api/v2/job_templates/$jtId/jobs/", + "schedules": "/api/v2/job_templates/$jtId/schedules/", + "activity_stream": "/api/v2/job_templates/$jtId/activity_stream/", + "launch": "/api/v2/job_templates/$jtId/launch/", + "notification_templates_any": "/api/v2/job_templates/$jtId/notification_templates_any/", + "notification_templates_success": "/api/v2/job_templates/$jtId/notification_templates_success/", + "notification_templates_error": "/api/v2/job_templates/$jtId/notification_templates_error/", + "access_list": "/api/v2/job_templates/$jtId/access_list/", + "survey_spec": "/api/v2/job_templates/$jtId/survey_spec/", + "object_roles": "/api/v2/job_templates/$jtId/object_roles/", + "instance_groups": "/api/v2/job_templates/$jtId/instance_groups/", + "slice_workflow_jobs": "/api/v2/job_templates/$jtId/slice_workflow_jobs/", + "copy": "/api/v2/job_templates/$jtId/copy/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Demo Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" + }, + "project": { + "id": 8, + "name": "cds_playbooks", + "description": "CDS - cds_playbooks Project", + "status": "ok", + "scm_type": "" + }, + "last_job": { + "id": 222, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "finished": "2019-06-12T11:20:27.892787Z", + "status": "successful", + "failed": false + }, + "last_update": { + "id": 222, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "status": "successful", + "failed": false + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "modified_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "object_roles": { + "admin_role": { + "description": "Can manage all aspects of the job template", + "name": "Admin", + "id": 51 + }, + "execute_role": { + "description": "May run the job template", + "name": "Execute", + "id": 52 + }, + "read_role": { + "description": "May view settings for the job template", + "name": "Read", + "id": 53 + } + }, + "user_capabilities": { + "edit": true, + "delete": true, + "start": true, + "schedule": true, + "copy": true + }, + "labels": { + "count": 0, + "results": [] + }, + "survey": { + "title": "", + "description": "" + }, + "recent_jobs": [ + { + "id": 222, + "status": "successful", + "finished": "2019-06-12T11:20:27.892787Z", + "type": "job" + }, + { + "id": 65, + "status": "successful", + "finished": "2019-06-03T18:27:19.114796Z", + "type": "job" + }, + { + "id": 64, + "status": "successful", + "finished": "2019-06-03T18:26:53.606618Z", + "type": "job" + }, + { + "id": 63, + "status": "successful", + "finished": "2019-06-03T18:24:36.072943Z", + "type": "job" + }, + { + "id": 62, + "status": "successful", + "finished": "2019-06-03T18:17:50.616528Z", + "type": "job" + }, + { + "id": 61, + "status": "successful", + "finished": "2019-06-03T18:04:42.995611Z", + "type": "job" + }, + { + "id": 60, + "status": "successful", + "finished": "2019-06-03T17:47:13.983951Z", + "type": "job" + }, + { + "id": 50, + "status": "successful", + "finished": "2019-05-30T15:47:55.700161Z", + "type": "job" + }, + { + "id": 49, + "status": "successful", + "finished": "2019-05-29T14:46:51.615926Z", + "type": "job" + }, + { + "id": 47, + "status": "successful", + "finished": "2019-05-27T20:23:58.656709Z", + "type": "job" + } + ], + "extra_credentials": [], + "credentials": [] + }, + "created": "2019-05-21T19:28:05.953730Z", + "modified": "2019-05-21T20:06:55.728697Z", + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "job_type": "run", + "inventory": 1, + "project": 8, + "playbook": "hello_world.yml", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "", + "job_tags": "", + "force_handlers": false, + "skip_tags": "", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": false, + "last_job_run": "2019-06-12T11:20:27.892787Z", + "last_job_failed": false, + "next_job_run": null, + "status": "successful", + "host_config_key": "", + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": true, + "ask_limit_on_launch": true, + "ask_tags_on_launch": true, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "survey_enabled": true, + "become_enabled": false, + "diff_mode": false, + "allow_simultaneous": false, + "custom_virtualenv": null, + "job_slice_count": 1, + "credential": null, + "vault_credential": null + }""" - every { - svc.setNodeTemplateAttributeValue( - "execute-remote-ansible", - "execute-command-logs", "N/A".asJsonPrimitive()) - } returns Unit + private fun getJobTemplateLaunch(jtId: Int) = """{ + "can_start_without_user_input": false, + "passwords_needed_to_start": [], + "ask_variables_on_launch": true, + "ask_tags_on_launch": true, + "ask_diff_mode_on_launch": false, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_limit_on_launch": true, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "survey_enabled": true, + "variables_needed_to_start": [ + "tor_group", + "site_id" + ], + "credential_needed_to_start": false, + "inventory_needed_to_start": false, + "job_template_data": { + "name": "hello_world_job_template", + "id": $jtId, + "description": "hello_world Runner Job Template" + }, + "defaults": { + "extra_vars": "", + "diff_mode": false, + "limit": "", + "job_tags": "", + "skip_tags": "", + "job_type": "run", + "verbosity": 0, + "inventory": { + "name": "Demo Inventory", + "id": 1 + } + } + }""" - every { - svc.setNodeTemplateAttributeValue( - "execute-remote-ansible", - "execute-command-logs", - "processed successfully".asJsonPrimitive()) - } returns Unit + private fun getInventory() = """{ + "count": 1, + "next": null, + "previous": null, + "results": [ + { + "id": 1, + "type": "inventory", + "url": "/api/v2/inventories/1/", + "related": { + "created_by": "/api/v2/users/1/", + "modified_by": "/api/v2/users/1/", + "hosts": "/api/v2/inventories/1/hosts/", + "groups": "/api/v2/inventories/1/groups/", + "root_groups": "/api/v2/inventories/1/root_groups/", + "variable_data": "/api/v2/inventories/1/variable_data/", + "script": "/api/v2/inventories/1/script/", + "tree": "/api/v2/inventories/1/tree/", + "inventory_sources": "/api/v2/inventories/1/inventory_sources/", + "update_inventory_sources": "/api/v2/inventories/1/update_inventory_sources/", + "activity_stream": "/api/v2/inventories/1/activity_stream/", + "job_templates": "/api/v2/inventories/1/job_templates/", + "ad_hoc_commands": "/api/v2/inventories/1/ad_hoc_commands/", + "access_list": "/api/v2/inventories/1/access_list/", + "object_roles": "/api/v2/inventories/1/object_roles/", + "instance_groups": "/api/v2/inventories/1/instance_groups/", + "copy": "/api/v2/inventories/1/copy/", + "organization": "/api/v2/organizations/1/" + }, + "summary_fields": { + "organization": { + "id": 1, + "name": "Default", + "description": "" + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "modified_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "object_roles": { + "admin_role": { + "description": "Can manage all aspects of the inventory", + "name": "Admin", + "id": 21 + }, + "update_role": { + "description": "May update project or inventory or group using the configured source update system", + "name": "Update", + "id": 22 + }, + "adhoc_role": { + "description": "May run ad hoc commands on an inventory", + "name": "Ad Hoc", + "id": 23 + }, + "use_role": { + "description": "Can use the inventory in a job template", + "name": "Use", + "id": 24 + }, + "read_role": { + "description": "May view settings for the inventory", + "name": "Read", + "id": 25 + } + }, + "user_capabilities": { + "edit": true, + "delete": true, + "copy": true, + "adhoc": true + } + }, + "created": "2019-05-21T15:45:31.954359Z", + "modified": "2019-05-21T15:45:31.954378Z", + "name": "Demo Inventory", + "description": "", + "organization": 1, + "kind": "", + "host_filter": null, + "variables": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "insights_credential": null, + "pending_deletion": false + } + ] + }""" - every { - svc.bluePrintContext() - } returns bluePrintRuntimeService.bluePrintContext() - return executionServiceInput - } + private fun newJobTemplateLaunch(jtId: Int, jobId: Int) = """{ + "job": $jobId, + "ignored_fields": {}, + "id": $jobId, + "type": "job", + "url": "/api/v2/jobs/$jobId/", + "related": { + "created_by": "/api/v2/users/1/", + "modified_by": "/api/v2/users/1/", + "labels": "/api/v2/jobs/$jobId/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/8/", + "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/", + "credentials": "/api/v2/jobs/$jobId/credentials/", + "unified_job_template": "/api/v2/job_templates/$jtId/", + "stdout": "/api/v2/jobs/$jobId/stdout/", + "job_events": "/api/v2/jobs/$jobId/job_events/", + "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/", + "activity_stream": "/api/v2/jobs/$jobId/activity_stream/", + "notifications": "/api/v2/jobs/$jobId/notifications/", + "job_template": "/api/v2/job_templates/$jtId/", + "cancel": "/api/v2/jobs/$jobId/cancel/", + "create_schedule": "/api/v2/jobs/$jobId/create_schedule/", + "relaunch": "/api/v2/jobs/$jobId/relaunch/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Demo Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" + }, + "project": { + "id": 8, + "name": "cds_playbooks", + "description": "CDS - cds_playbooks Project", + "status": "ok", + "scm_type": "" + }, + "job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template" + }, + "unified_job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "unified_job_type": "job" + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "modified_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "delete": true, + "start": true + }, + "labels": { + "count": 0, + "results": [] + }, + "extra_credentials": [], + "credentials": [] + }, + "created": "2019-06-12T11:21:26.891986Z", + "modified": "2019-06-12T11:21:27.016410Z", + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "job_type": "run", + "inventory": 1, + "project": 8, + "playbook": "hello_world.yml", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}", + "job_tags": "", + "force_handlers": false, + "skip_tags": "", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": false, + "unified_job_template": $jtId, + "launch_type": "manual", + "status": "pending", + "failed": false, + "started": null, + "finished": null, + "elapsed": 0, + "job_args": "", + "job_cwd": "", + "job_env": {}, + "job_explanation": "", + "execution_node": "", + "controller_node": "", + "result_traceback": "", + "event_processing_finished": false, + "job_template": $jtId, + "passwords_needed_to_start": [], + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": true, + "ask_limit_on_launch": true, + "ask_tags_on_launch": true, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "allow_simultaneous": false, + "artifacts": {}, + "scm_revision": "", + "instance_group": null, + "diff_mode": false, + "job_slice_number": 0, + "job_slice_count": 1, + "credential": null, + "vault_credential": null + }""" + + private fun getJobStatus1(jtId: Int, jobId: Int) = """{ + "id": $jobId, + "type": "job", + "url": "/api/v2/jobs/$jobId/", + "related": { + "created_by": "/api/v2/users/1/", + "labels": "/api/v2/jobs/$jobId/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/8/", + "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/", + "credentials": "/api/v2/jobs/$jobId/credentials/", + "unified_job_template": "/api/v2/job_templates/$jtId/", + "stdout": "/api/v2/jobs/$jobId/stdout/", + "job_events": "/api/v2/jobs/$jobId/job_events/", + "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/", + "activity_stream": "/api/v2/jobs/$jobId/activity_stream/", + "notifications": "/api/v2/jobs/$jobId/notifications/", + "job_template": "/api/v2/job_templates/$jtId/", + "cancel": "/api/v2/jobs/$jobId/cancel/", + "create_schedule": "/api/v2/jobs/$jobId/create_schedule/", + "relaunch": "/api/v2/jobs/$jobId/relaunch/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Demo Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" + }, + "project": { + "id": 8, + "name": "cds_playbooks", + "description": "CDS - cds_playbooks Project", + "status": "ok", + "scm_type": "" + }, + "job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template" + }, + "unified_job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "unified_job_type": "job" + }, + "instance_group": { + "name": "tower", + "id": 1 + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "delete": true, + "start": true + }, + "labels": { + "count": 0, + "results": [] + }, + "extra_credentials": [], + "credentials": [] + }, + "created": "2019-06-12T11:21:26.891986Z", + "modified": "2019-06-12T11:21:27.355185Z", + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "job_type": "run", + "inventory": 1, + "project": 8, + "playbook": "hello_world.yml", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}", + "job_tags": "", + "force_handlers": false, + "skip_tags": "", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": false, + "unified_job_template": $jtId, + "launch_type": "manual", + "status": "waiting", + "failed": false, + "started": null, + "finished": null, + "elapsed": 0, + "job_args": "", + "job_cwd": "", + "job_env": {}, + "job_explanation": "", + "execution_node": "awx", + "controller_node": "", + "result_traceback": "", + "event_processing_finished": false, + "job_template": $jtId, + "passwords_needed_to_start": [], + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": true, + "ask_limit_on_launch": true, + "ask_tags_on_launch": true, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "allow_simultaneous": false, + "artifacts": {}, + "scm_revision": "", + "instance_group": 1, + "diff_mode": false, + "job_slice_number": 0, + "job_slice_count": 1, + "host_status_counts": {}, + "playbook_counts": { + "play_count": 0, + "task_count": 0 + }, + "custom_virtualenv": null, + "credential": null, + "vault_credential": null + }""" + + private fun getJobStatus2(jtId: Int, jobId: Int) = """{ + "id": $jobId, + "type": "job", + "url": "/api/v2/jobs/$jobId/", + "related": { + "created_by": "/api/v2/users/1/", + "labels": "/api/v2/jobs/$jobId/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/8/", + "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/", + "credentials": "/api/v2/jobs/$jobId/credentials/", + "unified_job_template": "/api/v2/job_templates/$jtId/", + "stdout": "/api/v2/jobs/$jobId/stdout/", + "job_events": "/api/v2/jobs/$jobId/job_events/", + "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/", + "activity_stream": "/api/v2/jobs/$jobId/activity_stream/", + "notifications": "/api/v2/jobs/$jobId/notifications/", + "job_template": "/api/v2/job_templates/$jtId/", + "cancel": "/api/v2/jobs/$jobId/cancel/", + "create_schedule": "/api/v2/jobs/$jobId/create_schedule/", + "relaunch": "/api/v2/jobs/$jobId/relaunch/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Demo Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" + }, + "project": { + "id": 8, + "name": "cds_playbooks", + "description": "CDS - cds_playbooks Project", + "status": "ok", + "scm_type": "" + }, + "job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template" + }, + "unified_job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "unified_job_type": "job" + }, + "instance_group": { + "name": "tower", + "id": 1 + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "delete": true, + "start": true + }, + "labels": { + "count": 0, + "results": [] + }, + "extra_credentials": [], + "credentials": [] + }, + "created": "2019-06-12T11:21:26.891986Z", + "modified": "2019-06-12T11:21:27.355185Z", + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "job_type": "run", + "inventory": 1, + "project": 8, + "playbook": "hello_world.yml", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}", + "job_tags": "", + "force_handlers": false, + "skip_tags": "", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": false, + "unified_job_template": $jtId, + "launch_type": "manual", + "status": "running", + "failed": false, + "started": "2019-06-12T11:21:27.510766Z", + "finished": null, + "elapsed": 10.862184, + "job_args": "[\"ansible-playbook\", \"-u\", \"root\", \"-i\", \"/tmp/awx_223_ft8hu4p4/tmptmtwllu4\", \"-e\", \"@/tmp/awx_223_ft8hu4p4/env/extravars\", \"hello_world.yml\"]", + "job_cwd": "/var/lib/awx/projects/cds_playbooks_folder", + "job_env": { + "HOSTNAME": "awx", + "LC_ALL": "en_US.UTF-8", + "VIRTUAL_ENV": "/var/lib/awx/venv/ansible", + "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", + "SUPERVISOR_GROUP_NAME": "tower-processes", + "PWD": "/var/lib/awx", + "LANG": "en_US.UTF-8", + "PS1": "(awx) ", + "SUPERVISOR_ENABLED": "1", + "HOME": "/var/lib/awx", + "SHLVL": "2", + "LANGUAGE": "en_US.UTF-8", + "LC_CTYPE": "en_US.UTF-8", + "SUPERVISOR_PROCESS_NAME": "dispatcher", + "SUPERVISOR_SERVER_URL": "unix:///tmp/supervisor.sock", + "DJANGO_SETTINGS_MODULE": "awx.settings.production", + "DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199", + "TZ": "UTC", + "ANSIBLE_FORCE_COLOR": "True", + "ANSIBLE_HOST_KEY_CHECKING": "False", + "ANSIBLE_INVENTORY_UNPARSED_FAILED": "True", + "ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False", + "ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible", + "AWX_PRIVATE_DATA_DIR": "/tmp/awx_223_ft8hu4p4", + "PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python2.7/site-packages:/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/lib:", + "JOB_ID": "$jobId", + "INVENTORY_ID": "1", + "PROJECT_REVISION": "", + "ANSIBLE_RETRY_FILES_ENABLED": "False", + "MAX_EVENT_RES": "700000", + "ANSIBLE_CALLBACK_PLUGINS": "/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/plugins/callback", + "AWX_HOST": "https://towerhost", + "ANSIBLE_SSH_CONTROL_PATH_DIR": "/tmp/awx_223_ft8hu4p4/cp", + "ANSIBLE_STDOUT_CALLBACK": "awx_display", + "AWX_ISOLATED_DATA_DIR": "/tmp/awx_223_ft8hu4p4/artifacts/$jobId" + }, + "job_explanation": "", + "execution_node": "awx", + "controller_node": "", + "result_traceback": "", + "event_processing_finished": false, + "job_template": $jtId, + "passwords_needed_to_start": [], + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": true, + "ask_limit_on_launch": true, + "ask_tags_on_launch": true, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "allow_simultaneous": false, + "artifacts": {}, + "scm_revision": "", + "instance_group": 1, + "diff_mode": false, + "job_slice_number": 0, + "job_slice_count": 1, + "host_status_counts": {}, + "playbook_counts": { + "play_count": 1, + "task_count": 1 + }, + "custom_virtualenv": "/var/lib/awx/venv/ansible", + "credential": null, + "vault_credential": null + }""" + + private fun getJobStatus3(jtId: Int, jobId: Int) = """{ + "id": $jobId, + "type": "job", + "url": "/api/v2/jobs/$jobId/", + "related": { + "created_by": "/api/v2/users/1/", + "labels": "/api/v2/jobs/$jobId/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/8/", + "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/", + "credentials": "/api/v2/jobs/$jobId/credentials/", + "unified_job_template": "/api/v2/job_templates/$jtId/", + "stdout": "/api/v2/jobs/$jobId/stdout/", + "job_events": "/api/v2/jobs/$jobId/job_events/", + "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/", + "activity_stream": "/api/v2/jobs/$jobId/activity_stream/", + "notifications": "/api/v2/jobs/$jobId/notifications/", + "job_template": "/api/v2/job_templates/$jtId/", + "cancel": "/api/v2/jobs/$jobId/cancel/", + "create_schedule": "/api/v2/jobs/$jobId/create_schedule/", + "relaunch": "/api/v2/jobs/$jobId/relaunch/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Demo Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" + }, + "project": { + "id": 8, + "name": "cds_playbooks", + "description": "CDS - cds_playbooks Project", + "status": "ok", + "scm_type": "" + }, + "job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template" + }, + "unified_job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "unified_job_type": "job" + }, + "instance_group": { + "name": "tower", + "id": 1 + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "delete": true, + "start": true + }, + "labels": { + "count": 0, + "results": [] + }, + "extra_credentials": [], + "credentials": [] + }, + "created": "2019-06-12T11:21:26.891986Z", + "modified": "2019-06-12T11:21:27.355185Z", + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "job_type": "run", + "inventory": 1, + "project": 8, + "playbook": "hello_world.yml", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}", + "job_tags": "", + "force_handlers": false, + "skip_tags": "", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": false, + "unified_job_template": $jtId, + "launch_type": "manual", + "status": "running", + "failed": false, + "started": "2019-06-12T11:21:27.510766Z", + "finished": null, + "elapsed": 21.297881, + "job_args": "[\"ansible-playbook\", \"-u\", \"root\", \"-i\", \"/tmp/awx_223_ft8hu4p4/tmptmtwllu4\", \"-e\", \"@/tmp/awx_223_ft8hu4p4/env/extravars\", \"hello_world.yml\"]", + "job_cwd": "/var/lib/awx/projects/cds_playbooks_folder", + "job_env": { + "HOSTNAME": "awx", + "LC_ALL": "en_US.UTF-8", + "VIRTUAL_ENV": "/var/lib/awx/venv/ansible", + "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", + "SUPERVISOR_GROUP_NAME": "tower-processes", + "PWD": "/var/lib/awx", + "LANG": "en_US.UTF-8", + "PS1": "(awx) ", + "SUPERVISOR_ENABLED": "1", + "HOME": "/var/lib/awx", + "SHLVL": "2", + "LANGUAGE": "en_US.UTF-8", + "LC_CTYPE": "en_US.UTF-8", + "SUPERVISOR_PROCESS_NAME": "dispatcher", + "SUPERVISOR_SERVER_URL": "unix:///tmp/supervisor.sock", + "DJANGO_SETTINGS_MODULE": "awx.settings.production", + "DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199", + "TZ": "UTC", + "ANSIBLE_FORCE_COLOR": "True", + "ANSIBLE_HOST_KEY_CHECKING": "False", + "ANSIBLE_INVENTORY_UNPARSED_FAILED": "True", + "ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False", + "ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible", + "AWX_PRIVATE_DATA_DIR": "/tmp/awx_223_ft8hu4p4", + "PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python2.7/site-packages:/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/lib:", + "JOB_ID": "$jobId", + "INVENTORY_ID": "1", + "PROJECT_REVISION": "", + "ANSIBLE_RETRY_FILES_ENABLED": "False", + "MAX_EVENT_RES": "700000", + "ANSIBLE_CALLBACK_PLUGINS": "/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/plugins/callback", + "AWX_HOST": "https://towerhost", + "ANSIBLE_SSH_CONTROL_PATH_DIR": "/tmp/awx_223_ft8hu4p4/cp", + "ANSIBLE_STDOUT_CALLBACK": "awx_display", + "AWX_ISOLATED_DATA_DIR": "/tmp/awx_223_ft8hu4p4/artifacts/$jobId" + }, + "job_explanation": "", + "execution_node": "awx", + "controller_node": "", + "result_traceback": "", + "event_processing_finished": false, + "job_template": $jtId, + "passwords_needed_to_start": [], + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": true, + "ask_limit_on_launch": true, + "ask_tags_on_launch": true, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "allow_simultaneous": false, + "artifacts": {}, + "scm_revision": "", + "instance_group": 1, + "diff_mode": false, + "job_slice_number": 0, + "job_slice_count": 1, + "host_status_counts": {}, + "playbook_counts": { + "play_count": 1, + "task_count": 2 + }, + "custom_virtualenv": "/var/lib/awx/venv/ansible", + "credential": null, + "vault_credential": null + } """ + + private fun getJobStatus4(jtId: Int, jobId: Int) = """{ + "id": $jobId, + "type": "job", + "url": "/api/v2/jobs/$jobId/", + "related": { + "created_by": "/api/v2/users/1/", + "labels": "/api/v2/jobs/$jobId/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/8/", + "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/", + "credentials": "/api/v2/jobs/$jobId/credentials/", + "unified_job_template": "/api/v2/job_templates/$jtId/", + "stdout": "/api/v2/jobs/$jobId/stdout/", + "job_events": "/api/v2/jobs/$jobId/job_events/", + "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/", + "activity_stream": "/api/v2/jobs/$jobId/activity_stream/", + "notifications": "/api/v2/jobs/$jobId/notifications/", + "job_template": "/api/v2/job_templates/$jtId/", + "cancel": "/api/v2/jobs/$jobId/cancel/", + "create_schedule": "/api/v2/jobs/$jobId/create_schedule/", + "relaunch": "/api/v2/jobs/$jobId/relaunch/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Demo Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" + }, + "project": { + "id": 8, + "name": "cds_playbooks", + "description": "CDS - cds_playbooks Project", + "status": "ok", + "scm_type": "" + }, + "job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template" + }, + "unified_job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "unified_job_type": "job" + }, + "instance_group": { + "name": "tower", + "id": 1 + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "delete": true, + "start": true + }, + "labels": { + "count": 0, + "results": [] + }, + "extra_credentials": [], + "credentials": [] + }, + "created": "2019-06-12T11:21:26.891986Z", + "modified": "2019-06-12T11:21:27.355185Z", + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "job_type": "run", + "inventory": 1, + "project": 8, + "playbook": "hello_world.yml", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}", + "job_tags": "", + "force_handlers": false, + "skip_tags": "", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": false, + "unified_job_template": $jtId, + "launch_type": "manual", + "status": "successful", + "failed": false, + "started": "2019-06-12T11:21:27.510766Z", + "finished": "2019-06-12T11:21:48.993385Z", + "elapsed": 21.483, + "job_args": "[\"ansible-playbook\", \"-u\", \"root\", \"-i\", \"/tmp/awx_223_ft8hu4p4/tmptmtwllu4\", \"-e\", \"@/tmp/awx_223_ft8hu4p4/env/extravars\", \"hello_world.yml\"]", + "job_cwd": "/var/lib/awx/projects/cds_playbooks_folder", + "job_env": { + "HOSTNAME": "awx", + "LC_ALL": "en_US.UTF-8", + "VIRTUAL_ENV": "/var/lib/awx/venv/ansible", + "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", + "SUPERVISOR_GROUP_NAME": "tower-processes", + "PWD": "/var/lib/awx", + "LANG": "en_US.UTF-8", + "PS1": "(awx) ", + "SUPERVISOR_ENABLED": "1", + "HOME": "/var/lib/awx", + "SHLVL": "2", + "LANGUAGE": "en_US.UTF-8", + "LC_CTYPE": "en_US.UTF-8", + "SUPERVISOR_PROCESS_NAME": "dispatcher", + "SUPERVISOR_SERVER_URL": "unix:///tmp/supervisor.sock", + "DJANGO_SETTINGS_MODULE": "awx.settings.production", + "DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199", + "TZ": "UTC", + "ANSIBLE_FORCE_COLOR": "True", + "ANSIBLE_HOST_KEY_CHECKING": "False", + "ANSIBLE_INVENTORY_UNPARSED_FAILED": "True", + "ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False", + "ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible", + "AWX_PRIVATE_DATA_DIR": "/tmp/awx_223_ft8hu4p4", + "PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python2.7/site-packages:/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/lib:", + "JOB_ID": "$jobId", + "INVENTORY_ID": "1", + "PROJECT_REVISION": "", + "ANSIBLE_RETRY_FILES_ENABLED": "False", + "MAX_EVENT_RES": "700000", + "ANSIBLE_CALLBACK_PLUGINS": "/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/plugins/callback", + "AWX_HOST": "https://towerhost", + "ANSIBLE_SSH_CONTROL_PATH_DIR": "/tmp/awx_223_ft8hu4p4/cp", + "ANSIBLE_STDOUT_CALLBACK": "awx_display", + "AWX_ISOLATED_DATA_DIR": "/tmp/awx_223_ft8hu4p4/artifacts/$jobId" + }, + "job_explanation": "", + "execution_node": "awx", + "controller_node": "", + "result_traceback": "", + "event_processing_finished": true, + "job_template": $jtId, + "passwords_needed_to_start": [], + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": true, + "ask_limit_on_launch": true, + "ask_tags_on_launch": true, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "allow_simultaneous": false, + "artifacts": {}, + "scm_revision": "", + "instance_group": 1, + "diff_mode": false, + "job_slice_number": 0, + "job_slice_count": 1, + "host_status_counts": { + "ok": 1 + }, + "playbook_counts": { + "play_count": 1, + "task_count": 2 + }, + "custom_virtualenv": "/var/lib/awx/venv/ansible", + "credential": null, + "vault_credential": null + }""" + + private fun getReport() = """ + +PLAY [Hello World Sample] ****************************************************** + +TASK [Gathering Facts] ********************************************************* +ok: [localhost] + +TASK [Hello Message] *********************************************************** +ok: [localhost] => { + "msg": "Hello World!" } -//class MockRemoteScriptExecutionService : RemoteScriptExecutionService { -// override suspend fun init(selector: String) { -// } -// -// override suspend fun prepareEnv(prepareEnvInput: PrepareRemoteEnvInput): RemoteScriptExecutionOutput { -// assertEquals(prepareEnvInput.requestId, "123456-1000", "failed to match request id") -// assertNotNull(prepareEnvInput.packages, "failed to get packages") -// -// val remoteScriptExecutionOutput = mockk<RemoteScriptExecutionOutput>() -// every { remoteScriptExecutionOutput.response } returns "prepared successfully" -// every { remoteScriptExecutionOutput.status } returns StatusType.SUCCESS -// return remoteScriptExecutionOutput -// } -// -// override suspend fun executeCommand(remoteExecutionInput: RemoteScriptExecutionInput): RemoteScriptExecutionOutput { -// assertEquals(remoteExecutionInput.requestId, "123456-1000", "failed to match request id") -// -// val remoteScriptExecutionOutput = mockk<RemoteScriptExecutionOutput>() -// every { remoteScriptExecutionOutput.response } returns "processed successfully" -// every { remoteScriptExecutionOutput.status } returns StatusType.SUCCESS -// return remoteScriptExecutionOutput -// } -// -// override suspend fun close() { -// -// } -//} +PLAY RECAP ********************************************************************* +localhost : ok=2 changed=0 unreachable=0 failed=0 + +""" +} diff --git a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/resources/application-test.properties b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/resources/application-test.properties new file mode 100644 index 000000000..527eb8a26 --- /dev/null +++ b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/resources/application-test.properties @@ -0,0 +1,35 @@ +# +# Copyright © 2017-2018 AT&T Intellectual Property. +# +# Modifications Copyright © 2019 IBM, Bell Canada. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +blueprintsprocessor.db.primary.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 +blueprintsprocessor.db.primary.username=sa +blueprintsprocessor.db.primary.password= +blueprintsprocessor.db.primary.driverClassName=org.h2.Driver +blueprintsprocessor.db.primary.hibernateHbm2ddlAuto=create-drop +blueprintsprocessor.db.primary.hibernateDDLAuto=update +blueprintsprocessor.db.primary.hibernateNamingStrategy=org.hibernate.cfg.ImprovedNamingStrategy +blueprintsprocessor.db.primary.hibernateDialect=org.hibernate.dialect.H2Dialect +# Controller Blueprints Core Configuration +blueprintsprocessor.blueprintDeployPath=./target/blueprints/deploy +blueprintsprocessor.blueprintArchivePath=./target/blueprints/archive + +# Python executor +blueprints.processor.functions.python.executor.executionPath=./../../../../components/scripts/python/ccsdk_blueprints +blueprints.processor.functions.python.executor.modulePaths=./../../../../components/scripts/python/ccsdk_blueprints + +# Executor Options +blueprintprocessor.netconfExecutor.enabled=true
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/resources/payload/requests/remote-ansible-request-full.json b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/resources/payload/requests/remote-ansible-request-full.json new file mode 100644 index 000000000..11bb90b50 --- /dev/null +++ b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/resources/payload/requests/remote-ansible-request-full.json @@ -0,0 +1,32 @@ +{ + "actionIdentifiers": { + "blueprintName": "remote_ansible", + "blueprintVersion": "1.0.0", + "actionName": "execute-remote-ansible", + "mode": "sync" + }, + "commonHeader": { + "flags": { + "force": true, + "ttl": 3600 + }, + "originatorId": "mock", + "requestId": "123456-2000", + "subRequestId": "sub-123456-1000", + "timestamp": "2012-04-23T18:25:43.511Z" + }, + "payload": { + "execute-remote-ansible-request": { + "endpoint-selector": "awx", + "job-template-name": "hello_world_job_template", + "inventory": "Demo Inventory", + "limit": "123", + "tags": "some-tag", + "skip-tags": "some-skip-tag", + "extra-vars": { + "site_id": "3 - Belmont", + "tor_group": "vEPC" + } + } + } +} |