1 # ============LICENSE_START===============================================
2 # Copyright (C) 2020 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
8 # http://www.apache.org/licenses/LICENSE-2.0
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=================================================
19 from datetime import datetime
20 from jinja2 import Template
21 from flask import Flask, request
24 from pygments.util import xrange
25 from requests import ConnectionError
31 SERVICE_NAME = 'HealthCheck'
32 BASE_URL = 'http://localhost:8081'
34 TIME_BETWEEN_CHECKS = 60
46 stat_page_template = """
50 <meta http-equiv=\"refresh\" content=\"{{refreshTime}}\">
51 <title>Non-RealTime RIC Health Check</title>
55 <font face=\"monospace\">
56 Policy type ID:...............................{{policyTypeId}}<br>
57 Policy body path:.............................{{policyBodyPath}}<br>
58 Time of last check:...........................{{time}}<br>
59 Duration of check:............................{{duration}}<br>
60 Number of checks:.............................{{noOfChecks}}<br>
63 <font face=\"monospace\">
64 Number of unavailable Near-RT RICS:...........{{noOfUnavailableRics}}<br>
65 Number of Near-RT RICS not supporting type....{{noOfNotSupportingRics}}<br>
66 Number of Near-RT RICS supporting type:.......{{noOfSupportingRics}}<br>
69 <font face=\"monospace\">
70 Number of created policies:...................{{noOfCreatedPolicies}}<br>
71 Number of read policies:......................{{noOfReadPolicies}}<br>
72 Number of updated policies:...................{{noOfUpdatedPolicies}}<br>
73 Number of deleted policies:...................{{noOfDeletedPolicies}}<br>
79 test_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
80 policy_body_path = os.path.join(test_dir, 'auto-test','testdata','OSC','pihw_template.json')
84 no_of_unavailable_rics = 0
85 no_of_rics_not_supporting_type = 0
86 no_of_rics_supporting_type = 0
87 no_of_created_policies = 0
88 no_of_read_policies = 0
89 no_of_updated_policies = 0
90 no_of_deleted_policies = 0
94 def __init__(self, name, supported_types, state):
96 self.supports_type_to_use = self.policy_type_supported(supported_types)
98 self.no_of_created_policies = 0
99 self.no_of_read_policies = 0
100 self.no_of_updated_policies = 0
101 self.no_of_deleted_policies = 0
103 def update_supported_types(self, supported_types):
104 self.supports_type_to_use = self.policy_type_supported(supported_types)
106 def policy_type_supported(self, supported_policy_types):
107 for supported_type in supported_policy_types:
108 if type_to_use == supported_type:
114 class PolicyCheckThread (threading.Thread):
116 def __init__(self, thread_id, ric):
117 threading.Thread.__init__(self)
118 self.thread_id = thread_id
122 verboseprint(f'Checking ric: {self.ric.name}')
123 if put_policy(self.thread_id, self.ric.name):
124 verboseprint(f'Created policy: {self.thread_id} in ric: {self.ric.name}')
125 self.ric.no_of_created_policies += 1
127 if get_policy(self.thread_id):
128 verboseprint(f'Read policy: {self.thread_id} from ric: {self.ric.name}')
129 self.ric.no_of_read_policies += 1
130 if put_policy(self.thread_id, self.ric.name, update_value=1):
131 verboseprint(f'Updated policy: {self.thread_id} in ric: {self.ric.name}')
132 self.ric.no_of_updated_policies += 1
133 if delete_policy(self.thread_id):
134 verboseprint(f'Deleted policy: {self.thread_id} from ric: {self.ric.name}')
135 self.ric.no_of_deleted_policies += 1
138 class MonitorServer (threading.Thread):
140 threading.Thread.__init__(self)
143 verboseprint('Staring monitor server')
144 app.run(port=HOST_PORT, host=HOST_IP)
149 def produceStatsPage():
150 t = Template(stat_page_template)
151 page = t.render(refreshTime=TIME_BETWEEN_CHECKS, policyTypeId=type_to_use, policyBodyPath=policy_body_path,
152 time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), duration=duration, noOfChecks=no_of_checks,
153 noOfUnavailableRics=no_of_unavailable_rics, noOfNotSupportingRics=no_of_rics_not_supporting_type,
154 noOfSupportingRics=no_of_rics_supporting_type, noOfCreatedPolicies=no_of_created_policies,
155 noOfReadPolicies=no_of_read_policies, noOfUpdatedPolicies=no_of_updated_policies,
156 noOfDeletedPolicies=no_of_deleted_policies)
159 def get_rics_from_agent():
160 resp = requests.get(BASE_URL + '/rics')
162 verboseprint(f'Unable to get Rics {resp.status_code}')
167 def create_ric_dict(rics_as_json):
169 for ric_info in rics_as_json:
170 rics[ric_info["ricName"]] = (Ric(ric_info["ricName"], ric_info["policyTypes"], ric_info['state']))
171 verboseprint(f'Adding ric: {rics[ric_info["ricName"]]}')
178 for ric_info in get_rics_from_agent():
179 if ric_info["ricName"] in rics:
180 rics[ric_info["ricName"]].update_supported_types(ric_info["policyTypes"])
181 rics[ric_info["ricName"]].state = ric_info['state']
183 added_rics[ric_info["ricName"]] = (Ric(ric_info["ricName"], ric_info["policyTypes"]))
184 verboseprint(f'Adding ric: {rics[ric_info["ricName"]]}')
186 rics.update(added_rics)
189 def put_policy(thread_id, ric_name, update_value=0):
190 policy_id = f'thread_{thread_id}'
191 complete_url = f'{BASE_URL}/policy?type={type_to_use}&id={policy_id}&ric={ric_name}&service={SERVICE_NAME}'
192 headers = {'content-type': 'application/json'}
193 resp = requests.put(complete_url, policy_body.replace('XXX', str(thread_id + update_value)), headers=headers, verify=False)
196 verboseprint(f'Unable to create policy {resp}')
202 def get_policy(thread_id):
203 policy_id = f'thread_{thread_id}'
204 complete_url = f'{BASE_URL}/policy?id={policy_id}'
205 resp = requests.get(complete_url)
208 verboseprint(f'Unable to get policy {resp}')
214 def delete_policy(thread_id):
215 policy_id = f'thread_{thread_id}'
216 complete_url = f'{BASE_URL}/policy?id={policy_id}'
217 resp = requests.delete(complete_url)
220 verboseprint(f'Unable to delete policy for policy ID {policy_id}')
229 global no_of_unavailable_rics
230 global no_of_rics_not_supporting_type
231 global no_of_rics_supporting_type
232 global no_of_created_policies
233 global no_of_read_policies
234 global no_of_updated_policies
235 global no_of_deleted_policies
237 # Clear ric data between checks as it may have changed since last check.
238 no_of_unavailable_rics = 0
239 no_of_rics_not_supporting_type = 0
240 no_of_rics_supporting_type = 0
242 for ric in rics.values():
243 if not (ric.state == 'AVAILABLE' or ric.state == 'CONSISTENCY_CHECK'):
244 no_of_unavailable_rics += 1
245 elif ric.supports_type_to_use:
246 no_of_rics_supporting_type += 1
247 no_of_created_policies += ric.no_of_created_policies
248 no_of_read_policies += ric.no_of_read_policies
249 no_of_updated_policies += ric.no_of_updated_policies
250 no_of_deleted_policies += ric.no_of_deleted_policies
252 no_of_rics_not_supporting_type += 1
254 print(f'*********** Statistics {datetime.now().strftime("%Y-%m-%d %H:%M:%S")} *******************')
255 print(f'Duration of check: {duration.total_seconds()} seconds')
256 print(f'Number of checks: {no_of_checks}')
257 print(f'Number of unavailable Near-RT RICS: {no_of_unavailable_rics}')
258 print(f'Number of Near-RT RICS not supporting type: {no_of_rics_not_supporting_type}')
259 print(f'Number of Near-RT RICS supporting type: {no_of_rics_supporting_type}')
260 print(f'Number of created policies: {no_of_created_policies}')
261 print(f'Number of read policies: {no_of_read_policies}')
262 print(f'Number of updated policies: {no_of_updated_policies}')
263 print(f'Number of deleted policies: {no_of_deleted_policies}')
264 print('**************************************************************')
267 def run_check_threads(rics):
270 for ric in rics.values():
271 if ric.supports_type_to_use and (ric.state == 'AVAILABLE' or ric.state == 'CONSISTENCY_CHECK'): #or ric.name == 'ric_not_working':
272 policy_checker = PolicyCheckThread(thread_id, ric)
273 policy_checker.start()
275 threads.append(policy_checker)
277 for checker in threads:
281 def split_rics_equally(chunks):
282 # prep with empty dicts
283 return_list = [dict() for _ in xrange(chunks)]
284 if len(rics) < RIC_CHUNK_SIZE:
288 for k,v in rics.items():
289 return_list[idx][k] = v
290 if idx < chunks-1: # indexes start at 0
297 def get_no_of_chunks(size_of_chunks, size_to_chunk):
298 (q, _) = divmod(size_to_chunk, size_of_chunks)
302 if __name__ == '__main__':
303 parser = argparse.ArgumentParser(prog='PROG')
304 parser.add_argument('--policyTypeId', help='The ID of the policy type to use')
305 parser.add_argument('--policyBodyPath', help='The path to the JSON body of the policy to create')
306 parser.add_argument('-v', '--verbose', action='store_true', help='Turn on verbose printing')
307 parser.add_argument('--version', action='version', version='%(prog)s 1.0')
308 args = vars(parser.parse_args())
311 def verboseprint(*args, **kwargs):
312 print(*args, **kwargs)
314 verboseprint = lambda *a, **k: None # do-nothing function
316 if args["policyTypeId"]:
317 type_to_use = args["policyTypeId"]
319 if args["policyBodyPath"]:
320 policy_body_path = args["policyBodyPath"]
321 if not os.path.exists(policy_body_path):
322 print(f'Policy body {policy_body_path} does not exist.')
325 verboseprint(f'Using policy type {type_to_use}')
326 verboseprint(f'Using policy file {policy_body_path}')
328 with open(policy_body_path) as json_file:
329 policy_body = json_file.read()
330 verboseprint(f'Policy body: {policy_body}')
333 rics_from_agent = get_rics_from_agent()
334 except ConnectionError:
335 print(f'Policy Agent is not answering on {BASE_URL}, cannot start!')
338 rics = create_ric_dict(rics_from_agent)
340 monitor_server = MonitorServer()
341 monitor_server.start()
344 start_time = datetime.now()
345 chunked_rics = split_rics_equally(get_no_of_chunks(RIC_CHUNK_SIZE, rics.__len__()))
346 for ric_chunk in chunked_rics:
347 run_check_threads(ric_chunk)
350 finish_time = datetime.now()
351 duration = finish_time - start_time
353 sleep_time = TIME_BETWEEN_CHECKS - duration.total_seconds()
354 verboseprint(f'Sleeping {sleep_time} seconds')
355 time.sleep(sleep_time)
358 verboseprint('Exiting main')