diff options
63 files changed, 2827 insertions, 41 deletions
diff --git a/.gitignore b/.gitignore index e3e0e1f22..a2661f06f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # Node.js **/node +# Python +**/*.pyc + # Logs logs *.log diff --git a/cds-ui/client/src/app/feature-modules/blueprint/test-template/test-template.component.html b/cds-ui/client/src/app/feature-modules/blueprint/test-template/test-template.component.html index c69c511e6..fe322fada 100644 --- a/cds-ui/client/src/app/feature-modules/blueprint/test-template/test-template.component.html +++ b/cds-ui/client/src/app/feature-modules/blueprint/test-template/test-template.component.html @@ -21,7 +21,12 @@ limitations under the License. <div style="border: 1px solid #3f51b5; padding: 1em;"> <i class="fa fa-exclamation-circle" style="color: #3f51b5" aria-hidden="true"></i> - + Disclaimer*: The Test CBA Certification page allow the testing/certification team with the certification + of the CBA workflow action. Workflow action may include various action and subaction that result in content + resolution (using mS such as naming , netbox , and etc.), content generation (Jinja/Velocity) and content + distribution (netconf, restconf etc.) . Once the certification is complete, it is the responsibility of the + testing/certification team to rollback all the resource assignment and network function configuration that has + been reserved and distributed during the certification. </div> <div class="testTemplateContainer"> <div class="editorContainer"> diff --git a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/resources_definition_types.json b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/resources_definition_types.json index d926aa3fc..b771d25f9 100644 --- a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/resources_definition_types.json +++ b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/resources_definition_types.json @@ -68,8 +68,9 @@ "primary-config-data": { "type": "source-rest", "properties": { + "verb": "GET", "type": "JSON", - "url-path": "config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/vnf_name", + "url-path": "/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/vnf_name", "path": "/param/0/value", "input-key-mapping": { "service-instance-id": "service-instance-id", @@ -85,5 +86,92 @@ } } } + }, + "aai-get-resource": { + "tags": "aai-get", + "name": "aai-get-resource", + "property": { + "description": "primary aai data to get resource", + "type": "string" + }, + "updated-by": "Steve, Siani <steve.djissitchi@bell.ca>", + "sources": { + "primary-aai-data": { + "type": "source-rest", + "properties": { + "type": "JSON", + "verb": "GET", + "url-path": "/aai/v14/network/generic-vnfs/generic-vnf/$vnf-id", + "path": "", + "input-key-mapping": { + "vnf-id": "vnf-id" + }, + "output-key-mapping": { + }, + "key-dependencies": [ + "vnf-id" + ] + } + } + } + }, + "aai-put-resource": { + "tags": "aai-put", + "name": "aai-put-resource", + "property": { + "description": "primary aai data to update resource", + "type": "string" + }, + "updated-by": "Steve, Siani <steve.djissitchi@bell.ca>", + "sources": { + "primary-aai-data": { + "type": "source-rest", + "properties": { + "type": "JSON", + "verb": "PUT", + "url-path": "/query?format=resource", + "path": "", + "payload": "{\r\n\"start\": \"\\/nodes\\/vf-modules?vf-module-name=vf-module-name\",\r\n\"query\": \"\\/query\\/related-to?startingNodeType=vf-module&relatedToNodeType=generic-vnf\"\r\n}", + + "input-key-mapping": { + "vnf-id": "vnf-id" + }, + "output-key-mapping": { + }, + "key-dependencies": [ + "vnf-id" + ] + } + } + } + }, + "aai-post-resource": { + "tags": "aai-port", + "name": "aai-port-resource", + "property": { + "description": "primary aai data to create new resource", + "type": "string" + }, + "updated-by": "Steve, Siani <steve.djissitchi@bell.ca>", + "sources": { + "primary-aai-data": { + "type": "source-rest", + "properties": { + "type": "JSON", + "verb": "POST", + "url-path": "/aai/add/uri/here", + "path": "", + "payload": "", + "input-key-mapping": { + "vnf-id": "vnf-id" + }, + "output-key-mapping": { + }, + "key-dependencies": [ + "vnf-id" + ] + } + } + } } }
\ No newline at end of file diff --git a/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/artifact_types.json b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/artifact_types.json new file mode 100644 index 000000000..445236354 --- /dev/null +++ b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/artifact_types.json @@ -0,0 +1,12 @@ +{ + "artifact_types": { + "artifact-script-python": { + "description": "Python Script file", + "version": "1.0.0", + "derived_from": "tosca.artifacts.Implementation", + "file_ext": [ + "py" + ] + } + } +}
\ No newline at end of file diff --git a/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/data_types.json b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/data_types.json new file mode 100644 index 000000000..b22e30d00 --- /dev/null +++ b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/data_types.json @@ -0,0 +1,3 @@ +{ + "data_types": {} +}
\ No newline at end of file diff --git a/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/node_types.json b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/node_types.json new file mode 100644 index 000000000..cd63f0091 --- /dev/null +++ b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/node_types.json @@ -0,0 +1,51 @@ +{ + "node_types": { + "component-remote-python-executor": { + "description": "This is Remote Python Execution Component.", + "version": "1.0.0", + "attributes": { + "execution-logs": { + "required": true, + "type": "string" + } + }, + "capabilities": { + "component-node": { + "type": "tosca.capabilities.Node" + } + }, + "interfaces": { + "ComponentRemotePythonExecutor": { + "operations": { + "process": { + "inputs": { + "endpoint-selector": { + "description": "Remote Container or Server selector name.", + "required": false, + "type": "string", + "default": "remote-python" + }, + "dynamic-properties": { + "description": "Dynamic Json Content or DSL Json reference.", + "required": false, + "type": "json" + }, + "command": { + "description": "Command to execute.", + "required": true, + "type": "string" + } + } + } + } + } + }, + "derived_from": "tosca.nodes.Component" + }, + "tosca.nodes.Component": { + "description": "This is default Component Node", + "version": "1.0.0", + "derived_from": "tosca.nodes.Root" + } + } +}
\ No newline at end of file diff --git a/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/policy_types.json b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/policy_types.json new file mode 100644 index 000000000..2442ce877 --- /dev/null +++ b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/policy_types.json @@ -0,0 +1,3 @@ +{ + "policy_types": {} +}
\ No newline at end of file diff --git a/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/relationship_types.json b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/relationship_types.json new file mode 100644 index 000000000..097a30afd --- /dev/null +++ b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/relationship_types.json @@ -0,0 +1,3 @@ +{ + "relationship_types": {} +}
\ No newline at end of file diff --git a/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/remote_scripts.json b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/remote_scripts.json new file mode 100644 index 000000000..464911478 --- /dev/null +++ b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/remote_scripts.json @@ -0,0 +1,85 @@ +{ + "tosca_definitions_version": "controller_blueprint_1_0_0", + "metadata": { + "template_author": "Brinda Santh Muthuramalingam", + "author-email": "brindasanth@in.ibm.com", + "user-groups": "ADMIN, OPERATION", + "template_name": "remote_scripts", + "template_version": "1.0.0", + "template_tags": "brinda, tosca" + }, + "imports": [ + { + "file": "Definitions/data_types.json" + }, + { + "file": "Definitions/relationship_types.json" + }, + { + "file": "Definitions/artifact_types.json" + }, + { + "file": "Definitions/node_types.json" + }, + { + "file": "Definitions/policy_types.json" + } + ], + "topology_template": { + "workflows": { + "execute-remote-python": { + "steps": { + "execute-script": { + "description": "Execute Remote Python Script", + "target": "execute-remote-python", + "activities": [ + { + "call_operation": "" + } + ] + } + }, + "inputs": {}, + "outputs": { + "logs": { + "type": "json", + "value": { + "get_attribute": [ + "execute-remote-python", + "execution-logs" + ] + } + } + } + } + }, + "node_templates": { + "execute-remote-python": { + "type": "component-remote-python-executor", + "interfaces": { + "ComponentRemotePythonExecutor": { + "operations": { + "process": { + "implementation": { + "primary": "component-script", + "dependencies": [ + "pyaml" + ] + }, + "inputs": { + "command": "python SamplePython.py blah" + } + } + } + } + }, + "artifacts": { + "component-script": { + "type": "artifact-script-python", + "file": "Scripts/python/SamplePython.py" + } + } + } + } + } +}
\ No newline at end of file diff --git a/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/resources_definition_types.json b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/resources_definition_types.json new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/resources_definition_types.json @@ -0,0 +1 @@ +{}
\ No newline at end of file diff --git a/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Scripts/python/SamplePython.py b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Scripts/python/SamplePython.py new file mode 100644 index 000000000..5e20e2291 --- /dev/null +++ b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Scripts/python/SamplePython.py @@ -0,0 +1,5 @@ +#!/usr/bin/python + +import sys + +print(sys.argv[1])
\ No newline at end of file diff --git a/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/TOSCA-Metadata/TOSCA.meta b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/TOSCA-Metadata/TOSCA.meta new file mode 100644 index 000000000..5ca8aa031 --- /dev/null +++ b/components/model-catalog/blueprint-model/test-blueprint/remote_scripts/TOSCA-Metadata/TOSCA.meta @@ -0,0 +1,5 @@ +TOSCA-Meta-File-Version: 1.0.0 +CSAR-Version: 1.0 +Created-By: Brinda Santh <brindasanth@in.ibm.com> +Entry-Definitions: Definitions/remote_scripts.json +Template-Tags: Brinda Santh, remote_scripts
\ No newline at end of file diff --git a/components/model-catalog/definition-type/starter-type/node_type/component-remote-python-executor.json b/components/model-catalog/definition-type/starter-type/node_type/component-remote-python-executor.json new file mode 100644 index 000000000..99a4dd8dc --- /dev/null +++ b/components/model-catalog/definition-type/starter-type/node_type/component-remote-python-executor.json @@ -0,0 +1,42 @@ +{ + "description": "This is Remote Python Execution Component.", + "version": "1.0.0", + "attributes": { + "execution-logs": { + "required": true, + "type": "string" + } + }, + "capabilities": { + "component-node": { + "type": "tosca.capabilities.Node" + } + }, + "interfaces": { + "ComponentRemotePythonExecutor": { + "operations": { + "process": { + "inputs": { + "endpoint-selector": { + "description": "Remote Container or Server selector name.", + "required": false, + "type": "string", + "default": "remote-python" + }, + "dynamic-properties": { + "description": "Dynamic Json Content or DSL Json reference.", + "required": false, + "type": "json" + }, + "command": { + "description": "Command to execute.", + "required": true, + "type": "string" + } + } + } + } + } + }, + "derived_from": "tosca.nodes.Component" +}
\ No newline at end of file diff --git a/components/model-catalog/proto-definition/proto/CommandExecutor.proto b/components/model-catalog/proto-definition/proto/CommandExecutor.proto new file mode 100644 index 000000000..f488cc1b4 --- /dev/null +++ b/components/model-catalog/proto-definition/proto/CommandExecutor.proto @@ -0,0 +1,62 @@ +syntax = "proto3"; +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; +option java_multiple_files = true; +package org.onap.ccsdk.cds.controllerblueprints.command.api; + +message ExecutionInput { + string requestId = 1; + // Optional Id used to correlate multiple requests so that it can identify previous request information. + string correlationId = 2; + // Optional Blueprint Information used to identify CBA content information in shared file structure environment. + Identifiers identifiers = 3; + ScriptType scriptType = 4; + // Actual Command to Execute in Scripting Environment + string command = 5; + int32 timeOut = 6; + // Extra Dynamic Properties for Command processing in JSON format + google.protobuf.Struct properties = 7; + // Request Time Stamp + google.protobuf.Timestamp timestamp = 8; +} + +message PrepareEnvInput { + Identifiers identifiers = 1; + string requestId = 2; + // Optional Id used to correlate multiple requests so that it can identify previous request information. + string correlationId = 3; + ScriptType scriptType = 4; + repeated string packages = 5; + int32 timeOut = 6; + google.protobuf.Struct properties = 7; + google.protobuf.Timestamp timestamp = 8; +} + +message Identifiers { + string blueprintName = 1; + string blueprintVersion = 2; +} + +message ExecutionOutput { + string requestId = 1; + string response = 2; + ResponseStatus status = 3; + google.protobuf.Timestamp timestamp = 4; +} + +enum ResponseStatus { + SUCCESS = 0; + FAILURE = 1; +} + +enum ScriptType { + PYTHON = 0; + ANSIBLE = 1; + KOTLIN = 2; + SH = 3; +} + +service CommandExecutorService { + rpc prepareEnv (PrepareEnvInput) returns (ExecutionOutput); + rpc executeCommand (ExecutionInput) returns (ExecutionOutput); +} diff --git a/docs/datadictionary/media/image0.JPG b/docs/datadictionary/image0.JPG Binary files differindex 074d20076..074d20076 100644 --- a/docs/datadictionary/media/image0.JPG +++ b/docs/datadictionary/image0.JPG diff --git a/docs/datadictionary/media/image1.JPG b/docs/datadictionary/image1.JPG Binary files differindex a27502a75..a27502a75 100644 --- a/docs/datadictionary/media/image1.JPG +++ b/docs/datadictionary/image1.JPG diff --git a/docs/datadictionary/index.rst b/docs/datadictionary/index.rst index a7e78564f..24050000e 100644 --- a/docs/datadictionary/index.rst +++ b/docs/datadictionary/index.rst @@ -9,22 +9,22 @@ Resource Definition Introduction: ============= -A data dictionary models the how a specific resource can be resolved. +A Resource definition models the how a specific resource can be resolved. A resource is a variable/parameter in the context of the service. It can be anything, but it should not be confused with SDC or Openstack resources. -A data dictionary can have multiple sources to handle resolution in different ways. +A Resource definition can have multiple sources to handle resolution in different ways. -The main goal of data dictionary is to define re-usable entity that could be shared. +The main goal of Resource definition is to define re-usable entity that could be shared. Creation of data dictionaries is a standalone activity, separated from the blueprint design. -As part of modelling a data dictionary entry, the following generic information should be provided: +As part of modelling a Resource definition entry, the following generic information should be provided: |image0| -.. |image0| image:: media/image0.jpg +.. |image0| image:: image0.jpg :width: 7.88889in :height: 4.43750in @@ -34,7 +34,7 @@ The modeling does allow for data translation between external capability and CDS |image1| -.. |image1| image:: media/image0.jpg +.. |image1| image:: image1.jpg :width: 7.88889in :height: 4.43750in @@ -45,7 +45,7 @@ vf-module-model-customization-uuid and vf-module-label are two data dictionaries Here is how input-key-mapping, output-key-mapping and key-dependencies can be used: -vf-module-label data dictionary +vf-module-label Resource definition { "name" : "vf-module-label", @@ -79,4 +79,14 @@ Resource source: Defines the contract to resolve a resource. -A resource source is modeled, following http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/csprd01/TOSCA-Simple-Profile-YAML-v1.0-csprd01.html#DEFN_ENTITY_NODE_TYPE, and derives from the https://wiki.onap.org/display/DW/Modeling+Concepts#ModelingConcepts-NodeResourceSource
\ No newline at end of file +A resource source is modeled, following TOSCA_ node type definition and derives from the Resource_ source. + +Also please click below for detailed resource source details + +.. toctree:: + :maxdepth: 1 + + resourcesource + +.. _TOSCA: http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/csprd01/TOSCA-Simple-Profile-YAML-v1.0-csprd01.html#DEFN_ENTITY_NODE_TYPE +.. _Resource_: https://wiki.onap.org/display/DW/Modeling+Concepts#ModelingConcepts-NodeResourceSource
\ No newline at end of file diff --git a/ms/blueprintsprocessor/application/src/main/resources/application-dev.properties b/ms/blueprintsprocessor/application/src/main/resources/application-dev.properties index 0e2cdf9de..2b90998b1 100755 --- a/ms/blueprintsprocessor/application/src/main/resources/application-dev.properties +++ b/ms/blueprintsprocessor/application/src/main/resources/application-dev.properties @@ -47,4 +47,10 @@ blueprintsprocessor.restconfEnabled=true blueprintsprocessor.restclient.sdncodl.type=basic-auth
blueprintsprocessor.restclient.sdncodl.url=http://localhost:8282/
blueprintsprocessor.restclient.sdncodl.username=admin
-blueprintsprocessor.restclient.sdncodl.password=Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U
\ No newline at end of file +blueprintsprocessor.restclient.sdncodl.password=Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U + +# Executor Options +blueprintprocessor.resourceResolution.enabled=true +blueprintprocessor.netconfExecutor.enabled=true +blueprintprocessor.restConfExecutor.enabled=true +blueprintprocessor.remoteScriptCommand.enabled=false
\ No newline at end of file diff --git a/ms/blueprintsprocessor/application/src/main/resources/application.properties b/ms/blueprintsprocessor/application/src/main/resources/application.properties index b34609cd1..e5b1fe58f 100755 --- a/ms/blueprintsprocessor/application/src/main/resources/application.properties +++ b/ms/blueprintsprocessor/application/src/main/resources/application.properties @@ -13,11 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -#logging.level.web=DEBUG - # Web server config -server.port=8080 - blueprintsprocessor.grpcEnable=false blueprintsprocessor.httpPort=8080 blueprintsprocessor.grpcPort=9111 @@ -25,7 +21,8 @@ blueprintsprocessor.grpcPort=9111 # Blueprint Processor File Execution and Handling Properties blueprintsprocessor.blueprintDeployPath=/opt/app/onap/blueprints/deploy blueprintsprocessor.blueprintArchivePath=/opt/app/onap/blueprints/archive -blueprintsprocessor.blueprintWorkingPath=/opt/app/onap/blueprints/work +blueprintsprocessor.blueprintWorkingPath=/opt/app/onap/blueprints/working + # Primary Database Configuration blueprintsprocessor.db.primary.url=jdbc:mysql://db:3306/sdnctl blueprintsprocessor.db.primary.username=sdnctl @@ -49,3 +46,14 @@ blueprintsprocessor.restclient.sdncodl.type=basic-auth blueprintsprocessor.restclient.sdncodl.url=http://sdnc:8282/ blueprintsprocessor.restclient.sdncodl.username=admin blueprintsprocessor.restclient.sdncodl.password=Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U + +# Executor Options +blueprintprocessor.resourceResolution.enabled=true +blueprintprocessor.netconfExecutor.enabled=true +blueprintprocessor.restConfExecutor.enabled=true +blueprintprocessor.remoteScriptCommand.enabled=true + +blueprintsprocessor.grpcclient.remote-python.type=token-auth +blueprintsprocessor.grpcclient.remote-python.host=localhost +blueprintsprocessor.grpcclient.remote-python.port=50051 +blueprintsprocessor.grpcclient.remote-python.token=Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==
\ No newline at end of file diff --git a/ms/blueprintsprocessor/application/src/test/resources/application.properties b/ms/blueprintsprocessor/application/src/test/resources/application.properties index 307850547..7e462f25d 100644 --- a/ms/blueprintsprocessor/application/src/test/resources/application.properties +++ b/ms/blueprintsprocessor/application/src/test/resources/application.properties @@ -37,5 +37,11 @@ blueprintsprocessor.db.primary.hibernateDialect=org.hibernate.dialect.H2Dialect blueprints.processor.functions.python.executor.executionPath=/opt/app/onap/scripts/jython/ccsdk_blueprints blueprints.processor.functions.python.executor.modulePaths=/opt/app/onap/scripts/jython/ccsdk_blueprints -security.user.password: {bcrypt}$2a$10$duaUzVUVW0YPQCSIbGEkQOXwafZGwQ/b32/Ys4R1iwSSawFgz7QNu -security.user.name: ccsdkapps +security.user.password:{bcrypt}$2a$10$duaUzVUVW0YPQCSIbGEkQOXwafZGwQ/b32/Ys4R1iwSSawFgz7QNu +security.user.name:ccsdkapps + +# Executor Options +blueprintprocessor.resourceResolution.enabled=true +blueprintprocessor.netconfExecutor.enabled=true +blueprintprocessor.restConfExecutor.enabled=true +blueprintprocessor.remoteScriptCommand.enabled=false diff --git a/ms/blueprintsprocessor/functions/pom.xml b/ms/blueprintsprocessor/functions/pom.xml index 24cc352c9..3f948061f 100755 --- a/ms/blueprintsprocessor/functions/pom.xml +++ b/ms/blueprintsprocessor/functions/pom.xml @@ -47,6 +47,11 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.mock-server</groupId> + <artifactId>mockserver-netty</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <scope>test</scope> diff --git a/ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt b/ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt new file mode 100644 index 000000000..6437cdf03 --- /dev/null +++ b/ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt @@ -0,0 +1,134 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.functions.python.executor + +import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.* +import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractComponentFunction +import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.ExecutionServiceConstant +import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.RemoteScriptExecutionService +import org.onap.ccsdk.cds.controllerblueprints.command.api.ResponseStatus +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException +import org.onap.ccsdk.cds.controllerblueprints.core.asJsonNode +import org.onap.ccsdk.cds.controllerblueprints.core.checkFileExists +import org.onap.ccsdk.cds.controllerblueprints.core.checkNotBlank +import org.onap.ccsdk.cds.controllerblueprints.core.data.OperationAssignment +import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile +import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.config.ConfigurableBeanFactory +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean +import org.springframework.context.annotation.Scope +import org.springframework.stereotype.Component +import java.lang.Exception + +@ConditionalOnBean(name = [ExecutionServiceConstant.SERVICE_GRPC_REMOTE_SCRIPT_EXECUTION]) +@Component("component-remote-python-executor") +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +open class ComponentRemotePythonExecutor(private val remoteScriptExecutionService: RemoteScriptExecutionService) + : AbstractComponentFunction() { + + private val log = LoggerFactory.getLogger(ComponentRemotePythonExecutor::class.java)!! + + companion object { + const val INPUT_ENDPOINT_SELECTOR = "endpoint-selector" + const val INPUT_DYNAMIC_PROPERTIES = "dynamic-properties" + const val INPUT_COMMAND = "command" + } + + override suspend fun processNB(executionRequest: ExecutionServiceInput) { + + log.info("Processing : $operationInputs") + + val bluePrintContext = bluePrintRuntimeService.bluePrintContext() + val blueprintName = bluePrintContext.name() + val blueprintVersion = bluePrintContext.version() + + val operationAssignment: OperationAssignment = bluePrintContext + .nodeTemplateInterfaceOperation(nodeTemplateName, interfaceName, operationName) + + val artifactName: String = operationAssignment.implementation?.primary + ?: throw BluePrintProcessorException("missing primary field to get artifact name for node template ($nodeTemplateName)") + + val artifactDefinition = + bluePrintRuntimeService.resolveNodeTemplateArtifactDefinition(nodeTemplateName, artifactName) + + checkNotBlank(artifactDefinition.file) { "couldn't get python script path($artifactName)" } + + val pythonScript = normalizedFile(bluePrintContext.rootPath, artifactDefinition.file) + + checkFileExists(pythonScript) { "python script(${pythonScript.absolutePath}) doesn't exists" } + + val endPointSelector = getOperationInput(INPUT_ENDPOINT_SELECTOR) + val dynamicProperties = getOperationInput(INPUT_DYNAMIC_PROPERTIES) + val command = getOperationInput(INPUT_COMMAND).asText() + + // TODO("Python execution command and Resolve some expressions with dynamic properties") + val scriptCommand = command.replace(pythonScript.name, pythonScript.absolutePath) + + val dependencies = operationAssignment.implementation?.dependencies + + try { + // Open GRPC Connection + remoteScriptExecutionService.init(endPointSelector.asText()) + + var executionLogs = "" + + // If dependencies are defined, then install in remote server + if (dependencies != null && dependencies.isNotEmpty()) { + val prepareEnvInput = PrepareRemoteEnvInput(requestId = processId, + remoteIdentifier = RemoteIdentifier(blueprintName = blueprintName, + blueprintVersion = blueprintVersion), + remoteScriptType = RemoteScriptType.PYTHON, + packages = dependencies + ) + val prepareEnvOutput = remoteScriptExecutionService.prepareEnv(prepareEnvInput) + executionLogs = prepareEnvOutput.response + setOutput(executionLogs) + check(prepareEnvOutput.status == StatusType.SUCCESS) { + "failed to get prepare remote env response status for requestId(${prepareEnvInput.requestId})" + } + } + + val remoteExecutionInput = RemoteScriptExecutionInput( + requestId = processId, + remoteIdentifier = RemoteIdentifier(blueprintName = blueprintName, blueprintVersion = blueprintVersion), + remoteScriptType = RemoteScriptType.PYTHON, + command = scriptCommand) + val remoteExecutionOutput = remoteScriptExecutionService.executeCommand(remoteExecutionInput) + executionLogs += remoteExecutionOutput.response + setOutput(executionLogs) + check(remoteExecutionOutput.status == StatusType.SUCCESS) { + "failed to get prepare remote command response status for requestId(${remoteExecutionOutput.requestId})" + } + + } catch (e: Exception) { + log.error("", e) + } finally { + remoteScriptExecutionService.close() + } + } + + private fun setOutput(executionLogs: String) { + bluePrintRuntimeService.setNodeTemplateAttributeValue(nodeTemplateName, + "execution-logs", JacksonUtils.jsonNodeFromObject(executionLogs)) + } + + override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) { + bluePrintRuntimeService.getBluePrintError() + .addError("Failed in ComponentJythonExecutor : ${runtimeException.message}") + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/python-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutorTest.kt b/ms/blueprintsprocessor/functions/python-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutorTest.kt new file mode 100644 index 000000000..7cd5d5cac --- /dev/null +++ b/ms/blueprintsprocessor/functions/python-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutorTest.kt @@ -0,0 +1,91 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.functions.python.executor + +import com.fasterxml.jackson.databind.JsonNode +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.runBlocking +import org.junit.Test +import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.* +import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.RemoteScriptExecutionService +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants +import org.onap.ccsdk.cds.controllerblueprints.core.putJsonElement +import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils +import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + + +class ComponentRemotePythonExecutorTest { + + @Test + fun testComponentRemotePythonExecutor() { + runBlocking { + val remoteScriptExecutionService = MockRemoteScriptExecutionService() + + val componentRemotePythonExecutor = ComponentRemotePythonExecutor(remoteScriptExecutionService) + + val executionServiceInput = JacksonUtils.readValueFromClassPathFile("payload/requests/sample-activate-request.json", + ExecutionServiceInput::class.java)!! + + val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime("123456-1000", + "./../../../../components/model-catalog/blueprint-model/test-blueprint/remote_scripts") + + val stepMetaData: MutableMap<String, JsonNode> = hashMapOf() + stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE, "execute-remote-python") + stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_INTERFACE, "ComponentRemotePythonExecutor") + stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_OPERATION, "process") + componentRemotePythonExecutor.bluePrintRuntimeService = bluePrintRuntimeService + val stepInputData = StepData().apply { + name = "execute-remote-python" + properties = stepMetaData + } + executionServiceInput.stepData = stepInputData + componentRemotePythonExecutor.applyNB(executionServiceInput) + } + + } +} + +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") + assertEquals(prepareEnvInput.remoteScriptType, RemoteScriptType.PYTHON, "failed to match script type") + assertNotNull(prepareEnvInput.packages, "failed to get packages") + + val remoteScriptExecutionOutput = mockk<RemoteScriptExecutionOutput>() + 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") + assertEquals(remoteExecutionInput.remoteScriptType, RemoteScriptType.PYTHON, "failed to match script type") + + val remoteScriptExecutionOutput = mockk<RemoteScriptExecutionOutput>() + every { remoteScriptExecutionOutput.status } returns StatusType.SUCCESS + return remoteScriptExecutionOutput + } + + override suspend fun close() { + + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessor.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessor.kt index 9852e3438..2d726d487 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessor.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessor.kt @@ -101,7 +101,7 @@ open class RestResourceResolutionProcessor(private val blueprintRestLibPropertyS } } - private fun blueprintWebClientService(resourceAssignment: ResourceAssignment, + fun blueprintWebClientService(resourceAssignment: ResourceAssignment, restResourceSource: RestResourceSource): BlueprintWebClientService { return if (isNotEmpty(restResourceSource.endpointSelector)) { val restPropertiesJson = raRuntimeService.resolveDSLExpression(restResourceSource.endpointSelector!!) @@ -195,12 +195,8 @@ open class RestResourceResolutionProcessor(private val blueprintRestLibPropertyS checkNotEmpty(resourceAssignment.dictionaryName) { "resource assignment dictionary name is not defined for template key (${resourceAssignment.name})" } - checkEquals(ResourceDictionaryConstants.SOURCE_PRIMARY_CONFIG_DATA, resourceAssignment.dictionarySource) { - "resource assignment source is not ${ResourceDictionaryConstants.SOURCE_PRIMARY_CONFIG_DATA} but it is " + - "${resourceAssignment.dictionarySource}" - } - checkNotEmpty(resourceAssignment.dictionaryName) { - "resource assignment dictionary name is not defined for template key (${resourceAssignment.name})" + checkNotEmpty(resourceAssignment.dictionarySource) { + "resource assignment dictionary source is not defined for template key (${resourceAssignment.name})" } } @@ -208,5 +204,4 @@ open class RestResourceResolutionProcessor(private val blueprintRestLibPropertyS raRuntimeService.getBluePrintError().addError(runtimeException.message!!) } - }
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionServiceTest.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionServiceTest.kt index 3f251b104..9c2a100bc 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionServiceTest.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionServiceTest.kt @@ -128,7 +128,7 @@ class ResourceResolutionServiceTest { val artifactPrefix = "another" - // Velocity Artifact Definition Name + // Templating Artifact Definition Name val artifactTemplate = "$artifactPrefix-template" // Resource Assignment Artifact Definition Name val artifactMapping = "$artifactPrefix-mapping" diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintResLibPropertyService.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintResLibPropertyService.kt new file mode 100644 index 000000000..b79f48682 --- /dev/null +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintResLibPropertyService.kt @@ -0,0 +1,36 @@ +/* + * 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. + */ +package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.mock + +import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintProperties +import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestClientProperties +import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BluePrintRestLibPropertyService + +class MockBluePrintRestLibPropertyService(bluePrintProperties: BluePrintProperties) : + BluePrintRestLibPropertyService(bluePrintProperties) { + + fun mockBlueprintWebClientService (selector: String): + MockBlueprintWebClientService { + val prefix = "blueprintsprocessor.restclient.$selector" + val restClientProperties = restClientProperties(prefix) + return mockBlueprintWebClientService(restClientProperties) + } + + private fun mockBlueprintWebClientService(restClientProperties: RestClientProperties): + MockBlueprintWebClientService { + return MockBlueprintWebClientService(restClientProperties) + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt new file mode 100644 index 000000000..c6ca41351 --- /dev/null +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockBlueprintWebClientService.kt @@ -0,0 +1,124 @@ +/* + * 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. + */ +package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.mock + +import org.apache.http.message.BasicHeader +import org.mockserver.integration.ClientAndServer +import org.mockserver.model.Header +import org.mockserver.model.HttpRequest.request +import org.mockserver.model.HttpResponse.response +import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestClientProperties +import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType +import java.nio.charset.Charset +import java.util.* + +class MockBlueprintWebClientService(private var restClientProperties: RestClientProperties): BlueprintWebClientService { + private var mockServer: ClientAndServer + private var port: String = if (restClientProperties.url.split(":")[2].isEmpty()) "8080" + else restClientProperties.url.split(":")[2] + private var headers: Map<String, String> + + init { + mockServer = ClientAndServer.startClientAndServer(port.toInt()) + headers = defaultHeaders() + + // Create expected requests and responses + setRequest("GET", "/aai/v14/network/generic-vnfs/generic-vnf/123456") + setRequest("GET", "/config/GENERIC-RESOURCE-API:services/service/10/service-data/vnfs/vnf/123456/" + + "vnf-data/vnf-topology/vnf-parameters-data/param/vnf_name") + setRequestWithPayload("PUT", "/query", + "{\r\n\"start\": \"\\/nodes\\/vf-modules?vf-module-name=vf-module-name\",\r\n\"query\": \"\\/query\\/related-to?startingNodeType=vf-module&relatedToNodeType=generic-vnf\"\r\n}") + } + + override fun defaultHeaders(): Map<String, String> { + val encodedCredentials = this.setBasicAuth("admin", "aaiTest") + return mapOf( + HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE, + HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE, + HttpHeaders.AUTHORIZATION to "Basic $encodedCredentials") + } + + override fun host(uri: String): String { + return restClientProperties.url + uri + } + + fun tearDown() { + mockServer.close() + } + + override fun exchangeResource(method: String, path: String, payload: String): String { + val header = arrayOf(BasicHeader(HttpHeaders.AUTHORIZATION, headers[HttpHeaders.AUTHORIZATION])) + return when (method) { + "POST" -> { + post(path, payload, header) + } + "PUT" -> { + put(path, payload, header) + } + else -> { + get(path, header) + } + } + } + + private fun setRequest(method: String, path: String) { + val requestResponse = when (method) { + "POST" -> { + "Post response" + } + "PUT" -> { + "Put response" + } + else -> { + "Get response" + } + + } + mockServer.`when`(request().withHeaders(Header(HttpHeaders.AUTHORIZATION, headers[HttpHeaders.AUTHORIZATION])) + .withMethod(method) + .withPath(path) + ).respond(response().withStatusCode(200).withBody("{\"aai-resource\":\"$requestResponse\"}")) + } + + private fun setRequestWithPayload(method: String, path: String, payload: String) { + val requestResponse = when (method) { + "POST" -> { + "Post response" + } + "PUT" -> { + "Put response" + } + else -> { + "Get response" + } + + } + mockServer.`when`(request().withHeaders(Header(HttpHeaders.AUTHORIZATION, headers[HttpHeaders.AUTHORIZATION])) + .withMethod(method) + .withPath(path) + .withQueryStringParameter("format", "resource") + .withBody(payload) + ).respond(response().withStatusCode(200).withBody("{\"aai-resource\":\"$requestResponse\"}")) + } + + private fun setBasicAuth(username: String, password: String): String { + val credentialsString = "$username:$password" + return Base64.getEncoder().encodeToString( + credentialsString.toByteArray(Charset.defaultCharset())) + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockRestResourceResolutionProcessor.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockRestResourceResolutionProcessor.kt new file mode 100644 index 000000000..2c481dca3 --- /dev/null +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/mock/MockRestResourceResolutionProcessor.kt @@ -0,0 +1,159 @@ +/* + * 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. + */ +package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.mock + +import com.fasterxml.jackson.databind.node.ArrayNode +import com.fasterxml.jackson.databind.node.MissingNode +import org.apache.commons.collections.MapUtils +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.RestResourceSource +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor.ResourceAssignmentProcessor +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils +import org.onap.ccsdk.cds.controllerblueprints.core.* +import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils +import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment +import org.slf4j.LoggerFactory +import java.util.HashMap + +class MockRestResourceResolutionProcessor(private val blueprintRestLibPropertyService: + MockBluePrintRestLibPropertyService): ResourceAssignmentProcessor() { + + private val logger = LoggerFactory.getLogger(MockRestResourceResolutionProcessor::class.java) + + override fun resolveInputKeyMappingVariables(inputKeyMapping: Map<String, String>): Map<String, Any> { + val resolvedInputKeyMapping = HashMap<String, Any>() + if (MapUtils.isNotEmpty(inputKeyMapping)) { + resolvedInputKeyMapping["service-instance-id"] = "10" + resolvedInputKeyMapping["vnf_name"] = "vnf1" + resolvedInputKeyMapping["vnf-id"] = "123456" + } + return resolvedInputKeyMapping + } + + override fun getName(): String { + return "${ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-rest" + } + + override suspend fun processNB(executionRequest: ResourceAssignment) { + try { + // Check if It has Input + val value = getFromInput(executionRequest) + if (value == null || value is MissingNode) { + val dName = executionRequest.dictionaryName + val dSource = executionRequest.dictionarySource + val resourceDefinition = resourceDictionaries[dName] + + val resourceSource = resourceDefinition!!.sources[dSource] + + val resourceSourceProperties = resourceSource!!.properties + + val sourceProperties = + JacksonUtils.getInstanceFromMap(resourceSourceProperties!!, RestResourceSource::class.java) + + val path = nullToEmpty(sourceProperties.path) + val inputKeyMapping = sourceProperties.inputKeyMapping + + val resolvedInputKeyMapping = resolveInputKeyMappingVariables(inputKeyMapping!!).toMutableMap() + + // Resolving content Variables + val payload = resolveFromInputKeyMapping(nullToEmpty(sourceProperties.payload), resolvedInputKeyMapping) + val urlPath = + resolveFromInputKeyMapping(checkNotNull(sourceProperties.urlPath), resolvedInputKeyMapping) + val verb = resolveFromInputKeyMapping(nullToEmpty(sourceProperties.verb), resolvedInputKeyMapping) + + logger.info("$dSource dictionary information : ($urlPath), ($inputKeyMapping), (${sourceProperties.outputKeyMapping})") + + // Get the Rest Client Service + val restClientService = blueprintWebClientService(executionRequest) + + val response = restClientService.exchangeResource(verb, urlPath, payload) + if (response.isEmpty()) { + logger.warn("Failed to get $dSource result for dictionary name ($dName) using urlPath ($urlPath)") + } else { + populateResource(executionRequest, sourceProperties, response, path) + restClientService.tearDown() + } + } + } catch (e: Exception) { + ResourceAssignmentUtils.setFailedResourceDataValue(executionRequest, e.message) + throw BluePrintProcessorException("Failed in template key ($executionRequest) assignments with: ${e.message}", + e) + } + } + + override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ResourceAssignment) { + raRuntimeService.getBluePrintError().addError(runtimeException.message!!) + } + + private fun blueprintWebClientService(resourceAssignment: ResourceAssignment): MockBlueprintWebClientService { + return blueprintRestLibPropertyService.mockBlueprintWebClientService(resourceAssignment.dictionarySource!!) + } + + @Throws(BluePrintProcessorException::class) + private fun populateResource(resourceAssignment: ResourceAssignment, sourceProperties: RestResourceSource, + restResponse: String, path: String) { + val type = nullToEmpty(resourceAssignment.property?.type) + lateinit var entrySchemaType: String + + val outputKeyMapping = sourceProperties.outputKeyMapping + + val responseNode = JacksonUtils.jsonNode(restResponse).at(path) + + when (type) { + in BluePrintTypes.validPrimitiveTypes() -> { + ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, responseNode) + } + in BluePrintTypes.validCollectionTypes() -> { + // Array Types + entrySchemaType = resourceAssignment.property!!.entrySchema!!.type + val arrayNode = responseNode as ArrayNode + + if (entrySchemaType !in BluePrintTypes.validPrimitiveTypes()) { + val responseArrayNode = responseNode.toList() + for (responseSingleJsonNode in responseArrayNode) { + + val arrayChildNode = JacksonUtils.objectMapper.createObjectNode() + + outputKeyMapping!!.map { + val responseKeyValue = responseSingleJsonNode.get(it.key) + val propertyTypeForDataType = ResourceAssignmentUtils + .getPropertyType(raRuntimeService, entrySchemaType, it.key) + + JacksonUtils.populateJsonNodeValues(it.value, + responseKeyValue, propertyTypeForDataType, arrayChildNode) + } + arrayNode.add(arrayChildNode) + } + } + // Set the List of Complex Values + ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, arrayNode) + } + else -> { + // Complex Types + entrySchemaType = resourceAssignment.property!!.type + val objectNode = JacksonUtils.objectMapper.createObjectNode() + outputKeyMapping!!.map { + val responseKeyValue = responseNode.get(it.key) + val propertyTypeForDataType = ResourceAssignmentUtils + .getPropertyType(raRuntimeService, entrySchemaType, it.key) + JacksonUtils.populateJsonNodeValues(it.value, responseKeyValue, propertyTypeForDataType, objectNode) + } + // Set the List of Complex Values + ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, objectNode) + } + } + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/CapabilityResourceResolutionProcessorTest.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/CapabilityResourceResolutionProcessorTest.kt index 2af15c2be..66fdd8ff8 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/CapabilityResourceResolutionProcessorTest.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/CapabilityResourceResolutionProcessorTest.kt @@ -123,7 +123,6 @@ class CapabilityResourceResolutionProcessorTest { println(processorName) } } - } open class MockCapabilityService { diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessorTest.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessorTest.kt index 08174ed47..7e7e65635 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessorTest.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessorTest.kt @@ -16,13 +16,15 @@ package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor import kotlinx.coroutines.runBlocking -import org.junit.Ignore 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.functions.resource.resolution.ResourceAssignmentRuntimeService +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.mock.MockBluePrintRestLibPropertyService +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.mock.MockRestResourceResolutionProcessor import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils +import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestClientProperties import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BluePrintRestLibPropertyService import org.onap.ccsdk.cds.controllerblueprints.core.data.PropertyDefinition import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils @@ -31,18 +33,25 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.TestPropertySource import org.springframework.test.context.junit4.SpringRunner +import kotlin.test.AfterTest +import kotlin.test.BeforeTest import kotlin.test.assertNotNull @RunWith(SpringRunner::class) -@ContextConfiguration(classes = [RestResourceResolutionProcessor::class, BluePrintRestLibPropertyService::class, - BlueprintPropertyConfiguration::class, BluePrintProperties::class]) +@ContextConfiguration(classes = [MockRestResourceResolutionProcessor::class, MockBluePrintRestLibPropertyService::class, + BlueprintPropertyConfiguration::class, BluePrintProperties::class, RestClientProperties::class]) @TestPropertySource(locations = ["classpath:application-test.properties"]) class RestResourceResolutionProcessorTest { - @Autowired - lateinit var restResourceResolutionProcessor: RestResourceResolutionProcessor + lateinit var bluePrintRestLibPropertyService: MockBluePrintRestLibPropertyService + + private lateinit var restResourceResolutionProcessor: MockRestResourceResolutionProcessor + + @BeforeTest + fun init(){ + restResourceResolutionProcessor = MockRestResourceResolutionProcessor(bluePrintRestLibPropertyService) + } - @Ignore @Test fun `test rest resource resolution`() { runBlocking { @@ -55,7 +64,11 @@ class RestResourceResolutionProcessorTest { restResourceResolutionProcessor.resourceDictionaries = ResourceAssignmentUtils .resourceDefinitions(bluePrintContext.rootPath) - //TODO ("Mock the dependency values and rest service.") + val scriptPropertyInstances: MutableMap<String, Any> = mutableMapOf() + scriptPropertyInstances["mock-service1"] = MockCapabilityService() + scriptPropertyInstances["mock-service2"] = MockCapabilityService() + + restResourceResolutionProcessor.scriptPropertyInstances = scriptPropertyInstances val resourceAssignment = ResourceAssignment().apply { name = "rr-name" @@ -71,4 +84,70 @@ class RestResourceResolutionProcessorTest { println(processorName) } } + + @Test + fun `test rest aai get resource resolution`() { + runBlocking { + val bluePrintContext = BluePrintMetadataUtils.getBluePrintContext( + "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration") + + val resourceAssignmentRuntimeService = ResourceAssignmentRuntimeService("1234", bluePrintContext) + + restResourceResolutionProcessor.raRuntimeService = resourceAssignmentRuntimeService + restResourceResolutionProcessor.resourceDictionaries = ResourceAssignmentUtils + .resourceDefinitions(bluePrintContext.rootPath) + + val scriptPropertyInstances: MutableMap<String, Any> = mutableMapOf() + scriptPropertyInstances["mock-service1"] = MockCapabilityService() + scriptPropertyInstances["mock-service2"] = MockCapabilityService() + + restResourceResolutionProcessor.scriptPropertyInstances = scriptPropertyInstances + + val resourceAssignment = ResourceAssignment().apply { + name = "rr-aai" + dictionaryName = "aai-get-resource" + dictionarySource = "primary-aai-data" + property = PropertyDefinition().apply { + type = "string" + } + } + + val processorName = restResourceResolutionProcessor.applyNB(resourceAssignment) + assertNotNull(processorName, "couldn't get AAI Rest resource assignment processor name") + println(processorName) + } + } + + @Test + fun `test rest aai put resource resolution`() { + runBlocking { + val bluePrintContext = BluePrintMetadataUtils.getBluePrintContext( + "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration") + + val resourceAssignmentRuntimeService = ResourceAssignmentRuntimeService("1234", bluePrintContext) + + restResourceResolutionProcessor.raRuntimeService = resourceAssignmentRuntimeService + restResourceResolutionProcessor.resourceDictionaries = ResourceAssignmentUtils + .resourceDefinitions(bluePrintContext.rootPath) + + val scriptPropertyInstances: MutableMap<String, Any> = mutableMapOf() + scriptPropertyInstances["mock-service1"] = MockCapabilityService() + scriptPropertyInstances["mock-service2"] = MockCapabilityService() + + restResourceResolutionProcessor.scriptPropertyInstances = scriptPropertyInstances + + val resourceAssignment = ResourceAssignment().apply { + name = "rr-aai" + dictionaryName = "aai-put-resource" + dictionarySource = "primary-aai-data" + property = PropertyDefinition().apply { + type = "string" + } + } + + val processorName = restResourceResolutionProcessor.applyNB(resourceAssignment) + assertNotNull(processorName, "couldn't get AAI Rest resource assignment processor name") + println(processorName) + } + } }
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/resources/application-test.properties b/ms/blueprintsprocessor/functions/resource-resolution/src/test/resources/application-test.properties index 071b27afc..5deea31e1 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/resources/application-test.properties +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/resources/application-test.properties @@ -28,4 +28,14 @@ blueprintsprocessor.blueprintArchivePath=./target/blueprints/archive blueprintsprocessor.blueprintWorkingPath=./target/blueprints/work # Python executor blueprints.processor.functions.python.executor.executionPath=./../../../../components/scripts/python/ccsdk_blueprints -blueprints.processor.functions.python.executor.modulePaths=./../../../../components/scripts/python/ccsdk_blueprints
\ No newline at end of file +blueprints.processor.functions.python.executor.modulePaths=./../../../../components/scripts/python/ccsdk_blueprints + +blueprintsprocessor.restclient.primary-config-data.type=basic-auth +blueprintsprocessor.restclient.primary-config-data.url=http://127.0.0.1:9911 +blueprintsprocessor.restclient.primary-config-data.username=sampleuser +blueprintsprocessor.restclient.primary-config-data.password=sampletoken + +blueprintsprocessor.restclient.primary-aai-data.type=basic-auth +blueprintsprocessor.restclient.primary-aai-data.url=http://127.0.0.1:30800 +blueprintsprocessor.restclient.primary-aai-data.username=admin +blueprintsprocessor.restclient.primary-aai-data.password=aaiTest
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/pom.xml b/ms/blueprintsprocessor/modules/commons/grpc-lib/pom.xml new file mode 100644 index 000000000..e50b1915f --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/pom.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright © 2019 IBM. + ~ + ~ 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>commons</artifactId> + <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> + <version>0.4.2-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>grpc-lib</artifactId> + <packaging>jar</packaging> + <name>Blueprints Processor GRPC Lib</name> + <description>Blueprints Processor GRPC Lib</description> + + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.cds.controllerblueprints</groupId> + <artifactId>blueprint-core</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> + <artifactId>processor-core</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.cds.components</groupId> + <artifactId>proto-definition</artifactId> + </dependency> + </dependencies> + +</project>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibConfiguration.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibConfiguration.kt new file mode 100644 index 000000000..1bef3a0f2 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibConfiguration.kt @@ -0,0 +1,32 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.grpc + +import org.springframework.context.annotation.ComponentScan +import org.springframework.context.annotation.Configuration + +@Configuration +@ComponentScan +open class BluePrintGrpcLibConfiguration + +class GRPCLibConstants { + companion object { + const val SERVICE_BLUEPRINT_GRPC_LIB_PROPERTY = "blueprint-grpc-lib-property-service" + const val TYPE_TOKEN_AUTH = "token-auth" + const val TYPE_BASIC_AUTH = "basic-auth" + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibData.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibData.kt new file mode 100644 index 000000000..76e60bd0d --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibData.kt @@ -0,0 +1,32 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.grpc + +open class GrpcClientProperties { + lateinit var type: String + lateinit var host: String + var port: Int = -1 +} + +open class TokenAuthGrpcClientProperties : GrpcClientProperties() { + lateinit var token: String +} + +open class BasicAuthGrpcClientProperties : GrpcClientProperties() { + lateinit var username: String + lateinit var password: String +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BasicAuthGrpcClientService.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BasicAuthGrpcClientService.kt new file mode 100644 index 000000000..a175d8b3a --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BasicAuthGrpcClientService.kt @@ -0,0 +1,40 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.grpc.service + +import io.grpc.ManagedChannel +import io.grpc.internal.DnsNameResolverProvider +import io.grpc.internal.PickFirstLoadBalancerProvider +import io.grpc.netty.NettyChannelBuilder +import org.onap.ccsdk.cds.blueprintsprocessor.grpc.BasicAuthGrpcClientProperties + + +open class BasicAuthGrpcClientService(private val basicAuthGrpcClientProperties: BasicAuthGrpcClientProperties) + : BluePrintGrpcClientService { + + override suspend fun channel(): ManagedChannel { + val managedChannel = NettyChannelBuilder + .forAddress(basicAuthGrpcClientProperties.host, basicAuthGrpcClientProperties.port) + .nameResolverFactory(DnsNameResolverProvider()) + .loadBalancerFactory(PickFirstLoadBalancerProvider()) + // .intercept(BasicAuthClientInterceptor(basicAuthGrpcClientProperties)).usePlaintext() + .build() + return managedChannel + } + + +} diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcClientService.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcClientService.kt new file mode 100644 index 000000000..016c05035 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcClientService.kt @@ -0,0 +1,23 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.grpc.service + +import io.grpc.ManagedChannel + +interface BluePrintGrpcClientService { + suspend fun channel(): ManagedChannel +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyService.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyService.kt new file mode 100644 index 000000000..088533a71 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyService.kt @@ -0,0 +1,98 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.grpc.service + +import com.fasterxml.jackson.databind.JsonNode +import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintProperties +import org.onap.ccsdk.cds.blueprintsprocessor.grpc.BasicAuthGrpcClientProperties +import org.onap.ccsdk.cds.blueprintsprocessor.grpc.GRPCLibConstants +import org.onap.ccsdk.cds.blueprintsprocessor.grpc.GrpcClientProperties +import org.onap.ccsdk.cds.blueprintsprocessor.grpc.TokenAuthGrpcClientProperties +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException +import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils +import org.springframework.stereotype.Service + +@Service(GRPCLibConstants.SERVICE_BLUEPRINT_GRPC_LIB_PROPERTY) +open class BluePrintGrpcLibPropertyService(private var bluePrintProperties: BluePrintProperties) { + + fun blueprintGrpcClientService(jsonNode: JsonNode): BluePrintGrpcClientService { + val restClientProperties = grpcClientProperties(jsonNode) + return blueprintGrpcClientService(restClientProperties) + } + + fun blueprintGrpcClientService(selector: String): BluePrintGrpcClientService { + val prefix = "blueprintsprocessor.grpcclient.$selector" + val restClientProperties = grpcClientProperties(prefix) + return blueprintGrpcClientService(restClientProperties) + } + + + fun grpcClientProperties(jsonNode: JsonNode): GrpcClientProperties { + val type = jsonNode.get("type").textValue() + return when (type) { + GRPCLibConstants.TYPE_TOKEN_AUTH -> { + JacksonUtils.readValue(jsonNode, TokenAuthGrpcClientProperties::class.java)!! + } + GRPCLibConstants.TYPE_BASIC_AUTH -> { + JacksonUtils.readValue(jsonNode, BasicAuthGrpcClientProperties::class.java)!! + } + else -> { + throw BluePrintProcessorException("Grpc type($type) not supported") + } + } + } + + fun grpcClientProperties(prefix: String): GrpcClientProperties { + val type = bluePrintProperties.propertyBeanType( + "$prefix.type", String::class.java) + return when (type) { + GRPCLibConstants.TYPE_TOKEN_AUTH -> { + tokenAuthGrpcClientProperties(prefix) + } + GRPCLibConstants.TYPE_BASIC_AUTH -> { + basicAuthGrpcClientProperties(prefix) + } + else -> { + throw BluePrintProcessorException("Grpc type($type) not supported") + + } + } + } + + private fun blueprintGrpcClientService(grpcClientProperties: GrpcClientProperties): + BluePrintGrpcClientService { + when (grpcClientProperties) { + is TokenAuthGrpcClientProperties -> { + return TokenAuthGrpcClientService(grpcClientProperties) + } + is BasicAuthGrpcClientProperties -> { + return BasicAuthGrpcClientService(grpcClientProperties) + } + else -> { + throw BluePrintProcessorException("couldn't get grpc service for type(${grpcClientProperties.type})") + } + } + } + + private fun tokenAuthGrpcClientProperties(prefix: String): TokenAuthGrpcClientProperties { + return bluePrintProperties.propertyBeanType(prefix, TokenAuthGrpcClientProperties::class.java) + } + + private fun basicAuthGrpcClientProperties(prefix: String): BasicAuthGrpcClientProperties { + return bluePrintProperties.propertyBeanType(prefix, BasicAuthGrpcClientProperties::class.java) + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/TokenAuthGrpcClientService.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/TokenAuthGrpcClientService.kt new file mode 100644 index 000000000..dbff84211 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/TokenAuthGrpcClientService.kt @@ -0,0 +1,54 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.grpc.service + +import io.grpc.* +import io.grpc.internal.DnsNameResolverProvider +import io.grpc.internal.PickFirstLoadBalancerProvider +import io.grpc.netty.NettyChannelBuilder +import org.onap.ccsdk.cds.blueprintsprocessor.grpc.TokenAuthGrpcClientProperties + +class TokenAuthGrpcClientService(private val tokenAuthGrpcClientProperties: TokenAuthGrpcClientProperties) + : BluePrintGrpcClientService { + + override suspend fun channel(): ManagedChannel { + val managedChannel = NettyChannelBuilder + .forAddress(tokenAuthGrpcClientProperties.host, tokenAuthGrpcClientProperties.port) + .nameResolverFactory(DnsNameResolverProvider()) + .loadBalancerFactory(PickFirstLoadBalancerProvider()) + .intercept(TokenAuthClientInterceptor(tokenAuthGrpcClientProperties)).usePlaintext().build() + return managedChannel + } +} + +class TokenAuthClientInterceptor(private val tokenAuthGrpcClientProperties: TokenAuthGrpcClientProperties) : ClientInterceptor { + + override fun <ReqT, RespT> interceptCall(method: MethodDescriptor<ReqT, RespT>, + callOptions: CallOptions, channel: Channel): ClientCall<ReqT, RespT> { + + val authHeader = Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER) + + return object : ForwardingClientCall + .SimpleForwardingClientCall<ReqT, RespT>(channel.newCall(method, callOptions)) { + + override fun start(responseListener: Listener<RespT>, headers: Metadata) { + headers.put(authHeader, tokenAuthGrpcClientProperties.token) + super.start(responseListener, headers) + } + } + } +} diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyServiceTest.kt b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyServiceTest.kt new file mode 100644 index 000000000..a459d5fe2 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyServiceTest.kt @@ -0,0 +1,56 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.grpc.service + +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.grpc.BasicAuthGrpcClientProperties +import org.onap.ccsdk.cds.blueprintsprocessor.grpc.BluePrintGrpcLibConfiguration +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.TestPropertySource +import org.springframework.test.context.junit4.SpringRunner +import kotlin.test.assertNotNull + +@RunWith(SpringRunner::class) +@ContextConfiguration(classes = [BluePrintGrpcLibConfiguration::class, + BlueprintPropertyConfiguration::class, BluePrintProperties::class]) +@TestPropertySource(properties = +["blueprintsprocessor.grpcclient.sample.type=basic-auth", + "blueprintsprocessor.grpcclient.sample.host=127.0.0.1", + "blueprintsprocessor.grpcclient.sample.port=50505", + "blueprintsprocessor.grpcclient.sample.username=sampleuser", + "blueprintsprocessor.grpcclient.sample.password=sampleuser" +]) +class BluePrintGrpcLibPropertyServiceTest { + + @Autowired + lateinit var bluePrintGrpcLibPropertyService: BluePrintGrpcLibPropertyService + + @Test + fun testGrpcClientProperties() { + val properties = bluePrintGrpcLibPropertyService.grpcClientProperties( + "blueprintsprocessor.grpcclient.sample") as BasicAuthGrpcClientProperties + assertNotNull(properties, "failed to create property bean") + assertNotNull(properties.host, "failed to get host property in property bean") + assertNotNull(properties.port, "failed to get host property in property bean") + assertNotNull(properties.username, "failed to get host property in property bean") + assertNotNull(properties.password, "failed to get host property in property bean") + } +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/grpc-lib/src/test/resources/logback-test.xml b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/test/resources/logback-test.xml new file mode 100644 index 000000000..626b8f911 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/grpc-lib/src/test/resources/logback-test.xml @@ -0,0 +1,35 @@ +<!-- + ~ Copyright © 2019 IBM. + ~ + ~ 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. + --> + +<configuration> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <!-- encoders are assigned the type + ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> + <encoder> + <pattern>%d{HH:mm:ss.SSS} %-5level %logger{100} - %msg%n</pattern> + </encoder> + </appender> + + <logger name="org.springframework.test" level="warn"/> + <logger name="org.springframework" level="warn"/> + <logger name="org.hibernate" level="info"/> + <logger name="org.onap.ccsdk.cds.blueprintsprocessor" level="info"/> + + <root level="warn"> + <appender-ref ref="STDOUT"/> + </root> + +</configuration> diff --git a/ms/blueprintsprocessor/modules/commons/pom.xml b/ms/blueprintsprocessor/modules/commons/pom.xml index ebd905248..9b52565c1 100755 --- a/ms/blueprintsprocessor/modules/commons/pom.xml +++ b/ms/blueprintsprocessor/modules/commons/pom.xml @@ -35,6 +35,7 @@ <module>db-lib</module> <module>rest-lib</module> <module>dmaap-lib</module> + <module>grpc-lib</module> </modules> <dependencies> <dependency> diff --git a/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/api/data/BlueprintRemoteProcessorData.kt b/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/api/data/BlueprintRemoteProcessorData.kt new file mode 100644 index 000000000..da952c034 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/api/data/BlueprintRemoteProcessorData.kt @@ -0,0 +1,56 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.core.api.data + +import com.fasterxml.jackson.databind.JsonNode +import java.util.* + +enum class RemoteScriptType { + PYTHON, ANSIBLE, KOTLIN, SH +} + +enum class StatusType { + SUCCESS, FAILURE +} + +data class RemoteIdentifier(var blueprintName: String, + var blueprintVersion: String) + + +data class RemoteScriptExecutionInput(var requestId: String, + var correlationId: String? = null, + var remoteIdentifier: RemoteIdentifier? = null, + var remoteScriptType: RemoteScriptType, + var command: String, + var timeOut: Long = 30, + var properties: MutableMap<String, JsonNode> = hashMapOf() +) + + +data class RemoteScriptExecutionOutput(var requestId: String, + var response: String, + var status: StatusType = StatusType.SUCCESS, + var timestamp: Date = Date()) + +data class PrepareRemoteEnvInput(var requestId: String, + var correlationId: String? = null, + var remoteIdentifier: RemoteIdentifier? = null, + var remoteScriptType: RemoteScriptType, + var packages: MutableList<String>?, + var timeOut: Long = 120, + var properties: MutableMap<String, JsonNode> = hashMapOf() +)
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/services/execution-service/pom.xml b/ms/blueprintsprocessor/modules/services/execution-service/pom.xml index 9ce5292e8..d366f740d 100644 --- a/ms/blueprintsprocessor/modules/services/execution-service/pom.xml +++ b/ms/blueprintsprocessor/modules/services/execution-service/pom.xml @@ -54,6 +54,10 @@ <artifactId>rest-lib</artifactId> </dependency> <dependency> + <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> + <artifactId>grpc-lib</artifactId> + </dependency> + <dependency> <groupId>org.onap.ccsdk.cds.controllerblueprints</groupId> <artifactId>resource-dict</artifactId> </dependency> diff --git a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/ExecutionServiceConfiguration.kt b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/ExecutionServiceConfiguration.kt new file mode 100644 index 000000000..806c33039 --- /dev/null +++ b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/ExecutionServiceConfiguration.kt @@ -0,0 +1,29 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.services.execution + +import org.springframework.context.annotation.ComponentScan +import org.springframework.context.annotation.Configuration + +@Configuration +@ComponentScan +open class ExecutionServiceConfiguration + + +object ExecutionServiceConstant { + const val SERVICE_GRPC_REMOTE_SCRIPT_EXECUTION = "grpc-remote-script-execution-service" +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/RemoteScriptExecutionService.kt b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/RemoteScriptExecutionService.kt new file mode 100644 index 000000000..7db5f52a4 --- /dev/null +++ b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/RemoteScriptExecutionService.kt @@ -0,0 +1,150 @@ +/* + * Copyright © 2019 IBM. + * + * 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. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.services.execution + +import com.fasterxml.jackson.databind.JsonNode +import com.google.protobuf.Struct +import com.google.protobuf.Timestamp +import com.google.protobuf.util.JsonFormat +import io.grpc.ManagedChannel +import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.* +import org.onap.ccsdk.cds.blueprintsprocessor.grpc.service.BluePrintGrpcLibPropertyService +import org.onap.ccsdk.cds.controllerblueprints.command.api.* +import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.config.ConfigurableBeanFactory +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty +import org.springframework.context.annotation.Scope +import org.springframework.stereotype.Service + + +interface RemoteScriptExecutionService { + suspend fun init(selector: String) + suspend fun prepareEnv(prepareEnvInput: PrepareRemoteEnvInput): RemoteScriptExecutionOutput + suspend fun executeCommand(remoteExecutionInput: RemoteScriptExecutionInput): RemoteScriptExecutionOutput + suspend fun close() +} + +@Service(ExecutionServiceConstant.SERVICE_GRPC_REMOTE_SCRIPT_EXECUTION) +@ConditionalOnProperty(prefix = "blueprintprocessor.remoteScriptCommand", name = arrayOf("enabled"), + havingValue = "true", matchIfMissing = false) +@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +class GrpcRemoteScriptExecutionService(private val bluePrintGrpcLibPropertyService: BluePrintGrpcLibPropertyService) + : RemoteScriptExecutionService { + + private val log = LoggerFactory.getLogger(GrpcRemoteScriptExecutionService::class.java)!! + + private var channel: ManagedChannel? = null + private lateinit var commandExecutorServiceGrpc: CommandExecutorServiceGrpc.CommandExecutorServiceFutureStub + + override suspend fun init(selector: String) { + // Get the GRPC Client Service based on selector + val grpcClientService = bluePrintGrpcLibPropertyService.blueprintGrpcClientService(selector) + // Get the GRPC Channel + channel = grpcClientService.channel() + // Create Non Blocking Stub + commandExecutorServiceGrpc = CommandExecutorServiceGrpc.newFutureStub(channel) + + checkNotNull(commandExecutorServiceGrpc) { + "failed to create command executor grpc client for selector($selector)" + } + } + + override suspend fun prepareEnv(prepareEnvInput: PrepareRemoteEnvInput) + : RemoteScriptExecutionOutput { + val grpResponse = commandExecutorServiceGrpc.prepareEnv(prepareEnvInput.asGrpcData()).get() + + checkNotNull(grpResponse.status) { + "failed to get GRPC prepare env response status for requestId($prepareEnvInput.requestId)" + } + + val remoteScriptExecutionOutput = grpResponse.asJavaData() + log.debug("Received prepare env response from command server for requestId($prepareEnvInput.requestId)") + + return remoteScriptExecutionOutput + } + + override suspend fun executeCommand(remoteExecutionInput: RemoteScriptExecutionInput) + : RemoteScriptExecutionOutput { + + val grpResponse = commandExecutorServiceGrpc.executeCommand(remoteExecutionInput.asGrpcData()).get() + + checkNotNull(grpResponse.status) { + "failed to get GRPC response status for requestId($remoteExecutionInput.requestId)" + } + + val remoteScriptExecutionOutput = grpResponse.asJavaData() + log.debug("Received response from command server for requestId($remoteExecutionInput.requestId)") + + return remoteScriptExecutionOutput + } + + override suspend fun close() { + channel?.shutdownNow() + } + + + fun PrepareRemoteEnvInput.asGrpcData(): PrepareEnvInput { + val correlationId = this.correlationId ?: this.requestId + + return PrepareEnvInput.newBuilder() + .setIdentifiers(this.remoteIdentifier!!.asGrpcData()) + .setRequestId(this.requestId) + .setCorrelationId(correlationId) + .setScriptType(ScriptType.valueOf(this.remoteScriptType.name)) + .setTimeOut(this.timeOut.toInt()) + .addAllPackages(this.packages) + .setProperties(this.properties.asGrpcData()) + .build() + } + + fun RemoteScriptExecutionInput.asGrpcData(): ExecutionInput { + val correlationId = this.correlationId ?: this.requestId + return ExecutionInput.newBuilder() + .setRequestId(this.requestId) + .setCorrelationId(correlationId) + .setIdentifiers(this.remoteIdentifier!!.asGrpcData()) + .setScriptType(ScriptType.valueOf(this.remoteScriptType.name)) + .setCommand(this.command) + .setTimeOut(this.timeOut.toInt()) + .setProperties(this.properties.asGrpcData()) + .setTimestamp(Timestamp.getDefaultInstance()) + .build() + } + + fun RemoteIdentifier.asGrpcData(): Identifiers? { + return Identifiers.newBuilder() + .setBlueprintName(this.blueprintName) + .setBlueprintVersion(this.blueprintVersion) + .build() + } + + fun Map<String, JsonNode>.asGrpcData(): Struct { + val struct = Struct.newBuilder() + JsonFormat.parser().merge(JacksonUtils.getJson(this), struct) + return struct.build() + } + + fun ExecutionOutput.asJavaData(): RemoteScriptExecutionOutput { + return RemoteScriptExecutionOutput( + requestId = this.requestId, + response = this.response, + status = StatusType.valueOf(this.status.name) + ) + } + +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/parent/pom.xml b/ms/blueprintsprocessor/parent/pom.xml index c9505cb94..42abbc51d 100755 --- a/ms/blueprintsprocessor/parent/pom.xml +++ b/ms/blueprintsprocessor/parent/pom.xml @@ -16,7 +16,8 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.onap.ccsdk.cds</groupId> @@ -50,6 +51,7 @@ <mockk.version>1.9</mockk.version> <dmaap.client.version>1.1.5</dmaap.client.version> <jinja.version>2.5.0</jinja.version> + <mockkserver.version>5.5.1</mockkserver.version> </properties> <dependencyManagement> <dependencies> @@ -312,6 +314,11 @@ </dependency> <dependency> <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> + <artifactId>grpc-lib</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> <artifactId>execution-service</artifactId> <version>${project.version}</version> </dependency> @@ -401,6 +408,12 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.mock-server</groupId> + <artifactId>mockserver-netty</artifactId> + <version>${mockkserver.version}</version> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>${powermock.version}</version> diff --git a/ms/cds-sdc-listener/application/pom.xml b/ms/cds-sdc-listener/application/pom.xml index 657e3934e..c58bb130f 100644 --- a/ms/cds-sdc-listener/application/pom.xml +++ b/ms/cds-sdc-listener/application/pom.xml @@ -14,6 +14,7 @@ <version>1.2.2-SNAPSHOT</version> </parent> + <groupId>org.onap.ccsdk.cds</groupId> <modelVersion>4.0.0</modelVersion> <artifactId>cds-sdc-listener-application</artifactId> <version>0.4.2-SNAPSHOT</version> diff --git a/ms/command-executor/pom.xml b/ms/command-executor/pom.xml new file mode 100755 index 000000000..af1b4f43b --- /dev/null +++ b/ms/command-executor/pom.xml @@ -0,0 +1,155 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright © 2019 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. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onap.ccsdk.cds</groupId> + <artifactId>ms</artifactId> + <version>0.4.2-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + <artifactId>command-executor</artifactId> + <packaging>pom</packaging> + <name>Command Executor</name> + <description>Micro-service providing python environment with gRPC binding for command execution</description> + + <properties> + <assembly.id>maven</assembly.id> + <image.name>onap/ccsdk-commandexecutor</image.name> + <docker.buildArg.https_proxy>${https_proxy}</docker.buildArg.https_proxy> + <docker.push.phase>deploy</docker.push.phase> + <docker.verbose>true</docker.verbose> + <ccsdk.project.version>${project.version}</ccsdk.project.version> + <ccsdk.build.timestamp>${maven.build.timestamp}</ccsdk.build.timestamp> + </properties> + + <build> + <plugins> + <plugin> + <artifactId>maven-resources-plugin</artifactId> + <version>2.6</version> + <executions> + <execution> + <id>copy-dockerfile</id> + <goals> + <goal>copy-resources</goal> + </goals> + <phase>validate</phase> + <configuration> + <outputDirectory>${basedir}/target/docker-stage</outputDirectory> + <resources> + <resource> + <directory>src/main/docker</directory> + <includes> + <include>Dockerfile</include> + <include>start.sh</include> + </includes> + <filtering>true</filtering> + </resource> + </resources> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <version>3.1.0</version> + <configuration> + <outputDirectory>${basedir}/target/docker-stage</outputDirectory> + <descriptors> + <descriptor>src/main/docker/distribution.xml</descriptor> + </descriptors> + <tarLongFileMode>posix</tarLongFileMode> + </configuration> + <executions> + <execution> + <id>${assembly.id}</id> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.codehaus.groovy.maven</groupId> + <artifactId>gmaven-plugin</artifactId> + <version>1.0</version> + <executions> + <execution> + <phase>validate</phase> + <goals> + <goal>execute</goal> + </goals> + <configuration> + <source>${basedir}/../../TagVersion.groovy</source> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + + <profiles> + <profile> + <id>docker</id> + <build> + <plugins> + <plugin> + <groupId>io.fabric8</groupId> + <artifactId>docker-maven-plugin</artifactId> + <version>0.26.1</version> + <inherited>false</inherited> + <configuration> + <images> + <image> + <name>${image.name}</name> + <build> + <cleanup>try</cleanup> + <dockerFileDir>${basedir}/target/docker-stage</dockerFileDir> + <tags> + <tag>${project.docker.latestfulltag.version}</tag> + </tags> + </build> + </image> + </images> + <verbose>true</verbose> + </configuration> + <executions> + <execution> + <id>generate-images</id> + <phase>package</phase> + <goals> + <goal>build</goal> + </goals> + </execution> + <execution> + <id>push-images</id> + <phase>${docker.push.phase}</phase> + <goals> + <goal>build</goal> + <goal>push</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> +</project> diff --git a/ms/command-executor/src/main/docker/Dockerfile b/ms/command-executor/src/main/docker/Dockerfile new file mode 100644 index 000000000..50f592dd6 --- /dev/null +++ b/ms/command-executor/src/main/docker/Dockerfile @@ -0,0 +1,21 @@ +FROM python:3.6-slim + +ENV GRPC_PYTHON_VERSION 1.19.0 +RUN python -m pip install --upgrade pip +RUN pip install grpcio==${GRPC_PYTHON_VERSION} grpcio-tools==${GRPC_PYTHON_VERSION} +RUN pip install virtualenv + +COPY start.sh /opt/app/onap/start.sh +RUN chmod u+x /opt/app/onap/start.sh + +RUN mkdir -p /opt/app/onap/logs/ && touch /opt/app/onap/logs/application.log + +COPY @project.build.finalName@-@assembly.id@.tar.gz /source.tar.gz +RUN tar -xzf /source.tar.gz -C /tmp \ + && cp -rf /tmp/@project.build.finalName@/opt / \ + && rm -rf /source.tar.gz \ + && rm -rf /tmp/@project.build.finalName@ + +VOLUME /opt/app/onap/blueprints/deploy/ + +ENTRYPOINT /opt/app/onap/start.sh
\ No newline at end of file diff --git a/ms/command-executor/src/main/docker/distribution.xml b/ms/command-executor/src/main/docker/distribution.xml new file mode 100755 index 000000000..7b8c27021 --- /dev/null +++ b/ms/command-executor/src/main/docker/distribution.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright © 2019 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. + --> + +<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd"> + <id>${assembly.id}</id> + <formats> + <format>tar.gz</format> + </formats> + <fileSets> + <fileSet> + <directory>${project.basedir}/src/main/python</directory> + <outputDirectory>/opt/app/onap/python</outputDirectory> + </fileSet> + </fileSets> +</assembly>
\ No newline at end of file diff --git a/ms/command-executor/src/main/docker/start.sh b/ms/command-executor/src/main/docker/start.sh new file mode 100755 index 000000000..659038418 --- /dev/null +++ b/ms/command-executor/src/main/docker/start.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +# +# Copyright (C) 2019 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. +# + +if [ -z "${APP_PORT}" ] +then + echo "APP_PORT environment variable is not set, using default." + export APP_PORT=50051 +fi + +if [ -z "${BASIC_AUTH}" ] +then + echo "BASIC_AUTH environment variable is not set, using default." + export BASIC_AUTH="Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==" +fi + +cd /opt/app/onap/python/ +python server.py ${APP_PORT} ${BASIC_AUTH}
\ No newline at end of file diff --git a/ms/command-executor/src/main/python/command_executor_handler.py b/ms/command-executor/src/main/python/command_executor_handler.py new file mode 100644 index 000000000..4ae575b0f --- /dev/null +++ b/ms/command-executor/src/main/python/command_executor_handler.py @@ -0,0 +1,105 @@ +# +# Copyright (C) 2019 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. +# +import logging +import os +import subprocess +import virtualenv +import venv +from builtins import Exception, open, dict +from subprocess import CalledProcessError, PIPE + +import utils + + +class CommandExecutorHandler: + + def __init__(self, request): + self.logger = logging.getLogger(self.__class__.__name__) + self.blueprint_id = utils.get_blueprint_id(request) + self.venv_home = '/opt/app/onap/blueprints/deploy/' + self.blueprint_id + + def prepare_env(self, request, results): + self.create_venv() + if not self.activate_venv(): + return False + + for package in request.packages: + if not self.install(package, results): + return False + + # deactivate_venv(blueprint_id) + return True + + def execute_command(self, request, results): + if not self.activate_venv(): + return False + + try: + results.append(os.popen(request.command).read()) + except Exception as e: + self.logger.info("{} - Failed to execute command. Error: {}".format(self.blueprint_id, e)) + results.append(e) + return False + + # deactivate_venv(blueprint_id) + return True + + def install(self, package, results): + self.logger.info("{} - Install package({}) in Python Virtual Environment".format(self.blueprint_id, package)) + command = ["pip", "install", package] + + env = dict(os.environ) + # fixme - parameterize + # env['https_proxy'] = "https://fastweb.int.bell.ca:8083" + + try: + results.append(subprocess.run(command, check=True, stdout=PIPE, stderr=PIPE, env=env).stdout.decode()) + return True + except CalledProcessError as e: + results.append(e.stderr.decode()) + return False + + def create_venv(self): + self.logger.info("{} - Create Python Virtual Environment".format(self.blueprint_id)) + try: + bin_dir = self.venv_home + "/bin" + # venv doesn't populate the activate_this.py script, hence we use from virtualenv + venv.create(self.venv_home, with_pip=True, system_site_packages=True) + virtualenv.writefile(os.path.join(bin_dir, "activate_this.py"), virtualenv.ACTIVATE_THIS) + except Exception as err: + self.logger.info( + "{} - Failed to provision Python Virtual Environment. Error: {}".format(self.blueprint_id, err)) + + def activate_venv(self): + self.logger.info("{} - Activate Python Virtual Environment".format(self.blueprint_id)) + + path = "%s/bin/activate_this.py" % self.venv_home + try: + exec (open(path).read(), {'__file__': path}) + return True + except Exception as err: + self.logger.info( + "{} - Failed to activate Python Virtual Environment. Error: {}".format(self.blueprint_id, err)) + return False + + def deactivate_venv(self): + self.logger.info("{} - Deactivate Python Virtual Environment".format(self.blueprint_id)) + command = ["deactivate"] + try: + subprocess.run(command, check=True) + except Exception as err: + self.logger.info( + "{} - Failed to deactivate Python Virtual Environment. Error: {}".format(self.blueprint_id, err)) diff --git a/ms/command-executor/src/main/python/command_executor_server.py b/ms/command-executor/src/main/python/command_executor_server.py new file mode 100644 index 000000000..3596a0ec5 --- /dev/null +++ b/ms/command-executor/src/main/python/command_executor_server.py @@ -0,0 +1,57 @@ +#!/usr/bin/python + +# +# Copyright (C) 2019 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. +# +import logging + +import proto.CommandExecutor_pb2_grpc as CommandExecutor_pb2_grpc + +from command_executor_handler import CommandExecutorHandler +import utils + +_ONE_DAY_IN_SECONDS = 60 * 60 * 24 + + +class CommandExecutorServer(CommandExecutor_pb2_grpc.CommandExecutorServiceServicer): + + def __init__(self): + self.logger = logging.getLogger(self.__class__.__name__) + + def prepareEnv(self, request, context): + blueprint_id = utils.get_blueprint_id(request) + self.logger.info("{} - Received prepareEnv request".format(blueprint_id)) + self.logger.info(request) + + results = [] + handler = CommandExecutorHandler(request) + if not handler.prepare_env(request, results): + self.logger.info("{} - Failed to prepare python environment. {}".format(blueprint_id, results)) + return utils.build_response(request, results, False) + self.logger.info("{} - Package installation logs {}".format(blueprint_id, results)) + return utils.build_response(request, results) + + def executeCommand(self, request, context): + blueprint_id = utils.get_blueprint_id(request) + self.logger.info("{} - Received executeCommand request".format(blueprint_id)) + self.logger.info(request) + + results = [] + handler = CommandExecutorHandler(request) + if not handler.execute_command(request, results): + self.logger.info("{} - Failed to executeCommand. {}".format(blueprint_id, results)) + return utils.build_response(request, results, False) + self.logger.info("{} - Execute command logs: {}".format(blueprint_id, results)) + return utils.build_response(request, results) diff --git a/ms/command-executor/src/main/python/proto/CommandExecutor_pb2.py b/ms/command-executor/src/main/python/proto/CommandExecutor_pb2.py new file mode 100644 index 000000000..637d37d87 --- /dev/null +++ b/ms/command-executor/src/main/python/proto/CommandExecutor_pb2.py @@ -0,0 +1,422 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: CommandExecutor.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='CommandExecutor.proto', + package='org.onap.ccsdk.cds.controllerblueprints.command.api', + syntax='proto3', + serialized_options=_b('P\001'), + serialized_pb=_b('\n\x15\x43ommandExecutor.proto\x12\x33org.onap.ccsdk.cds.controllerblueprints.command.api\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xe4\x02\n\x0e\x45xecutionInput\x12\x11\n\trequestId\x18\x01 \x01(\t\x12\x15\n\rcorrelationId\x18\x02 \x01(\t\x12U\n\x0bidentifiers\x18\x03 \x01(\x0b\x32@.org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers\x12S\n\nscriptType\x18\x04 \x01(\x0e\x32?.org.onap.ccsdk.cds.controllerblueprints.command.api.ScriptType\x12\x0f\n\x07\x63ommand\x18\x05 \x01(\t\x12\x0f\n\x07timeOut\x18\x06 \x01(\x05\x12+\n\nproperties\x18\x07 \x01(\x0b\x32\x17.google.protobuf.Struct\x12-\n\ttimestamp\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xe6\x02\n\x0fPrepareEnvInput\x12U\n\x0bidentifiers\x18\x01 \x01(\x0b\x32@.org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers\x12\x11\n\trequestId\x18\x02 \x01(\t\x12\x15\n\rcorrelationId\x18\x03 \x01(\t\x12S\n\nscriptType\x18\x04 \x01(\x0e\x32?.org.onap.ccsdk.cds.controllerblueprints.command.api.ScriptType\x12\x10\n\x08packages\x18\x05 \x03(\t\x12\x0f\n\x07timeOut\x18\x06 \x01(\x05\x12+\n\nproperties\x18\x07 \x01(\x0b\x32\x17.google.protobuf.Struct\x12-\n\ttimestamp\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\">\n\x0bIdentifiers\x12\x15\n\rblueprintName\x18\x01 \x01(\t\x12\x18\n\x10\x62lueprintVersion\x18\x02 \x01(\t\"\xba\x01\n\x0f\x45xecutionOutput\x12\x11\n\trequestId\x18\x01 \x01(\t\x12\x10\n\x08response\x18\x02 \x01(\t\x12S\n\x06status\x18\x03 \x01(\x0e\x32\x43.org.onap.ccsdk.cds.controllerblueprints.command.api.ResponseStatus\x12-\n\ttimestamp\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp**\n\x0eResponseStatus\x12\x0b\n\x07SUCCESS\x10\x00\x12\x0b\n\x07\x46\x41ILURE\x10\x01*9\n\nScriptType\x12\n\n\x06PYTHON\x10\x00\x12\x0b\n\x07\x41NSIBLE\x10\x01\x12\n\n\x06KOTLIN\x10\x02\x12\x06\n\x02SH\x10\x03\x32\xd1\x02\n\x16\x43ommandExecutorService\x12\x98\x01\n\nprepareEnv\x12\x44.org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput\x1a\x44.org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput\x12\x9b\x01\n\x0e\x65xecuteCommand\x12\x43.org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput\x1a\x44.org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutputB\x02P\x01\x62\x06proto3') + , + dependencies=[google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) + +_RESPONSESTATUS = _descriptor.EnumDescriptor( + name='ResponseStatus', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ResponseStatus', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='SUCCESS', index=0, number=0, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='FAILURE', index=1, number=1, + serialized_options=None, + type=None), + ], + containing_type=None, + serialized_options=None, + serialized_start=1114, + serialized_end=1156, +) +_sym_db.RegisterEnumDescriptor(_RESPONSESTATUS) + +ResponseStatus = enum_type_wrapper.EnumTypeWrapper(_RESPONSESTATUS) +_SCRIPTTYPE = _descriptor.EnumDescriptor( + name='ScriptType', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ScriptType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='PYTHON', index=0, number=0, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ANSIBLE', index=1, number=1, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='KOTLIN', index=2, number=2, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SH', index=3, number=3, + serialized_options=None, + type=None), + ], + containing_type=None, + serialized_options=None, + serialized_start=1158, + serialized_end=1215, +) +_sym_db.RegisterEnumDescriptor(_SCRIPTTYPE) + +ScriptType = enum_type_wrapper.EnumTypeWrapper(_SCRIPTTYPE) +SUCCESS = 0 +FAILURE = 1 +PYTHON = 0 +ANSIBLE = 1 +KOTLIN = 2 +SH = 3 + + + +_EXECUTIONINPUT = _descriptor.Descriptor( + name='ExecutionInput', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='requestId', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.requestId', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='correlationId', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.correlationId', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='identifiers', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.identifiers', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='scriptType', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.scriptType', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='command', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.command', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='timeOut', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.timeOut', index=5, + number=6, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='properties', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.properties', index=6, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='timestamp', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.timestamp', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=142, + serialized_end=498, +) + + +_PREPAREENVINPUT = _descriptor.Descriptor( + name='PrepareEnvInput', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='identifiers', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.identifiers', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='requestId', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.requestId', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='correlationId', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.correlationId', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='scriptType', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.scriptType', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='packages', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.packages', index=4, + number=5, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='timeOut', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.timeOut', index=5, + number=6, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='properties', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.properties', index=6, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='timestamp', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.timestamp', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=501, + serialized_end=859, +) + + +_IDENTIFIERS = _descriptor.Descriptor( + name='Identifiers', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='blueprintName', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers.blueprintName', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='blueprintVersion', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers.blueprintVersion', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=861, + serialized_end=923, +) + + +_EXECUTIONOUTPUT = _descriptor.Descriptor( + name='ExecutionOutput', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='requestId', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput.requestId', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='response', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput.response', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='status', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput.status', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='timestamp', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput.timestamp', index=3, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=926, + serialized_end=1112, +) + +_EXECUTIONINPUT.fields_by_name['identifiers'].message_type = _IDENTIFIERS +_EXECUTIONINPUT.fields_by_name['scriptType'].enum_type = _SCRIPTTYPE +_EXECUTIONINPUT.fields_by_name['properties'].message_type = google_dot_protobuf_dot_struct__pb2._STRUCT +_EXECUTIONINPUT.fields_by_name['timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_PREPAREENVINPUT.fields_by_name['identifiers'].message_type = _IDENTIFIERS +_PREPAREENVINPUT.fields_by_name['scriptType'].enum_type = _SCRIPTTYPE +_PREPAREENVINPUT.fields_by_name['properties'].message_type = google_dot_protobuf_dot_struct__pb2._STRUCT +_PREPAREENVINPUT.fields_by_name['timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_EXECUTIONOUTPUT.fields_by_name['status'].enum_type = _RESPONSESTATUS +_EXECUTIONOUTPUT.fields_by_name['timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +DESCRIPTOR.message_types_by_name['ExecutionInput'] = _EXECUTIONINPUT +DESCRIPTOR.message_types_by_name['PrepareEnvInput'] = _PREPAREENVINPUT +DESCRIPTOR.message_types_by_name['Identifiers'] = _IDENTIFIERS +DESCRIPTOR.message_types_by_name['ExecutionOutput'] = _EXECUTIONOUTPUT +DESCRIPTOR.enum_types_by_name['ResponseStatus'] = _RESPONSESTATUS +DESCRIPTOR.enum_types_by_name['ScriptType'] = _SCRIPTTYPE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +ExecutionInput = _reflection.GeneratedProtocolMessageType('ExecutionInput', (_message.Message,), dict( + DESCRIPTOR = _EXECUTIONINPUT, + __module__ = 'CommandExecutor_pb2' + # @@protoc_insertion_point(class_scope:org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput) + )) +_sym_db.RegisterMessage(ExecutionInput) + +PrepareEnvInput = _reflection.GeneratedProtocolMessageType('PrepareEnvInput', (_message.Message,), dict( + DESCRIPTOR = _PREPAREENVINPUT, + __module__ = 'CommandExecutor_pb2' + # @@protoc_insertion_point(class_scope:org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput) + )) +_sym_db.RegisterMessage(PrepareEnvInput) + +Identifiers = _reflection.GeneratedProtocolMessageType('Identifiers', (_message.Message,), dict( + DESCRIPTOR = _IDENTIFIERS, + __module__ = 'CommandExecutor_pb2' + # @@protoc_insertion_point(class_scope:org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers) + )) +_sym_db.RegisterMessage(Identifiers) + +ExecutionOutput = _reflection.GeneratedProtocolMessageType('ExecutionOutput', (_message.Message,), dict( + DESCRIPTOR = _EXECUTIONOUTPUT, + __module__ = 'CommandExecutor_pb2' + # @@protoc_insertion_point(class_scope:org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput) + )) +_sym_db.RegisterMessage(ExecutionOutput) + + +DESCRIPTOR._options = None + +_COMMANDEXECUTORSERVICE = _descriptor.ServiceDescriptor( + name='CommandExecutorService', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorService', + file=DESCRIPTOR, + index=0, + serialized_options=None, + serialized_start=1218, + serialized_end=1555, + methods=[ + _descriptor.MethodDescriptor( + name='prepareEnv', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorService.prepareEnv', + index=0, + containing_service=None, + input_type=_PREPAREENVINPUT, + output_type=_EXECUTIONOUTPUT, + serialized_options=None, + ), + _descriptor.MethodDescriptor( + name='executeCommand', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorService.executeCommand', + index=1, + containing_service=None, + input_type=_EXECUTIONINPUT, + output_type=_EXECUTIONOUTPUT, + serialized_options=None, + ), +]) +_sym_db.RegisterServiceDescriptor(_COMMANDEXECUTORSERVICE) + +DESCRIPTOR.services_by_name['CommandExecutorService'] = _COMMANDEXECUTORSERVICE + +# @@protoc_insertion_point(module_scope) diff --git a/ms/command-executor/src/main/python/proto/CommandExecutor_pb2_grpc.py b/ms/command-executor/src/main/python/proto/CommandExecutor_pb2_grpc.py new file mode 100644 index 000000000..3ea8ec4d6 --- /dev/null +++ b/ms/command-executor/src/main/python/proto/CommandExecutor_pb2_grpc.py @@ -0,0 +1,63 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc + +import proto.CommandExecutor_pb2 as CommandExecutor__pb2 + + +class CommandExecutorServiceStub(object): + # missing associated documentation comment in .proto file + pass + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.prepareEnv = channel.unary_unary( + '/org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorService/prepareEnv', + request_serializer=CommandExecutor__pb2.PrepareEnvInput.SerializeToString, + response_deserializer=CommandExecutor__pb2.ExecutionOutput.FromString, + ) + self.executeCommand = channel.unary_unary( + '/org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorService/executeCommand', + request_serializer=CommandExecutor__pb2.ExecutionInput.SerializeToString, + response_deserializer=CommandExecutor__pb2.ExecutionOutput.FromString, + ) + + +class CommandExecutorServiceServicer(object): + # missing associated documentation comment in .proto file + pass + + def prepareEnv(self, request, context): + # missing associated documentation comment in .proto file + pass + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def executeCommand(self, request, context): + # missing associated documentation comment in .proto file + pass + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_CommandExecutorServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'prepareEnv': grpc.unary_unary_rpc_method_handler( + servicer.prepareEnv, + request_deserializer=CommandExecutor__pb2.PrepareEnvInput.FromString, + response_serializer=CommandExecutor__pb2.ExecutionOutput.SerializeToString, + ), + 'executeCommand': grpc.unary_unary_rpc_method_handler( + servicer.executeCommand, + request_deserializer=CommandExecutor__pb2.ExecutionInput.FromString, + response_serializer=CommandExecutor__pb2.ExecutionOutput.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) diff --git a/ms/command-executor/src/main/python/proto/__init__.py b/ms/command-executor/src/main/python/proto/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ms/command-executor/src/main/python/proto/__init__.py diff --git a/ms/command-executor/src/main/python/request_header_validator_interceptor.py b/ms/command-executor/src/main/python/request_header_validator_interceptor.py new file mode 100644 index 000000000..261357337 --- /dev/null +++ b/ms/command-executor/src/main/python/request_header_validator_interceptor.py @@ -0,0 +1,38 @@ +# +# Copyright (C) 2019 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. +# + +import grpc + + +def _unary_unary_rpc_terminator(code, details): + def terminate(ignored_request, context): + context.abort(code, details) + + return grpc.unary_unary_rpc_method_handler(terminate) + + +class RequestHeaderValidatorInterceptor(grpc.ServerInterceptor): + + def __init__(self, header, value, code, details): + self._header = header + self._value = value + self._terminator = _unary_unary_rpc_terminator(code, details) + + def intercept_service(self, continuation, handler_call_details): + if (self._header, self._value) in handler_call_details.invocation_metadata: + return continuation(handler_call_details) + else: + return self._terminator diff --git a/ms/command-executor/src/main/python/server.py b/ms/command-executor/src/main/python/server.py new file mode 100644 index 000000000..de620474b --- /dev/null +++ b/ms/command-executor/src/main/python/server.py @@ -0,0 +1,72 @@ +#!/usr/bin/python + +# +# Copyright (C) 2019 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. +# +from builtins import KeyboardInterrupt +from concurrent import futures +import logging +import time +import sys + +import grpc + +import proto.CommandExecutor_pb2_grpc as CommandExecutor_pb2_grpc + +from request_header_validator_interceptor import RequestHeaderValidatorInterceptor +from command_executor_server import CommandExecutorServer + +logger = logging.getLogger("Server") + +_ONE_DAY_IN_SECONDS = 60 * 60 * 24 + + +def serve(): + port = sys.argv[1] + basic_auth = sys.argv[2] + ' ' + sys.argv[3] + + header_validator = RequestHeaderValidatorInterceptor( + 'authorization', basic_auth, grpc.StatusCode.UNAUTHENTICATED, + 'Access denied!') + + server = grpc.server( + futures.ThreadPoolExecutor(max_workers=10), + interceptors=(header_validator,)) + + CommandExecutor_pb2_grpc.add_CommandExecutorServiceServicer_to_server( + CommandExecutorServer(), server) + + server.add_insecure_port('[::]:' + port) + server.start() + + logger.info("Command Executor Server started on %s" % port) + + try: + while True: + time.sleep(_ONE_DAY_IN_SECONDS) + except KeyboardInterrupt: + server.stop(0) + + +if __name__ == '__main__': + logging_formater = '%(asctime)s - %(name)s - %(threadName)s - %(levelname)s - %(message)s' + logging.basicConfig(filename='/opt/app/onap/logs/application.log', level=logging.DEBUG, + format=logging_formater) + console = logging.StreamHandler() + console.setLevel(logging.INFO) + formatter = logging.Formatter(logging_formater) + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + serve() diff --git a/ms/command-executor/src/main/python/utils.py b/ms/command-executor/src/main/python/utils.py new file mode 100644 index 000000000..6260997f3 --- /dev/null +++ b/ms/command-executor/src/main/python/utils.py @@ -0,0 +1,37 @@ +# +# Copyright (C) 2019 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. +# +from google.protobuf.timestamp_pb2 import Timestamp + +import proto.CommandExecutor_pb2 as CommandExecutor_pb2 + + +def get_blueprint_id(request): + blueprint_name = request.identifiers.blueprintName + blueprint_version = request.identifiers.blueprintVersion + return blueprint_name + '/' + blueprint_version + + +def build_response(request, results, is_success=True): + if is_success: + status = CommandExecutor_pb2.SUCCESS + else: + status = CommandExecutor_pb2.FAILURE + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + return CommandExecutor_pb2.ExecutionOutput(requestId=request.requestId, response="".join(results), status=status, + timestamp=timestamp) diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt index d45571cdf..72c2c1df3 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt @@ -97,6 +97,10 @@ fun <T : Any> Map<String, *>.castValue(key: String, valueType: KClass<T>): T { } } +fun ArrayNode.asListOfString(): List<String> { + return JacksonUtils.getListFromJsonNode(this, String::class.java) +} + /** * Convert Json to map of json node, the root fields will be map keys */ diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/dictionary/dictionary_schema.json b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/dictionary/dictionary_schema.json index cac8770af..0e1f84278 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/test/resources/dictionary/dictionary_schema.json +++ b/ms/controllerblueprints/modules/blueprint-core/src/test/resources/dictionary/dictionary_schema.json @@ -51,8 +51,46 @@ "default": { "type": "any" }, - "aai": { - "type": "any" + "primary-aai-data": { + "type": "object", + "properties": { + "verb": { + "type": "string", + "required": true + }, + "path": { + "type": "string", + "required": true + }, + "url-path": { + "type": "string", + "required": true + }, + "payload": { + "type": "string", + "required": false + }, + "input-key-mapping": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "type": { + "type": "string", + "required": true + }, + "output-key-mapping": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base": { + "type": "string", + "required": true + } + } }, "primary-config-data": { "type": "object", @@ -177,7 +215,7 @@ } } }, - "aai": { + "primary-aai-data": { "type": "object", "properties": { "names": { diff --git a/ms/controllerblueprints/modules/service/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/enhancer/BluePrintEnhancerServiceImplTest.kt b/ms/controllerblueprints/modules/service/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/enhancer/BluePrintEnhancerServiceImplTest.kt index e82ffc458..d06d5db9a 100644 --- a/ms/controllerblueprints/modules/service/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/enhancer/BluePrintEnhancerServiceImplTest.kt +++ b/ms/controllerblueprints/modules/service/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/enhancer/BluePrintEnhancerServiceImplTest.kt @@ -92,6 +92,14 @@ class BluePrintEnhancerServiceImplTest { } + @Test + @Throws(Exception::class) + fun testRemoteScriptsEnhancementAndValidation() { + val basePath = "./../../../../components/model-catalog/blueprint-model/test-blueprint/remote_scripts" + testComponentInvokeEnhancementAndValidation(basePath, "remote_scripts-enhance") + + } + private fun testComponentInvokeEnhancementAndValidation(basePath: String, targetDirName: String) { runBlocking { val targetPath = normalizedPathName("target/blueprints/enrichment", targetDirName) @@ -105,7 +113,7 @@ class BluePrintEnhancerServiceImplTest { val valid = bluePrintValidatorService.validateBluePrints(targetPath) Assert.assertTrue("blueprint($basePath) validation failed ", valid) -// deleteDir(targetPath) + deleteDir(targetPath) } } diff --git a/ms/pom.xml b/ms/pom.xml index 6f84a1438..d1c87c995 100644 --- a/ms/pom.xml +++ b/ms/pom.xml @@ -35,6 +35,7 @@ <modules> <module>controllerblueprints</module> <module>blueprintsprocessor</module> + <module>command-executor</module> <module>cds-sdc-listener</module> </modules> </project> |