3 # ============LICENSE_START=======================================================
5 # ================================================================================
6 # Copyright (C) 2018 AT&T Intellectual Property. All rights
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
13 # http://www.apache.org/licenses/LICENSE-2.0
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 # ===================================================================
30 import SimpleHTTPServer
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()
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)
58 def signal_handler(signal_sent, frame):
60 if signal_sent == signal.SIGINT:
61 print('Got Ctrl-C (SIGINT)')
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))
71 def check_credentials(self):
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',):
81 self.send_header(key, value)
83 with open(content_file,'rb') as f:
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('<','<').replace('>','>').replace('?','?').replace('*','*').replace('\\','*').replace(':',':').replace('|','|')
98 print("Cached file name after escaping (used for cache storage) : %s" % cached_file_folder)
99 return cached_file_folder
101 def _get_cached_content_file_name(self,cached_file_folder):
102 return "%s/.file" % (cached_file_folder,)
104 def _get_cached_header_file_name(self,cached_file_folder):
105 return "%s/.header" % (cached_file_folder,)
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)
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
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)
130 elif self.path.startswith("/dcae-operationstatus") and http_type == "GET":
131 if not _file_available:
132 print "self.path start with /dcae-operationstatus, generating response json..."
133 jsonGenerated = "{\"operationType\": \"operationType1\", \"status\": \"succeeded\"}"
134 print "jsonGenerated: " + jsonGenerated
137 os.makedirs(cached_file_folder, 0777)
139 if e.errno != errno.EEXIST:
141 print(cached_file_folder+" already exists")
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)
148 elif self.path.startswith("/sdc/v1/catalog/services/") and http_type == "POST":
149 if not _file_available:
150 print "self.path start with /sdc/v1/catalog/services/, generating response json..."
151 jsondata = json.loads(self.data_string)
152 jsonGenerated = "{\"artifactName\":\"" + jsondata['artifactName'] + "\",\"artifactType\":\"" + jsondata['artifactType'] + "\",\"artifactURL\":\"" + self.path + "\",\"artifactDescription\":\"" + jsondata['description'] + "\",\"artifactChecksum\":\"ZjJlMjVmMWE2M2M1OTM2MDZlODlmNTVmZmYzNjViYzM=\",\"artifactUUID\":\"" + str(uuid.uuid4()) + "\",\"artifactVersion\":\"1\"}"
153 print "jsonGenerated: " + jsonGenerated
155 os.makedirs(cached_file_folder, 0777)
156 with open(cached_file_header, 'w') as f:
157 f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
158 with open(cached_file_content, 'w') as f:
159 f.write(jsonGenerated)
161 elif self.path.startswith("/dcae-deployments/") and (http_type == "PUT" or http_type == "DELETE"):
162 if not _file_available:
163 print "self.path start with /dcae-deployments/, generating response json..."
164 #jsondata = json.loads(self.data_string)
165 jsonGenerated = "{\"links\":{\"status\":\"http:\/\/" + PROXY_ADDRESS + "\/dcae-operationstatus\",\"test2\":\"test2\"}}"
166 print "jsonGenerated: " + jsonGenerated
168 os.makedirs(cached_file_folder, 0777)
169 with open(cached_file_header, 'w') as f:
170 f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
171 with open(cached_file_content, 'w') as f:
172 f.write(jsonGenerated)
174 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"):
175 print "self.path start with /pdp/api/, copying body to response ..."
176 if not os.path.exists(cached_file_folder):
177 os.makedirs(cached_file_folder, 0777)
178 with open(cached_file_header, 'w+') as f:
179 f.write("{\"Content-Length\": \"" + str(len(self.data_string)) + "\", \"Content-Type\": \""+str(self.headers['Content-Type'])+"\"}")
180 with open(cached_file_content, 'w+') as f:
181 f.write(self.data_string)
183 elif self.path.startswith("/policy/api/v1/policytypes/") and http_type == "POST":
184 print "self.path start with POST new policy API /pdp/api/, copying body to response ..."
185 if not os.path.exists(cached_file_folder):
186 os.makedirs(cached_file_folder, 0777)
187 with open(cached_file_header, 'w+') as f:
188 f.write("{\"Content-Length\": \"" + str(len(self.data_string)) + "\", \"Content-Type\": \""+str(self.headers['Content-Type'])+"\"}")
189 with open(cached_file_content, 'w+') as f:
190 f.write(self.data_string)
192 elif self.path.startswith("/policy/api/v1/policytypes/") and http_type == "DELETE":
193 print "self.path start with DELETE new policy API /policy/api/v1/policytypes/ ..."
194 if not os.path.exists(cached_file_folder):
195 os.makedirs(cached_file_folder, 0777)
197 with open(cached_file_header, 'w+') as f:
198 f.write("{\"Content-Length\": \"" + str(len("")) + "\", \"Content-Type\": \""+str("")+"\"}")
199 with open(cached_file_content, 'w+') as f:
200 f.write(self.data_string)
202 elif self.path.startswith("/policy/pap/v1/pdps/policies") and http_type == "POST":
203 print "self.path start with POST new policy API /policy/pap/v1/pdps/ ..."
204 if not os.path.exists(cached_file_folder):
205 os.makedirs(cached_file_folder, 0777)
206 with open(cached_file_header, 'w+') as f:
207 f.write("{\"Content-Length\": \"" + str(len("")) + "\", \"Content-Type\": \""+str("")+"\"}")
208 with open(cached_file_content, 'w+') as f:
209 f.write(self.data_string)
211 elif self.path.startswith("/policy/api/v1/policytypes/") and http_type == "GET":
212 print "self.path start with /policy/api/v1/policytypes/, generating response json..."
213 jsonGenerated = "{\"policyTypeId\": \"onap.policies.controlloop.operational\",\"policyTypeVersion\": \"1.0.0\",\"policyId\": \"OPERATIONAL_z711F_v1_0_ResourceInstanceName1_tca\"}"
214 print "jsonGenerated: " + jsonGenerated
215 if not os.path.exists(cached_file_folder):
216 os.makedirs(cached_file_folder, 0777)
218 with open(cached_file_header, 'w') as f:
219 f.write("{\"Content-Length\": \"" + str(len(jsonGenerated)) + "\", \"Content-Type\": \"application/json\"}")
220 with open(cached_file_content, 'w') as f:
221 f.write(jsonGenerated)
228 cached_file_folder = ""
229 cached_file_content =""
230 cached_file_header=""
231 print("\n\n\nGot a GET request for %s " % self.path)
234 self.check_credentials()
235 # Verify if it's a special case
236 is_special = self._execute_content_generated_cases("GET")
238 cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
239 cached_file_content = self._get_cached_content_file_name(cached_file_folder)
240 cached_file_header = self._get_cached_header_file_name(cached_file_folder)
242 cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
243 cached_file_content = self._get_cached_content_file_name(cached_file_folder)
244 cached_file_header = self._get_cached_header_file_name(cached_file_folder)
246 _file_available = os.path.exists(cached_file_content)
248 if not _file_available:
249 print("Request for data currently not present in cache: %s" % (cached_file_folder,))
252 self.send_response(404)
254 self.wfile.write('404 Not found, no remote HOST specified on the emulator !!!')
255 return "404 Not found, no remote HOST specified on the emulator !!!"
257 url = '%s%s' % (HOST, self.path)
258 response = requests.get(url, auth=AUTH, headers=HEADERS, stream=True)
260 if response.status_code == 200:
261 self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
263 print('Error when requesting file :')
264 print('Requested url : %s' % (url,))
265 print('Status code : %s' % (response.status_code,))
266 print('Content : %s' % (response.content,))
267 self.send_response(response.status_code)
269 self.wfile.write('404 Not found, nothing found on the remote server !!!')
270 return response.content
272 print("Request for data currently present in cache: %s" % (cached_file_folder,))
274 self._send_content(cached_file_header, cached_file_content)
276 if self.path.startswith("/dcae-service-types?asdcResourceId="):
277 print "DCAE case deleting folder created " + cached_file_folder
278 shutil.rmtree(cached_file_folder, ignore_errors=False, onerror=None)
280 print "NOT in DCAE case deleting folder created " + cached_file_folder
283 cached_file_folder = ""
284 cached_file_content =""
285 cached_file_header=""
286 print("\n\n\nGot a POST for %s" % self.path)
287 self.check_credentials()
288 self.data_string = self.rfile.read(int(self.headers['Content-Length']))
289 print("data-string:\n %s" % self.data_string)
290 print("self.headers:\n %s" % self.headers)
292 is_special = self._execute_content_generated_cases("POST")
294 cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
295 cached_file_content = self._get_cached_content_file_name(cached_file_folder)
296 cached_file_header = self._get_cached_header_file_name(cached_file_folder)
298 cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
299 cached_file_content = self._get_cached_content_file_name(cached_file_folder)
300 cached_file_header = self._get_cached_header_file_name(cached_file_folder)
302 _file_available = os.path.exists(cached_file_content)
304 if not _file_available:
307 self.send_response(404)
309 self.wfile.write('404 Not found, no remote HOST specified on the emulator !!!')
310 return "404 Not found, no remote HOST specified on the emulator !!!"
312 print("Request for data currently not present in cache: %s" % (cached_file_folder,))
314 url = '%s%s' % (HOST, self.path)
315 print("url: %s" % (url,))
316 response = requests.post(url, data=self.data_string, headers=self.headers, stream=True)
318 if response.status_code == 200:
319 self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
321 print('Error when requesting file :')
322 print('Requested url : %s' % (url,))
323 print('Status code : %s' % (response.status_code,))
324 print('Content : %s' % (response.content,))
325 self.send_response(response.status_code)
327 self.wfile.write('404 Not found, nothing found on the remote server !!!')
328 return response.content
330 print("Request for data present in cache: %s" % (cached_file_folder,))
332 self._send_content(cached_file_header, cached_file_content)
335 cached_file_folder = ""
336 cached_file_content =""
337 cached_file_header=""
338 print("\n\n\nGot a PUT for %s " % self.path)
339 self.check_credentials()
340 self.data_string = self.rfile.read(int(self.headers['Content-Length']))
341 print("data-string:\n %s" % self.data_string)
342 print("self.headers:\n %s" % self.headers)
344 is_special = self._execute_content_generated_cases("PUT")
346 cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
347 cached_file_content = self._get_cached_content_file_name(cached_file_folder)
348 cached_file_header = self._get_cached_header_file_name(cached_file_folder)
350 cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
351 cached_file_content = self._get_cached_content_file_name(cached_file_folder)
352 cached_file_header = self._get_cached_header_file_name(cached_file_folder)
354 _file_available = os.path.exists(cached_file_content)
356 if not _file_available:
358 self.send_response(404)
360 self.wfile.write('404 Not found, no remote HOST specified on the emulator !!!')
361 return "404 Not found, no remote HOST specified on the emulator !!!"
363 print("Request for data currently not present in cache: %s" % (cached_file_folder,))
365 url = '%s%s' % (HOST, self.path)
366 print("url: %s" % (url,))
367 response = requests.put(url, data=self.data_string, headers=self.headers, stream=True)
369 if response.status_code == 200:
370 self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
372 print('Error when requesting file :')
373 print('Requested url : %s' % (url,))
374 print('Status code : %s' % (response.status_code,))
375 print('Content : %s' % (response.content,))
376 self.send_response(response.status_code)
378 self.wfile.write('404 Not found, nothing found on the remote server !!!')
379 return response.content
381 print("Request for data present in cache: %s" % (cached_file_folder,))
383 self._send_content(cached_file_header, cached_file_content)
387 cached_file_folder = ""
388 cached_file_content =""
389 cached_file_header=""
390 print("\n\n\nGot a DELETE for %s " % self.path)
391 self.check_credentials()
392 if self.headers.get('Content-Length') is not None:
393 self.data_string = self.rfile.read(int(self.headers['Content-Length']))
395 self.data_string = "empty generated"
396 print("self.headers:\n %s" % self.headers)
398 is_special = self._execute_content_generated_cases("DELETE")
400 cached_file_folder = self._get_cached_file_folder_name(TMP_ROOT)
401 cached_file_content = self._get_cached_content_file_name(cached_file_folder)
402 cached_file_header = self._get_cached_header_file_name(cached_file_folder)
404 cached_file_folder = self._get_cached_file_folder_name(CACHE_ROOT)
405 cached_file_content = self._get_cached_content_file_name(cached_file_folder)
406 cached_file_header = self._get_cached_header_file_name(cached_file_folder)
408 _file_available = os.path.exists(cached_file_content)
410 if not _file_available:
412 self.send_response(404)
414 self.wfile.write('404 Not found, no remote HOST specified on the emulator !!!')
415 return "404 Not found, no remote HOST specified on the emulator !!!"
417 print("Request for data currently not present in cache: %s" % (cached_file_folder,))
419 url = '%s%s' % (HOST, self.path)
420 print("url: %s" % (url,))
421 response = requests.put(url, data=self.data_string, headers=self.headers, stream=True)
423 if response.status_code == 200:
424 self._write_cache(cached_file_folder, cached_file_header, cached_file_content, response)
426 print('Error when requesting file :')
427 print('Requested url : %s' % (url,))
428 print('Status code : %s' % (response.status_code,))
429 print('Content : %s' % (response.content,))
430 self.send_response(response.status_code)
432 self.wfile.write('404 Not found, nothing found on the remote server !!!')
433 return response.content
435 print("Request for data present in cache: %s" % (cached_file_folder,))
437 self._send_content(cached_file_header, cached_file_content)
441 # Main code that start the HTTP server
442 httpd = SocketServer.ForkingTCPServer(('', PORT), Proxy)
443 httpd.allow_reuse_address = True
444 print "Listening on port "+ str(PORT) + "(Press Ctrl+C/Ctrl+Z to stop HTTPD Caching script)"
445 print "Caching folder " + CACHE_ROOT + ", Tmp folder for generated files " + TMP_ROOT
446 signal.signal(signal.SIGINT, signal_handler)
447 httpd.serve_forever()