833598f2dd6816a0ec45d236e74cd8de6e9ac638
[it/otf.git] / a1-sdnc-vth / app / helpers / response_helper.py
1 import ast\r
2 import requests\r
3 from configparser import ConfigParser\r
4 import os\r
5 import datetime\r
6 import json\r
7 from flask import request, jsonify, current_app\r
8 from app.helpers.time_helper import unix_time_millis\r
9 from app.errors.bad_request_exception import BadRequestException\r
10 \r
11 """\r
12     Module Info:\r
13 """\r
14 def create_headers(enable_cache=True, content_type="application/json", connection="Keep-Alive"):\r
15     headers = {'Cache-Control':'no-cache, no-store, must-revalidate', "Pragma":"no-cache", "Expires":"0"} if not enable_cache else {}\r
16     headers['content-type'] = content_type\r
17     headers['connection'] = connection\r
18     return headers\r
19 def create_url(config=None, uri_path = "/", url_string=None):\r
20     return config['api']['base_url'] +":"+ config['api']['port']+uri_path if url_string is None else url_string\r
21 \r
22 def valid_string_json(string, response_message="Invalid json string in query or jsonBody, format requires quoted json object e.g. \"{'key':'value, key2:{'innerKey':'innerValue'}}\""):\r
23     try:\r
24         string_to_dict = ast.literal_eval(string)\r
25     except(Exception):\r
26         raise BadRequestException(406, response_message)\r
27     return True\r
28 def route_check(config=None, get_function=None, post_function=None, put_function=None, delete_function=None):\r
29     """\r
30      Info:\r
31         Since all routes do the same pre-check and have a similar skeleton, this function just refactored the pre-check for code reuse\r
32      Arguments (**kwargs): pass in the specified key(s) and  method(s) that handle the type of method, method must be allowed by route decorator\r
33         get_function => type: function\r
34         put_function => type: function\r
35         delete_function => type: function\r
36     Returns:\r
37         returns the return of the function call, typically a jsonified response.\r
38         you can capture response in a var and execute logic or you can just return the function call/response \r
39     E.G.:\r
40         response = route_check(post_function = handle_post)\r
41         return route_check(get_function = handle_get, post_function = handle_post)\r
42     """\r
43     if not request.is_json: raise BadRequestException(406, "Invalid Json Request")\r
44 \r
45     response_dict = vth_response_dic()\r
46     start_time = unix_time_millis(datetime.datetime.now())\r
47     status_code = 200\r
48     ret_url = request.args.get('retURL')\r
49 \r
50     query = ""\r
51     json_body = ""\r
52     request_data = request.json\r
53     json_keys = set(request_data)\r
54     action_request = request_data.get("action").lower()\r
55     valid_actions = {"geta1policytype", "geta1policy", "puta1policy", "deletea1policy", "geta1policystatus"}\r
56     required_keys = {"action", "auth", "action_data"}\r
57 \r
58     #check for valid action and json request contains required keys\r
59     if not required_keys <= json_keys: raise BadRequestException(406, "Json request is missing required keys {}".format(required_keys))\r
60     if not action_request in valid_actions: raise BadRequestException(406, "Action is not supported {}".format(action_request))\r
61     #check request's action_data key contains required keys\r
62     if 'query' not in request.json['action_data']: raise BadRequestException(406, "action_data must contain query and jsonBody ")\r
63     if 'jsonBody' not in request.json['action_data']: raise BadRequestException(406, "action_data must contain query and jsonBody")\r
64 \r
65     query = request.json['action_data']['query'] if 'query' in request.json['action_data'] else ""\r
66     json_body = request.json['action_data']['jsonBody'] if 'jsonBody' in request.json['action_data'] else ""\r
67 \r
68     if valid_string_json(query) and valid_string_json(json_body):\r
69         if(request.method == 'GET'):\r
70             response_dict = get_function(request, response_dict, config)\r
71         elif(request.method == 'POST'):\r
72             response_dict = post_function(request, response_dict, config)\r
73         elif(request.method == 'PUT'):\r
74             response_dict = put_function(request, response_dict, config)\r
75         elif(request.method == 'DELETE'):\r
76             response_dict = delete_function(request, response_dict, config)\r
77     else:\r
78         raise BadRequestException(406, "Invalid JSON Strings")\r
79     end_time = unix_time_millis(datetime.datetime.now())\r
80     response_dict['vthResponse']['testDurationMS'] = end_time-start_time\r
81     if ret_url is not None:\r
82         sendCallback(ret_url,response_dict)\r
83         return '',200\r
84     return jsonify(response_dict), status_code\r
85 \r
86 def get_proxies(config):\r
87     proxy_enabled = config.getboolean('resource', 'proxy_enabled')\r
88     req_proxies = {\r
89         'http': None,\r
90         'https': None\r
91     }\r
92     if not proxy_enabled:\r
93         return None\r
94     else:\r
95         req_proxies['http'] = config['resource']['http_proxy']         \r
96         req_proxies['https'] = config['resource']['https_proxy']\r
97         return req_proxies\r
98 def get_credentials(json_data, config):\r
99     auth_enabled = config.getboolean('auth', 'creds_enabled')\r
100     if not auth_enabled:\r
101         return None\r
102     else:\r
103         username = config['auth']['username'] if 'username' not in json_data['auth'] else json_data['auth']['username']\r
104         password = config['auth']['password'] if 'password' not in json_data['auth'] else json_data['auth']['password']\r
105         return (username, password)\r
106 def vth_response_dic():\r
107     """\r
108     Args:\r
109     Returns:\r
110     Examples:\r
111     """\r
112     response_data = {\r
113         "vthResponse": {\r
114             "testDurationMS": "",\r
115             'dateTimeUTC': str(datetime.datetime.now()),\r
116             "abstractMessage": "Success",\r
117             "resultData": {}\r
118         }\r
119     }\r
120     return response_data\r
121 #TODO data is data from callback and not my json response\r
122 def sendCallback(url, data):\r
123     try:\r
124         if type(data) is not dict:\r
125             data = {"msg": data}\r
126         current_app.logger.info("sending callback")\r
127         requests.post(url, json=data)\r
128     except Exception as e:\r
129         current_app.logger.info(e)\r
130     return\r
131 \r
132 def get_request_data(request):\r
133     if not request.is_json:\r
134         raise ValueError("request must be json")\r
135     requestData = request.get_json()\r
136     return requestData\r
137 \r
138 \r
139 def valid_json(data):\r
140 \r
141     try:\r
142         _ = json.loads(data)\r
143     except ValueError as e:\r
144         return False\r
145     return True\r
146 def get_config(config_file_name):\r
147     config = ConfigParser(os.environ)\r
148     config.read(config_file_name)\r
149     return config\r
150 \r
151 def validate_request(request_data, isPublish=True):\r
152     return\r
153     missing_params = []\r
154 \r
155     if 'topic_name' not in request_data:\r
156         missing_params.append("topic_name")\r
157     if isPublish:\r
158         if 'data' not in request_data:\r
159             missing_params.append('data')\r
160     else:\r
161         if 'consumer_group' not in request_data:\r
162             missing_params.append('consumer_group')\r
163         if 'consumer_id' not in request_data:\r
164             missing_params.append('consumer_id')\r
165 \r
166     if missing_params:\r
167         err_msg = '{} request requires the following: '.format('publish' if isPublish else 'subscribe')\r
168         err_msg += ','.join(missing_params)\r
169         raise KeyError(err_msg)\r
170 \r
171 \r
172 def build_url(config, request_data, is_publish=True):\r
173     if is_publish:\r
174         base_path = config['resource']['base_address'] + config['resource']['publish']\r
175         topic_name = request_data['topic_name']\r
176         publish_address = base_path.format(topic_name=topic_name)\r
177         return publish_address\r
178 \r
179     base_path = config['resource']['base_address'] + config['resource']['subscribe']\r
180     topic_name = request_data['topic_name']\r
181     consumer_group = request_data['consumer_group']\r
182     consumer_id = request_data['consumer_id']\r
183     subscribe_address = base_path.format(topic_name=topic_name, consumer_group=consumer_group, consumer_id=consumer_id)\r
184     if ('timeout' in request_data):\r
185         subscribe_address = (subscribe_address + '?timeout={}').format(request_data['timeout'])\r
186     return subscribe_address\r
187 \r
188 \r
189 def send_request(url, config, is_subscribe_request=False, payload=None):\r
190     # setup default values\r
191     auth_enabled = config.getboolean('auth', 'auth_enabled')\r
192     proxy_enabled = config.getboolean('resource', 'proxy_enabled')\r
193     username = ''\r
194     password = ''\r
195     req_proxies = {\r
196         'http': None,\r
197         'https': None\r
198     }\r
199     # place proxy and authentication information\r
200     if auth_enabled:\r
201         username = config['auth']['username']\r
202         password = config['auth']['password']\r
203     if proxy_enabled:\r
204         req_proxies['http'] = config['resource']['http_proxy']\r
205         req_proxies['https'] = config['resource']['https_proxy']\r
206 \r
207     # for subscribe request\r
208     if is_subscribe_request:\r
209         return requests.get(url,\r
210                             auth=(username, password) if auth_enabled else None,\r
211                             proxies=req_proxies if proxy_enabled else None)\r
212     # for publish request\r
213     req_headers = {'Content-type': 'application/json'}\r
214     return requests.post(url,\r
215                          json=payload,\r
216                          auth=(username, password) if auth_enabled else None,\r
217                          proxies=req_proxies if proxy_enabled else None,\r
218                          headers=req_headers)\r