Merge "Test template css changes"
authorDan Timoney <dtimoney@att.com>
Fri, 19 Apr 2019 00:30:03 +0000 (00:30 +0000)
committerGerrit Code Review <gerrit@onap.org>
Fri, 19 Apr 2019 00:30:03 +0000 (00:30 +0000)
64 files changed:
.gitignore
components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/artifact_types.json [new file with mode: 0644]
components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/data_types.json [new file with mode: 0644]
components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/node_types.json [new file with mode: 0644]
components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/policy_types.json [new file with mode: 0644]
components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/relationship_types.json [new file with mode: 0644]
components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/remote_scripts.json [new file with mode: 0644]
components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Definitions/resources_definition_types.json [new file with mode: 0644]
components/model-catalog/blueprint-model/test-blueprint/remote_scripts/Scripts/python/SamplePython.py [new file with mode: 0644]
components/model-catalog/blueprint-model/test-blueprint/remote_scripts/TOSCA-Metadata/TOSCA.meta [new file with mode: 0644]
components/model-catalog/definition-type/starter-type/node_type/component-remote-python-executor.json
components/model-catalog/proto-definition/proto/CommandExecutor.proto
docs/datadictionary/dbsystemcode.rst [new file with mode: 0644]
docs/datadictionary/image0.JPG [moved from docs/datadictionary/media/image0.JPG with 100% similarity]
docs/datadictionary/image1.JPG [moved from docs/datadictionary/media/image1.JPG with 100% similarity]
docs/datadictionary/index.rst
docs/datadictionary/resourcesource.rst
docs/datadictionary/restsourcecode.rst [new file with mode: 0644]
docs/datadictionary/sourcecapabilitycode.rst [new file with mode: 0644]
docs/datadictionary/sourcedefaultcode.rst [new file with mode: 0644]
docs/datadictionary/sourceinputcode.rst [new file with mode: 0644]
docs/datadictionary/sourceprimarydbcode.rst [new file with mode: 0644]
docs/dynamicapi.rst [new file with mode: 0644]
docs/flexibleplugin.rst [new file with mode: 0644]
docs/media/dyanmicapi.JPG [new file with mode: 0644]
docs/resourceassignment.rst
ms/blueprintsprocessor/application/src/main/resources/application-dev.properties
ms/blueprintsprocessor/application/src/main/resources/application.properties
ms/blueprintsprocessor/application/src/test/resources/application.properties
ms/blueprintsprocessor/functions/python-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutor.kt
ms/blueprintsprocessor/functions/python-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/python/executor/ComponentRemotePythonExecutorTest.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibConfiguration.kt
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/BluePrintGrpcLibData.kt
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BasicAuthGrpcClientService.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcClientService.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyService.kt
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/TokenAuthGrpcClientService.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/api/data/BlueprintRemoteProcessorData.kt
ms/blueprintsprocessor/modules/services/execution-service/pom.xml
ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/ExecutionServiceConfiguration.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/RemoteScriptExecutionService.kt
ms/blueprintsprocessor/parent/pom.xml
ms/cds-sdc-listener/application/pom.xml
ms/cds-sdc-listener/application/src/main/docker/Dockerfile [new file with mode: 0644]
ms/cds-sdc-listener/application/src/main/docker/docker-compose.yaml [new file with mode: 0644]
ms/cds-sdc-listener/application/src/main/docker/start.sh [new file with mode: 0755]
ms/cds-sdc-listener/application/src/main/resources/application.yml
ms/cds-sdc-listener/application/src/main/resources/logback.xml [new file with mode: 0644]
ms/cds-sdc-listener/distribution/pom.xml [deleted file]
ms/command-executor/pom.xml [new file with mode: 0755]
ms/command-executor/src/main/docker/Dockerfile [new file with mode: 0644]
ms/command-executor/src/main/docker/distribution.xml [new file with mode: 0755]
ms/command-executor/src/main/docker/start.sh [new file with mode: 0755]
ms/command-executor/src/main/python/command_executor_handler.py [new file with mode: 0644]
ms/command-executor/src/main/python/command_executor_server.py [new file with mode: 0644]
ms/command-executor/src/main/python/proto/CommandExecutor_pb2.py [new file with mode: 0644]
ms/command-executor/src/main/python/proto/CommandExecutor_pb2_grpc.py [new file with mode: 0644]
ms/command-executor/src/main/python/proto/__init__.py [new file with mode: 0644]
ms/command-executor/src/main/python/request_header_validator_interceptor.py [new file with mode: 0644]
ms/command-executor/src/main/python/server.py [new file with mode: 0644]
ms/command-executor/src/main/python/utils.py [new file with mode: 0644]
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt
ms/controllerblueprints/modules/service/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/enhancer/BluePrintEnhancerServiceImplTest.kt
ms/pom.xml

index e3e0e1f..a2661f0 100644 (file)
@@ -1,6 +1,9 @@
 # Node.js
 **/node
 
+# Python
+**/*.pyc
+
 # Logs
 logs
 *.log
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 (file)
index 0000000..4452363
--- /dev/null
@@ -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 (file)
index 0000000..b22e30d
--- /dev/null
@@ -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 (file)
index 0000000..cd63f00
--- /dev/null
@@ -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 (file)
index 0000000..2442ce8
--- /dev/null
@@ -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 (file)
index 0000000..097a30a
--- /dev/null
@@ -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 (file)
index 0000000..4649114
--- /dev/null
@@ -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 (file)
index 0000000..9e26dfe
--- /dev/null
@@ -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 (file)
index 0000000..5e20e22
--- /dev/null
@@ -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 (file)
index 0000000..5ca8aa0
--- /dev/null
@@ -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
index df2095c..99a4dd8 100644 (file)
@@ -1,6 +1,12 @@
 {
-  "description": "This is Jython Execution Component.",
+  "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"
             "endpoint-selector": {
               "description": "Remote Container or Server selector name.",
               "required": false,
-              "type": "string"
+              "type": "string",
+              "default": "remote-python"
             },
             "dynamic-properties": {
               "description": "Dynamic Json Content or DSL Json reference.",
               "required": false,
               "type": "json"
-            }
-          },
-          "outputs": {
-            "response-data": {
-              "description": "Execution Response Data in JSON format.",
-              "required": false,
-              "type": "json"
             },
-            "status": {
-              "description": "Status of the Component Execution ( success or failure )",
+            "command": {
+              "description": "Command to execute.",
               "required": true,
               "type": "string"
             }
index e95e555..f488cc1 100644 (file)
@@ -6,27 +6,30 @@ 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 = 2;
-    ScriptType scriptType = 3;
+    Identifiers identifiers = 3;
+    ScriptType scriptType = 4;
     // Actual Command to Execute in Scripting Environment
-    string command = 4;
-    int32 timeOut = 5;
+    string command = 5;
+    int32 timeOut = 6;
     // Extra Dynamic Properties for Command processing in JSON format
-    google.protobuf.Struct properties = 6;
+    google.protobuf.Struct properties = 7;
     // Request Time Stamp
-    google.protobuf.Timestamp timestamp = 7;
+    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 = 2;
-    ScriptType scriptType = 3;
-    repeated string packages = 4;
-    int32 timeOut = 5;
-    google.protobuf.Struct properties = 6;
-    google.protobuf.Timestamp timestamp = 7;
+    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 {
diff --git a/docs/datadictionary/dbsystemcode.rst b/docs/datadictionary/dbsystemcode.rst
new file mode 100644 (file)
index 0000000..5051d1e
--- /dev/null
@@ -0,0 +1,15 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright (C) 2019 IBM.
+
+Dbsystemcode
+============
+
+"dsl_definitions": {
+  "dynamic-db-source": {
+    "type": "maria-db",
+    "url": "jdbc:mysql://localhost:3306/sdnctl",
+    "username": "sdnctl",
+    "password": "sdnctl"
+  }
+}
\ No newline at end of file
index a7e7856..2405000 100644 (file)
@@ -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
index fffeec3..2b60990 100644 (file)
@@ -42,21 +42,21 @@ CDS is currently deployed along the side of SDNC, hence the primary database con
 
 |image0|
 
-.. |image0| image:: image0.jpg
+.. |image0| image:: sqltable.jpg
    :width: 7.88889in 
    :height: 4.43750in
 
 .. toctree::
    :maxdepth: 1  
 
-       sourceprimarydb
+       sourceprimarydbcode
        
 Connection to a specific database can be expressed through the endpoint-selector property, which refers to a macro defining the information about the database the connect to. Understand TOSCA Macro in the context of CDS.
 
 .. toctree::
    :maxdepth: 1 
 
-       dbsystem
+       dbsystemcode
 
 
 REST:
@@ -68,14 +68,14 @@ CDS is currently deployed along the side of SDNC, hence the default rest connect
 
 |image1|
 
-.. |image1| image:: image1.jpg
+.. |image1| image:: resttable.jpg
    :width: 7.88889in 
    :height: 4.43750in
 
 .. toctree::
    :maxdepth: 1
    
-   rest
+   restsourcecode
 
 Connection to a specific REST system can be expressed through the endpoint-selector property, which refers to a macro defining the information about the REST system the connect to. Understand TOSCA Macro in the context of CDS.
 
@@ -90,7 +90,7 @@ For source code of Authentication click below link:
 .. toctree::
    :maxdepth: 1
    
-   auth
+   restauth
 
 Capability:
 ===========
@@ -99,7 +99,7 @@ Expects a script to be provided.
 
 |image2|
 
-.. |image2| image:: image2.jpg
+.. |image2| image:: capabilitytable.jpg
    :width: 7.88889in 
    :height: 4.43750in
    
@@ -107,4 +107,4 @@ Expects a script to be provided.
 .. toctree::
    :maxdepth: 1   
 
-       source-capability   
+       sourcecapabilitycode
diff --git a/docs/datadictionary/restsourcecode.rst b/docs/datadictionary/restsourcecode.rst
new file mode 100644 (file)
index 0000000..90b0298
--- /dev/null
@@ -0,0 +1,90 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright (C) 2019 IBM.
+
+Rest Source Code:
+=================
+
+{
+  "description": "This is Rest Resource Source Node Type",
+  "version": "1.0.0",
+  "properties": {
+    "type": {
+      "required": false,
+      "type": "string",
+      "default": "JSON",
+      "constraints": [
+        {
+          "valid_values": [
+            "JSON"
+          ]
+        }
+      ]
+    },
+    "verb": {
+      "required": false,
+      "type": "string",
+      "default": "GET",
+      "constraints": [
+        {
+          "valid_values": [
+            "GET", "POST", "DELETE", "PUT"
+          ]
+        }
+      ]
+    },
+    "payload": {
+      "required": false,
+      "type": "string",
+      "default": ""
+    },
+    "endpoint-selector": {
+      "required": false,
+      "type": "string"
+    },
+    "url-path": {
+      "required": true,
+      "type": "string"
+    },
+    "path": {
+      "required": true,
+      "type": "string"
+    },
+    "expression-type": {
+      "required": false,
+      "type": "string",
+      "default": "JSON_PATH",
+      "constraints": [
+        {
+          "valid_values": [
+            "JSON_PATH",
+            "JSON_POINTER"
+          ]
+        }
+      ]
+    },
+    "input-key-mapping": {
+      "required": false,
+      "type": "map",
+      "entry_schema": {
+        "type": "string"
+      }
+    },
+    "output-key-mapping": {
+      "required": false,
+      "type": "map",
+      "entry_schema": {
+        "type": "string"
+      }
+    },
+    "key-dependencies": {
+      "required": true,
+      "type": "list",
+      "entry_schema": {
+        "type": "string"
+      }
+    }
+  },
+  "derived_from": "tosca.nodes.ResourceSource"
+}
+
diff --git a/docs/datadictionary/sourcecapabilitycode.rst b/docs/datadictionary/sourcecapabilitycode.rst
new file mode 100644 (file)
index 0000000..a917676
--- /dev/null
@@ -0,0 +1,48 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright (C) 2019 IBM.
+
+Source Capability Code
+======================
+
+{
+  "description": "This is Component Resource Source Node Type",
+  "version": "1.0.0",
+  "properties": {
+    "script-type": {
+      "required": true,
+      "type": "string",
+      "default": "kotlin",
+      "constraints": [
+        {
+          "valid_values": [
+            "kotlin",
+            "jython"
+          ]
+        }
+      ]
+    },
+    "script-class-reference": {
+      "description": "Capability reference name for internal and kotlin, for jython script file path",
+      "required": true,
+      "type": "string"
+    },
+    "instance-dependencies": {
+      "required": false,
+      "description": "Instance dependency Names to Inject to Kotlin / Jython Script.",
+      "type": "list",
+      "entry_schema": {
+        "type": "string"
+      }
+    },
+    "key-dependencies": {
+      "description": "Resource Resolution dependency dictionary names.",
+      "required": true,
+      "type": "list",
+      "entry_schema": {
+        "type": "string"
+      }
+    }
+  },
+  "derived_from": "tosca.nodes.ResourceSource"
+}
diff --git a/docs/datadictionary/sourcedefaultcode.rst b/docs/datadictionary/sourcedefaultcode.rst
new file mode 100644 (file)
index 0000000..243f87f
--- /dev/null
@@ -0,0 +1,13 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright (C) 2019 IBM.
+
+Source Default code
+===================
+
+{
+  "description": "This is Default Resource Source Node Type",
+  "version": "1.0.0",
+  "properties": {},
+  "derived_from": "tosca.nodes.ResourceSource"
+}
\ No newline at end of file
diff --git a/docs/datadictionary/sourceinputcode.rst b/docs/datadictionary/sourceinputcode.rst
new file mode 100644 (file)
index 0000000..b859272
--- /dev/null
@@ -0,0 +1,13 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright (C) 2019 IBM.
+
+Source Input code
+=================
+
+{
+  "description": "This is Input Resource Source Node Type",
+  "version": "1.0.0",
+  "properties": {},
+  "derived_from": "tosca.nodes.ResourceSource"
+}
\ No newline at end of file
diff --git a/docs/datadictionary/sourceprimarydbcode.rst b/docs/datadictionary/sourceprimarydbcode.rst
new file mode 100644 (file)
index 0000000..e2e0b2d
--- /dev/null
@@ -0,0 +1,54 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright (C) 2019 IBM.
+
+Source Primary DB Code:
+=======================
+
+{
+  "description": "This is Database Resource Source Node Type",
+  "version": "1.0.0",
+  "properties": {
+    "type": {
+      "required": true,
+      "type": "string",
+      "constraints": [
+        {
+          "valid_values": [
+            "SQL"
+          ]
+        }
+      ]
+    },
+    "endpoint-selector": {
+      "required": false,
+      "type": "string"
+    },
+    "query": {
+      "required": true,
+      "type": "string"
+    },
+    "input-key-mapping": {
+      "required": false,
+      "type": "map",
+      "entry_schema": {
+        "type": "string"
+      }
+    },
+    "output-key-mapping": {
+      "required": false,
+      "type": "map",
+      "entry_schema": {
+        "type": "string"
+      }
+    },
+    "key-dependencies": {
+      "required": true,
+      "type": "list",
+      "entry_schema": {
+        "type": "string"
+      }
+    }
+  },
+  "derived_from": "tosca.nodes.ResourceSource"
+}
\ No newline at end of file
diff --git a/docs/dynamicapi.rst b/docs/dynamicapi.rst
new file mode 100644 (file)
index 0000000..eaf9987
--- /dev/null
@@ -0,0 +1,24 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright (C) 2019 IBM.
+
+Dynamic API
+-----------
+
+The nature of the API request and response is meant to be model driven and dynamic. They both share the same definition.
+
+The actionName, under the actionIdentifiers refers to the name of a Workflow (see workflow)
+
+The content of the payload is what is fully dynamic / model driven.
+
+The first top level element will always be either $actionName-request for a request or $actionName-response for a response.
+
+Then the content within this element is fully based on the workflow input and output.
+
+Here is how the a generic request and response look like.
+
+|image0|
+
+.. |image0| image:: media/dynamicapi.jpg
+   :height: 4.43750in
+   :width: 7.88889in
\ No newline at end of file
diff --git a/docs/flexibleplugin.rst b/docs/flexibleplugin.rst
new file mode 100644 (file)
index 0000000..5c83ac9
--- /dev/null
@@ -0,0 +1,17 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International License.
+.. http://creativecommons.org/licenses/by/4.0
+.. Copyright (C) 2019 IBM.
+
+Flexible Plug-in
+----------------
+
+Interaction with external systems is made plug-able, removing development cycle to support new endpoint.
+
+Currently, REST or SQL external systems are supported.
+
+An external system might be used by multiple resources, or by multiple scripts.
+
+In order to share the external system information, TOSCA provides a way to create macros using dsl_definitions:
+
+http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.2/csd01/TOSCA-Simple-Profile-YAML-v1.2-csd01.html#_Toc494454160
+http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.2/csd01/TOSCA-Simple-Profile-YAML-v1.2-csd01.html#_Toc494454173
diff --git a/docs/media/dyanmicapi.JPG b/docs/media/dyanmicapi.JPG
new file mode 100644 (file)
index 0000000..3e00da3
Binary files /dev/null and b/docs/media/dyanmicapi.JPG differ
index be8b08e..f4fab4e 100644 (file)
@@ -3,7 +3,7 @@
 .. Copyright (C) 2019 IBM.
 
 Resource Assignment 
-===================
+-------------------
 .. toctree::
    :maxdepth: 1
    
index 0e2cdf9..2b90998 100755 (executable)
@@ -47,4 +47,10 @@ blueprintsprocessor.restconfEnabled=true
 blueprintsprocessor.restclient.sdncodl.type=basic-auth\r
 blueprintsprocessor.restclient.sdncodl.url=http://localhost:8282/\r
 blueprintsprocessor.restclient.sdncodl.username=admin\r
-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
index b34609c..e5b1fe5 100755 (executable)
 #  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
index 3078505..7e462f2 100644 (file)
@@ -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
index d34dbb7..6437cdf 100644 (file)
@@ -18,28 +18,35 @@ 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)
+    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) {
@@ -51,51 +58,77 @@ open class ComponentRemotePythonExecutor(private val remoteScriptExecutionServic
         val blueprintVersion = bluePrintContext.version()
 
         val operationAssignment: OperationAssignment = bluePrintContext
-                .nodeTemplateInterfaceOperation(nodeTemplateName, interfaceName, operationName)
+            .nodeTemplateInterfaceOperation(nodeTemplateName, interfaceName, operationName)
 
         val artifactName: String = operationAssignment.implementation?.primary
-                ?: throw BluePrintProcessorException("missing primary field to get artifact name for node template ($nodeTemplateName)")
+            ?: throw BluePrintProcessorException("missing primary field to get artifact name for node template ($nodeTemplateName)")
 
-        val artifactDefinition = bluePrintRuntimeService.resolveNodeTemplateArtifactDefinition(nodeTemplateName, artifactName)
+        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" }
-        //TODO ("Get the ENDPOINT SELECTOR and resolve the Remote Server")
+
         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: String = "python ${pythonScript.absolutePath}"
+        val scriptCommand = command.replace(pythonScript.name, pythonScript.absolutePath)
+
+        val dependencies = operationAssignment.implementation?.dependencies
+
+        try {
+            // Open GRPC Connection
+            remoteScriptExecutionService.init(endPointSelector.asText())
+
+            var executionLogs = ""
 
-        val packages = operationAssignment.implementation?.dependencies
-        // If dependencies are defined, then install in remote server
-        if (packages != null && !packages.isEmpty()) {
-            val prepareEnvInput = PrepareRemoteEnvInput(requestId = processId,
+            // 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 = arrayListOf()
-            )
-            val prepareEnvOutput = remoteScriptExecutionService.prepareEnv(prepareEnvInput)
-            checkNotNull(prepareEnvOutput) {
-                "failed to get prepare remote env response for requestId(${prepareEnvInput.requestId})"
+                    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(
+            val remoteExecutionInput = RemoteScriptExecutionInput(
                 requestId = processId,
                 remoteIdentifier = RemoteIdentifier(blueprintName = blueprintName, blueprintVersion = blueprintVersion),
                 remoteScriptType = RemoteScriptType.PYTHON,
                 command = scriptCommand)
-        val remoteExecutionOutput = remoteScriptExecutionService.executeCommand(remoteExecutionInput)
-        checkNotNull(remoteExecutionOutput) {
-            "failed to get prepare remote command response for requestId(${remoteExecutionOutput.requestId})"
+            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}")
+            .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 (file)
index 0000000..7cd5d5c
--- /dev/null
@@ -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
index 3fbc427..1bef3a0 100644 (file)
@@ -26,6 +26,7 @@ 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
index 1e082b4..76e60bd 100644 (file)
@@ -22,7 +22,11 @@ open class GrpcClientProperties {
     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 (file)
index 0000000..a175d8b
--- /dev/null
@@ -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 (file)
index 0000000..016c050
--- /dev/null
@@ -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
index 7510d1d..088533a 100644 (file)
@@ -21,6 +21,7 @@ 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
@@ -28,9 +29,24 @@ 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)!!
             }
@@ -44,6 +60,9 @@ open class BluePrintGrpcLibPropertyService(private var bluePrintProperties: Blue
         val type = bluePrintProperties.propertyBeanType(
                 "$prefix.type", String::class.java)
         return when (type) {
+            GRPCLibConstants.TYPE_TOKEN_AUTH -> {
+                tokenAuthGrpcClientProperties(prefix)
+            }
             GRPCLibConstants.TYPE_BASIC_AUTH -> {
                 basicAuthGrpcClientProperties(prefix)
             }
@@ -54,6 +73,25 @@ open class BluePrintGrpcLibPropertyService(private var bluePrintProperties: Blue
         }
     }
 
+    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)
     }
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 (file)
index 0000000..dbff842
--- /dev/null
@@ -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)
+            }
+        }
+    }
+}
index 90eb933..da952c0 100644 (file)
 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
 }
 
-data class RemoteIdentifier(var blueprintName: String? = null,
-                            var blueprintVersion: String? = null)
+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,
@@ -35,9 +41,14 @@ data class RemoteScriptExecutionInput(var requestId: String,
 )
 
 
-data class RemoteScriptExecutionOutput(var requestId: String, var response: String)
+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,
index 9ce5292..d366f74 100644 (file)
             <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId>
             <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>
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 (file)
index 0000000..806c330
--- /dev/null
@@ -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
index 5d279ce..7db5f52 100644 (file)
 
 package org.onap.ccsdk.cds.blueprintsprocessor.services.execution
 
-import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.PrepareRemoteEnvInput
-import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.RemoteScriptExecutionInput
-import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.RemoteScriptExecutionOutput
+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
index 0ad5666..42abbc5 100755 (executable)
@@ -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>
                 <artifactId>dmaap-lib</artifactId>
                 <version>${project.version}</version>
             </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>
index c58bb13..3f8e1a3 100644 (file)
@@ -6,7 +6,8 @@
   ~ proprietary to Bell Canada and are protected by trade secret or copyright law.
   ~ Unauthorized copying of this file, via any medium is strictly prohibited.
   -->
-<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">
 
   <parent>
     <groupId>org.onap.ccsdk.parent</groupId>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>cds-sdc-listener-application</artifactId>
   <version>0.4.2-SNAPSHOT</version>
-  <name>CDS-SDC Listener Application </name>
+  <name>CDS-SDC Listener Application</name>
 
   <properties>
     <grpc.version>1.17.1</grpc.version>
     <protobuf.version>3.6.1</protobuf.version>
+    <image.name>onap/ccsdk-cds-sdc-listener</image.name>
+    <docker.push.phase>deploy</docker.push.phase>
+    <project.version>${parent.version}</project.version>
+    <!-- Start of Docker Related Properties -->
+    <docker.fabric.version>0.26.1</docker.fabric.version>
+    <ccsdk.project.version>${project.version}</ccsdk.project.version>
   </properties>
 
   <dependencies>
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <version>1.8</version>
+        <executions>
+          <execution>
+            <id>copy</id>
+            <phase>package</phase>
+            <configuration>
+              <target>
+                <echo>ANT TASK - copying Docker files</echo>
+                <copy todir="${basedir}/target/docker-stage" overwrite="true" flatten="true">
+                  <fileset dir="${basedir}/src/main/docker">
+                    <include name="Dockerfile"/>
+                    <include name="start.sh"/>
+                  </fileset>
+                  <fileset dir="${basedir}/target">
+                    <include name="*.jar"/>
+                  </fileset>
+                  <fileset dir="${basedir}/src/main/resources/">
+                    <include name="application.yml"/>
+                  </fileset>
+                </copy>
+              </target>
+            </configuration>
+            <goals>
+              <goal>run</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>${docker.fabric.version}</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.latestminortag.version}</tag>
+                      <tag>${project.docker.latestfulltag.version}</tag>
+                      <tag>${project.docker.latesttagtimestamp.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/cds-sdc-listener/application/src/main/docker/Dockerfile b/ms/cds-sdc-listener/application/src/main/docker/Dockerfile
new file mode 100644 (file)
index 0000000..062f657
--- /dev/null
@@ -0,0 +1,13 @@
+FROM openjdk:8-jdk-alpine
+
+ENV HTTP_PROXY  ${HTTP_PROXY}
+ENV HTTPS_PROXY ${HTTPS_PROXY}
+
+RUN mkdir -p /opt/app/onap/ /opt/app/onap/config
+WORKDIR  /opt/app/onap/
+COPY start.sh /opt/app/onap/
+COPY application.yml /opt/app/onap/config
+RUN chmod 751 /opt/app/onap/start.sh
+COPY cds-sdc-listener-application-0.4.2-SNAPSHOT.jar /opt/app/onap/cds-sdc-listener-distribution.jar
+EXPOSE 9000
+ENTRYPOINT /opt/app/onap/start.sh
diff --git a/ms/cds-sdc-listener/application/src/main/docker/docker-compose.yaml b/ms/cds-sdc-listener/application/src/main/docker/docker-compose.yaml
new file mode 100644 (file)
index 0000000..1e73847
--- /dev/null
@@ -0,0 +1,29 @@
+version: '3.3'
+
+services:
+  cds-sdc-listener:
+    image: onap/cdssdclistener:latest
+    container_name: cdssdclistener
+    restart: always
+    environment:
+      asdcAddress: localhost:8443
+      messageBusAddress: localhost
+      sdcusername: vid
+      password: Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U
+      pollingInterval: 15
+      pollingTimeout: 15
+      relevantArtifactTypes: TOSCA_CSAR
+      consumerGroup: cds-id-local
+      environmentName: AUTO
+      consumerId: cds-id-local
+      keyStorePassword:
+      keyStorePath:
+      activateServerTLSAuth: "false"
+      isUseHttpsWithDmaap: "false"
+      archivePath: /opt/app/onap/cds-sdc-listener/
+      grpcAddress: localhost
+      grpcPort: 9111
+      authHeader: Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==
+      #port needed by Liveness probe
+      healthcheckPort: "9000"
+      sprintWebListenerEnabled: "true"
diff --git a/ms/cds-sdc-listener/application/src/main/docker/start.sh b/ms/cds-sdc-listener/application/src/main/docker/start.sh
new file mode 100755 (executable)
index 0000000..f24d156
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+extraArgs=$@
+java -jar /opt/app/onap/cds-sdc-listener-distribution.jar \
+-Dspring.config=/opt/app/onap/config/application.yml \
+-Djava.security.egd=file:/dev/./urandom \
+${extraArgs}
index 0c2c60d..b3f8443 100644 (file)
@@ -1,27 +1,27 @@
 listenerservice:
-    config:
-      asdcAddress: localhost:8443
-      messageBusAddress: localhost
-      user: vid
-      password: Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U
-      pollingInterval: 15
-      pollingTimeout: 60
-      relevantArtifactTypes: TOSCA_CSAR
-      consumerGroup: cds-id-local
-      environmentName: AUTO
-      consumerId: cds-id-local
-      keyStorePassword:
-      keyStorePath:
-      activateServerTLSAuth : false
-      isUseHttpsWithDmaap: false
-      archivePath: /opt/app/onap/cds-sdc-listener/
-      grpcAddress: localhost
-      grpcPort: 9111
-      authHeader: Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==
+  config:
+    asdcAddress: ${asdcAddress:localhost:8443}
+    messageBusAddress: ${messageBusAddress:localhost}
+    user: ${sdcusername:vid}
+    password: ${password:Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U}
+    pollingInterval: ${pollingInterval:15}
+    pollingTimeout: ${pollingTimeout:60}
+    relevantArtifactTypes: ${relevantArtifactTypes:TOSCA_CSAR}
+    consumerGroup: ${consumerGroup:cds-id-local}
+    environmentName: ${environmentName:AUTO}
+    consumerId: ${consumerId:cds-id-local}
+    keyStorePassword: ${keyStorePassword}
+    keyStorePath: ${keyStorePath}
+    activateServerTLSAuth : ${activateServerTLSAuth:false}
+    isUseHttpsWithDmaap: ${isUseHttpsWithDmaap:false}
+    archivePath: ${archivePath:/opt/app/onap/cds-sdc-listener/}
+    grpcAddress: ${grpcAddress:localhost}
+    grpcPort: ${grpcPort:9111}
+    authHeader: ${authHeader:Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==}
 #port needed by Liveness probe
 server:
-  port: 9000
+  port: ${healthcheckPort:9000}
 #set spring.main.web-environment=false if you want to NOT to open a port for healthcheck.
-#spring:
-#  main:
-#    web-environment: false
\ No newline at end of file
+spring:
+  main:
+    web-environment: ${sprintWebListenerEnabled:true}
diff --git a/ms/cds-sdc-listener/application/src/main/resources/logback.xml b/ms/cds-sdc-listener/application/src/main/resources/logback.xml
new file mode 100644 (file)
index 0000000..b26cbcb
--- /dev/null
@@ -0,0 +1,33 @@
+<!--
+Copyright (C) 2019 Bell Canada
+
+Unless otherwise specified, all software contained herein is licensed
+under the Apache License, Version 2.0 (the License);
+you may not use this software 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">
+    <encoder>
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <root level="info">
+    <appender-ref ref="STDOUT"/>
+  </root>
+
+  <logger name="org.springframework" level="info"/>
+  <logger name="org.springframework.web" level="info"/>
+  <logger name="org.onap.ccsdk.cds" level="info"/>
+  
+</configuration>
diff --git a/ms/cds-sdc-listener/distribution/pom.xml b/ms/cds-sdc-listener/distribution/pom.xml
deleted file mode 100644 (file)
index 59e3824..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  ~ Copyright (C) 2019 Bell Canada. All rights reserved.
-  ~
-  ~ NOTICE:  All the intellectual and technical concepts contained herein are
-  ~ proprietary to Bell Canada and are protected by trade secret or copyright law.
-  ~ Unauthorized copying of this file, via any medium is strictly prohibited.
-  -->
-<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>cds-sdc-listener</artifactId>
-    <groupId>org.onap.ccsdk.cds</groupId>
-    <version>0.4.2-SNAPSHOT</version>
-  </parent>
-
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>org.onap.ccsdk.cds</groupId>
-  <artifactId>cds-sdc-listener-distribution</artifactId>
-  <name>CDS-SDC Listener Distribution</name>
-
-  <properties>
-    <image.name>onap/ccsdk-cdssdclistener</image.name>
-    <docker.push.phase>deploy</docker.push.phase>
-  </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>*</include>
-                  </includes>
-                  <filtering>true</filtering>
-                </resource>
-              </resources>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-
-  <profiles>
-    <profile>
-      <id>docker</id>
-      <build>
-        <plugins>
-          <plugin>
-            <!-- Maven plugin for managing docker images and containers -->
-            <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.version}</tag>
-                      <tag>${project.version}-STAGING-${maven.build.timestamp}</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/pom.xml b/ms/command-executor/pom.xml
new file mode 100755 (executable)
index 0000000..af1b4f4
--- /dev/null
@@ -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 (file)
index 0000000..50f592d
--- /dev/null
@@ -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 (executable)
index 0000000..7b8c270
--- /dev/null
@@ -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 (executable)
index 0000000..6590384
--- /dev/null
@@ -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 (file)
index 0000000..4ae575b
--- /dev/null
@@ -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 (file)
index 0000000..3596a0e
--- /dev/null
@@ -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 (file)
index 0000000..637d37d
--- /dev/null
@@ -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 (file)
index 0000000..3ea8ec4
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..2613573
--- /dev/null
@@ -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 (file)
index 0000000..de62047
--- /dev/null
@@ -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 (file)
index 0000000..6260997
--- /dev/null
@@ -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)
index d45571c..72c2c1d 100644 (file)
@@ -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
  */
index e82ffc4..d06d5db 100644 (file)
@@ -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)
         }
     }
 
index 6f84a14..d1c87c9 100644 (file)
@@ -35,6 +35,7 @@
     <modules>
         <module>controllerblueprints</module>
         <module>blueprintsprocessor</module>
+        <module>command-executor</module>
         <module>cds-sdc-listener</module>
     </modules>
 </project>