blob: d627f381efa84867d6860e1029aaa0b189e14e93 [file] [log] [blame]
Alex0989ecf2022-03-29 13:43:21 -05001# Author: Alex Savatieiev (osavatieiev@mirantis.com; a.savex@gmail.com)
2# Copyright 2019-2022 Mirantis, Inc.
Alexe0c5b9e2019-04-23 18:51:23 -05003import json
4import os
5import platform
6import sys
7from copy import deepcopy
8from multiprocessing.dummy import Pool
9from subprocess import PIPE, Popen
10
11_os = platform.system()
12_packets = {}
13
14_defaults = {
15 "ip": None,
16 "size": 0,
17 "fragmentation": False,
18 "count": 1,
19 "exit_timeout": 1,
20 "response_timeout": 1,
21 "numeric": True
22}
23
24_help_message = \
25 "Invalid parameters. Use: 'ping.py [PKT_SIZE] <IP>' or 'ping.py n.json'\n"
26
27_template = {
28 "returncode": -1,
29 "stdout": "",
30 "stderr": ""
31}
32
33
34def shell(command):
35 _ps = Popen(
36 " ".join(command),
37 shell=True,
38 stdout=PIPE,
39 stderr=PIPE
40 )
41 _out = _ps.communicate()
42 _err = _out[1]
43 _out = _out[0]
44 return _ps.returncode, _out, _err
45
46
47def write_help():
48 _t = deepcopy(_template)
49 _t["returncode"] = 1
50 _t["stderr"] = _help_message
51 write_outcome(_t)
52
53
54def write_outcome(_params):
55 sys.stdout.write(json.dumps(_params))
56
57
58def do_ping(_params):
59 # Load params and defaults
60 _d = deepcopy(_defaults)
61 for key in _params:
62 _d[key] = _params[key]
63
64 # Build cmd
65 _cmd = ["ping"]
66 if _os == "Darwin":
67 if not _d["fragmentation"]:
68 _cmd.append("-D")
69 if _d["exit_timeout"]:
70 _cmd += ["-t", str(_d["exit_timeout"])]
71 elif _os == "Linux":
72 if not _d["fragmentation"]:
73 _cmd += ["-M", "do"]
74 if _d["exit_timeout"]:
75 _cmd += ["-w", str(_d["exit_timeout"])]
76 else:
77 # Windows or other OS
78 _t = deepcopy(_template)
79 _t["returncode"] = 1
80 _t["stderr"] = \
81 "ping.py: '{}' support not implemented".format(_os)
82 write_outcome(_t)
83 sys.exit(1)
84
85 if _d["size"]:
86 _cmd += ["-s", str(_d["size"])]
87 if _d["count"]:
88 _cmd += ["-c", str(_d["count"])]
89 if _d["numeric"]:
90 _cmd.append("-n")
91 if _d["response_timeout"]:
92 _cmd += ["-W", str(_d["response_timeout"])]
93
94 _cmd.append(_d["ip"])
95 # sys.stdout.write("# {}\n".format(" ".join(_cmd)))
96 _r, _out, _err = shell(_cmd)
97
98 # TODO: parse results, latency, etc
99 _t = deepcopy(_template)
100 _t["returncode"] = _r
101 _t["stdout"] = _out
102 _t["stderr"] = _err
103 _params.update(_t)
104 return _params
105
106
107def load_targets(filename):
108 # load target ips from json
109 with open(filename, "r") as f:
110 j = json.load(f)
111
112 return j
113
114
115if len(sys.argv) < 2:
116 # no params given
117 write_help()
118elif len(sys.argv) < 3:
119 # one param: decide if it json file or IP
120 _arg = sys.argv[1]
121 if os.path.isfile(_arg):
122 _packets = load_targets(_arg)
123 # up to 15 packets at once
124 pool = Pool(15)
125 # prepare threaded map
126 _param_map = []
Alex3bc95f62020-03-05 17:00:04 -0600127 for _node, _data in _packets.items():
Alexe0c5b9e2019-04-23 18:51:23 -0500128 if isinstance(_data, list):
129 for target in _data:
130 _param_map.append(target)
131 elif isinstance(_data, dict):
132 _param_map.append(_data)
133 else:
134 _t = deepcopy(_template)
135 _t["returncode"] = 1
136 _t["stderr"] = \
137 "TypeError: 'list' or 'dict' expected. " \
138 "Got '{}': '{}'".format(
139 type(_data).__name__,
140 _data
141 )
142 _packets[_node] = _t
143 _threaded_out = pool.map(do_ping, _param_map)
144 for _out in _threaded_out:
Alex7b0ee9a2021-09-21 17:16:17 -0500145 if sys.version_info[0] > 2:
146 # in python3 stdout will be a bytes object
147 _out['stdout'] = _out['stdout'].decode('utf-8')
148 _out['stderr'] = _out['stderr'].decode('utf-8')
Alexe0c5b9e2019-04-23 18:51:23 -0500149 if isinstance(_packets[_out["tgt_host"]], dict):
150 _packets[_out["tgt_host"]] = _out
151 elif isinstance(_packets[_out["tgt_host"]], list):
152 _packets[_out["tgt_host"]][_out["ip_index"]] = _out
Alex7b0ee9a2021-09-21 17:16:17 -0500153 # dump
Alexe0c5b9e2019-04-23 18:51:23 -0500154 sys.stdout.write(json.dumps(_packets))
155 else:
156 # IP given
157 _ip = sys.argv[1]
158 write_outcome(do_ping(_ip))
159elif len(sys.argv) < 4:
160 # two params: size and IP
161 _s = sys.argv[1]
162 _ip = sys.argv[2]
163 write_outcome(do_ping(_ip, size=_s))
164else:
165 # too many params given
166 write_help()