First version of HealtCheck test
[nonrtric.git] / test / usecases / healthcheck / src / main.py
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
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
18 import argparse
19 from datetime import datetime
20 from pygments.util import xrange
21 from requests import ConnectionError
22 import requests
23 import sys
24 import threading
25 import time
26
27 SERVICE_NAME = 'HealthCheck'
28 BASE_URL = 'http://localhost:8081'
29 RIC_CHUNK_SIZE = 10
30 TIME_BETWEEN_CHECKS = 60
31
32 type_to_use = ''
33 policy_body = ''
34
35
36 class Ric:
37
38     def __init__(self, name, supported_types, state):
39         self.name = name
40         self.supports_type_to_use = self.policy_type_supported(supported_types)
41         self.state = state
42         self.no_of_created_policies = 0
43         self.no_of_read_policies = 0
44         self.no_of_updated_policies = 0
45         self.no_of_deleted_policies = 0
46
47     def update_supported_types(self, supported_types):
48         self.supports_type_to_use = self.policy_type_supported(supported_types)
49
50     def policy_type_supported(self, supported_policy_types):
51         for supported_type in supported_policy_types:
52             if type_to_use == supported_type:
53                 return True
54
55         return False
56
57
58 class PolicyCheckThread (threading.Thread):
59
60     def __init__(self, thread_id, ric):
61         threading.Thread.__init__(self)
62         self.thread_id = thread_id
63         self.ric = ric
64
65     def run(self):
66         verboseprint(f'Checking ric: {self.ric.name}')
67         if put_policy(self.thread_id, self.ric.name):
68             verboseprint(f'Created policy: {self.thread_id} in ric: {self.ric.name}')
69             self.ric.no_of_created_policies += 1
70             time.sleep(0.5)
71             if get_policy(self.thread_id):
72                 verboseprint(f'Read policy: {self.thread_id} from ric: {self.ric.name}')
73                 self.ric.no_of_read_policies += 1
74             if put_policy(self.thread_id, self.ric.name, update_value=1):
75                 verboseprint(f'Updated policy: {self.thread_id} in ric: {self.ric.name}')
76                 self.ric.no_of_updated_policies += 1
77             if delete_policy(self.thread_id):
78                 verboseprint(f'Deleted policy: {self.thread_id} from ric: {self.ric.name}')
79                 self.ric.no_of_deleted_policies += 1
80
81
82 def get_rics_from_agent():
83     resp = requests.get(BASE_URL + '/rics')
84     if not resp.ok:
85         verboseprint(f'Unable to get Rics {resp.status_code}')
86         return {}
87     return resp.json()
88
89
90 def create_ric_dict(rics_as_json):
91     rics = {}
92     for ric_info in rics_as_json:
93         rics[ric_info["ricName"]] = (Ric(ric_info["ricName"], ric_info["policyTypes"], ric_info['state']))
94         verboseprint(f'Adding ric: {rics[ric_info["ricName"]]}')
95
96     return rics
97
98
99 def update_rics():
100     added_rics = {}
101     for ric_info in get_rics_from_agent():
102         if ric_info["ricName"] in rics:
103             rics[ric_info["ricName"]].update_supported_types(ric_info["policyTypes"])
104             rics[ric_info["ricName"]].state = ric_info['state']
105         else:
106             added_rics[ric_info["ricName"]] = (Ric(ric_info["ricName"], ric_info["policyTypes"]))
107             verboseprint(f'Adding ric: {rics[ric_info["ricName"]]}')
108
109     rics.update(added_rics)
110
111
112 def put_policy(thread_id, ric_name, update_value=0):
113     policy_id = f'thread_{thread_id}'
114     complete_url = f'{BASE_URL}/policy?type={type_to_use}&id={policy_id}&ric={ric_name}&service={SERVICE_NAME}'
115     headers = {'content-type': 'application/json'}
116     resp = requests.put(complete_url, policy_body.replace('XXX', str(thread_id + update_value)), headers=headers, verify=False)
117
118     if not resp.ok:
119         verboseprint(f'Unable to create policy {resp}')
120         return False
121     else:
122         return True
123
124
125 def get_policy(thread_id):
126     policy_id = f'thread_{thread_id}'
127     complete_url = f'{BASE_URL}/policy?id={policy_id}'
128     resp = requests.get(complete_url)
129
130     if not resp.ok:
131         verboseprint(f'Unable to get policy {resp}')
132         return False
133     else:
134         return True
135
136
137 def delete_policy(thread_id):
138     policy_id = f'thread_{thread_id}'
139     complete_url = f'{BASE_URL}/policy?id={policy_id}'
140     resp = requests.delete(complete_url)
141
142     if not resp.ok:
143         verboseprint(f'Unable to delete policy for policy ID {policy_id}')
144         return False
145
146     return True
147
148
149 def statistics(duration):
150     no_of_unavailable_rics = 0
151     no_of_rics_not_supporting_type = 0
152     no_of_rics_supporting_type = 0
153     no_of_created_policies = 0
154     no_of_read_policies = 0
155     no_of_updated_policies = 0
156     no_of_deleted_policies = 0
157
158     for ric in rics.values():
159         if not (ric.state == 'AVAILABLE' or ric.state == 'CONSISTENCY_CHECK'):
160             no_of_unavailable_rics += 1
161         elif ric.supports_type_to_use:
162             no_of_rics_supporting_type += 1
163             no_of_created_policies += ric.no_of_created_policies
164             no_of_read_policies += ric.no_of_read_policies
165             no_of_updated_policies += ric.no_of_updated_policies
166             no_of_deleted_policies += ric.no_of_deleted_policies
167         else:
168             no_of_rics_not_supporting_type += 1
169
170     print(f'*********** Statistics {datetime.now().strftime("%Y-%m-%d %H:%M:%S")} ***********')
171     print(f'Duration of check:                  {duration.total_seconds()} seconds')
172     print(f'Number of checks:                   {no_of_checks}')
173     print(f'Number of unavailable rics:         {no_of_unavailable_rics}')
174     print(f'Number of rics not supporting type: {no_of_rics_not_supporting_type}')
175     print(f'Number of rics supporting type:     {no_of_rics_supporting_type}')
176     print(f'Number of created policies:         {no_of_created_policies}')
177     print(f'Number of read policies:            {no_of_read_policies}')
178     print(f'Number of updated policies:         {no_of_updated_policies}')
179     print(f'Number of deleted policies:         {no_of_deleted_policies}')
180     print('******************************************************')
181
182
183 def run_check_threads(rics):
184     thread_id = 1
185     threads = []
186     for ric in rics.values():
187         if ric.supports_type_to_use and (ric.state == 'AVAILABLE' or ric.state == 'CONSISTENCY_CHECK'): #or ric.name == 'ric_not_working':
188             policy_checker = PolicyCheckThread(thread_id, ric)
189             policy_checker.start()
190             thread_id += 1
191             threads.append(policy_checker)
192
193     for checker in threads:
194         checker.join()
195
196
197 def split_rics_equally(chunks):
198     # prep with empty dicts
199     return_list = [dict() for _ in xrange(chunks)]
200     idx = 0
201     for k,v in rics.items():
202         return_list[idx][k] = v
203         if idx < chunks-1:  # indexes start at 0
204             idx += 1
205         else:
206             idx = 0
207     return return_list
208
209
210 def get_no_of_chunks(size_of_chunks, size_to_chunk):
211     (q, _) = divmod(size_to_chunk, size_of_chunks)
212     return q
213
214
215 if __name__ == '__main__':
216     parser = argparse.ArgumentParser(prog='PROG')
217     parser.add_argument('policyTypeId', help='The ID of the policy type to use')
218     parser.add_argument('policyBodyPath', help='The path to the JSON body of the policy to create')
219     parser.add_argument('-v', '--verbose', action='store_true', help='Turn on verbose printing')
220     parser.add_argument('--version', action='version', version='%(prog)s 1.0')
221     args = vars(parser.parse_args())
222
223     if args['verbose']:
224         def verboseprint(*args, **kwargs):
225             print(*args, **kwargs)
226     else:
227         verboseprint = lambda *a, **k: None # do-nothing function
228
229     verboseprint(f'Using policy type {args["policyTypeId"]}')
230     verboseprint(f'Using policy file {args["policyBodyPath"]}')
231
232     type_to_use = args["policyTypeId"]
233     with open(args["policyBodyPath"]) as json_file:
234         policy_body = json_file.read()
235         verboseprint(f'Policy body: {policy_body}')
236
237     try:
238         rics_from_agent = get_rics_from_agent()
239     except ConnectionError:
240         print(f'Policy Agent is not answering on {BASE_URL}, cannot start!')
241         sys.exit(1)
242
243     rics = create_ric_dict(rics_from_agent)
244
245     no_of_checks = 0
246     while True:
247         start_time = datetime.now()
248         chunked_rics = split_rics_equally(get_no_of_chunks(RIC_CHUNK_SIZE, rics.__len__()))
249         for ric_chunk in chunked_rics:
250             run_check_threads(ric_chunk)
251
252         no_of_checks += 1
253         finish_time = datetime.now()
254         duration = finish_time - start_time
255         statistics(duration)
256         sleep_time = TIME_BETWEEN_CHECKS - duration.total_seconds()
257         verboseprint(f'Sleeping {sleep_time} seconds')
258         time.sleep(sleep_time)
259         update_rics()
260
261     verboseprint('Exiting main')