Fix to expose the port outside the container
[nonrtric/plt/rappcatalogue.git] / catalogue-enhanced / src / catalogue_manager.py
1 #  ============LICENSE_START===============================================
2 #  Copyright (C) 2022 Nordix Foundation. All rights reserved.
3 #  ========================================================================
4 #  Licensed under the Apache License, Version 2.0 (the "License");
5 #  you may not use this file except in compliance with the License.
6 #  You may obtain a copy of the License at
7 #
8 #       http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #  Unless required by applicable law or agreed to in writing, software
11 #  distributed under the License is distributed on an "AS IS" BASIS,
12 #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 #  See the License for the specific language governing permissions and
14 #  limitations under the License.
15 #  ============LICENSE_END=================================================
16 #
17
18 import os
19 import json
20
21 from flask import request, Response
22 from jsonschema import validate
23 from var_declaration import rapp_registry
24 from zipfile import ZipFile
25 from io import TextIOWrapper
26 from util import ToscametaFormatChecker
27
28 # Constsants
29 APPL_JSON='application/json'
30 TEXT_PLAIN='text/plain'
31 APPL_PROB_JSON='application/problem+json'
32
33 # API Function: Query for all rapp identifiers
34 def query_all_rapp_ids():
35
36   res = list(rapp_registry.keys())
37   return (res, 200)
38
39
40 # API Function: Get a rapp definition
41 def query_rapp_by_id(rappid):
42
43   rapp_id = str(rappid)
44
45   if (rapp_id not in rapp_registry.keys()):
46     pjson=create_problem_json(None, "The rapp does not exist.", 404, None, rapp_id)
47     return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON)
48
49   return Response(json.dumps(rapp_registry[rapp_id]), 200, mimetype=APPL_JSON)
50
51
52 # API Function: Register, or update, a rapp definition
53 def register_rapp(rappid):
54
55   rapp_id=str(rappid)
56
57   try:
58     data = request.data
59     data = json.loads(data)
60   except Exception:
61     pjson=create_problem_json(None, "The rapp definition is corrupt or missing.", 400, None, rapp_id)
62     return Response(json.dumps(pjson), 400, mimetype=APPL_PROB_JSON)
63
64   return_code = 201
65   if rapp_id in rapp_registry.keys():
66     return_code = 200
67
68   # Register or update rapp definition
69   rapp_registry[rapp_id] = data
70
71   return Response(json.dumps(data), return_code, mimetype=APPL_JSON)
72
73
74 # API Function: Unregister a rapp from catalogue
75 def unregister_rapp(rappid):
76
77   rapp_id = str(rappid)
78
79   if (rapp_id not in rapp_registry.keys()):
80     pjson = create_problem_json(None, "The rapp definition does not exist.", 404, None, rapp_id)
81     return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON)
82
83   # Delete rapp definition
84   del rapp_registry[rapp_id]
85
86   return Response('', 204, mimetype=APPL_JSON)
87
88 # API Function: Query api list by rapp_id and service_type: produced or consumed
89 def query_api_list_by_rapp_id_and_service_type(rappid, servicetype):
90
91   rapp_id = str(rappid)
92   service_type = str(servicetype)
93
94   if (rapp_id in rapp_registry.keys()):
95
96     rapp_definition = rapp_registry[rapp_id]
97     try:
98       arr_api_list = rapp_definition['apiList']
99       arr_filtered_api_list = [arr_item for arr_item in arr_api_list if arr_item['serviceType'] == service_type]
100       return (arr_filtered_api_list, 200)
101     except Exception as err:
102       print('An error occured:', err)
103       pjson=create_problem_json(None, "The rapp definition is corrupt or missing.", 400, None, rapp_id)
104       return Response(json.dumps(pjson), 400, mimetype=APPL_PROB_JSON)
105
106   return ([], 200)
107
108 # API Function: Validate and return TOSCA.meta file content
109 def query_tosca_meta_content_by_rapp_id(rappid):
110
111   rapp_id = str(rappid)
112
113   if (rapp_id not in rapp_registry.keys()):
114     pjson=create_problem_json(None, "The rapp does not exist.", 404, None, rapp_id)
115     return Response(json.dumps(pjson), 404, mimetype=APPL_PROB_JSON)
116
117   with open_zip_and_filter('/usr/src/app/csar/rapp1/rapp1.csar') as tosca_file:
118     tosca_meta = []
119     while True:
120       line = tosca_file.readline()  # Get next line from file
121       if not line:  # end of file is reached
122         break
123       else:
124         tosca_meta.append(line.strip())
125
126   print('TOSCA.meta content:', tosca_meta)
127   is_valid = validate_tosca_meta_format(tosca_meta)
128
129   if is_valid == True:
130     content = tosca_meta
131     return Response(json.dumps(content), 200, mimetype=APPL_JSON)
132
133   return ([], 200)
134
135 # Helper: Open CSAR zip file and returns TOSCA.meta
136 def validate_tosca_meta_format(toscameta):
137
138   if len(toscameta) >= 3:
139     file_tag = split_and_strip(toscameta[0])
140     csar_tag = split_and_strip(toscameta[1])
141     crby_tag = split_and_strip(toscameta[2])
142
143     checker = ToscametaFormatChecker(file_tag, csar_tag, crby_tag)  # util.py: validater
144     result = checker.validate()
145
146     if result == True:  # Log: Validated or NOT
147       print('Validated:', checker)
148     else:
149       print('NOT Validated:', checker)
150     return result
151
152   return False
153
154 # Helper: Splits given string by colon and strip
155 def split_and_strip(string):
156   result = [x.strip() for x in string.split(':')]
157   return result[0]
158
159 # Helper: Open CSAR zip file and returns TOSCA.meta file
160 def open_zip_and_filter(filename):
161
162   try:
163     with ZipFile(filename, 'r') as zip_object:
164       file_names = zip_object.namelist()
165       for file_name in file_names:
166         if file_name.endswith('TOSCA.meta'):
167           return TextIOWrapper(zip_object.open(file_name))  # TextIOWrapper: provides buffered text stream
168
169       pjson=create_problem_json(None, "TOSCA.meta file is corrupt or missing.", 400, None, rapp_id)
170       return Response(json.dumps(pjson), 400, mimetype=APPL_PROB_JSON)
171   except Exception as err:
172     print('An error occured:', err)
173     pjson=create_problem_json(None, "The CSAR zip content is corrupt or missing.", 400, None, rapp_id)
174     return Response(json.dumps(pjson), 400, mimetype=APPL_PROB_JSON)
175   finally:
176     zip_object.close()
177
178 # Helper: Create a problem json object
179 def create_problem_json(type_of, title, status, detail, instance):
180
181   error = {}
182   if type_of is not None:
183     error["type"] = type_of
184   if title is not None:
185     error["title"] = title
186   if status is not None:
187     error["status"] = status
188   if detail is not None:
189     error["detail"] = detail
190   if instance is not None:
191     error["instance"] = instance
192   return error
193
194
195 # Helper: Create a problem json based on a generic http response code
196 def create_error_response(code):
197
198     if code == 400:
199       return(create_problem_json(None, "Bad request", 400, "Object in payload not properly formulated or not related to the method", None))
200     elif code == 404:
201       return(create_problem_json(None, "Not found", 404, "No resource found at the URI", None))
202     elif code == 405:
203       return(create_problem_json(None, "Method not allowed", 405, "Method not allowed for the URI", None))
204     elif code == 408:
205       return(create_problem_json(None, "Request timeout", 408, "Request timeout", None))
206     elif code == 409:
207       return(create_problem_json(None, "Conflict", 409, "Request could not be processed in the current state of the resource", None))
208     elif code == 429:
209       return(create_problem_json(None, "Too many requests", 429, "Too many requests have been sent in a given amount of time", None))
210     elif code == 503:
211       return(create_problem_json(None, "Service unavailable", 503, "The provider is currently unable to handle the request due to a temporary overload", None))
212     elif code == 507:
213       return(create_problem_json(None, "Insufficient storage", 507, "The method could not be performed on the resource because the provider is unable to store the representation needed to successfully complete the request", None))
214     else:
215       return(create_problem_json(None, "Unknown", code, "Not implemented response code", None))