Add CommandExecutor handler 23/84923/10
authorAlexis de Talhouët <adetalhouet89@gmail.com>
Fri, 12 Apr 2019 22:52:29 +0000 (18:52 -0400)
committerAlexis de Talhouët <adetalhouet89@gmail.com>
Tue, 16 Apr 2019 14:38:51 +0000 (10:38 -0400)
Change-Id: I7a4fbd13d11618ed6b2c85827ec2ced1cb65b31f
Issue-ID: CCCSDK-1215
Signed-off-by: Alexis de Talhouët <adetalhouet89@gmail.com>
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
ms/command-executor/src/main/python/utils.py [new file with mode: 0644]

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..3027859
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# 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 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.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:
+            print("{} - 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):
+        print("{} - Install package({}) in Python Virtual Environment".format(self.blueprint_id, package))
+        command = ["pip", "install", package]
+
+        env = dict(os.environ)
+        # 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):
+        print("{} - 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:
+            print("{} - Failed to provision Python Virtual Environment. Error: {}".format(self.blueprint_id, err))
+
+    def activate_venv(self):
+        print("{} - 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:
+            print("{} - Failed to activate Python Virtual Environment. Error: {}".format(self.blueprint_id, err))
+            return False
+
+    def deactivate_venv(self):
+        print("{} - Deactivate Python Virtual Environment".format(self.blueprint_id))
+        command = ["deactivate"]
+        try:
+            subprocess.run(command, check=True)
+        except Exception as err:
+            print("{} - Failed to deactivate Python Virtual Environment. Error: {}".format(self.blueprint_id, err))
index 35eed8e..b62f150 100644 (file)
@@ -25,6 +25,8 @@ import grpc
 import proto.CommandExecutor_pb2_grpc as CommandExecutor_pb2_grpc
 
 from request_header_validator_interceptor import RequestHeaderValidatorInterceptor
+from command_executor_handler import CommandExecutorHandler
+import utils
 
 _ONE_DAY_IN_SECONDS = 60 * 60 * 24
 
@@ -32,10 +34,30 @@ _ONE_DAY_IN_SECONDS = 60 * 60 * 24
 class CommandExecutorServer(CommandExecutor_pb2_grpc.CommandExecutorServiceServicer):
 
     def prepareEnv(self, request, context):
-        return
+        blueprint_id = utils.get_blueprint_id(request)
+        print("{} - Received prepareEnv request".format(blueprint_id))
+        print (request)
+
+        results = []
+        handler = CommandExecutorHandler(request)
+        if not handler.prepare_env(request, results):
+            print("{} - Failed to prepare python environment. {}".format(blueprint_id, results))
+            return utils.build_response(request, results, False)
+        print("{} - Package installation logs {}".format(blueprint_id, results))
+        return utils.build_response(request, results)
 
     def executeCommand(self, request, context):
-        return
+        blueprint_id = utils.get_blueprint_id(request)
+        print("{} - Received executeCommand request".format(blueprint_id))
+        print(request)
+
+        results = []
+        handler = CommandExecutorHandler(request)
+        if not handler.execute_command(request, results):
+            print("{} - Failed to executeCommand. {}".format(blueprint_id, results))
+            return utils.build_response(request, results, False)
+        print("{} - Execute command logs: {}".format(blueprint_id, results))
+        return utils.build_response(request, results)
 
 
 def 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..b0013b9
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# 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 map, bytes
+
+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)