Fix frontend docker
[clamp.git] / src / test / resources / http-cache / third_party_proxy.py
1 #!/usr/bin/env python2
2 ###
3 # ============LICENSE_START=======================================================
4 # ONAP CLAMP
5 # ================================================================================
6 # Copyright (C) 2018 AT&T Intellectual Property. All rights
7 #                             reserved.
8 # ================================================================================
9 # Licensed under the Apache License, Version 2.0 (the "License");
10 # you may not use this file except in compliance with the License.
11 # You may obtain a copy of the License at
12 #
13 # http://www.apache.org/licenses/LICENSE-2.0
14 #
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS,
17 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 # See the License for the specific language governing permissions and
19 # limitations under the License.
20 # ============LICENSE_END============================================
21 # ===================================================================
22 #
23 ###
24
25 import json
26 import requests
27 import os
28 import errno
29 import sys
30 import SimpleHTTPServer
31 import SocketServer
32 import argparse
33 import tempfile
34 import signal
35 import uuid
36 import shutil
37
38 parser = argparse.ArgumentParser(description="3rd party Cache & Replay")
39 parser.add_argument("--username", "-u", type=str, help="Set the username for contacting 3rd party - only used for GET")
40 parser.add_argument("--password", "-p", type=str, help="Set the password for contacting 3rd party - only used for GET")
41 parser.add_argument("--root",     "-r", default=tempfile.mkdtemp(), type=str, help="Root folder for the proxy cache")
42 parser.add_argument("--temp",     "-t", default=tempfile.mkdtemp(), type=str, help="Temp folder for the generated content")
43 parser.add_argument("--proxy"         , type=str, help="Url of the  Act as a proxy. If not set, this script only uses the cache and will return a 404 if files aren't found")
44 parser.add_argument("--port",     "-P", type=int, default="8081", help="Port on which the proxy should listen to")
45 parser.add_argument("--verbose",  "-v", type=bool, help="Print more information in case of error")
46 parser.add_argument("--proxyaddress","-a", type=str, help="Address of this proxy, generally either third-party-proxy:8085 or localhost:8085 depending if started with docker-compose or not")
47 options = parser.parse_args()
48
49
50 PORT = options.port
51 HOST = options.proxy
52 AUTH = (options.username, options.password)
53 HEADERS = {'X-ECOMP-InstanceID':'CLAMP'}
54 CACHE_ROOT = str(options.root)
55 TMP_ROOT = str(options.temp)
56 PROXY_ADDRESS=str(options.proxyaddress)
57
58 def signal_handler(signal_sent, frame):
59     global httpd
60     if signal_sent == signal.SIGINT:
61         print('Got Ctrl-C (SIGINT)')
62         httpd.socket.close()
63         httpd.shutdown()
64         httpd.server_close()
65
66 class Proxy(SimpleHTTPServer.SimpleHTTPRequestHandler):
67     def print_headers(self):
68         for header,value in self.headers.items():
69             print("header: %s : %s" % (header, value))
70
71     def check_credentials(self):
72         pass
73
74     def _send_content(self, header_file, content_file):
75         self.send_response(200)
76         with open(header_file, 'rb') as f:
77             headers = json.load(f)
78             for key,value in headers.items():
79                 if key in ('Transfer-Encoding',):
80                     continue
81                 self.send_header(key, value)
82             self.end_headers()
83         with open(content_file,'rb') as f:
84             fc = f.read()
85             self.wfile.write(fc)
86
87     def _write_cache(self,cached_file_folder, header_file, content_file, response):
88         os.makedirs(cached_file_folder, 0777)
89         with open(content_file, 'w') as f:
90             f.write(response.raw.read())
91         with open(header_file, 'w') as f:
92             json.dump(dict(response.raw.headers), f)
93     # Entry point of the code
94     def _get_cached_file_folder_name(self,folder):
95         cached_file_folder = '%s/%s' % (folder, self.path,)
96         print("Cached file name before escaping : %s" % cached_file_folder)
97         cached_file_folder = cached_file_folder.replace('<','&#60;').replace('>','&#62;').replace('?','&#63;').replace('*','&#42;').replace('\\','&#42;').replace(':','&#58;').replace('|','&#124;')
98         print("Cached file name after escaping (used for cache storage) : %s" % cached_file_folder)
99         return cached_file_folder
100     
101     def _get_cached_content_file_name(self,cached_file_folder):
102         return "%s/.file" % (cached_file_folder,)
103     
104     def _get_cached_header_file_name(self,cached_file_folder):
105         return "%s/.header" % (cached_file_folder,)
106     
107     def _execute_content_generated_cases(self,http_type):
108      print("Testing special cases, cache files will be sent to :" +TMP_ROOT)
109      cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
110      cached_file_content = self._get_cached_content_file_name(cached_file_folder)
111      cached_file_header = self._get_cached_header_file_name(cached_file_folder)
112      _file_available = os.path.exists(cached_file_content)
113     
114      if self.path.startswith("/dcae-service-types?asdcResourceId=") and http_type == "GET":
115         if not _file_available:
116             print "self.path start with /dcae-service-types?asdcResourceId=, generating response json..."
117             uuidGenerated = str(uuid.uuid4())
118             typeId = "typeId-" + uuidGenerated
119             typeName = "typeName-" + uuidGenerated
120             print "typeId generated: " + typeName + " and typeName: "+ typeId
121             jsonGenerated = "{\"totalCount\":1, \"items\":[{\"typeId\":\"" + typeId + "\", \"typeName\":\"" + typeName +"\"}]}"
122             print "jsonGenerated: " + jsonGenerated
123     
124             os.makedirs(cached_file_folder, 0777)
125             with open(cached_file_header, 'w') as f:
126                 f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
127             with open(cached_file_content, 'w') as f:
128                 f.write(jsonGenerated)
129         return True
130      elif self.path.startswith("/dcae-operationstatus/install") and http_type == "GET":
131         if not _file_available:
132             print "self.path start with /dcae-operationstatus/install, generating response json..."
133             jsonGenerated =  "{\"operationType\": \"install\", \"status\": \"succeeded\"}"
134             print "jsonGenerated: " + jsonGenerated
135     
136             try:
137                 os.makedirs(cached_file_folder, 0777)
138             except OSError as e:
139                 if e.errno != errno.EEXIST:
140                     raise
141                 print(cached_file_folder+" already exists")
142     
143             with open(cached_file_header, 'w') as f:
144                 f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
145             with open(cached_file_content, 'w') as f:
146                 f.write(jsonGenerated)
147         return True
148      elif self.path.startswith("/dcae-operationstatus/uninstall") and http_type == "GET":
149         if not _file_available:
150             print "self.path start with /dcae-operationstatus/uninstall, generating response json..."
151             jsonGenerated =  "{\"operationType\": \"uninstall\", \"status\": \"succeeded\"}"
152             print "jsonGenerated: " + jsonGenerated
153     
154             try:
155                 os.makedirs(cached_file_folder, 0777)
156             except OSError as e:
157                 if e.errno != errno.EEXIST:
158                     raise
159                 print(cached_file_folder+" already exists")
160     
161             with open(cached_file_header, 'w') as f:
162                 f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
163             with open(cached_file_content, 'w') as f:
164                 f.write(jsonGenerated)
165         return True
166      elif self.path.startswith("/sdc/v1/catalog/services/") and http_type == "POST":
167         if not _file_available:
168             print "self.path start with /sdc/v1/catalog/services/, generating response json..."
169             jsondata = json.loads(self.data_string)
170             jsonGenerated = "{\"artifactName\":\"" + jsondata['artifactName'] + "\",\"artifactType\":\"" + jsondata['artifactType'] + "\",\"artifactURL\":\"" + self.path + "\",\"artifactDescription\":\"" + jsondata['description'] + "\",\"artifactChecksum\":\"ZjJlMjVmMWE2M2M1OTM2MDZlODlmNTVmZmYzNjViYzM=\",\"artifactUUID\":\"" + str(uuid.uuid4()) + "\",\"artifactVersion\":\"1\"}"
171             print "jsonGenerated: " + jsonGenerated
172     
173             os.makedirs(cached_file_folder, 0777)
174             with open(cached_file_header, 'w') as f:
175                 f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
176             with open(cached_file_content, 'w') as f:
177                 f.write(jsonGenerated)
178         return True
179      elif self.path.startswith("/dcae-deployments/") and http_type == "PUT":
180             print "self.path start with /dcae-deployments/ DEPLOY, generating response json..."
181             #jsondata = json.loads(self.data_string)
182             jsonGenerated = "{\"operationType\":\"install\",\"status\":\"processing\",\"links\":{\"status\":\"http:\/\/" + PROXY_ADDRESS + "\/dcae-operationstatus/install\"}}"
183             print "jsonGenerated: " + jsonGenerated
184             if not os.path.exists(cached_file_folder):
185                 os.makedirs(cached_file_folder, 0777)
186             with open(cached_file_header, 'w+') as f:
187                 f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
188             with open(cached_file_content, 'w+') as f:
189                 f.write(jsonGenerated)
190                 return True
191      elif self.path.startswith("/dcae-deployments/") and http_type == "DELETE":
192             print "self.path start with /dcae-deployments/ UNDEPLOY, generating response json..."
193             #jsondata = json.loads(self.data_string)
194             jsonGenerated = "{\"operationType\":\"uninstall\",\"status\":\"processing\",\"links\":{\"status\":\"http:\/\/" + PROXY_ADDRESS + "\/dcae-operationstatus/uninstall\"}}"
195             print "jsonGenerated: " + jsonGenerated
196             if not os.path.exists(cached_file_folder):
197                 os.makedirs(cached_file_folder, 0777)
198             with open(cached_file_header, 'w+') as f:
199                 f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
200             with open(cached_file_content, 'w+') as f:
201                 f.write(jsonGenerated)
202             return True
203      elif (self.path.startswith("/pdp/api/") and (http_type == "PUT" or http_type == "DELETE")) or (self.path.startswith("/pdp/api/policyEngineImport") and http_type == "POST"):
204         print "self.path start with /pdp/api/, copying body to response ..."
205         if not os.path.exists(cached_file_folder):
206             os.makedirs(cached_file_folder, 0777)
207         with open(cached_file_header, 'w+') as f:
208             f.write("{\"Content-Length\": \"" + str(len(self.data_string)) + "\", \"Content-Type\": \""+str(self.headers['Content-Type'])+"\"}")
209         with open(cached_file_content, 'w+') as f:
210             f.write(self.data_string)
211         return True
212      elif self.path.startswith("/policy/api/v1/policytypes/") and http_type == "POST":
213         print "self.path start with POST new policy API /pdp/api/, copying body to response ..."
214         if not os.path.exists(cached_file_folder):
215             os.makedirs(cached_file_folder, 0777)
216         with open(cached_file_header, 'w+') as f:
217             f.write("{\"Content-Length\": \"" + str(len(self.data_string)) + "\", \"Content-Type\": \""+str(self.headers['Content-Type'])+"\"}")
218         with open(cached_file_content, 'w+') as f:
219             f.write(self.data_string)
220         return True
221      elif self.path.startswith("/policy/api/v1/policytypes/") and http_type == "DELETE":
222         print "self.path start with DELETE new policy API /policy/api/v1/policytypes/ ..."
223         if not os.path.exists(cached_file_folder):
224             os.makedirs(cached_file_folder, 0777)
225     
226         with open(cached_file_header, 'w+') as f:
227                 f.write("{\"Content-Length\": \"" + str(len("")) + "\", \"Content-Type\": \""+str("")+"\"}")
228         with open(cached_file_content, 'w+') as f:
229                 f.write(self.data_string)
230         return True
231      elif self.path.startswith("/policy/pap/v1/pdps/policies") and http_type == "POST":
232         print "self.path start with POST new policy API /policy/pap/v1/pdps/ ..."
233         if not os.path.exists(cached_file_folder):
234             os.makedirs(cached_file_folder, 0777)
235         with open(cached_file_header, 'w+') as f:
236                 f.write("{\"Content-Length\": \"" + str(len("")) + "\", \"Content-Type\": \""+str("")+"\"}")
237         with open(cached_file_content, 'w+') as f:
238                 f.write(self.data_string)
239         return True
240      elif self.path.startswith("/policy/api/v1/policytypes/") and http_type == "GET":
241         print "self.path start with /policy/api/v1/policytypes/, generating response json..."
242         jsonGenerated =  "{\"policyTypeId\": \"onap.policies.controlloop.operational\",\"policyTypeVersion\": \"1.0.0\",\"policyId\": \"OPERATIONAL_z711F_v1_0_ResourceInstanceName1_tca\"}"
243         print "jsonGenerated: " + jsonGenerated
244         if not os.path.exists(cached_file_folder):
245             os.makedirs(cached_file_folder, 0777)
246
247         with open(cached_file_header, 'w') as f:
248             f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
249         with open(cached_file_content, 'w') as f:
250             f.write(jsonGenerated)
251         return True
252      else:
253         return False
254
255     
256     def do_GET(self):
257         cached_file_folder = ""
258         cached_file_content =""
259         cached_file_header=""
260         print("\n\n\nGot a GET request for %s " % self.path)
261
262         self.print_headers()
263         self.check_credentials()
264         # Verify if it's a special case
265         is_special = self._execute_content_generated_cases("GET")
266         if is_special:
267             cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
268             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
269             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
270         else:
271             cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
272             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
273             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
274
275         _file_available = os.path.exists(cached_file_content)
276
277         if not _file_available:
278             print("Request for data currently not present in cache: %s" % (cached_file_folder,))
279
280             if not HOST:
281                 self.send_response(404)
282                 self.end_headers()
283                 self.wfile.write('404 Not found, no remote HOST specified on the emulator !!!')
284                 return "404 Not found, no remote HOST specified on the emulator !!!"
285
286             url = '%s%s' % (HOST, self.path)
287             response = requests.get(url, auth=AUTH, headers=HEADERS, stream=True)
288
289             if response.status_code == 200:
290                 self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
291             else:
292                 print('Error when requesting file :')
293                 print('Requested url : %s' % (url,))
294                 print('Status code : %s' % (response.status_code,))
295                 print('Content : %s' % (response.content,))
296                 self.send_response(response.status_code)
297                 self.end_headers()
298                 self.wfile.write('404 Not found, nothing found on the remote server !!!')
299                 return response.content
300         else:
301             print("Request for data currently present in cache: %s" % (cached_file_folder,))
302
303         self._send_content(cached_file_header, cached_file_content)
304
305         if self.path.startswith("/dcae-service-types?asdcResourceId="):
306             print "DCAE case deleting folder created " + cached_file_folder
307             shutil.rmtree(cached_file_folder, ignore_errors=False, onerror=None)
308         else:
309             print "NOT in DCAE case deleting folder created " + cached_file_folder
310
311     def do_POST(self):
312         cached_file_folder = ""
313         cached_file_content =""
314         cached_file_header=""
315         print("\n\n\nGot a POST for %s" % self.path)
316         self.check_credentials()
317         self.data_string = self.rfile.read(int(self.headers['Content-Length']))
318         print("data-string:\n %s" % self.data_string)
319         print("self.headers:\n %s" % self.headers)
320
321         is_special = self._execute_content_generated_cases("POST")
322         if is_special:
323             cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
324             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
325             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
326         else:
327             cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
328             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
329             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
330
331         _file_available = os.path.exists(cached_file_content)
332
333         if not _file_available:
334         
335             if not HOST:
336                 self.send_response(404)
337                 self.end_headers()
338                 self.wfile.write('404 Not found, no remote HOST specified on the emulator !!!')
339                 return "404 Not found, no remote HOST specified on the emulator !!!"
340
341             print("Request for data currently not present in cache: %s" % (cached_file_folder,))
342
343             url = '%s%s' % (HOST, self.path)
344             print("url: %s" % (url,))
345             response = requests.post(url, data=self.data_string, headers=self.headers, stream=True)
346
347             if response.status_code == 200:
348                 self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
349             else:
350                 print('Error when requesting file :')
351                 print('Requested url : %s' % (url,))
352                 print('Status code : %s' % (response.status_code,))
353                 print('Content : %s' % (response.content,))
354                 self.send_response(response.status_code)
355                 self.end_headers()
356                 self.wfile.write('404 Not found, nothing found on the remote server !!!')
357                 return response.content
358         else:
359             print("Request for data present in cache: %s" % (cached_file_folder,))
360
361         self._send_content(cached_file_header, cached_file_content)
362
363     def do_PUT(self):
364         cached_file_folder = ""
365         cached_file_content =""
366         cached_file_header=""
367         print("\n\n\nGot a PUT for %s " % self.path)
368         self.check_credentials()
369         self.data_string = self.rfile.read(int(self.headers['Content-Length']))
370         print("data-string:\n %s" % self.data_string)
371         print("self.headers:\n %s" % self.headers)
372
373         is_special = self._execute_content_generated_cases("PUT")
374         if is_special:
375             cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
376             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
377             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
378         else:
379             cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
380             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
381             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
382
383         _file_available = os.path.exists(cached_file_content)
384
385         if not _file_available:
386             if not HOST:
387                 self.send_response(404)
388                 self.end_headers()
389                 self.wfile.write('404 Not found, no remote HOST specified on the emulator !!!')
390                 return "404 Not found, no remote HOST specified on the emulator !!!"
391
392             print("Request for data currently not present in cache: %s" % (cached_file_folder,))
393
394             url = '%s%s' % (HOST, self.path)
395             print("url: %s" % (url,))
396             response = requests.put(url, data=self.data_string, headers=self.headers, stream=True)
397
398             if response.status_code == 200:
399                 self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
400             else:
401                 print('Error when requesting file :')
402                 print('Requested url : %s' % (url,))
403                 print('Status code : %s' % (response.status_code,))
404                 print('Content : %s' % (response.content,))
405                 self.send_response(response.status_code)
406                 self.end_headers()
407                 self.wfile.write('404 Not found, nothing found on the remote server !!!')
408                 return response.content
409         else:
410             print("Request for data present in cache: %s" % (cached_file_folder,))
411
412         self._send_content(cached_file_header, cached_file_content)
413
414
415     def do_DELETE(self):
416         cached_file_folder = ""
417         cached_file_content =""
418         cached_file_header=""
419         print("\n\n\nGot a DELETE for %s " % self.path)
420         self.check_credentials()
421         if self.headers.get('Content-Length') is not None:
422             self.data_string = self.rfile.read(int(self.headers['Content-Length']))
423         else:
424             self.data_string = "empty generated"
425         print("self.headers:\n %s" % self.headers)
426
427         is_special = self._execute_content_generated_cases("DELETE")
428         if is_special:
429             cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
430             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
431             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
432         else:
433             cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
434             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
435             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
436
437         _file_available = os.path.exists(cached_file_content)
438
439         if not _file_available:
440             if not HOST:
441                 self.send_response(404)
442                 self.end_headers()
443                 self.wfile.write('404 Not found, no remote HOST specified on the emulator !!!')
444                 return "404 Not found, no remote HOST specified on the emulator !!!"
445
446             print("Request for data currently not present in cache: %s" % (cached_file_folder,))
447
448             url = '%s%s' % (HOST, self.path)
449             print("url: %s" % (url,))
450             response = requests.put(url, data=self.data_string, headers=self.headers, stream=True)
451
452             if response.status_code == 200:
453                 self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
454             else:
455                 print('Error when requesting file :')
456                 print('Requested url : %s' % (url,))
457                 print('Status code : %s' % (response.status_code,))
458                 print('Content : %s' % (response.content,))
459                 self.send_response(response.status_code)
460                 self.end_headers()
461                 self.wfile.write('404 Not found, nothing found on the remote server !!!')
462                 return response.content
463         else:
464             print("Request for data present in cache: %s" % (cached_file_folder,))
465
466         self._send_content(cached_file_header, cached_file_content)
467
468
469
470 # Main code that start the HTTP server
471 httpd = SocketServer.ForkingTCPServer(('', PORT), Proxy)
472 httpd.allow_reuse_address = True
473 print "Listening on port "+ str(PORT) + "(Press Ctrl+C/Ctrl+Z to stop HTTPD Caching script)"
474 print "Caching folder " + CACHE_ROOT + ", Tmp folder for generated files " + TMP_ROOT 
475 signal.signal(signal.SIGINT, signal_handler)
476 httpd.serve_forever()