blob: fdf6d422642390d31e1202ea8411aaa5a04ae67e [file] [log] [blame]
elinuxhenrik233225c2020-04-28 15:31:33 +02001# ============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
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
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=================================================
16#
17
18import argparse
19from datetime import datetime
elinuxhenrik9e8b7842020-06-05 10:23:27 +020020from jinja2 import Template
21from flask import Flask, request
22import os.path
23from os import path
elinuxhenrik233225c2020-04-28 15:31:33 +020024from pygments.util import xrange
25from requests import ConnectionError
26import requests
27import sys
28import threading
29import time
30
31SERVICE_NAME = 'HealthCheck'
32BASE_URL = 'http://localhost:8081'
33RIC_CHUNK_SIZE = 10
34TIME_BETWEEN_CHECKS = 60
35
36type_to_use = ''
37policy_body = ''
38
elinuxhenrik9e8b7842020-06-05 10:23:27 +020039app = Flask(__name__)
40
41# Server info
42HOST_IP = "::"
43HOST_PORT = 9990
44APP_URL = "/stats"
45
46stat_page_template = """
47<!DOCTYPE html>
48<html>
49 <head>
50 <meta http-equiv=\"refresh\" content=\"{{refreshTime}}\">
51 <title>Non-RealTime RIC Health Check</title>
52 </head>
53 <body>
54 <h3>General</h3>
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>
61 </font>
62 <h3>Near-RT RICs</h3>
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>
67 </font>
68 <h3>Policies</h3>
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>
74 </font>
75 </body>
76</html>
77"""
78type_to_use = "2"
79test_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
80policy_body_path = os.path.join(test_dir, 'auto-test','testdata','OSC','pihw_template.json')
81
82duration = 0
83no_of_checks = 0
84no_of_unavailable_rics = 0
85no_of_rics_not_supporting_type = 0
86no_of_rics_supporting_type = 0
87no_of_created_policies = 0
88no_of_read_policies = 0
89no_of_updated_policies = 0
90no_of_deleted_policies = 0
elinuxhenrik233225c2020-04-28 15:31:33 +020091
92class Ric:
93
94 def __init__(self, name, supported_types, state):
95 self.name = name
96 self.supports_type_to_use = self.policy_type_supported(supported_types)
97 self.state = state
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
102
103 def update_supported_types(self, supported_types):
104 self.supports_type_to_use = self.policy_type_supported(supported_types)
105
106 def policy_type_supported(self, supported_policy_types):
107 for supported_type in supported_policy_types:
108 if type_to_use == supported_type:
109 return True
110
111 return False
112
113
114class PolicyCheckThread (threading.Thread):
115
116 def __init__(self, thread_id, ric):
117 threading.Thread.__init__(self)
118 self.thread_id = thread_id
119 self.ric = ric
120
121 def run(self):
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
126 time.sleep(0.5)
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
136
137
elinuxhenrik9e8b7842020-06-05 10:23:27 +0200138class MonitorServer (threading.Thread):
139 def __init__(self):
140 threading.Thread.__init__(self)
141
142 def run(self):
143 verboseprint('Staring monitor server')
144 app.run(port=HOST_PORT, host=HOST_IP)
145
146
147@app.route(APP_URL,
148 methods=['GET'])
149def 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)
157 return page,200
158
elinuxhenrik233225c2020-04-28 15:31:33 +0200159def get_rics_from_agent():
160 resp = requests.get(BASE_URL + '/rics')
161 if not resp.ok:
162 verboseprint(f'Unable to get Rics {resp.status_code}')
163 return {}
164 return resp.json()
165
166
167def create_ric_dict(rics_as_json):
168 rics = {}
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"]]}')
172
173 return rics
174
175
176def update_rics():
177 added_rics = {}
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']
182 else:
183 added_rics[ric_info["ricName"]] = (Ric(ric_info["ricName"], ric_info["policyTypes"]))
184 verboseprint(f'Adding ric: {rics[ric_info["ricName"]]}')
185
186 rics.update(added_rics)
187
188
189def 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)
194
195 if not resp.ok:
196 verboseprint(f'Unable to create policy {resp}')
197 return False
198 else:
199 return True
200
201
202def 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)
206
207 if not resp.ok:
208 verboseprint(f'Unable to get policy {resp}')
209 return False
210 else:
211 return True
212
213
214def 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)
218
219 if not resp.ok:
220 verboseprint(f'Unable to delete policy for policy ID {policy_id}')
221 return False
222
223 return True
224
225
elinuxhenrik9e8b7842020-06-05 10:23:27 +0200226def statistics():
227 global duration
228 global no_of_checks
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
236
237 # Clear ric data between checks as it may have changed since last check.
elinuxhenrik233225c2020-04-28 15:31:33 +0200238 no_of_unavailable_rics = 0
239 no_of_rics_not_supporting_type = 0
240 no_of_rics_supporting_type = 0
elinuxhenrik233225c2020-04-28 15:31:33 +0200241
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
251 else:
252 no_of_rics_not_supporting_type += 1
253
elinuxhenrik9e8b7842020-06-05 10:23:27 +0200254 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('**************************************************************')
elinuxhenrik233225c2020-04-28 15:31:33 +0200265
266
267def run_check_threads(rics):
268 thread_id = 1
269 threads = []
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()
274 thread_id += 1
275 threads.append(policy_checker)
276
277 for checker in threads:
278 checker.join()
279
280
281def split_rics_equally(chunks):
282 # prep with empty dicts
283 return_list = [dict() for _ in xrange(chunks)]
elinuxhenrik9e8b7842020-06-05 10:23:27 +0200284 if len(rics) < RIC_CHUNK_SIZE:
285 return [rics]
286
elinuxhenrik233225c2020-04-28 15:31:33 +0200287 idx = 0
288 for k,v in rics.items():
289 return_list[idx][k] = v
290 if idx < chunks-1: # indexes start at 0
291 idx += 1
292 else:
293 idx = 0
294 return return_list
295
296
297def get_no_of_chunks(size_of_chunks, size_to_chunk):
298 (q, _) = divmod(size_to_chunk, size_of_chunks)
299 return q
300
301
302if __name__ == '__main__':
303 parser = argparse.ArgumentParser(prog='PROG')
elinuxhenrik9e8b7842020-06-05 10:23:27 +0200304 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')
elinuxhenrik233225c2020-04-28 15:31:33 +0200306 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())
309
310 if args['verbose']:
311 def verboseprint(*args, **kwargs):
312 print(*args, **kwargs)
313 else:
314 verboseprint = lambda *a, **k: None # do-nothing function
315
elinuxhenrik9e8b7842020-06-05 10:23:27 +0200316 if args["policyTypeId"]:
317 type_to_use = args["policyTypeId"]
elinuxhenrik233225c2020-04-28 15:31:33 +0200318
elinuxhenrik9e8b7842020-06-05 10:23:27 +0200319 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.')
323 sys.exit(1)
324
325 verboseprint(f'Using policy type {type_to_use}')
326 verboseprint(f'Using policy file {policy_body_path}')
327
328 with open(policy_body_path) as json_file:
elinuxhenrik233225c2020-04-28 15:31:33 +0200329 policy_body = json_file.read()
330 verboseprint(f'Policy body: {policy_body}')
331
332 try:
333 rics_from_agent = get_rics_from_agent()
334 except ConnectionError:
335 print(f'Policy Agent is not answering on {BASE_URL}, cannot start!')
336 sys.exit(1)
337
338 rics = create_ric_dict(rics_from_agent)
339
elinuxhenrik9e8b7842020-06-05 10:23:27 +0200340 monitor_server = MonitorServer()
341 monitor_server.start()
342
elinuxhenrik233225c2020-04-28 15:31:33 +0200343 while True:
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)
348
349 no_of_checks += 1
350 finish_time = datetime.now()
351 duration = finish_time - start_time
elinuxhenrik9e8b7842020-06-05 10:23:27 +0200352 statistics()
elinuxhenrik233225c2020-04-28 15:31:33 +0200353 sleep_time = TIME_BETWEEN_CHECKS - duration.total_seconds()
354 verboseprint(f'Sleeping {sleep_time} seconds')
355 time.sleep(sleep_time)
356 update_rics()
357
358 verboseprint('Exiting main')