|
1 |
| -#!/usr/bin/python3 |
2 |
| - |
3 |
| -import argparse |
4 |
| -import gzip |
5 |
| -import io |
6 |
| -import json |
7 |
| -import os |
8 |
| -import requests |
9 |
| -import socket |
10 |
| -import sys |
11 |
| -import time |
12 |
| - |
13 |
| -support_test = [ |
14 |
| - "/v1/eula", |
15 |
| -] |
16 |
| - |
17 |
| -support_global = [ |
18 |
| - "/v1/system/license", |
19 |
| - "/v1/internal/system", |
20 |
| - "/v1/system/summary", |
21 |
| - "/v2/system/config", |
22 |
| - "/v1/system/rbac", |
23 |
| - "/v1/fed/member", |
24 |
| - "/v1/user_role", |
25 |
| - "/v1/user", |
26 |
| - "/v1/api_key", |
27 |
| - "/v1/password_profile", |
28 |
| - "/v1/server", |
29 |
| - "/v1/server/_platform_/user", |
30 |
| - "/v1/partner/ibm_sa_config", |
31 |
| - "/v1/compliance/profile", |
32 |
| - "/v1/scan/config", |
33 |
| - "/v1/scan/status", |
34 |
| - "/v1/scan/scanner", |
35 |
| - "/v1/scan/platform", |
36 |
| - "/v1/scan/platform/platform", |
37 |
| - "/v1/scan/registry", |
38 |
| - "/v1/admission/state", |
39 |
| - "/v1/admission/rules", |
40 |
| - |
41 |
| - "/v1/domain", |
42 |
| - "/v1/service", |
43 |
| - "/v1/group", |
44 |
| - "/v1/custom_check", |
45 |
| - "/v1/process_profile", |
46 |
| - "/v1/file_monitor", |
47 |
| - "/v1/dlp/sensor", |
48 |
| - "/v1/dlp/group", |
49 |
| - "/v1/waf/sensor", |
50 |
| - "/v1/waf/group", |
51 |
| - "/v1/policy/rule", |
52 |
| - "/v1/response/rule", |
53 |
| - "/v1/conversation", |
54 |
| - "/v1/vulnerability/profile", |
55 |
| - "/v1/scan/sigstore/root_of_trust?with_verifiers=true", |
56 |
| - |
57 |
| - "/v1/log/activity", |
58 |
| - "/v1/log/event", |
59 |
| - "/v1/log/incident", |
60 |
| - "/v1/log/threat", |
61 |
| - "/v1/log/violation", |
62 |
| - "/v1/log/audit", |
63 |
| - |
64 |
| - "/v1/debug/internal_subnets", |
65 |
| - "/v1/debug/ip2workload", |
66 |
| - "/v1/debug/controller/sync", |
67 |
| - "/v1/debug/system/stats", |
68 |
| - "/v1/debug/registry/image/openshift", |
69 |
| - "/v1/debug/admission_stats", |
70 |
| -] |
71 |
| - |
72 |
| -support_global_post = [ |
73 |
| - "/v1/csp/file/support?data=adapter_versions", |
74 |
| -] |
75 |
| - |
76 |
| -support_host = [ |
77 |
| - "/v1/host", |
78 |
| - "/v1/debug/ip2workload?f_node=%s", |
79 |
| -] |
80 |
| - |
81 |
| -support_controller = [ |
82 |
| - "/v1/controller", |
83 |
| - "/v1/controller/%s/counter", |
84 |
| - # "/v1/controller/%s/logs?start=0&limit=100000", # 1000 lines * 100 |
85 |
| - # "/v1/controller/%s/logs?start=-1&limit=100000", # 1000 lines * 100 |
86 |
| - # "/v1/controller/%s/config", |
87 |
| -] |
88 |
| - |
89 |
| -support_enforcer = [ |
90 |
| - "/v1/enforcer", |
91 |
| - # "/v1/enforcer/%s/config", |
92 |
| - "/v1/enforcer/%s/counter", |
93 |
| - "/v1/enforcer/%s/stats", |
94 |
| - "/v1/enforcer/%s/probe_summary", |
95 |
| - "/v1/debug/policy/rule?f_enforcer=%s", |
96 |
| - "/v1/session?f_enforcer=%s", |
97 |
| - "/v1/debug/dlp/wlrule?f_enforcer=%s", |
98 |
| - "/v1/debug/dlp/rule?f_enforcer=%s", |
99 |
| - # "/v1/enforcer/%s/logs?start=0&limit=100000", # 1000 lines * 100 |
100 |
| - # "/v1/enforcer/%s/logs?start=-1&limit=100000", # 1000 lines * 100 |
101 |
| -] |
102 |
| - |
103 |
| -# Very expensive to call every workload one by one |
104 |
| -support_workload = [ |
105 |
| - "/v2/workload?view=pod", |
106 |
| - # "/v1/workload/%s/process_history", |
107 |
| -] |
108 |
| - |
109 |
| -ENV_CTRL_SERVER_IP = "CTRL_SERVER_IP" |
110 |
| -ENV_CTRL_SERVER_PORT = "CTRL_SERVER_PORT" |
111 |
| - |
112 |
| -class RestException(Exception): |
113 |
| - message = "An unknown exception occurred." |
114 |
| - |
115 |
| - def __init__(self, **kwargs): |
116 |
| - try: |
117 |
| - super(RestException, self).__init__(self.message % kwargs) |
118 |
| - self.msg = self.message % kwargs |
119 |
| - except Exception: |
120 |
| - super(RestException, self).__init__(self.message) |
121 |
| - |
122 |
| -class ConnectionError(RestException): |
123 |
| - message = "Fail to connect to server" |
124 |
| - |
125 |
| -class ConnectTimeout(RestException): |
126 |
| - message = "Connection timeout" |
127 |
| - |
128 |
| -class RequestError(RestException): |
129 |
| - message = "Request error" |
130 |
| - |
131 |
| -class RestClient(object): |
132 |
| - |
133 |
| - def __init__(self, server, port, token, cookie): |
134 |
| - if server: |
135 |
| - self.server = server |
136 |
| - elif ENV_CTRL_SERVER_IP in os.environ: |
137 |
| - self.server = os.environ.get(ENV_CTRL_SERVER_IP) |
138 |
| - else: |
139 |
| - self.server = "127.0.0.1" |
140 |
| - |
141 |
| - if port: |
142 |
| - self.port = port |
143 |
| - elif ENV_CTRL_SERVER_PORT in os.environ: |
144 |
| - self.port = os.environ.get(ENV_CTRL_SERVER_PORT) |
145 |
| - else: |
146 |
| - self.port = 10443 |
147 |
| - |
148 |
| - self.url = "https://%s:%s" % (self.server, self.port) |
149 |
| - |
150 |
| - self.sess = requests.Session() |
151 |
| - self.sess.headers.update({"Content-Type": "application/json"}) |
152 |
| - self.sess.headers.update({"X-Auth-Token": token}) |
153 |
| - if cookie is not None: |
154 |
| - self.sess.headers.update({"X-R-Sess": cookie}) |
155 |
| - |
156 |
| - try: |
157 |
| - if hasattr(requests.packages.urllib3, "disable_warnings"): |
158 |
| - requests.packages.urllib3.disable_warnings() |
159 |
| - except AttributeError: |
160 |
| - pass |
161 |
| - |
162 |
| - |
163 |
| - def request(self, method, path, body=None, decode=True): |
164 |
| - try: |
165 |
| - resp = self.sess.request(method, "%s%s" % (self.url, path), data=body, verify=False) |
166 |
| - except requests.exceptions.ConnectionError: |
167 |
| - raise ConnectionError() |
168 |
| - except requests.exceptions.Timeout: |
169 |
| - raise ConnectTimeout() |
170 |
| - except requests.exceptions.RequestException: |
171 |
| - raise RequestError() |
172 |
| - |
173 |
| - try: |
174 |
| - if decode: |
175 |
| - data = resp.json() |
176 |
| - raw = False |
177 |
| - else: |
178 |
| - data = resp |
179 |
| - raw = True |
180 |
| - except Exception as e: |
181 |
| - data = resp |
182 |
| - raw = True |
183 |
| - |
184 |
| - return resp.status_code, resp.text, data, raw |
185 |
| - |
186 |
| -def support_request(method, path, output): |
187 |
| - output.write('"%s":\n' % path) |
188 |
| - |
189 |
| - if path.find('?') == -1: |
190 |
| - path = "{}?support=true".format(path) |
191 |
| - else: |
192 |
| - path = "{}&support=true".format(path) |
193 |
| - _, _, data, raw = client.request(method, path) |
194 |
| - if raw: |
195 |
| - output.write(data.content) |
196 |
| - else: |
197 |
| - output.write(json.dumps(data, indent=4, sort_keys=True)) |
198 |
| - output.write(",\n") |
199 |
| - return data |
200 |
| - |
201 |
| -def support(client, jointID, enforcers, output): |
202 |
| - output.write('{') |
203 |
| - output.write('"Manager": "%s",\n' % socket.gethostname()) |
204 |
| - output.write('"Time": "%s",\n' % time.strftime("%c")) |
205 |
| - |
206 |
| - # Test |
207 |
| - for _, _path in enumerate(support_test): |
208 |
| - path = _path |
209 |
| - if jointID: |
210 |
| - path = "/v1/fed/cluster/{}{}".format(jointID, _path) |
211 |
| - output.write('"%s": {},\n' % path) |
212 |
| - status, _, data, _ = client.request("GET", path) |
213 |
| - if status != requests.codes.ok: |
214 |
| - output.write(json.dumps(data, indent=4, sort_keys=True) + "\n") |
215 |
| - return status |
216 |
| - |
217 |
| - # Global (GET) |
218 |
| - for _, _path in enumerate(support_global): |
219 |
| - path = _path |
220 |
| - if jointID: |
221 |
| - path = "/v1/fed/cluster/{}{}".format(jointID, _path) |
222 |
| - support_request("GET", path, output) |
223 |
| - |
224 |
| - # Global (POST) |
225 |
| - for _, _path in enumerate(support_global_post): |
226 |
| - path = _path |
227 |
| - if jointID: |
228 |
| - path = "/v1/fed/cluster/{}{}".format(jointID, _path) |
229 |
| - support_request("POST", path, output) |
230 |
| - |
231 |
| - # Host |
232 |
| - path = support_host[0] |
233 |
| - if jointID: |
234 |
| - path = "/v1/fed/cluster/{}{}".format(jointID, path) |
235 |
| - data = support_request("GET", path, output) |
236 |
| - entries = data.get("hosts") |
237 |
| - if entries and len(entries): |
238 |
| - ids = [entry["id"] for entry in entries] |
239 |
| - for _, _path in enumerate(support_host[1:]): |
240 |
| - path = _path |
241 |
| - if jointID: |
242 |
| - path = "/v1/fed/cluster/{}{}".format(jointID, _path) |
243 |
| - for id in ids: |
244 |
| - support_request("GET", path % id, output) |
245 |
| - |
246 |
| - # Controller |
247 |
| - path = support_controller[0] |
248 |
| - if jointID: |
249 |
| - path = "/v1/fed/cluster/{}{}".format(jointID, path) |
250 |
| - data = support_request("GET", path, output) |
251 |
| - entries = data.get("controllers") |
252 |
| - if entries and len(entries): |
253 |
| - ids = [entry["id"] for entry in entries] |
254 |
| - for _, _path in enumerate(support_controller[1:]): |
255 |
| - path = _path |
256 |
| - if jointID: |
257 |
| - path = "/v1/fed/cluster/{}{}".format(jointID, _path) |
258 |
| - for id in ids: |
259 |
| - support_request("GET", path % id, output) |
260 |
| - |
261 |
| - # Enforcer |
262 |
| - path = support_enforcer[0] |
263 |
| - if jointID: |
264 |
| - path = "/v1/fed/cluster/{}{}".format(jointID, path) |
265 |
| - data = support_request("GET", path, output) |
266 |
| - entries = data.get("enforcers") |
267 |
| - if enforcers and entries and len(entries) > 0: |
268 |
| - all = [entry["id"] for entry in entries] |
269 |
| - ids = [] |
270 |
| - |
271 |
| - if enforcers == "ALL": |
272 |
| - ids = all |
273 |
| - else: |
274 |
| - enfs = enforcers.split(",") |
275 |
| - if len(enfs) > 0: |
276 |
| - for _, id in enumerate(all): |
277 |
| - for _, e in enumerate(enfs): |
278 |
| - if id.startswith(e): |
279 |
| - ids.append(id) |
280 |
| - break |
281 |
| - |
282 |
| - for _, _path in enumerate(support_enforcer[1:]): |
283 |
| - path = _path |
284 |
| - if jointID: |
285 |
| - path = "/v1/fed/cluster/{}{}".format(jointID, _path) |
286 |
| - |
287 |
| - for id in ids: |
288 |
| - support_request("GET", path % id, output) |
289 |
| - |
290 |
| - # Workload |
291 |
| - path = support_workload[0] |
292 |
| - if jointID: |
293 |
| - path = "/v1/fed/cluster/{}{}".format(jointID, path) |
294 |
| - data = support_request("GET", path, output) |
295 |
| - entries = data.get("workloads") |
296 |
| - if entries and len(entries): |
297 |
| - ids = [entry["brief"]["id"] for entry in entries] |
298 |
| - for _, _path in enumerate(support_workload[1:]): |
299 |
| - path = _path |
300 |
| - if jointID: |
301 |
| - path = "/v1/fed/cluster/{}{}".format(jointID, _path) |
302 |
| - for id in ids: |
303 |
| - support_request("GET", path % id, output) |
304 |
| - |
305 |
| - # add a dummy entry to correct the trailing comma |
306 |
| - output.write('"END":{}\n') |
307 |
| - output.write('}') |
308 |
| - return 0 |
309 |
| - |
310 |
| -if __name__ == "__main__": |
311 |
| - parser = argparse.ArgumentParser(description='NeuVector Support Script.') |
312 |
| - parser.add_argument('-s', '--server', help='controller IP address.') |
313 |
| - parser.add_argument('-p', '--port', type=int, help='controller port.') |
314 |
| - parser.add_argument('-t', '--token', help='login token.') |
315 |
| - parser.add_argument('-r', '--ress', help='Rancher cookie.') |
316 |
| - parser.add_argument('-o', '--output', help='output filename.') |
317 |
| - parser.add_argument('-e', '--enforcers', help='comma separated enforcer ids.') # if not specified means all enforcers |
318 |
| - parser.add_argument('-j', '--joint', help='remote joint cluster id.') # if not specified, meaning get local support logs |
319 |
| - args = parser.parse_args() |
320 |
| - |
321 |
| - client = RestClient(args.server, args.port, args.token, args.ress) |
322 |
| - |
323 |
| - rc = 0 |
324 |
| - if args.output: |
325 |
| - (path, name) = os.path.split(args.output) |
326 |
| - if not name: |
327 |
| - sys.exit(-1) |
328 |
| - |
329 |
| - tmpfile = os.path.join(path, "." + name) |
330 |
| - with gzip.open(tmpfile, 'wb') as output: |
331 |
| - with io.TextIOWrapper(output, encoding='utf-8') as encode: |
332 |
| - rc = support(client, args.joint, args.enforcers, encode) |
333 |
| - os.rename(tmpfile, args.output) |
334 |
| - else: |
335 |
| - rc = support(client, args.joint, args.enforcers, sys.stdout) |
336 |
| - |
337 |
| - sys.exit(rc) |
| 1 | +#!/bin/sh |
| 2 | +if [ -f /.venv/bin/activate ]; then |
| 3 | + source /.venv/bin/activate |
| 4 | +fi |
| 5 | +python /usr/local/bin/support.py "$@" |
0 commit comments