Add bi-directional GRPC python executor.
[ccsdk/cds.git] / ms / py-executor / blueprints_grpc / executor_utils.py
1 #!/usr/bin/python
2 #
3 #  Copyright © 2018-2019 AT&T Intellectual Property.
4 #
5 #  Licensed under the Apache License, Version 2.0 (the "License");
6 #  you may not use this file except in compliance with the License.
7 #  You may obtain a copy of the License at
8 #
9 #      http://www.apache.org/licenses/LICENSE-2.0
10 #
11 #  Unless required by applicable law or agreed to in writing, software
12 #  distributed under the License is distributed on an "AS IS" BASIS,
13 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 #  See the License for the specific language governing permissions and
15 #  limitations under the License.
16
17 from google.protobuf.timestamp_pb2 import Timestamp
18 from google.protobuf import struct_pb2
19 from google.protobuf import json_format
20 import sys, importlib, importlib.util, json, time, datetime
21 import logging
22 from .proto.BluePrintProcessing_pb2 import ExecutionServiceInput, ExecutionServiceOutput
23 from .proto.BluePrintCommon_pb2 import Status, EVENT_COMPONENT_TRACE, EVENT_COMPONENT_PROCESSING, \
24     EVENT_COMPONENT_EXECUTED, EVENT_COMPONENT_NOTIFICATION
25 from .script_executor_configuration import ScriptExecutorConfiguration
26
27 logger = logging.getLogger("Utils")
28
29
30 def current_time():
31     ts = time.time()
32     return datetime.datetime.fromtimestamp(ts).strftime("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
33
34
35 def blueprint_id(input: ExecutionServiceInput):
36     blueprint_name = input.actionIdentifiers.blueprintName
37     blueprint_version = input.actionIdentifiers.blueprintVersion
38     return blueprint_name + '/' + blueprint_version
39
40
41 def blueprint_location(config: ScriptExecutorConfiguration, input: ExecutionServiceInput):
42     blueprint_name = input.actionIdentifiers.blueprintName
43     blueprint_version = input.actionIdentifiers.blueprintVersion
44     return config.blueprints_processor('blueprintDeployPath') + '/' + blueprint_name + '/' + blueprint_version
45
46
47 def instance_for_input(config: ScriptExecutorConfiguration, input: ExecutionServiceInput):
48     blueprint_name = input.actionIdentifiers.blueprintName
49     blueprint_version = input.actionIdentifiers.blueprintVersion
50     action_name = input.actionIdentifiers.actionName
51     # Get Blueprint python script location
52     script_location = blueprint_location(config, input) + '/' + 'Scripts/python/__init__.py'
53     logger.info(script_location)
54
55     # Create Dynamic Module Name
56     module_name = blueprint_name + '-' + blueprint_version
57     spec = importlib.util.spec_from_file_location(module_name, script_location)
58     logger.info(spec)
59     dynamic_module = importlib.util.module_from_spec(spec)
60     # Add blueprint modules
61     sys.modules[spec.name] = dynamic_module
62     spec.loader.exec_module(dynamic_module)
63     script_clazz = getattr(dynamic_module, action_name)
64     return script_clazz()
65
66
67 def log_response(input: ExecutionServiceInput, message: str):
68     payload = struct_pb2.Struct()
69     payload['message'] = message
70     status = Status()
71     status.timestamp = current_time()
72     status.eventType = EVENT_COMPONENT_TRACE
73     return ExecutionServiceOutput(commonHeader=input.commonHeader,
74                                   actionIdentifiers=input.actionIdentifiers,
75                                   payload=payload, status=status)
76
77
78 def send_notification(input: ExecutionServiceInput, message: str):
79     payload = struct_pb2.Struct()
80     payload['message'] = message
81     status = Status()
82     status.timestamp = current_time()
83     status.eventType = EVENT_COMPONENT_NOTIFICATION
84     return ExecutionServiceOutput(commonHeader=input.commonHeader,
85                                   actionIdentifiers=input.actionIdentifiers,
86                                   payload=payload, status=status)
87
88
89 def ack_response(input: ExecutionServiceInput):
90     timestamp = Timestamp()
91     timestamp.GetCurrentTime()
92     response_common_header = input.commonHeader
93     status = Status()
94     status.timestamp = current_time()
95     status.eventType = EVENT_COMPONENT_PROCESSING
96     return ExecutionServiceOutput(commonHeader=response_common_header,
97                                   actionIdentifiers=input.actionIdentifiers,
98                                   status=status)
99
100
101 def success_response(input: ExecutionServiceInput, property_json: json, code: int):
102     timestamp = Timestamp()
103     timestamp.GetCurrentTime()
104     status = Status()
105     status.timestamp = current_time()
106     status.eventType = EVENT_COMPONENT_EXECUTED
107     status.code = code
108     status.message = 'success'
109     payload_struct = create_response_payload_from_json(input.actionIdentifiers.actionName, property_json)
110     return ExecutionServiceOutput(commonHeader=input.commonHeader,
111                                   actionIdentifiers=input.actionIdentifiers, status=status, payload=payload_struct)
112
113
114 def failure_response(input: ExecutionServiceInput, property_json: json, error_code: int,
115                      error_message: str):
116     timestamp = Timestamp()
117     timestamp.GetCurrentTime()
118     status = Status()
119     status.timestamp = current_time()
120     status.eventType = EVENT_COMPONENT_EXECUTED
121     status.code = error_code
122     status.message = 'failure'
123     payload_struct = create_response_payload_from_json(input.actionIdentifiers.actionName, property_json)
124     status.errorMessage = error_message
125     return ExecutionServiceOutput(commonHeader=input.commonHeader,
126                                   actionIdentifiers=input.actionIdentifiers, status=status, payload=payload_struct)
127
128
129 def create_response_payload_from_json(action_name, property_json: json):
130     # Create response Pay load json from property Json
131     payload_key = action_name + '-response'
132     response_payload = {}
133     response_payload[payload_key] = property_json
134     response_payload_json = json.dumps(response_payload)
135     # Create Struct from Json
136     payload_struct = struct_pb2.Struct()
137     json_format.Parse(str(response_payload_json), payload_struct, ignore_unknown_fields=True)
138     return payload_struct