initial version
authorlloretgalleg <illoret@indra.es>
Sat, 1 Aug 2020 06:05:58 +0000 (06:05 +0000)
committerlloretgalleg <illoret@indra.es>
Sat, 1 Aug 2020 06:06:06 +0000 (06:06 +0000)
Signed-off-by: lloretgalleg <illoret@indra.es>
29 files changed:
Dockerfile [new file with mode: 0644]
osm_ee/__init__.py [new file with mode: 0644]
osm_ee/__pycache__/__init__.cpython-36.pyc [new file with mode: 0644]
osm_ee/__pycache__/base_ee.cpython-36.pyc [new file with mode: 0644]
osm_ee/__pycache__/exceptions.cpython-36.pyc [new file with mode: 0644]
osm_ee/__pycache__/frontend_client.cpython-36.pyc [new file with mode: 0644]
osm_ee/__pycache__/frontend_grpc.cpython-36.pyc [new file with mode: 0644]
osm_ee/__pycache__/frontend_pb2.cpython-36.pyc [new file with mode: 0644]
osm_ee/__pycache__/frontend_server.cpython-36.pyc [new file with mode: 0644]
osm_ee/base_ee.py [new file with mode: 0644]
osm_ee/exceptions.py [new file with mode: 0644]
osm_ee/frontend.proto [new file with mode: 0644]
osm_ee/frontend_client.py [new file with mode: 0644]
osm_ee/frontend_grpc.py [new file with mode: 0644]
osm_ee/frontend_pb2.py [new file with mode: 0644]
osm_ee/frontend_server.py [new file with mode: 0644]
osm_ee/scripts/ee_start.sh [new file with mode: 0755]
osm_ee/util/__init__.py [new file with mode: 0644]
osm_ee/util/__pycache__/__init__.cpython-36.pyc [new file with mode: 0644]
osm_ee/util/__pycache__/util_ansible.cpython-36.pyc [new file with mode: 0644]
osm_ee/util/__pycache__/util_ee.cpython-36.pyc [new file with mode: 0644]
osm_ee/util/util_ansible.py [new file with mode: 0644]
osm_ee/util/util_ee.py [new file with mode: 0644]
osm_ee/vnf/__init__.py [new file with mode: 0644]
osm_ee/vnf/__pycache__/__init__.cpython-36.pyc [new file with mode: 0644]
osm_ee/vnf/__pycache__/vnf_ee.cpython-36.pyc [new file with mode: 0644]
osm_ee/vnf/install.sh [new file with mode: 0644]
osm_ee/vnf/vnf_ee.py [new file with mode: 0644]
setup.py [new file with mode: 0644]

diff --git a/Dockerfile b/Dockerfile
new file mode 100644 (file)
index 0000000..d811e1a
--- /dev/null
@@ -0,0 +1,50 @@
+# Copyright 2018 Telefonica S.A.
+#
+# 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 ubuntu:18.04
+
+# Set the working directory to /app
+WORKDIR /app/EE
+
+# Libraries used by the base osm defined ee
+RUN apt-get update && apt-get install -y git python3 python3-pip \
+    && python3 -m pip install --upgrade pip \
+    && python3 -m pip install -U grpcio-tools \
+    && python3 -m pip install -U grpclib \
+    && python3 -m pip install -U PyYAML
+
+# Copy the current directory contents into the container at /app/LCM
+ADD . /app/EE
+
+# Install as module
+RUN python3 -m pip install -e /app/EE
+
+# Install SNMP Generator and its dependencies
+#RUN apt-get install -y python3-pip unzip build-essential libsnmp-dev wget curl
+#RUN curl -s https://storage.googleapis.com/golang/go1.11.8.linux-amd64.tar.gz| tar -v -C /usr/local -xz
+#ENV PATH $PATH:/usr/local/go/bin
+#ENV GOPATH /go
+#RUN go get github.com/go-logfmt/logfmt \
+#    && go get github.com/go-kit/kit/log
+#RUN wget -q https://github.com/prometheus/snmp_exporter/archive/v0.17.0.tar.gz -P /tmp/ \
+#    && tar -C /tmp -xf /tmp/v0.17.0.tar.gz \
+#    && (cd /tmp/snmp_exporter-0.17.0/generator && go build) \
+#    && cp /tmp/snmp_exporter-0.17.0/generator/generator /usr/local/bin/snmp_generator
+
+EXPOSE 50051
+
+#CMD python3 -m osm_ee.frontend_server
+# For development
+CMD [ "bash", "-c", "while true; do /app/EE/osm_ee/scripts/ee_start.sh ; sleep 5; done" ]
diff --git a/osm_ee/__init__.py b/osm_ee/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/osm_ee/__pycache__/__init__.cpython-36.pyc b/osm_ee/__pycache__/__init__.cpython-36.pyc
new file mode 100644 (file)
index 0000000..678249a
Binary files /dev/null and b/osm_ee/__pycache__/__init__.cpython-36.pyc differ
diff --git a/osm_ee/__pycache__/base_ee.cpython-36.pyc b/osm_ee/__pycache__/base_ee.cpython-36.pyc
new file mode 100644 (file)
index 0000000..f00b8d4
Binary files /dev/null and b/osm_ee/__pycache__/base_ee.cpython-36.pyc differ
diff --git a/osm_ee/__pycache__/exceptions.cpython-36.pyc b/osm_ee/__pycache__/exceptions.cpython-36.pyc
new file mode 100644 (file)
index 0000000..b3522d8
Binary files /dev/null and b/osm_ee/__pycache__/exceptions.cpython-36.pyc differ
diff --git a/osm_ee/__pycache__/frontend_client.cpython-36.pyc b/osm_ee/__pycache__/frontend_client.cpython-36.pyc
new file mode 100644 (file)
index 0000000..cafe8a1
Binary files /dev/null and b/osm_ee/__pycache__/frontend_client.cpython-36.pyc differ
diff --git a/osm_ee/__pycache__/frontend_grpc.cpython-36.pyc b/osm_ee/__pycache__/frontend_grpc.cpython-36.pyc
new file mode 100644 (file)
index 0000000..c73803e
Binary files /dev/null and b/osm_ee/__pycache__/frontend_grpc.cpython-36.pyc differ
diff --git a/osm_ee/__pycache__/frontend_pb2.cpython-36.pyc b/osm_ee/__pycache__/frontend_pb2.cpython-36.pyc
new file mode 100644 (file)
index 0000000..0424a29
Binary files /dev/null and b/osm_ee/__pycache__/frontend_pb2.cpython-36.pyc differ
diff --git a/osm_ee/__pycache__/frontend_server.cpython-36.pyc b/osm_ee/__pycache__/frontend_server.cpython-36.pyc
new file mode 100644 (file)
index 0000000..d3622cb
Binary files /dev/null and b/osm_ee/__pycache__/frontend_server.cpython-36.pyc differ
diff --git a/osm_ee/base_ee.py b/osm_ee/base_ee.py
new file mode 100644 (file)
index 0000000..6728c49
--- /dev/null
@@ -0,0 +1,105 @@
+##
+# Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
+# This file is part of OSM
+# All Rights Reserved.
+#
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+import asyncio
+import logging
+import yaml
+import os
+
+from osm_ee.vnf.vnf_ee import VnfEE
+
+
+class BaseEE:
+
+    RETURN_STATUS_LIST = ["OK", "PROCESSING", "ERROR"]
+    CONFIG_FILE = "/app/storage/config.yaml"
+    SSH_KEY_FILE = "~/.ssh/id_rsa.pub"
+    HEALTH_CHECK_ACTION = "health-check"
+
+    def __init__(self):
+        self.logger = logging.getLogger('osm_ee.base')
+
+        # Check if configuration is stored and load it
+        if os.path.exists(self.CONFIG_FILE):
+            with open(self.CONFIG_FILE, 'r') as file:
+                self.config_params = yaml.load(file, Loader=yaml.FullLoader)
+                self.logger.debug("Load existing config from file: {}".format(self.config_params))
+        else:
+            self.config_params = {}
+
+        self.vnf_ee = VnfEE(self.config_params)
+
+    async def get_ssh_key(self):
+        self.logger.debug("Obtain ssh key")
+        filename = os.path.expanduser(self.SSH_KEY_FILE)
+        with open(filename) as reader:
+            ssh_key = reader.read()
+        return ssh_key
+
+    async def run_action(self, id, name, params):
+        self.logger.debug("Execute action id: {}, name: {}, params: {}".format(id, name, params))
+
+        try:
+            # Health-check
+            if name == self.HEALTH_CHECK_ACTION:
+                yield "OK", "Health-check ok"
+            else:
+
+                # Obtain dynamically code to be executed
+                method = getattr(self.vnf_ee, name)
+
+                # Convert params from yaml format
+                action_params = yaml.safe_load(params)
+
+                if name == "config":
+                    self.logger.debug("Store config info in file: {}".format(self.CONFIG_FILE))
+                    self.config_params.update(action_params)
+                    with open(self.CONFIG_FILE, 'w') as file:
+                        config = yaml.dump(self.config_params, file)
+
+                async for return_status, detailed_message in method(id, action_params):
+                    if return_status not in self.RETURN_STATUS_LIST:
+                        yield "ERROR", "Invalid return status"
+                    else:
+                        yield return_status, str(detailed_message)
+        except AttributeError as e:
+            error_msg = "Action name: {} not implemented".format(name)
+            self.logger.error(error_msg)
+            yield "ERROR", error_msg
+        except Exception as e:
+            self.logger.error("Error executing action id, name: {},{}: {}".format(id, name, str(e)), exc_info=True)
+            yield "ERROR", str(e)
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.DEBUG)
+
+    loop = asyncio.get_event_loop()
+    try:
+        ee = BaseEE()
+        id = "test1"
+        name = "touch2"
+        params = {"file_path": "/var/tmp/testfile1.txt"}
+        action = asyncio.ensure_future(ee.run_action(id, name, params))
+        loop.run_until_complete(action)
+    finally:
+        loop.close()
diff --git a/osm_ee/exceptions.py b/osm_ee/exceptions.py
new file mode 100644 (file)
index 0000000..4829197
--- /dev/null
@@ -0,0 +1,27 @@
+##
+# Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
+# This file is part of OSM
+# All Rights Reserved.
+#
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+class ExecEnvException(Exception):
+    """Exception thrown by the EE if the actions can't be invoked or there is any generic error"""
+
+class VnfException(Exception):
+    """Exception thrown by the Vnf EE code in case of error"""
\ No newline at end of file
diff --git a/osm_ee/frontend.proto b/osm_ee/frontend.proto
new file mode 100644 (file)
index 0000000..36d0158
--- /dev/null
@@ -0,0 +1,39 @@
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "com.etsi.osm.lcm.osm_ee";
+option java_outer_classname = "GrpcExecutor";
+option objc_class_prefix = "OEE";
+
+package osm_ee;
+
+service FrontendExecutor {
+
+    // Execute action leaving open a channel for notifications
+    rpc RunPrimitive (PrimitiveRequest) returns (stream PrimitiveReply) {}
+
+    // Sends a greeting
+    rpc GetSshKey (SshKeyRequest) returns (SshKeyReply) {}
+}
+
+// Request parameters
+message PrimitiveRequest {
+    string id=1;
+    string name=2;
+    string params=3;
+}
+
+message PrimitiveReply {
+    string status=1;
+    string detailed_message=2;
+}
+
+// The request message containing the user's name.
+message SshKeyRequest {
+  // empty
+}
+
+// The response message containing the greetings
+message SshKeyReply {
+  string message = 1;
+}
diff --git a/osm_ee/frontend_client.py b/osm_ee/frontend_client.py
new file mode 100644 (file)
index 0000000..0c34580
--- /dev/null
@@ -0,0 +1,85 @@
+##
+# Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
+# This file is part of OSM
+# All Rights Reserved.
+#
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+import sys
+import yaml
+import asyncio
+import uuid
+import traceback
+import os
+import socket
+
+from grpclib.client import Channel
+
+from osm_ee.frontend_pb2 import PrimitiveRequest, PrimitiveReply
+from osm_ee.frontend_pb2 import SshKeyRequest, SshKeyReply
+from osm_ee.frontend_grpc import FrontendExecutorStub
+
+
+async def frontend_client(host_name, port, primitive_name, params):
+
+    ip_addr = socket.gethostbyname(host_name)
+    channel = Channel(ip_addr, port)
+    try:
+        stub = FrontendExecutorStub(channel)
+
+        if (primitive_name == "get_ssh_key"):
+            print("Get ssh key")
+            reply: SshKeyReply = await stub.GetSshKey(SshKeyRequest())
+            print(reply.message)
+        else:
+            async with stub.RunPrimitive.open() as stream:
+                primitive_id = str(uuid.uuid1())
+                print("Execute primitive {}, params: {}".format(primitive_name, params))
+                await stream.send_message(
+                    PrimitiveRequest(id=primitive_id, name=primitive_name, params=yaml.dump(params)), end=True)
+                async for reply in stream:
+                    print(reply)
+                #replies = [reply async for reply in stream]
+                #print(replies)
+    except Exception as e:
+        print("Error executing primitive {}: {}".format(primitive_name, str(e)))
+        #print(traceback.format_exc())
+    finally:
+        channel.close()
+
+
+if __name__ == '__main__':
+
+    args = sys.argv[1:]
+    if (len(args) < 1):
+        print("Usage: host port primitive_name params")
+    else:
+        host_name = args[0]
+        port = args[1]
+        primitive_name = args[2]
+        arg_params = args[3] if len(args) >= 4 else ""
+        print(primitive_name)
+        print(arg_params)
+        params = yaml.safe_load(arg_params)
+
+        loop = asyncio.get_event_loop()
+        try:
+            task = asyncio.ensure_future(frontend_client(host_name, port, primitive_name, params))
+            loop.run_until_complete(task)
+        finally:
+            loop.close()
diff --git a/osm_ee/frontend_grpc.py b/osm_ee/frontend_grpc.py
new file mode 100644 (file)
index 0000000..b2b95d3
--- /dev/null
@@ -0,0 +1,56 @@
+# Generated by the Protocol Buffers compiler. DO NOT EDIT!
+# source: osm_ee/frontend.proto
+# plugin: grpclib.plugin.main
+import abc
+import typing
+
+import grpclib.const
+import grpclib.client
+if typing.TYPE_CHECKING:
+    import grpclib.server
+
+import osm_ee.frontend_pb2
+
+
+class FrontendExecutorBase(abc.ABC):
+
+    @abc.abstractmethod
+    async def RunPrimitive(self, stream: 'grpclib.server.Stream[osm_ee.frontend_pb2.PrimitiveRequest, osm_ee.frontend_pb2.PrimitiveReply]') -> None:
+        pass
+
+    @abc.abstractmethod
+    async def GetSshKey(self, stream: 'grpclib.server.Stream[osm_ee.frontend_pb2.SshKeyRequest, osm_ee.frontend_pb2.SshKeyReply]') -> None:
+        pass
+
+    def __mapping__(self) -> typing.Dict[str, grpclib.const.Handler]:
+        return {
+            '/osm_ee.FrontendExecutor/RunPrimitive': grpclib.const.Handler(
+                self.RunPrimitive,
+                grpclib.const.Cardinality.UNARY_STREAM,
+                osm_ee.frontend_pb2.PrimitiveRequest,
+                osm_ee.frontend_pb2.PrimitiveReply,
+            ),
+            '/osm_ee.FrontendExecutor/GetSshKey': grpclib.const.Handler(
+                self.GetSshKey,
+                grpclib.const.Cardinality.UNARY_UNARY,
+                osm_ee.frontend_pb2.SshKeyRequest,
+                osm_ee.frontend_pb2.SshKeyReply,
+            ),
+        }
+
+
+class FrontendExecutorStub:
+
+    def __init__(self, channel: grpclib.client.Channel) -> None:
+        self.RunPrimitive = grpclib.client.UnaryStreamMethod(
+            channel,
+            '/osm_ee.FrontendExecutor/RunPrimitive',
+            osm_ee.frontend_pb2.PrimitiveRequest,
+            osm_ee.frontend_pb2.PrimitiveReply,
+        )
+        self.GetSshKey = grpclib.client.UnaryUnaryMethod(
+            channel,
+            '/osm_ee.FrontendExecutor/GetSshKey',
+            osm_ee.frontend_pb2.SshKeyRequest,
+            osm_ee.frontend_pb2.SshKeyReply,
+        )
diff --git a/osm_ee/frontend_pb2.py b/osm_ee/frontend_pb2.py
new file mode 100644 (file)
index 0000000..8cdc485
--- /dev/null
@@ -0,0 +1,233 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+# source: osm_ee/frontend.proto
+
+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()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+  name='osm_ee/frontend.proto',
+  package='osm_ee',
+  syntax='proto3',
+  serialized_options=b'\n\027com.etsi.osm.lcm.osm_eeB\014GrpcExecutorP\001\242\002\003OEE',
+  serialized_pb=b'\n\x15osm_ee/frontend.proto\x12\x06osm_ee\"<\n\x10PrimitiveRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06params\x18\x03 \x01(\t\":\n\x0ePrimitiveReply\x12\x0e\n\x06status\x18\x01 \x01(\t\x12\x18\n\x10\x64\x65tailed_message\x18\x02 \x01(\t\"\x0f\n\rSshKeyRequest\"\x1e\n\x0bSshKeyReply\x12\x0f\n\x07message\x18\x01 \x01(\t2\x93\x01\n\x10\x46rontendExecutor\x12\x44\n\x0cRunPrimitive\x12\x18.osm_ee.PrimitiveRequest\x1a\x16.osm_ee.PrimitiveReply\"\x00\x30\x01\x12\x39\n\tGetSshKey\x12\x15.osm_ee.SshKeyRequest\x1a\x13.osm_ee.SshKeyReply\"\x00\x42/\n\x17\x63om.etsi.osm.lcm.osm_eeB\x0cGrpcExecutorP\x01\xa2\x02\x03OEEb\x06proto3'
+)
+
+
+
+
+_PRIMITIVEREQUEST = _descriptor.Descriptor(
+  name='PrimitiveRequest',
+  full_name='osm_ee.PrimitiveRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='id', full_name='osm_ee.PrimitiveRequest.id', 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='name', full_name='osm_ee.PrimitiveRequest.name', 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='params', full_name='osm_ee.PrimitiveRequest.params', 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),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=33,
+  serialized_end=93,
+)
+
+
+_PRIMITIVEREPLY = _descriptor.Descriptor(
+  name='PrimitiveReply',
+  full_name='osm_ee.PrimitiveReply',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='status', full_name='osm_ee.PrimitiveReply.status', 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='detailed_message', full_name='osm_ee.PrimitiveReply.detailed_message', 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=95,
+  serialized_end=153,
+)
+
+
+_SSHKEYREQUEST = _descriptor.Descriptor(
+  name='SshKeyRequest',
+  full_name='osm_ee.SshKeyRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=155,
+  serialized_end=170,
+)
+
+
+_SSHKEYREPLY = _descriptor.Descriptor(
+  name='SshKeyReply',
+  full_name='osm_ee.SshKeyReply',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='message', full_name='osm_ee.SshKeyReply.message', 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),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=172,
+  serialized_end=202,
+)
+
+DESCRIPTOR.message_types_by_name['PrimitiveRequest'] = _PRIMITIVEREQUEST
+DESCRIPTOR.message_types_by_name['PrimitiveReply'] = _PRIMITIVEREPLY
+DESCRIPTOR.message_types_by_name['SshKeyRequest'] = _SSHKEYREQUEST
+DESCRIPTOR.message_types_by_name['SshKeyReply'] = _SSHKEYREPLY
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+PrimitiveRequest = _reflection.GeneratedProtocolMessageType('PrimitiveRequest', (_message.Message,), {
+  'DESCRIPTOR' : _PRIMITIVEREQUEST,
+  '__module__' : 'osm_ee.frontend_pb2'
+  # @@protoc_insertion_point(class_scope:osm_ee.PrimitiveRequest)
+  })
+_sym_db.RegisterMessage(PrimitiveRequest)
+
+PrimitiveReply = _reflection.GeneratedProtocolMessageType('PrimitiveReply', (_message.Message,), {
+  'DESCRIPTOR' : _PRIMITIVEREPLY,
+  '__module__' : 'osm_ee.frontend_pb2'
+  # @@protoc_insertion_point(class_scope:osm_ee.PrimitiveReply)
+  })
+_sym_db.RegisterMessage(PrimitiveReply)
+
+SshKeyRequest = _reflection.GeneratedProtocolMessageType('SshKeyRequest', (_message.Message,), {
+  'DESCRIPTOR' : _SSHKEYREQUEST,
+  '__module__' : 'osm_ee.frontend_pb2'
+  # @@protoc_insertion_point(class_scope:osm_ee.SshKeyRequest)
+  })
+_sym_db.RegisterMessage(SshKeyRequest)
+
+SshKeyReply = _reflection.GeneratedProtocolMessageType('SshKeyReply', (_message.Message,), {
+  'DESCRIPTOR' : _SSHKEYREPLY,
+  '__module__' : 'osm_ee.frontend_pb2'
+  # @@protoc_insertion_point(class_scope:osm_ee.SshKeyReply)
+  })
+_sym_db.RegisterMessage(SshKeyReply)
+
+
+DESCRIPTOR._options = None
+
+_FRONTENDEXECUTOR = _descriptor.ServiceDescriptor(
+  name='FrontendExecutor',
+  full_name='osm_ee.FrontendExecutor',
+  file=DESCRIPTOR,
+  index=0,
+  serialized_options=None,
+  serialized_start=205,
+  serialized_end=352,
+  methods=[
+  _descriptor.MethodDescriptor(
+    name='RunPrimitive',
+    full_name='osm_ee.FrontendExecutor.RunPrimitive',
+    index=0,
+    containing_service=None,
+    input_type=_PRIMITIVEREQUEST,
+    output_type=_PRIMITIVEREPLY,
+    serialized_options=None,
+  ),
+  _descriptor.MethodDescriptor(
+    name='GetSshKey',
+    full_name='osm_ee.FrontendExecutor.GetSshKey',
+    index=1,
+    containing_service=None,
+    input_type=_SSHKEYREQUEST,
+    output_type=_SSHKEYREPLY,
+    serialized_options=None,
+  ),
+])
+_sym_db.RegisterServiceDescriptor(_FRONTENDEXECUTOR)
+
+DESCRIPTOR.services_by_name['FrontendExecutor'] = _FRONTENDEXECUTOR
+
+# @@protoc_insertion_point(module_scope)
diff --git a/osm_ee/frontend_server.py b/osm_ee/frontend_server.py
new file mode 100644 (file)
index 0000000..079503d
--- /dev/null
@@ -0,0 +1,89 @@
+##
+# Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
+# This file is part of OSM
+# All Rights Reserved.
+#
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+import asyncio
+import logging
+import os
+
+from grpclib.utils import graceful_exit
+from grpclib.server import Server, Stream
+
+from osm_ee.frontend_grpc import FrontendExecutorBase
+from osm_ee.frontend_pb2 import PrimitiveRequest, PrimitiveReply
+from osm_ee.frontend_pb2 import SshKeyRequest, SshKeyReply
+
+from osm_ee.base_ee import BaseEE
+import osm_ee.util.util_ee as util_ee
+
+
+class FrontendExecutor(FrontendExecutorBase):
+
+    def __init__(self):
+        self.logger = logging.getLogger('osm_ee.frontend_server')
+        self.base_ee = BaseEE()
+
+    async def RunPrimitive(self, stream: Stream[PrimitiveRequest, PrimitiveReply]) -> None:
+        request = await stream.recv_message()
+        try:
+            self.logger.debug(f'Run primitive: id {request.id}, name: {request.name}, params: {request.params}')
+            async for status, detailed_message in self.base_ee.run_action(request.id, request.name, request.params):
+                self.logger.debug(f'Send response {status}, {detailed_message}')
+                await stream.send_message(
+                    PrimitiveReply(status=status, detailed_message=detailed_message))
+        except Exception as e:
+            self.logger.debug(f'Error executing primitive: id {request.id}, name: {request.name}, error_msg: {str(e)}')
+            await stream.send_message(
+                PrimitiveReply(status="ERROR", detailed_message=str(e)))
+
+    async def GetSshKey(self, stream: Stream[SshKeyRequest, SshKeyReply]) -> None:
+        request = await stream.recv_message()
+        assert request is not None
+        message = await self.base_ee.get_ssh_key()
+        await stream.send_message(SshKeyReply(message=message))
+
+
+async def main(*, host: str = '0.0.0.0', port: int = 50051) -> None:
+    logging.basicConfig()
+    logger = logging.getLogger('osm_ee')
+    logger.setLevel(logging.DEBUG)
+
+    # Generate ssh key
+    file_dir = os.path.expanduser("~/.ssh/id_rsa")
+    command = "ssh-keygen -q -t rsa -N '' -f {}".format(file_dir)
+    return_code, stdout, stderr = await util_ee.local_async_exec(command)
+    logger.debug("Generated ssh_key, return_code: {}".format(return_code))
+
+    # Start server
+    server = Server([FrontendExecutor()])
+    with graceful_exit([server]):
+        await server.start(host, port)
+        logging.getLogger('osm_ee.frontend_server').debug(f'Serving on {host}:{port}')
+        await server.wait_closed()
+
+
+if __name__ == '__main__':
+    loop = asyncio.get_event_loop()
+    try:
+        main_task = asyncio.ensure_future(main())
+        loop.run_until_complete(main_task)
+    finally:
+        loop.close()
diff --git a/osm_ee/scripts/ee_start.sh b/osm_ee/scripts/ee_start.sh
new file mode 100755 (executable)
index 0000000..0364dc4
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash
+##
+# Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
+# 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.
+##
+
+# This script is intended for launching RO from a docker container.
+# It waits for mysql server ready, normally running on a separate container, ...
+# then it checks if database is present and creates it if needed.
+# Finally it launches RO server.
+
+EE_PATH=/app/EE
+
+# Install vnf vendor additional required libraries
+echo "Install additional libraries"
+bash ${EE_PATH}/osm_ee/vnf/install.sh
+
+# Start frontend
+echo "Starting frontend server"
+python3 -m osm_ee.frontend_server
diff --git a/osm_ee/util/__init__.py b/osm_ee/util/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/osm_ee/util/__pycache__/__init__.cpython-36.pyc b/osm_ee/util/__pycache__/__init__.cpython-36.pyc
new file mode 100644 (file)
index 0000000..138334b
Binary files /dev/null and b/osm_ee/util/__pycache__/__init__.cpython-36.pyc differ
diff --git a/osm_ee/util/__pycache__/util_ansible.cpython-36.pyc b/osm_ee/util/__pycache__/util_ansible.cpython-36.pyc
new file mode 100644 (file)
index 0000000..d6cbaeb
Binary files /dev/null and b/osm_ee/util/__pycache__/util_ansible.cpython-36.pyc differ
diff --git a/osm_ee/util/__pycache__/util_ee.cpython-36.pyc b/osm_ee/util/__pycache__/util_ee.cpython-36.pyc
new file mode 100644 (file)
index 0000000..2c6940c
Binary files /dev/null and b/osm_ee/util/__pycache__/util_ee.cpython-36.pyc differ
diff --git a/osm_ee/util/util_ansible.py b/osm_ee/util/util_ansible.py
new file mode 100644 (file)
index 0000000..8f27875
--- /dev/null
@@ -0,0 +1,46 @@
+##
+# Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
+# This file is part of OSM
+# All Rights Reserved.
+#
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+import logging
+import json
+from shlex import quote
+
+import osm_ee.util.util_ee as util_ee
+
+logger = logging.getLogger("osm_ee.util_ansible")
+
+
+async def execute_playbook(playbook_name: str, inventory: str, extra_vars: dict,
+                           ) -> (int, str):
+
+    command = 'ansible-playbook --inventory={} --extra-vars {} {}'.format(quote(inventory),
+                                                                          quote(json.dumps(extra_vars)),
+                                                                          quote(playbook_name))
+
+    logger.debug("Command to be executed: {}".format(command))
+
+    return_code, stdout, stderr = await util_ee.local_async_exec(command)
+    logger.debug("Return code: {}".format(return_code))
+    logger.debug("stdout: {}".format(stdout))
+    logger.debug("stderr: {}".format(stderr))
+
+    return return_code, stdout, stderr
diff --git a/osm_ee/util/util_ee.py b/osm_ee/util/util_ee.py
new file mode 100644 (file)
index 0000000..1d0a232
--- /dev/null
@@ -0,0 +1,60 @@
+##
+# Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
+# This file is part of OSM
+# All Rights Reserved.
+#
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+import logging
+import asyncio
+from shlex import split
+
+logger = logging.getLogger("osm_ee.util")
+
+
+async def local_async_exec(command: str
+                           ) -> (int, str, str):
+    """
+        Executed a local command using asyncio.
+        TODO - do not know yet if return error code, and stdout and strerr or just one of them
+    """
+    scommand = split(command)
+
+    logger.debug("Execute local command: {}".format(command))
+    process = await asyncio.create_subprocess_exec(
+        *scommand,
+        stdout=asyncio.subprocess.PIPE,
+        stderr=asyncio.subprocess.PIPE
+    )
+
+    # wait for command terminate
+    stdout, stderr = await process.communicate()
+
+    return_code = process.returncode
+    logger.debug("Return code: {}".format(return_code))
+
+    output = ""
+    if stdout:
+        output = stdout.decode()
+        logger.debug("Output: {}".format(output))
+
+    if stderr:
+        out_err = stderr.decode()
+        logger.debug("Stderr: {}".format(out_err))
+
+    return return_code, stdout, stderr
diff --git a/osm_ee/vnf/__init__.py b/osm_ee/vnf/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/osm_ee/vnf/__pycache__/__init__.cpython-36.pyc b/osm_ee/vnf/__pycache__/__init__.cpython-36.pyc
new file mode 100644 (file)
index 0000000..70afb9e
Binary files /dev/null and b/osm_ee/vnf/__pycache__/__init__.cpython-36.pyc differ
diff --git a/osm_ee/vnf/__pycache__/vnf_ee.cpython-36.pyc b/osm_ee/vnf/__pycache__/vnf_ee.cpython-36.pyc
new file mode 100644 (file)
index 0000000..27ab0d3
Binary files /dev/null and b/osm_ee/vnf/__pycache__/vnf_ee.cpython-36.pyc differ
diff --git a/osm_ee/vnf/install.sh b/osm_ee/vnf/install.sh
new file mode 100644 (file)
index 0000000..e0e56ff
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/bash
+##
+# Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
+# 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.
+##
+
+# This script is intended for launching RO from a docker container.
+# It waits for mysql server ready, normally running on a separate container, ...
+# then it checks if database is present and creates it if needed.
+# Finally it launches RO server.
+
+echo "Sample install.sh "
\ No newline at end of file
diff --git a/osm_ee/vnf/vnf_ee.py b/osm_ee/vnf/vnf_ee.py
new file mode 100644 (file)
index 0000000..10c2e33
--- /dev/null
@@ -0,0 +1,54 @@
+##
+# Copyright 2019 Telefonica Investigacion y Desarrollo, S.A.U.
+# This file is part of OSM
+# All Rights Reserved.
+#
+# 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.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+import asyncio
+import logging
+
+from osm_ee.exceptions import VnfException
+
+
+class VnfEE:
+
+    def __init__(self, config_params):
+        self.logger = logging.getLogger('osm_ee.vnf')
+        self.config_params = config_params
+
+    async def config(self, id, params):
+        self.logger.debug("Execute action config params: {}".format(params))
+        # Config action is special, params are merged with previous config calls
+        self.config_params.update(params)
+        yield "OK", "Configured"
+
+    async def sleep(self, id, params):
+        self.logger.debug("Execute action sleep, params: {}".format(params))
+
+        for i in range(3):
+            await asyncio.sleep(5)
+            self.logger.debug("Temporal result return, params: {}".format(params))
+            yield "PROCESSING", f"Processing {i} action id {id}"
+        yield "OK", f"Processed action id {id}"
+
+    @staticmethod
+    def _check_required_params(params, required_params):
+        for required_param in required_params:
+            if required_param not in params:
+                raise VnfException("Missing required param: {}".format(required_param))
diff --git a/setup.py b/setup.py
new file mode 100644 (file)
index 0000000..ab68a84
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# Copyright 2018 Telefonica S.A.
+#
+# 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 setuptools import setup
+
+_name = "osm_ee"
+
+_description = 'OSM Resource Orchestrator'
+_author = 'ETSI OSM'
+_author_email = 'illoret@indra.es'
+_maintainer = 'alfonso.tiernosepulveda'
+_maintainer_email = 'alfonso.tiernosepulveda@telefonica.com'
+_license = 'Apache 2.0'
+_url = 'TOBEDEFINED'
+_requirements = [
+    # Libraries needed by the code defined by osm
+    "PyYAML",
+    "grpcio-tools",
+    "grpclib",
+    "protobuf",
+
+    # Libraries defined by the vnf code, they should be in an external file
+    #"asyncssh",
+]
+
+setup(
+    name=_name,
+    #version_command=('0.1'), # TODO - replace for a git command
+    version='1.0',
+    description=_description,
+    long_description=open('README.rst').read(),
+    author=_author,
+    author_email=_author_email,
+    maintainer=_maintainer,
+    maintainer_email=_maintainer_email,
+    url=_url,
+    license=_license,
+    packages=[_name],
+    package_dir={_name: _name},
+
+    install_requires=_requirements,
+    include_package_data=True,
+    setup_requires=['setuptools-version-command'],
+)
\ No newline at end of file