| Alex | 0989ecf | 2022-03-29 13:43:21 -0500 | [diff] [blame^] | 1 | #    Author: Alex Savatieiev (osavatieiev@mirantis.com; a.savex@gmail.com) | 
 | 2 | #    Copyright 2019-2022 Mirantis, Inc. | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 3 | import ipaddress | 
 | 4 | import json | 
 | 5 |  | 
| Alex | 92e07ce | 2019-05-31 16:00:03 -0500 | [diff] [blame] | 6 | from cfg_checker.common import logger_cli | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 7 | from cfg_checker.helpers.console_utils import Progress | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 8 |  | 
 | 9 |  | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 10 | # This is independent class with a salt.nodes input | 
 | 11 | class NetworkPinger(object): | 
| Alex | e9908f7 | 2020-05-19 16:04:53 -0500 | [diff] [blame] | 12 |     def __init__( | 
 | 13 |         self, | 
| Alex | aae5804 | 2020-12-31 11:48:28 -0600 | [diff] [blame] | 14 |         mapper, | 
| Alex | e9908f7 | 2020-05-19 16:04:53 -0500 | [diff] [blame] | 15 |         detailed=False, | 
| Alex | e9908f7 | 2020-05-19 16:04:53 -0500 | [diff] [blame] | 16 |         skip_list=None, | 
 | 17 |         skip_list_file=None | 
 | 18 |     ): | 
| Alex | 9a4ad21 | 2020-10-01 18:04:25 -0500 | [diff] [blame] | 19 |         logger_cli.info("# Initializing Pinger") | 
| Alex | aae5804 | 2020-12-31 11:48:28 -0600 | [diff] [blame] | 20 |         self.mapper = mapper | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 21 |         # only data | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 22 |         self.detailed_summary = detailed | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 23 |         self.results = {} | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 24 |  | 
 | 25 |     def _collect_node_addresses(self, target_net): | 
 | 26 |         # use reclass model and standard methods | 
 | 27 |         # to create list of nodes with target network | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 28 |         _networks = self.mapper.map_network(self.mapper.RUNTIME) | 
 | 29 |         if target_net in _networks: | 
 | 30 |             return _networks[target_net] | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 31 |         else: | 
 | 32 |             logger_cli.info( | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 33 |                 "# Target network of {} not found after mapping".format( | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 34 |                     target_net.exploded | 
 | 35 |                 ) | 
 | 36 |             ) | 
 | 37 |             return None | 
 | 38 |  | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 39 |     def _get_packets_data(self, network_cidr_str, mtu): | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 40 |         # Conduct actual ping using network CIDR | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 41 |         logger_cli.debug("... collecting node pairs") | 
| Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 42 |         _fake_if = ipaddress.IPv4Interface(str(network_cidr_str)) | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 43 |         _net = _fake_if.network | 
 | 44 |         # collect nodes and ips from reclass | 
 | 45 |         nodes = self._collect_node_addresses(_net) | 
 | 46 |         # build list of packets to be sent | 
 | 47 |         # source -> target | 
 | 48 |         _count = 0 | 
 | 49 |         _packets = {} | 
 | 50 |         _nodes = sorted(nodes.keys()) | 
 | 51 |         _nodes_total = len(_nodes) | 
 | 52 |         logger_cli.info("-> {} nodes found within subnet of '{}'".format( | 
 | 53 |             _nodes_total, | 
 | 54 |             network_cidr_str | 
 | 55 |         )) | 
 | 56 |         while len(_nodes) > 0: | 
 | 57 |             src_host = _nodes.pop() | 
 | 58 |             src_data = nodes[src_host] | 
 | 59 |             src_if_name = src_data[0]['name'] | 
 | 60 |             src_ips = [str(_if.ip) for _if in src_data[0]['ifs']] | 
 | 61 |             _packets[src_host] = { | 
 | 62 |                 "ip": src_ips[0], | 
 | 63 |                 "if_name": src_if_name, | 
 | 64 |                 "targets": {} | 
 | 65 |             } | 
 | 66 |  | 
| Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 67 |             for tgt_host, tgt_data in nodes.items(): | 
| Alex | e9547d8 | 2019-06-03 15:22:50 -0500 | [diff] [blame] | 68 |                 _t = _packets[src_host]["targets"] | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 69 |                 for tgt_if in tgt_data: | 
 | 70 |                     tgt_if_name = tgt_if['name'] | 
 | 71 |                     _ip_index = 0 | 
 | 72 |                     for tgt_ip in tgt_if['ifs']: | 
 | 73 |                         _ip = str(tgt_ip.ip) | 
 | 74 |                         if _ip not in src_ips: | 
| Alex | e9547d8 | 2019-06-03 15:22:50 -0500 | [diff] [blame] | 75 |                             if tgt_host not in _t: | 
 | 76 |                                 _t[tgt_host] = [] | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 77 |                             # Handling mtu and packet size | 
 | 78 |                             if mtu == 0: | 
 | 79 |                                 # Detect MTU | 
 | 80 |                                 _mtu = int(tgt_if['mtu']) | 
 | 81 |                             else: | 
 | 82 |                                 _mtu = mtu | 
 | 83 |                             _packet_size = int(_mtu)-20-8 if _mtu != 0 else 0 | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 84 |                             _tgt = { | 
 | 85 |                                 "ip": _ip, | 
 | 86 |                                 "tgt_host": tgt_host, | 
 | 87 |                                 "ip_index": _ip_index, | 
 | 88 |                                 "if_name": tgt_if_name, | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 89 |                                 "mtu": _mtu, | 
 | 90 |                                 "size": _packet_size | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 91 |                             } | 
| Alex | e9547d8 | 2019-06-03 15:22:50 -0500 | [diff] [blame] | 92 |                             _t[tgt_host].append( | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 93 |                                 _tgt | 
 | 94 |                             ) | 
 | 95 |                             _count += 1 | 
 | 96 |                             _ip_index += 1 | 
 | 97 |                         else: | 
 | 98 |                             pass | 
 | 99 |         logger_cli.info("-> {} packets to send".format(_count)) | 
 | 100 |  | 
| Alex | 92e07ce | 2019-05-31 16:00:03 -0500 | [diff] [blame] | 101 |         if not _count: | 
 | 102 |             logger_cli.warning( | 
 | 103 |                 "\n# WARNING: No packets to send for '{}', " | 
 | 104 |                 "check network configuration\n".format(network_cidr_str) | 
 | 105 |             ) | 
 | 106 |  | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 107 |             return None, _packets, _nodes_total | 
 | 108 |         else: | 
 | 109 |             return _count, _packets, _nodes_total | 
 | 110 |  | 
 | 111 |     def _process_result(self, src, src_data, result): | 
 | 112 |         # Parse output | 
 | 113 |         try: | 
 | 114 |             _result = json.loads(result) | 
 | 115 |         except (ValueError, TypeError): | 
 | 116 |             self.mapper.errors.add_error( | 
 | 117 |                 self.mapper.errors.NET_NODE_NON_RESPONSIVE, | 
 | 118 |                 node=src, | 
 | 119 |                 response=result | 
 | 120 |             ) | 
 | 121 |  | 
 | 122 |             _msg = "# ERROR: Unexpected return for '{}': '{}'\n".format( | 
 | 123 |                 src, | 
 | 124 |                 result | 
 | 125 |             ) | 
 | 126 |  | 
 | 127 |             return False, _msg | 
 | 128 |  | 
 | 129 |         # Handle return codes | 
 | 130 |         for tgt_node, _tgt_ips in _result.items(): | 
 | 131 |             for _params in _tgt_ips: | 
 | 132 |                 _body = "{}({}) --{}--> {}({}@{})\n".format( | 
 | 133 |                         src, | 
 | 134 |                         src_data["if_name"], | 
 | 135 |                         _params["returncode"], | 
 | 136 |                         tgt_node, | 
 | 137 |                         _params["if_name"], | 
 | 138 |                         _params["ip"] | 
 | 139 |                     ) | 
 | 140 |                 _stdout = "" | 
 | 141 |                 _stderr = "" | 
 | 142 |                 if len(_params["stdout"]) > 0: | 
 | 143 |                     _stdout = "stdout:\n{}\n".format(_params["stdout"]) | 
 | 144 |                 if len(_params["stderr"]) > 0: | 
 | 145 |                     _stderr = "stderr:\n{}\n".format(_params["stderr"]) | 
 | 146 |  | 
 | 147 |                 if not _params["returncode"]: | 
 | 148 |                     # 0 | 
 | 149 |                     self.mapper.errors.add_error( | 
 | 150 |                         self.mapper.errors.NET_PING_SUCCESS, | 
 | 151 |                         ping_path=_body, | 
 | 152 |                         stdout=_stdout, | 
 | 153 |                         stderr=_stderr | 
 | 154 |                     ) | 
 | 155 |                 elif _params["returncode"] == 68: | 
 | 156 |                     # 68 is a 'can't resove host error' | 
 | 157 |                     self.mapper.errors.add_error( | 
 | 158 |                         self.mapper.errors.NET_PING_NOT_RESOLVED, | 
 | 159 |                         ping_path=_body, | 
 | 160 |                         stdout=_stdout, | 
 | 161 |                         stderr=_stderr | 
 | 162 |                     ) | 
 | 163 |                 elif _params["returncode"] > 1: | 
 | 164 |                     # >1 is when no actial (any) response | 
 | 165 |                     self.mapper.errors.add_error( | 
 | 166 |                         self.mapper.errors.NET_PING_ERROR, | 
 | 167 |                         ping_path=_body, | 
 | 168 |                         stdout=_stdout, | 
 | 169 |                         stderr=_stderr | 
 | 170 |                     ) | 
 | 171 |                 else: | 
 | 172 |                     # 1 is for timeouts amd/or packet lost | 
 | 173 |                     self.mapper.errors.add_error( | 
 | 174 |                         self.mapper.errors.NET_PING_TIMEOUT, | 
 | 175 |                         ping_path=_body, | 
 | 176 |                         stdout=_stdout, | 
 | 177 |                         stderr=_stderr | 
 | 178 |                     ) | 
 | 179 |         return True, _result | 
 | 180 |  | 
 | 181 |     def print_summary(self, cidr, data): | 
 | 182 |         # Print summary of ping activity in node-node perspective | 
 | 183 |         logger_cli.info("\n-> {}, {} nodes".format(cidr, len(data))) | 
 | 184 |         # iterate nodes | 
 | 185 |         for _n, _d in data.items(): | 
 | 186 |             # targets | 
 | 187 |             _total = len(_d['targets']) | 
 | 188 |             _fail = [] | 
 | 189 |             _pass = [] | 
 | 190 |             _mtus = [] | 
 | 191 |             for _f, _t in _d['targets'].items(): | 
 | 192 |                 # filter data | 
 | 193 |                 _fail += [[_f, _l] for _l in _t if _l['returncode']] | 
 | 194 |                 _pass += [[_f, _l] for _l in _t if not _l['returncode']] | 
 | 195 |                 _mtus += [str(_l['mtu']) for _l in _t] | 
 | 196 |             # summary of passed | 
 | 197 |             # source node | 
 | 198 |             logger_cli.info( | 
 | 199 |                 "  PASS: {}/{} nodes from {} ({}:{}) with MTU {}".format( | 
 | 200 |                     len(_pass), | 
 | 201 |                     _total, | 
 | 202 |                     _n, | 
 | 203 |                     _d['if_name'], | 
 | 204 |                     _d['ip'], | 
 | 205 |                     ",".join(list(set(_mtus))) | 
 | 206 |                 ) | 
 | 207 |             ) | 
 | 208 |             # print fails | 
 | 209 |             for node, _dict in _fail: | 
 | 210 |                 logger_cli.info( | 
 | 211 |                     "\tFAIL: {} ({}:{}) with {}/{}".format( | 
 | 212 |                         node, | 
 | 213 |                         _dict['if_name'], | 
 | 214 |                         _dict['ip'], | 
 | 215 |                         _dict['size'], | 
 | 216 |                         _dict['mtu'] | 
 | 217 |                     ) | 
 | 218 |                 ) | 
 | 219 |  | 
 | 220 |         # logger_cli.info(self.mapper.errors.get_summary(print_zeros=False)) | 
 | 221 |         return | 
 | 222 |  | 
 | 223 |     def print_details(self, cidr, data): | 
 | 224 |         def _print_stds(stdout, stderr): | 
 | 225 |             logger_cli.debug("    stdout:\n") | 
 | 226 |             for line in stdout.splitlines(): | 
 | 227 |                 logger_cli.debug("      {}".format(line)) | 
 | 228 |             if not stderr: | 
 | 229 |                 logger_cli.debug("    stderr: <empty>") | 
 | 230 |             else: | 
 | 231 |                 logger_cli.debug("    stderr:\n") | 
 | 232 |                 for line in stderr.splitlines(): | 
 | 233 |                     logger_cli.debug("      {}".format(line)) | 
 | 234 |  | 
 | 235 |         logger_cli.info("\n---> {}, {} nodes".format(cidr, len(data))) | 
 | 236 |         # iterate nodes | 
 | 237 |         for _n, _d in data.items(): | 
 | 238 |             # targets | 
 | 239 |             _fail = [] | 
 | 240 |             _pass = [] | 
 | 241 |             for _f, _t in _d['targets'].items(): | 
 | 242 |                 # filter data | 
 | 243 |                 _fail += [[_f, _l] for _l in _t if _l['returncode']] | 
 | 244 |                 _pass += [[_f, _l] for _l in _t if not _l['returncode']] | 
 | 245 |             # summary of passed | 
 | 246 |             # source node | 
 | 247 |             logger_cli.info( | 
 | 248 |                 "======= from {} ({}:{})".format( | 
 | 249 |                     _n, | 
 | 250 |                     _d['if_name'], | 
 | 251 |                     _d['ip'] | 
 | 252 |                 ) | 
 | 253 |             ) | 
 | 254 |             for node, _dict in _pass: | 
 | 255 |                 logger_cli.info( | 
 | 256 |                     " + PASS: to {} ({}:{}) with {}/{}".format( | 
 | 257 |                         node, | 
 | 258 |                         _dict['if_name'], | 
 | 259 |                         _dict['ip'], | 
 | 260 |                         _dict['size'], | 
 | 261 |                         _dict['mtu'] | 
 | 262 |                     ) | 
 | 263 |                 ) | 
 | 264 |                 _print_stds(_dict['stdout'], _dict['stderr']) | 
 | 265 |             # print fails | 
 | 266 |             for node, _dict in _fail: | 
 | 267 |                 logger_cli.info( | 
 | 268 |                     " - FAIL: to {} ({}:{}) with {}/{}".format( | 
 | 269 |                         node, | 
 | 270 |                         _dict['if_name'], | 
 | 271 |                         _dict['ip'], | 
 | 272 |                         _dict['size'], | 
 | 273 |                         _dict['mtu'] | 
 | 274 |                     ) | 
 | 275 |                 ) | 
 | 276 |                 _print_stds(_dict['stdout'], _dict['stderr']) | 
 | 277 |  | 
 | 278 |         # Detailed errors | 
 | 279 |         # logger_cli.info( | 
 | 280 |         #     "\n{}\n".format( | 
 | 281 |         #         self.mapper.errors.get_errors() | 
 | 282 |         #     ) | 
 | 283 |         # ) | 
 | 284 |         return | 
 | 285 |  | 
 | 286 |  | 
 | 287 | class SaltNetworkPinger(NetworkPinger): | 
 | 288 |     def __init__( | 
 | 289 |         self, | 
 | 290 |         mapper, | 
 | 291 |         detailed=False, | 
 | 292 |         skip_list=None, | 
 | 293 |         skip_list_file=None | 
 | 294 |     ): | 
 | 295 |         super(SaltNetworkPinger, self).__init__( | 
 | 296 |             mapper, | 
 | 297 |             detailed=detailed, | 
 | 298 |             skip_list=skip_list, | 
 | 299 |             skip_list_file=skip_list_file | 
 | 300 |         ) | 
 | 301 |  | 
 | 302 |     def ping_nodes(self, network_cidr_str, mtu): | 
 | 303 |         #  get packets | 
 | 304 |         _count, _packets, _nodes_total = self._get_packets_data( | 
 | 305 |             network_cidr_str, | 
 | 306 |             mtu | 
 | 307 |         ) | 
 | 308 |         if not _count: | 
 | 309 |             return None | 
| Alex | 92e07ce | 2019-05-31 16:00:03 -0500 | [diff] [blame] | 310 |  | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 311 |         # do ping of packets | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 312 |         logger_cli.info( | 
 | 313 |             "-> Pinging nodes in {}".format(network_cidr_str)) | 
| Alex | aae5804 | 2020-12-31 11:48:28 -0600 | [diff] [blame] | 314 |         self.mapper.master.prepare_script_on_active_nodes("ping.py") | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 315 |         _progress = Progress(_count) | 
 | 316 |         _progress_index = 0 | 
 | 317 |         _node_index = 0 | 
| Alex | 3bc95f6 | 2020-03-05 17:00:04 -0600 | [diff] [blame] | 318 |         for src, src_data in _packets.items(): | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 319 |             _targets = src_data["targets"] | 
 | 320 |             _node_index += 1 | 
 | 321 |             # create 'targets.json' on source host | 
| Alex | aae5804 | 2020-12-31 11:48:28 -0600 | [diff] [blame] | 322 |             _path = self.mapper.master.prepare_json_on_node( | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 323 |                 src, | 
 | 324 |                 _targets, | 
 | 325 |                 "targets.json" | 
 | 326 |             ) | 
 | 327 |             # execute ping.py | 
| Alex | aae5804 | 2020-12-31 11:48:28 -0600 | [diff] [blame] | 328 |             _results = self.mapper.master.execute_script_on_node( | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 329 |                 src, | 
 | 330 |                 "ping.py", | 
 | 331 |                 args=[_path] | 
 | 332 |             ) | 
 | 333 |             _progress_index += len(_targets) | 
 | 334 |             # print progress | 
 | 335 |             _progress.write_progress( | 
 | 336 |                 _progress_index, | 
 | 337 |                 note='/ {}/{} nodes / current {}'.format( | 
 | 338 |                     _node_index, | 
 | 339 |                     _nodes_total, | 
 | 340 |                     src | 
 | 341 |                 ) | 
 | 342 |             ) | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 343 |             # Parse results back in place | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 344 |             _ret_code, _data = self._process_result( | 
 | 345 |                 src, src_data, | 
 | 346 |                 _results[src] | 
 | 347 |             ) | 
 | 348 |             if not _ret_code: | 
 | 349 |                 _progress.clearline() | 
 | 350 |                 logger_cli.error(_data) | 
 | 351 |                 continue | 
 | 352 |             else: | 
 | 353 |                 src_data["targets"] = _data | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 354 |  | 
| Alex | d9fd85e | 2019-05-16 16:58:24 -0500 | [diff] [blame] | 355 |         _progress.end() | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 356 |  | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 357 |         return _packets | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 358 |  | 
| Alex | 92e07ce | 2019-05-31 16:00:03 -0500 | [diff] [blame] | 359 |  | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 360 | class KubeNetworkPinger(NetworkPinger): | 
 | 361 |     def __init__( | 
 | 362 |         self, | 
 | 363 |         mapper, | 
 | 364 |         detailed=False, | 
 | 365 |         skip_list=None, | 
 | 366 |         skip_list_file=None | 
 | 367 |     ): | 
 | 368 |         super(KubeNetworkPinger, self).__init__( | 
 | 369 |             mapper, | 
 | 370 |             detailed=detailed, | 
 | 371 |             skip_list=skip_list, | 
 | 372 |             skip_list_file=skip_list_file | 
| Alex | e0c5b9e | 2019-04-23 18:51:23 -0500 | [diff] [blame] | 373 |         ) | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 374 |  | 
 | 375 |     def ping_nodes(self, network_cidr_str, mtu): | 
 | 376 |         #  get packets | 
 | 377 |         _count, _packets, _nodes_total = self._get_packets_data( | 
 | 378 |             network_cidr_str, | 
 | 379 |             mtu | 
 | 380 |         ) | 
 | 381 |         if not _count: | 
 | 382 |             return None | 
 | 383 |  | 
 | 384 |         # do ping of packets | 
 | 385 |         logger_cli.info( | 
 | 386 |             "-> Pinging nodes in {}".format(network_cidr_str)) | 
 | 387 |         _progress = Progress(_count) | 
 | 388 |         _progress_index = 0 | 
 | 389 |         _node_index = 0 | 
 | 390 |         for src, src_data in _packets.items(): | 
 | 391 |             _targets = src_data["targets"] | 
 | 392 |             _node_index += 1 | 
 | 393 |             # create 'targets.json' on source host | 
 | 394 |             _ds = self.mapper.get_daemonset() | 
 | 395 |             _pname = self.mapper.master.get_pod_name_in_daemonset_by_node( | 
 | 396 |                 src, | 
 | 397 |                 _ds | 
 | 398 |             ) | 
 | 399 |             _path = self.mapper.master.prepare_json_in_pod( | 
 | 400 |                 _pname, | 
 | 401 |                 _ds.metadata.namespace, | 
 | 402 |                 _targets, | 
 | 403 |                 "targets.json" | 
 | 404 |             ) | 
 | 405 |             # execute ping.py | 
| Alex | dcb792f | 2021-10-04 14:24:21 -0500 | [diff] [blame] | 406 |             _result = self.mapper.master.exec_script_on_target_pod( | 
| Alex | 7b0ee9a | 2021-09-21 17:16:17 -0500 | [diff] [blame] | 407 |                 _pname, | 
 | 408 |                 "ping.py", | 
 | 409 |                 args=[_path] | 
 | 410 |             ) | 
 | 411 |             _progress_index += len(_targets) | 
 | 412 |             # print progress | 
 | 413 |             _progress.write_progress( | 
 | 414 |                 _progress_index, | 
 | 415 |                 note='/ {}/{} nodes / current {}'.format( | 
 | 416 |                     _node_index, | 
 | 417 |                     _nodes_total, | 
 | 418 |                     src | 
 | 419 |                 ) | 
 | 420 |             ) | 
 | 421 |             # Parse results back in place | 
 | 422 |             _ret_code, _data = self._process_result( | 
 | 423 |                 src, src_data, | 
 | 424 |                 _result | 
 | 425 |             ) | 
 | 426 |             if not _ret_code: | 
 | 427 |                 _progress.clearline() | 
 | 428 |                 logger_cli.error(_data) | 
 | 429 |                 continue | 
 | 430 |             else: | 
 | 431 |                 src_data["targets"] = _data | 
 | 432 |  | 
 | 433 |         _progress.end() | 
 | 434 |  | 
 | 435 |         return _packets |