diff options
Diffstat (limited to 'ms/command-executor/src')
11 files changed, 878 insertions, 0 deletions
diff --git a/ms/command-executor/src/main/docker/Dockerfile b/ms/command-executor/src/main/docker/Dockerfile new file mode 100644 index 000000000..50f592dd6 --- /dev/null +++ b/ms/command-executor/src/main/docker/Dockerfile @@ -0,0 +1,21 @@ +FROM python:3.6-slim + +ENV GRPC_PYTHON_VERSION 1.19.0 +RUN python -m pip install --upgrade pip +RUN pip install grpcio==${GRPC_PYTHON_VERSION} grpcio-tools==${GRPC_PYTHON_VERSION} +RUN pip install virtualenv + +COPY start.sh /opt/app/onap/start.sh +RUN chmod u+x /opt/app/onap/start.sh + +RUN mkdir -p /opt/app/onap/logs/ && touch /opt/app/onap/logs/application.log + +COPY @project.build.finalName@-@assembly.id@.tar.gz /source.tar.gz +RUN tar -xzf /source.tar.gz -C /tmp \ + && cp -rf /tmp/@project.build.finalName@/opt / \ + && rm -rf /source.tar.gz \ + && rm -rf /tmp/@project.build.finalName@ + +VOLUME /opt/app/onap/blueprints/deploy/ + +ENTRYPOINT /opt/app/onap/start.sh
\ No newline at end of file diff --git a/ms/command-executor/src/main/docker/distribution.xml b/ms/command-executor/src/main/docker/distribution.xml new file mode 100755 index 000000000..7b8c27021 --- /dev/null +++ b/ms/command-executor/src/main/docker/distribution.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright © 2019 Bell Canada. + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd"> + <id>${assembly.id}</id> + <formats> + <format>tar.gz</format> + </formats> + <fileSets> + <fileSet> + <directory>${project.basedir}/src/main/python</directory> + <outputDirectory>/opt/app/onap/python</outputDirectory> + </fileSet> + </fileSets> +</assembly>
\ No newline at end of file diff --git a/ms/command-executor/src/main/docker/start.sh b/ms/command-executor/src/main/docker/start.sh new file mode 100755 index 000000000..659038418 --- /dev/null +++ b/ms/command-executor/src/main/docker/start.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +# +# Copyright (C) 2019 Bell Canada. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +if [ -z "${APP_PORT}" ] +then + echo "APP_PORT environment variable is not set, using default." + export APP_PORT=50051 +fi + +if [ -z "${BASIC_AUTH}" ] +then + echo "BASIC_AUTH environment variable is not set, using default." + export BASIC_AUTH="Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==" +fi + +cd /opt/app/onap/python/ +python server.py ${APP_PORT} ${BASIC_AUTH}
\ No newline at end of file diff --git a/ms/command-executor/src/main/python/command_executor_handler.py b/ms/command-executor/src/main/python/command_executor_handler.py new file mode 100644 index 000000000..4ae575b0f --- /dev/null +++ b/ms/command-executor/src/main/python/command_executor_handler.py @@ -0,0 +1,105 @@ +# +# Copyright (C) 2019 Bell Canada. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import logging +import os +import subprocess +import virtualenv +import venv +from builtins import Exception, open, dict +from subprocess import CalledProcessError, PIPE + +import utils + + +class CommandExecutorHandler: + + def __init__(self, request): + self.logger = logging.getLogger(self.__class__.__name__) + self.blueprint_id = utils.get_blueprint_id(request) + self.venv_home = '/opt/app/onap/blueprints/deploy/' + self.blueprint_id + + def prepare_env(self, request, results): + self.create_venv() + if not self.activate_venv(): + return False + + for package in request.packages: + if not self.install(package, results): + return False + + # deactivate_venv(blueprint_id) + return True + + def execute_command(self, request, results): + if not self.activate_venv(): + return False + + try: + results.append(os.popen(request.command).read()) + except Exception as e: + self.logger.info("{} - Failed to execute command. Error: {}".format(self.blueprint_id, e)) + results.append(e) + return False + + # deactivate_venv(blueprint_id) + return True + + def install(self, package, results): + self.logger.info("{} - Install package({}) in Python Virtual Environment".format(self.blueprint_id, package)) + command = ["pip", "install", package] + + env = dict(os.environ) + # fixme - parameterize + # env['https_proxy'] = "https://fastweb.int.bell.ca:8083" + + try: + results.append(subprocess.run(command, check=True, stdout=PIPE, stderr=PIPE, env=env).stdout.decode()) + return True + except CalledProcessError as e: + results.append(e.stderr.decode()) + return False + + def create_venv(self): + self.logger.info("{} - Create Python Virtual Environment".format(self.blueprint_id)) + try: + bin_dir = self.venv_home + "/bin" + # venv doesn't populate the activate_this.py script, hence we use from virtualenv + venv.create(self.venv_home, with_pip=True, system_site_packages=True) + virtualenv.writefile(os.path.join(bin_dir, "activate_this.py"), virtualenv.ACTIVATE_THIS) + except Exception as err: + self.logger.info( + "{} - Failed to provision Python Virtual Environment. Error: {}".format(self.blueprint_id, err)) + + def activate_venv(self): + self.logger.info("{} - Activate Python Virtual Environment".format(self.blueprint_id)) + + path = "%s/bin/activate_this.py" % self.venv_home + try: + exec (open(path).read(), {'__file__': path}) + return True + except Exception as err: + self.logger.info( + "{} - Failed to activate Python Virtual Environment. Error: {}".format(self.blueprint_id, err)) + return False + + def deactivate_venv(self): + self.logger.info("{} - Deactivate Python Virtual Environment".format(self.blueprint_id)) + command = ["deactivate"] + try: + subprocess.run(command, check=True) + except Exception as err: + self.logger.info( + "{} - Failed to deactivate Python Virtual Environment. Error: {}".format(self.blueprint_id, err)) diff --git a/ms/command-executor/src/main/python/command_executor_server.py b/ms/command-executor/src/main/python/command_executor_server.py new file mode 100644 index 000000000..3596a0ec5 --- /dev/null +++ b/ms/command-executor/src/main/python/command_executor_server.py @@ -0,0 +1,57 @@ +#!/usr/bin/python + +# +# Copyright (C) 2019 Bell Canada. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import logging + +import proto.CommandExecutor_pb2_grpc as CommandExecutor_pb2_grpc + +from command_executor_handler import CommandExecutorHandler +import utils + +_ONE_DAY_IN_SECONDS = 60 * 60 * 24 + + +class CommandExecutorServer(CommandExecutor_pb2_grpc.CommandExecutorServiceServicer): + + def __init__(self): + self.logger = logging.getLogger(self.__class__.__name__) + + def prepareEnv(self, request, context): + blueprint_id = utils.get_blueprint_id(request) + self.logger.info("{} - Received prepareEnv request".format(blueprint_id)) + self.logger.info(request) + + results = [] + handler = CommandExecutorHandler(request) + if not handler.prepare_env(request, results): + self.logger.info("{} - Failed to prepare python environment. {}".format(blueprint_id, results)) + return utils.build_response(request, results, False) + self.logger.info("{} - Package installation logs {}".format(blueprint_id, results)) + return utils.build_response(request, results) + + def executeCommand(self, request, context): + blueprint_id = utils.get_blueprint_id(request) + self.logger.info("{} - Received executeCommand request".format(blueprint_id)) + self.logger.info(request) + + results = [] + handler = CommandExecutorHandler(request) + if not handler.execute_command(request, results): + self.logger.info("{} - Failed to executeCommand. {}".format(blueprint_id, results)) + return utils.build_response(request, results, False) + self.logger.info("{} - Execute command logs: {}".format(blueprint_id, results)) + return utils.build_response(request, results) diff --git a/ms/command-executor/src/main/python/proto/CommandExecutor_pb2.py b/ms/command-executor/src/main/python/proto/CommandExecutor_pb2.py new file mode 100644 index 000000000..637d37d87 --- /dev/null +++ b/ms/command-executor/src/main/python/proto/CommandExecutor_pb2.py @@ -0,0 +1,422 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: CommandExecutor.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='CommandExecutor.proto', + package='org.onap.ccsdk.cds.controllerblueprints.command.api', + syntax='proto3', + serialized_options=_b('P\001'), + serialized_pb=_b('\n\x15\x43ommandExecutor.proto\x12\x33org.onap.ccsdk.cds.controllerblueprints.command.api\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xe4\x02\n\x0e\x45xecutionInput\x12\x11\n\trequestId\x18\x01 \x01(\t\x12\x15\n\rcorrelationId\x18\x02 \x01(\t\x12U\n\x0bidentifiers\x18\x03 \x01(\x0b\x32@.org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers\x12S\n\nscriptType\x18\x04 \x01(\x0e\x32?.org.onap.ccsdk.cds.controllerblueprints.command.api.ScriptType\x12\x0f\n\x07\x63ommand\x18\x05 \x01(\t\x12\x0f\n\x07timeOut\x18\x06 \x01(\x05\x12+\n\nproperties\x18\x07 \x01(\x0b\x32\x17.google.protobuf.Struct\x12-\n\ttimestamp\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xe6\x02\n\x0fPrepareEnvInput\x12U\n\x0bidentifiers\x18\x01 \x01(\x0b\x32@.org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers\x12\x11\n\trequestId\x18\x02 \x01(\t\x12\x15\n\rcorrelationId\x18\x03 \x01(\t\x12S\n\nscriptType\x18\x04 \x01(\x0e\x32?.org.onap.ccsdk.cds.controllerblueprints.command.api.ScriptType\x12\x10\n\x08packages\x18\x05 \x03(\t\x12\x0f\n\x07timeOut\x18\x06 \x01(\x05\x12+\n\nproperties\x18\x07 \x01(\x0b\x32\x17.google.protobuf.Struct\x12-\n\ttimestamp\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\">\n\x0bIdentifiers\x12\x15\n\rblueprintName\x18\x01 \x01(\t\x12\x18\n\x10\x62lueprintVersion\x18\x02 \x01(\t\"\xba\x01\n\x0f\x45xecutionOutput\x12\x11\n\trequestId\x18\x01 \x01(\t\x12\x10\n\x08response\x18\x02 \x01(\t\x12S\n\x06status\x18\x03 \x01(\x0e\x32\x43.org.onap.ccsdk.cds.controllerblueprints.command.api.ResponseStatus\x12-\n\ttimestamp\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp**\n\x0eResponseStatus\x12\x0b\n\x07SUCCESS\x10\x00\x12\x0b\n\x07\x46\x41ILURE\x10\x01*9\n\nScriptType\x12\n\n\x06PYTHON\x10\x00\x12\x0b\n\x07\x41NSIBLE\x10\x01\x12\n\n\x06KOTLIN\x10\x02\x12\x06\n\x02SH\x10\x03\x32\xd1\x02\n\x16\x43ommandExecutorService\x12\x98\x01\n\nprepareEnv\x12\x44.org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput\x1a\x44.org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput\x12\x9b\x01\n\x0e\x65xecuteCommand\x12\x43.org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput\x1a\x44.org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutputB\x02P\x01\x62\x06proto3') + , + dependencies=[google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) + +_RESPONSESTATUS = _descriptor.EnumDescriptor( + name='ResponseStatus', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ResponseStatus', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='SUCCESS', index=0, number=0, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='FAILURE', index=1, number=1, + serialized_options=None, + type=None), + ], + containing_type=None, + serialized_options=None, + serialized_start=1114, + serialized_end=1156, +) +_sym_db.RegisterEnumDescriptor(_RESPONSESTATUS) + +ResponseStatus = enum_type_wrapper.EnumTypeWrapper(_RESPONSESTATUS) +_SCRIPTTYPE = _descriptor.EnumDescriptor( + name='ScriptType', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ScriptType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='PYTHON', index=0, number=0, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='ANSIBLE', index=1, number=1, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='KOTLIN', index=2, number=2, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='SH', index=3, number=3, + serialized_options=None, + type=None), + ], + containing_type=None, + serialized_options=None, + serialized_start=1158, + serialized_end=1215, +) +_sym_db.RegisterEnumDescriptor(_SCRIPTTYPE) + +ScriptType = enum_type_wrapper.EnumTypeWrapper(_SCRIPTTYPE) +SUCCESS = 0 +FAILURE = 1 +PYTHON = 0 +ANSIBLE = 1 +KOTLIN = 2 +SH = 3 + + + +_EXECUTIONINPUT = _descriptor.Descriptor( + name='ExecutionInput', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='requestId', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.requestId', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='correlationId', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.correlationId', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='identifiers', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.identifiers', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='scriptType', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.scriptType', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='command', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.command', index=4, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='timeOut', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.timeOut', index=5, + number=6, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='properties', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.properties', index=6, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='timestamp', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput.timestamp', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=142, + serialized_end=498, +) + + +_PREPAREENVINPUT = _descriptor.Descriptor( + name='PrepareEnvInput', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='identifiers', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.identifiers', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='requestId', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.requestId', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='correlationId', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.correlationId', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='scriptType', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.scriptType', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='packages', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.packages', index=4, + number=5, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='timeOut', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.timeOut', index=5, + number=6, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='properties', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.properties', index=6, + number=7, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='timestamp', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput.timestamp', index=7, + number=8, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=501, + serialized_end=859, +) + + +_IDENTIFIERS = _descriptor.Descriptor( + name='Identifiers', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='blueprintName', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers.blueprintName', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='blueprintVersion', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers.blueprintVersion', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=861, + serialized_end=923, +) + + +_EXECUTIONOUTPUT = _descriptor.Descriptor( + name='ExecutionOutput', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='requestId', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput.requestId', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='response', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput.response', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='status', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput.status', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='timestamp', full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput.timestamp', index=3, + number=4, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=926, + serialized_end=1112, +) + +_EXECUTIONINPUT.fields_by_name['identifiers'].message_type = _IDENTIFIERS +_EXECUTIONINPUT.fields_by_name['scriptType'].enum_type = _SCRIPTTYPE +_EXECUTIONINPUT.fields_by_name['properties'].message_type = google_dot_protobuf_dot_struct__pb2._STRUCT +_EXECUTIONINPUT.fields_by_name['timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_PREPAREENVINPUT.fields_by_name['identifiers'].message_type = _IDENTIFIERS +_PREPAREENVINPUT.fields_by_name['scriptType'].enum_type = _SCRIPTTYPE +_PREPAREENVINPUT.fields_by_name['properties'].message_type = google_dot_protobuf_dot_struct__pb2._STRUCT +_PREPAREENVINPUT.fields_by_name['timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_EXECUTIONOUTPUT.fields_by_name['status'].enum_type = _RESPONSESTATUS +_EXECUTIONOUTPUT.fields_by_name['timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +DESCRIPTOR.message_types_by_name['ExecutionInput'] = _EXECUTIONINPUT +DESCRIPTOR.message_types_by_name['PrepareEnvInput'] = _PREPAREENVINPUT +DESCRIPTOR.message_types_by_name['Identifiers'] = _IDENTIFIERS +DESCRIPTOR.message_types_by_name['ExecutionOutput'] = _EXECUTIONOUTPUT +DESCRIPTOR.enum_types_by_name['ResponseStatus'] = _RESPONSESTATUS +DESCRIPTOR.enum_types_by_name['ScriptType'] = _SCRIPTTYPE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +ExecutionInput = _reflection.GeneratedProtocolMessageType('ExecutionInput', (_message.Message,), dict( + DESCRIPTOR = _EXECUTIONINPUT, + __module__ = 'CommandExecutor_pb2' + # @@protoc_insertion_point(class_scope:org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionInput) + )) +_sym_db.RegisterMessage(ExecutionInput) + +PrepareEnvInput = _reflection.GeneratedProtocolMessageType('PrepareEnvInput', (_message.Message,), dict( + DESCRIPTOR = _PREPAREENVINPUT, + __module__ = 'CommandExecutor_pb2' + # @@protoc_insertion_point(class_scope:org.onap.ccsdk.cds.controllerblueprints.command.api.PrepareEnvInput) + )) +_sym_db.RegisterMessage(PrepareEnvInput) + +Identifiers = _reflection.GeneratedProtocolMessageType('Identifiers', (_message.Message,), dict( + DESCRIPTOR = _IDENTIFIERS, + __module__ = 'CommandExecutor_pb2' + # @@protoc_insertion_point(class_scope:org.onap.ccsdk.cds.controllerblueprints.command.api.Identifiers) + )) +_sym_db.RegisterMessage(Identifiers) + +ExecutionOutput = _reflection.GeneratedProtocolMessageType('ExecutionOutput', (_message.Message,), dict( + DESCRIPTOR = _EXECUTIONOUTPUT, + __module__ = 'CommandExecutor_pb2' + # @@protoc_insertion_point(class_scope:org.onap.ccsdk.cds.controllerblueprints.command.api.ExecutionOutput) + )) +_sym_db.RegisterMessage(ExecutionOutput) + + +DESCRIPTOR._options = None + +_COMMANDEXECUTORSERVICE = _descriptor.ServiceDescriptor( + name='CommandExecutorService', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorService', + file=DESCRIPTOR, + index=0, + serialized_options=None, + serialized_start=1218, + serialized_end=1555, + methods=[ + _descriptor.MethodDescriptor( + name='prepareEnv', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorService.prepareEnv', + index=0, + containing_service=None, + input_type=_PREPAREENVINPUT, + output_type=_EXECUTIONOUTPUT, + serialized_options=None, + ), + _descriptor.MethodDescriptor( + name='executeCommand', + full_name='org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorService.executeCommand', + index=1, + containing_service=None, + input_type=_EXECUTIONINPUT, + output_type=_EXECUTIONOUTPUT, + serialized_options=None, + ), +]) +_sym_db.RegisterServiceDescriptor(_COMMANDEXECUTORSERVICE) + +DESCRIPTOR.services_by_name['CommandExecutorService'] = _COMMANDEXECUTORSERVICE + +# @@protoc_insertion_point(module_scope) diff --git a/ms/command-executor/src/main/python/proto/CommandExecutor_pb2_grpc.py b/ms/command-executor/src/main/python/proto/CommandExecutor_pb2_grpc.py new file mode 100644 index 000000000..3ea8ec4d6 --- /dev/null +++ b/ms/command-executor/src/main/python/proto/CommandExecutor_pb2_grpc.py @@ -0,0 +1,63 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +import grpc + +import proto.CommandExecutor_pb2 as CommandExecutor__pb2 + + +class CommandExecutorServiceStub(object): + # missing associated documentation comment in .proto file + pass + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.prepareEnv = channel.unary_unary( + '/org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorService/prepareEnv', + request_serializer=CommandExecutor__pb2.PrepareEnvInput.SerializeToString, + response_deserializer=CommandExecutor__pb2.ExecutionOutput.FromString, + ) + self.executeCommand = channel.unary_unary( + '/org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorService/executeCommand', + request_serializer=CommandExecutor__pb2.ExecutionInput.SerializeToString, + response_deserializer=CommandExecutor__pb2.ExecutionOutput.FromString, + ) + + +class CommandExecutorServiceServicer(object): + # missing associated documentation comment in .proto file + pass + + def prepareEnv(self, request, context): + # missing associated documentation comment in .proto file + pass + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def executeCommand(self, request, context): + # missing associated documentation comment in .proto file + pass + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_CommandExecutorServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'prepareEnv': grpc.unary_unary_rpc_method_handler( + servicer.prepareEnv, + request_deserializer=CommandExecutor__pb2.PrepareEnvInput.FromString, + response_serializer=CommandExecutor__pb2.ExecutionOutput.SerializeToString, + ), + 'executeCommand': grpc.unary_unary_rpc_method_handler( + servicer.executeCommand, + request_deserializer=CommandExecutor__pb2.ExecutionInput.FromString, + response_serializer=CommandExecutor__pb2.ExecutionOutput.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'org.onap.ccsdk.cds.controllerblueprints.command.api.CommandExecutorService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) diff --git a/ms/command-executor/src/main/python/proto/__init__.py b/ms/command-executor/src/main/python/proto/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ms/command-executor/src/main/python/proto/__init__.py diff --git a/ms/command-executor/src/main/python/request_header_validator_interceptor.py b/ms/command-executor/src/main/python/request_header_validator_interceptor.py new file mode 100644 index 000000000..261357337 --- /dev/null +++ b/ms/command-executor/src/main/python/request_header_validator_interceptor.py @@ -0,0 +1,38 @@ +# +# Copyright (C) 2019 Bell Canada. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import grpc + + +def _unary_unary_rpc_terminator(code, details): + def terminate(ignored_request, context): + context.abort(code, details) + + return grpc.unary_unary_rpc_method_handler(terminate) + + +class RequestHeaderValidatorInterceptor(grpc.ServerInterceptor): + + def __init__(self, header, value, code, details): + self._header = header + self._value = value + self._terminator = _unary_unary_rpc_terminator(code, details) + + def intercept_service(self, continuation, handler_call_details): + if (self._header, self._value) in handler_call_details.invocation_metadata: + return continuation(handler_call_details) + else: + return self._terminator diff --git a/ms/command-executor/src/main/python/server.py b/ms/command-executor/src/main/python/server.py new file mode 100644 index 000000000..de620474b --- /dev/null +++ b/ms/command-executor/src/main/python/server.py @@ -0,0 +1,72 @@ +#!/usr/bin/python + +# +# Copyright (C) 2019 Bell Canada. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from builtins import KeyboardInterrupt +from concurrent import futures +import logging +import time +import sys + +import grpc + +import proto.CommandExecutor_pb2_grpc as CommandExecutor_pb2_grpc + +from request_header_validator_interceptor import RequestHeaderValidatorInterceptor +from command_executor_server import CommandExecutorServer + +logger = logging.getLogger("Server") + +_ONE_DAY_IN_SECONDS = 60 * 60 * 24 + + +def serve(): + port = sys.argv[1] + basic_auth = sys.argv[2] + ' ' + sys.argv[3] + + header_validator = RequestHeaderValidatorInterceptor( + 'authorization', basic_auth, grpc.StatusCode.UNAUTHENTICATED, + 'Access denied!') + + server = grpc.server( + futures.ThreadPoolExecutor(max_workers=10), + interceptors=(header_validator,)) + + CommandExecutor_pb2_grpc.add_CommandExecutorServiceServicer_to_server( + CommandExecutorServer(), server) + + server.add_insecure_port('[::]:' + port) + server.start() + + logger.info("Command Executor Server started on %s" % port) + + try: + while True: + time.sleep(_ONE_DAY_IN_SECONDS) + except KeyboardInterrupt: + server.stop(0) + + +if __name__ == '__main__': + logging_formater = '%(asctime)s - %(name)s - %(threadName)s - %(levelname)s - %(message)s' + logging.basicConfig(filename='/opt/app/onap/logs/application.log', level=logging.DEBUG, + format=logging_formater) + console = logging.StreamHandler() + console.setLevel(logging.INFO) + formatter = logging.Formatter(logging_formater) + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + serve() diff --git a/ms/command-executor/src/main/python/utils.py b/ms/command-executor/src/main/python/utils.py new file mode 100644 index 000000000..6260997f3 --- /dev/null +++ b/ms/command-executor/src/main/python/utils.py @@ -0,0 +1,37 @@ +# +# Copyright (C) 2019 Bell Canada. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from google.protobuf.timestamp_pb2 import Timestamp + +import proto.CommandExecutor_pb2 as CommandExecutor_pb2 + + +def get_blueprint_id(request): + blueprint_name = request.identifiers.blueprintName + blueprint_version = request.identifiers.blueprintVersion + return blueprint_name + '/' + blueprint_version + + +def build_response(request, results, is_success=True): + if is_success: + status = CommandExecutor_pb2.SUCCESS + else: + status = CommandExecutor_pb2.FAILURE + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + return CommandExecutor_pb2.ExecutionOutput(requestId=request.requestId, response="".join(results), status=status, + timestamp=timestamp) |