Merge "Fix imports in CsarInstallerItCase."
[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     
236         with open(cached_file_header, 'w+') as f:
237                 f.write("{\"Content-Length\": \"" + str(len("")) + "\", \"Content-Type\": \""+str("")+"\"}")
238         with open(cached_file_content, 'w+') as f:
239                 f.write(self.data_string)
240         return True
241      elif self.path.startswith("/policy/api/v1/policytypes/") and http_type == "GET":
242         print "self.path start with /policy/api/v1/policytypes/, generating response json..."
243         jsonGenerated =  "{\"policyTypeId\": \"onap.policies.controlloop.operational\",\"policyTypeVersion\": \"1.0.0\",\"policyId\": \"OPERATIONAL_z711F_v1_0_ResourceInstanceName1_tca\"}"
244         print "jsonGenerated: " + jsonGenerated
245         if not os.path.exists(cached_file_folder):
246             os.makedirs(cached_file_folder, 0777)
247
248         with open(cached_file_header, 'w') as f:
249             f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
250         with open(cached_file_content, 'w') as f:
251             f.write(jsonGenerated)
252         return True
253      else:
254         return False
255
256     
257     def do_GET(self):
258         cached_file_folder = ""
259         cached_file_content =""
260         cached_file_header=""
261         print("\n\n\nGot a GET request for %s " % self.path)
262
263         self.print_headers()
264         self.check_credentials()
265         # Verify if it's a special case
266         is_special = self._execute_content_generated_cases("GET")
267         if is_special:
268             cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
269             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
270             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
271         else:
272             cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
273             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
274             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
275
276         _file_available = os.path.exists(cached_file_content)
277
278         if not _file_available:
279             print("Request for data currently not present in cache: %s" % (cached_file_folder,))
280
281             if not HOST:
282                 self.send_response(404)
283                 return "404 Not found"
284
285             url = '%s%s' % (HOST, self.path)
286             response = requests.get(url, auth=AUTH, headers=HEADERS, stream=True)
287
288             if response.status_code == 200:
289                 self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
290             else:
291                 print('Error when requesting file :')
292                 print('Requested url : %s' % (url,))
293                 print('Status code : %s' % (response.status_code,))
294                 print('Content : %s' % (response.content,))
295                 self.send_response(response.status_code)
296                 return response.content
297         else:
298             print("Request for data currently present in cache: %s" % (cached_file_folder,))
299
300         self._send_content(cached_file_header, cached_file_content)
301
302         if self.path.startswith("/dcae-service-types?asdcResourceId="):
303             print "DCAE case deleting folder created " + cached_file_folder
304             shutil.rmtree(cached_file_folder, ignore_errors=False, onerror=None)
305         else:
306             print "NOT in DCAE case deleting folder created " + cached_file_folder
307
308     def do_POST(self):
309         cached_file_folder = ""
310         cached_file_content =""
311         cached_file_header=""
312         print("\n\n\nGot a POST for %s" % self.path)
313         self.check_credentials()
314         self.data_string = self.rfile.read(int(self.headers['Content-Length']))
315         print("data-string:\n %s" % self.data_string)
316         print("self.headers:\n %s" % self.headers)
317
318         is_special = self._execute_content_generated_cases("POST")
319         if is_special:
320             cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
321             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
322             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
323         else:
324             cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
325             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
326             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
327
328         _file_available = os.path.exists(cached_file_content)
329
330         if not _file_available:
331         
332             if not HOST:
333                 self.send_response(404)
334                 return "404 Not found"
335
336             print("Request for data currently not present in cache: %s" % (cached_file_folder,))
337
338             url = '%s%s' % (HOST, self.path)
339             print("url: %s" % (url,))
340             response = requests.post(url, data=self.data_string, headers=self.headers, stream=True)
341
342             if response.status_code == 200:
343                 self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
344             else:
345                 print('Error when requesting file :')
346                 print('Requested url : %s' % (url,))
347                 print('Status code : %s' % (response.status_code,))
348                 print('Content : %s' % (response.content,))
349                 self.send_response(response.status_code)
350                 return response.content
351         else:
352             print("Request for data present in cache: %s" % (cached_file_folder,))
353
354         self._send_content(cached_file_header, cached_file_content)
355
356     def do_PUT(self):
357         cached_file_folder = ""
358         cached_file_content =""
359         cached_file_header=""
360         print("\n\n\nGot a PUT for %s " % self.path)
361         self.check_credentials()
362         self.data_string = self.rfile.read(int(self.headers['Content-Length']))
363         print("data-string:\n %s" % self.data_string)
364         print("self.headers:\n %s" % self.headers)
365
366         is_special = self._execute_content_generated_cases("PUT")
367         if is_special:
368             cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
369             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
370             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
371         else:
372             cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
373             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
374             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
375
376         _file_available = os.path.exists(cached_file_content)
377
378         if not _file_available:
379             if not HOST:
380                 self.send_response(404)
381                 return "404 Not found"
382
383             print("Request for data currently not present in cache: %s" % (cached_file_folder,))
384
385             url = '%s%s' % (HOST, self.path)
386             print("url: %s" % (url,))
387             response = requests.put(url, data=self.data_string, headers=self.headers, stream=True)
388
389             if response.status_code == 200:
390                 self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
391             else:
392                 print('Error when requesting file :')
393                 print('Requested url : %s' % (url,))
394                 print('Status code : %s' % (response.status_code,))
395                 print('Content : %s' % (response.content,))
396                 self.send_response(response.status_code)
397                 return response.content
398         else:
399             print("Request for data present in cache: %s" % (cached_file_folder,))
400
401         self._send_content(cached_file_header, cached_file_content)
402
403
404     def do_DELETE(self):
405         cached_file_folder = ""
406         cached_file_content =""
407         cached_file_header=""
408         print("\n\n\nGot a DELETE for %s " % self.path)
409         self.check_credentials()
410         if self.headers.get('Content-Length') is not None:
411             self.data_string = self.rfile.read(int(self.headers['Content-Length']))
412         else:
413             self.data_string = "empty generated"
414         print("self.headers:\n %s" % self.headers)
415
416         is_special = self._execute_content_generated_cases("DELETE")
417         if is_special:
418             cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
419             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
420             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
421         else:
422             cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
423             cached_file_content = self._get_cached_content_file_name(cached_file_folder)
424             cached_file_header = self._get_cached_header_file_name(cached_file_folder)
425
426         _file_available = os.path.exists(cached_file_content)
427
428         if not _file_available:
429             if not HOST:
430                 self.send_response(404)
431                 return "404 Not found"
432
433             print("Request for data currently not present in cache: %s" % (cached_file_folder,))
434
435             url = '%s%s' % (HOST, self.path)
436             print("url: %s" % (url,))
437             response = requests.put(url, data=self.data_string, headers=self.headers, stream=True)
438
439             if response.status_code == 200:
440                 self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
441             else:
442                 print('Error when requesting file :')
443                 print('Requested url : %s' % (url,))
444                 print('Status code : %s' % (response.status_code,))
445                 print('Content : %s' % (response.content,))
446                 self.send_response(response.status_code)
447                 return response.content
448         else:
449             print("Request for data present in cache: %s" % (cached_file_folder,))
450
451         self._send_content(cached_file_header, cached_file_content)
452
453
454
455 # Main code that start the HTTP server
456 httpd = SocketServer.ForkingTCPServer(('', PORT), Proxy)
457 httpd.allow_reuse_address = True
458 print "Listening on port "+ str(PORT) + "(Press Ctrl+C/Ctrl+Z to stop HTTPD Caching script)"
459 print "Caching folder " + CACHE_ROOT + ", Tmp folder for generated files " + TMP_ROOT 
460 signal.signal(signal.SIGINT, signal_handler)
461 httpd.serve_forever()