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 policy_body_path = 'pihw_template.json'
83 no_of_unavailable_rics = 0
84 no_of_rics_not_supporting_type = 0
85 no_of_rics_supporting_type = 0
86 no_of_created_policies = 0
87 no_of_read_policies = 0
88 no_of_updated_policies = 0
89 no_of_deleted_policies = 0
93 def __init__(self, name, supported_types, state):
95 self.supports_type_to_use = self.policy_type_supported(supported_types)
97 self.no_of_created_policies = 0
98 self.no_of_read_policies = 0
99 self.no_of_updated_policies = 0
100 self.no_of_deleted_policies = 0
102 def update_supported_types(self, supported_types):
103 self.supports_type_to_use = self.policy_type_supported(supported_types)
105 def policy_type_supported(self, supported_policy_types):
106 for supported_type in supported_policy_types:
107 if type_to_use == supported_type:
113 class PolicyCheckThread (threading.Thread):
115 def __init__(self, thread_id, ric):
116 threading.Thread.__init__(self)
117 self.thread_id = thread_id
121 verboseprint(f'Checking ric: {self.ric.name}')
122 if put_policy(self.thread_id, self.ric.name):
123 verboseprint(f'Created policy: {self.thread_id} in ric: {self.ric.name}')
124 self.ric.no_of_created_policies += 1
126 if get_policy(self.thread_id):
127 verboseprint(f'Read policy: {self.thread_id} from ric: {self.ric.name}')
128 self.ric.no_of_read_policies += 1
129 if put_policy(self.thread_id, self.ric.name, update_value=1):
130 verboseprint(f'Updated policy: {self.thread_id} in ric: {self.ric.name}')
131 self.ric.no_of_updated_policies += 1
132 if delete_policy(self.thread_id):
133 verboseprint(f'Deleted policy: {self.thread_id} from ric: {self.ric.name}')
134 self.ric.no_of_deleted_policies += 1
137 class MonitorServer (threading.Thread):
139 threading.Thread.__init__(self)
142 verboseprint('Staring monitor server')
143 app.run(port=HOST_PORT, host=HOST_IP)
148 def produceStatsPage():
149 t = Template(stat_page_template)
150 page = t.render(refreshTime=TIME_BETWEEN_CHECKS, policyTypeId=type_to_use, policyBodyPath=policy_body_path,
151 time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), duration=duration, noOfChecks=no_of_checks,
152 noOfUnavailableRics=no_of_unavailable_rics, noOfNotSupportingRics=no_of_rics_not_supporting_type,
153 noOfSupportingRics=no_of_rics_supporting_type, noOfCreatedPolicies=no_of_created_policies,
154 noOfReadPolicies=no_of_read_policies, noOfUpdatedPolicies=no_of_updated_policies,
155 noOfDeletedPolicies=no_of_deleted_policies)
158 def get_rics_from_agent():
159 resp = requests.get(BASE_URL + '/rics')
161 verboseprint(f'Unable to get Rics {resp.status_code}')
166 def create_ric_dict(rics_as_json):
168 for ric_info in rics_as_json:
169 rics[ric_info["ricName"]] = (Ric(ric_info["ricName"], ric_info["policyTypes"], ric_info['state']))
170 verboseprint(f'Adding ric: {rics[ric_info["ricName"]]}')
177 for ric_info in get_rics_from_agent():
178 if ric_info["ricName"] in rics:
179 rics[ric_info["ricName"]].update_supported_types(ric_info["policyTypes"])
180 rics[ric_info["ricName"]].state = ric_info['state']
182 added_rics[ric_info["ricName"]] = (Ric(ric_info["ricName"], ric_info["policyTypes"]))
183 verboseprint(f'Adding ric: {rics[ric_info["ricName"]]}')
185 rics.update(added_rics)
188 def put_policy(thread_id, ric_name, update_value=0):
189 policy_id = f'thread_{thread_id}'
190 complete_url = f'{BASE_URL}/policy?type={type_to_use}&id={policy_id}&ric={ric_name}&service={SERVICE_NAME}'
191 headers = {'content-type': 'application/json'}
192 resp = requests.put(complete_url, policy_body.replace('XXX', str(thread_id + update_value)), headers=headers, verify=False)
195 verboseprint(f'Unable to create policy {resp}')
201 def get_policy(thread_id):
202 policy_id = f'thread_{thread_id}'
203 complete_url = f'{BASE_URL}/policy?id={policy_id}'
204 resp = requests.get(complete_url)
207 verboseprint(f'Unable to get policy {resp}')
213 def delete_policy(thread_id):
214 policy_id = f'thread_{thread_id}'
215 complete_url = f'{BASE_URL}/policy?id={policy_id}'
216 resp = requests.delete(complete_url)
219 verboseprint(f'Unable to delete policy for policy ID {policy_id}')
228 global no_of_unavailable_rics
229 global no_of_rics_not_supporting_type
230 global no_of_rics_supporting_type
231 global no_of_created_policies
232 global no_of_read_policies
233 global no_of_updated_policies
234 global no_of_deleted_policies
236 # Clear ric data between checks as it may have changed since last check.
237 no_of_unavailable_rics = 0
238 no_of_rics_not_supporting_type = 0
239 no_of_rics_supporting_type = 0
241 for ric in rics.values():
242 if not (ric.state == 'AVAILABLE' or ric.state == 'CONSISTENCY_CHECK'):
243 no_of_unavailable_rics += 1
244 elif ric.supports_type_to_use:
245 no_of_rics_supporting_type += 1
246 no_of_created_policies += ric.no_of_created_policies
247 no_of_read_policies += ric.no_of_read_policies
248 no_of_updated_policies += ric.no_of_updated_policies
249 no_of_deleted_policies += ric.no_of_deleted_policies
251 no_of_rics_not_supporting_type += 1
253 print(f'*********** Statistics {datetime.now().strftime("%Y-%m-%d %H:%M:%S")} *******************')
254 print(f'Duration of check: {duration.total_seconds()} seconds')
255 print(f'Number of checks: {no_of_checks}')
256 print(f'Number of unavailable Near-RT RICS: {no_of_unavailable_rics}')
257 print(f'Number of Near-RT RICS not supporting type: {no_of_rics_not_supporting_type}')
258 print(f'Number of Near-RT RICS supporting type: {no_of_rics_supporting_type}')
259 print(f'Number of created policies: {no_of_created_policies}')
260 print(f'Number of read policies: {no_of_read_policies}')
261 print(f'Number of updated policies: {no_of_updated_policies}')
262 print(f'Number of deleted policies: {no_of_deleted_policies}')
263 print('**************************************************************')
266 def run_check_threads(rics):
269 for ric in rics.values():
270 if ric.supports_type_to_use and (ric.state == 'AVAILABLE' or ric.state == 'CONSISTENCY_CHECK'): #or ric.name == 'ric_not_working':
271 policy_checker = PolicyCheckThread(thread_id, ric)
272 policy_checker.start()
274 threads.append(policy_checker)
276 for checker in threads:
280 def split_rics_equally(chunks):
281 # prep with empty dicts
282 return_list = [dict() for _ in xrange(chunks)]
283 if len(rics) < RIC_CHUNK_SIZE:
287 for k,v in rics.items():
288 return_list[idx][k] = v
289 if idx < chunks-1: # indexes start at 0
296 def get_no_of_chunks(size_of_chunks, size_to_chunk):
297 (q, _) = divmod(size_to_chunk, size_of_chunks)
301 if __name__ == '__main__':
302 parser = argparse.ArgumentParser(prog='PROG')
303 parser.add_argument('--policyTypeId', help='The ID of the policy type to use')
304 parser.add_argument('--policyBodyPath', help='The path to the JSON body of the policy to create')
305 parser.add_argument('-v', '--verbose', action='store_true', help='Turn on verbose printing')
306 parser.add_argument('--version', action='version', version='%(prog)s 1.0')
307 args = vars(parser.parse_args())
310 def verboseprint(*args, **kwargs):
311 print(*args, **kwargs)
313 verboseprint = lambda *a, **k: None # do-nothing function
315 if args["policyTypeId"]:
316 type_to_use = args["policyTypeId"]
318 if args["policyBodyPath"]:
319 policy_body_path = args["policyBodyPath"]
320 if not os.path.exists(policy_body_path):
321 print(f'Policy body {policy_body_path} does not exist.')
324 verboseprint(f'Using policy type {type_to_use}')
325 verboseprint(f'Using policy file {policy_body_path}')
327 with open(policy_body_path) as json_file:
328 policy_body = json_file.read()
329 verboseprint(f'Policy body: {policy_body}')
332 rics_from_agent = get_rics_from_agent()
333 except ConnectionError:
334 print(f'A1PMS is not answering on {BASE_URL}, cannot start!')
337 rics = create_ric_dict(rics_from_agent)
339 monitor_server = MonitorServer()
340 monitor_server.start()
343 start_time = datetime.now()
344 chunked_rics = split_rics_equally(get_no_of_chunks(RIC_CHUNK_SIZE, rics.__len__()))
345 for ric_chunk in chunked_rics:
346 run_check_threads(ric_chunk)
349 finish_time = datetime.now()
350 duration = finish_time - start_time
352 sleep_time = TIME_BETWEEN_CHECKS - duration.total_seconds()
353 verboseprint(f'Sleeping {sleep_time} seconds')
354 time.sleep(sleep_time)
357 verboseprint('Exiting main')