nginx-lens 0.3.2__py3-none-any.whl → 0.3.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nginx-lens might be problematic. Click here for more details.
- commands/health.py +12 -2
- commands/resolve.py +9 -3
- {nginx_lens-0.3.2.dist-info → nginx_lens-0.3.3.dist-info}/METADATA +1 -1
- {nginx_lens-0.3.2.dist-info → nginx_lens-0.3.3.dist-info}/RECORD +9 -9
- upstream_checker/checker.py +0 -13
- {nginx_lens-0.3.2.dist-info → nginx_lens-0.3.3.dist-info}/WHEEL +0 -0
- {nginx_lens-0.3.2.dist-info → nginx_lens-0.3.3.dist-info}/entry_points.txt +0 -0
- {nginx_lens-0.3.2.dist-info → nginx_lens-0.3.3.dist-info}/licenses/LICENSE +0 -0
- {nginx_lens-0.3.2.dist-info → nginx_lens-0.3.3.dist-info}/top_level.txt +0 -0
commands/health.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import sys
|
|
1
2
|
import typer
|
|
2
3
|
from rich.console import Console
|
|
3
4
|
from rich.table import Table
|
|
@@ -22,14 +23,16 @@ def health(
|
|
|
22
23
|
nginx-lens health /etc/nginx/nginx.conf --timeout 5 --retries 3 --mode http
|
|
23
24
|
nginx-lens health /etc/nginx/nginx.conf --resolve
|
|
24
25
|
"""
|
|
26
|
+
exit_code = 0
|
|
27
|
+
|
|
25
28
|
try:
|
|
26
29
|
tree = parse_nginx_config(config_path)
|
|
27
30
|
except FileNotFoundError:
|
|
28
31
|
console.print(f"[red]Файл {config_path} не найден. Проверьте путь к конфигу.[/red]")
|
|
29
|
-
|
|
32
|
+
sys.exit(1)
|
|
30
33
|
except Exception as e:
|
|
31
34
|
console.print(f"[red]Ошибка при разборе {config_path}: {e}[/red]")
|
|
32
|
-
|
|
35
|
+
sys.exit(1)
|
|
33
36
|
|
|
34
37
|
upstreams = tree.get_upstreams()
|
|
35
38
|
results = check_upstreams(upstreams, timeout=timeout, retries=retries, mode=mode.lower())
|
|
@@ -50,6 +53,10 @@ def health(
|
|
|
50
53
|
status = "Healthy" if srv["healthy"] else "Unhealthy"
|
|
51
54
|
color = "green" if srv["healthy"] else "red"
|
|
52
55
|
|
|
56
|
+
# Проверяем статус здоровья
|
|
57
|
+
if not srv["healthy"]:
|
|
58
|
+
exit_code = 1
|
|
59
|
+
|
|
53
60
|
if resolve:
|
|
54
61
|
resolved_list = []
|
|
55
62
|
if name in resolved_info:
|
|
@@ -64,11 +71,14 @@ def health(
|
|
|
64
71
|
# Если есть "invalid resolve", показываем красным, иначе зеленым
|
|
65
72
|
if any("invalid resolve" in r for r in resolved_list):
|
|
66
73
|
table.add_row(srv["address"], f"[{color}]{status}[/{color}]", f"[red]{resolved_str}[/red]")
|
|
74
|
+
exit_code = 1
|
|
67
75
|
else:
|
|
68
76
|
table.add_row(srv["address"], f"[{color}]{status}[/{color}]", f"[green]{resolved_str}[/green]")
|
|
69
77
|
else:
|
|
70
78
|
table.add_row(srv["address"], f"[{color}]{status}[/{color}]", "[yellow]Failed to resolve[/yellow]")
|
|
79
|
+
exit_code = 1
|
|
71
80
|
else:
|
|
72
81
|
table.add_row(srv["address"], f"[{color}]{status}[/{color}]")
|
|
73
82
|
|
|
74
83
|
console.print(table)
|
|
84
|
+
sys.exit(exit_code)
|
commands/resolve.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import sys
|
|
1
2
|
import typer
|
|
2
3
|
from rich.console import Console
|
|
3
4
|
from rich.table import Table
|
|
@@ -16,19 +17,21 @@ def resolve(
|
|
|
16
17
|
Пример:
|
|
17
18
|
nginx-lens resolve /etc/nginx/nginx.conf
|
|
18
19
|
"""
|
|
20
|
+
exit_code = 0
|
|
21
|
+
|
|
19
22
|
try:
|
|
20
23
|
tree = parse_nginx_config(config_path)
|
|
21
24
|
except FileNotFoundError:
|
|
22
25
|
console.print(f"[red]Файл {config_path} не найден. Проверьте путь к конфигу.[/red]")
|
|
23
|
-
|
|
26
|
+
sys.exit(1)
|
|
24
27
|
except Exception as e:
|
|
25
28
|
console.print(f"[red]Ошибка при разборе {config_path}: {e}[/red]")
|
|
26
|
-
|
|
29
|
+
sys.exit(1)
|
|
27
30
|
|
|
28
31
|
upstreams = tree.get_upstreams()
|
|
29
32
|
if not upstreams:
|
|
30
33
|
console.print("[yellow]Не найдено ни одного upstream в конфигурации.[/yellow]")
|
|
31
|
-
|
|
34
|
+
sys.exit(0) # Нет upstream - это не ошибка, просто нет чего проверять
|
|
32
35
|
|
|
33
36
|
results = resolve_upstreams(upstreams)
|
|
34
37
|
|
|
@@ -47,10 +50,13 @@ def resolve(
|
|
|
47
50
|
# Если есть "invalid resolve", показываем красным, иначе зеленым
|
|
48
51
|
if any("invalid resolve" in r for r in resolved_list):
|
|
49
52
|
table.add_row(upstream_name, srv["address"], f"[red]{resolved_str}[/red]")
|
|
53
|
+
exit_code = 1
|
|
50
54
|
else:
|
|
51
55
|
table.add_row(upstream_name, srv["address"], f"[green]{resolved_str}[/green]")
|
|
52
56
|
else:
|
|
53
57
|
table.add_row(upstream_name, srv["address"], "[red]Failed to resolve[/red]")
|
|
58
|
+
exit_code = 1
|
|
54
59
|
|
|
55
60
|
console.print(table)
|
|
61
|
+
sys.exit(exit_code)
|
|
56
62
|
|
|
@@ -15,10 +15,10 @@ commands/analyze.py,sha256=W6begSgXNjgKJGoGeguR3WKgHPLkClWXxxpDcqvsJdc,8343
|
|
|
15
15
|
commands/cli.py,sha256=brzp6xDDWIrm7ibaoT4x94hgAdBB2DVWniXoK8dRylE,782
|
|
16
16
|
commands/diff.py,sha256=C7gRIWh6DNWHzjiQBPVTn-rZ40m2KCY75Zd6Q4URJIE,2076
|
|
17
17
|
commands/graph.py,sha256=xB6KjXBkLmm5gII3e-5BMRGO7WeTwc7EFxRGzYgnme4,5947
|
|
18
|
-
commands/health.py,sha256=
|
|
18
|
+
commands/health.py,sha256=MIFORCxH9wFH6954h7pmYhbBiqDUVMU6BDHBqWmuSLI,3710
|
|
19
19
|
commands/include.py,sha256=5PTYG5C00-AlWfIgpQXLq9E7C9yTFSv7HrZkM5ogDps,2224
|
|
20
20
|
commands/logs.py,sha256=RkPUdIpbO9dOVL56lemreYRuAjMjcqqMxRCKOFv2gC4,3691
|
|
21
|
-
commands/resolve.py,sha256=
|
|
21
|
+
commands/resolve.py,sha256=sRsEFgGmqS0WBg9VZBiLXB4KjaiFj8kKRprHYq-f9lI,2383
|
|
22
22
|
commands/route.py,sha256=-x_71u6ENl3iO-oxK3bdE8v5eZKf4xRCydeUyXMFVrY,3163
|
|
23
23
|
commands/syntax.py,sha256=ZWFdaL8LVv9S694wlk2aV3HJKb0OSKjw3wNgTlNvFR8,3418
|
|
24
24
|
commands/tree.py,sha256=mDfx0Aeg1EDQSYQoJ2nJIkSd_uP7ZR7pEqy7Cw3clQ0,2161
|
|
@@ -26,13 +26,13 @@ exporter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
26
26
|
exporter/graph.py,sha256=WYUrqUgCaK6KihgxAcRHaQn4oMo6b7ybC8yb_36ZIsA,3995
|
|
27
27
|
exporter/html.py,sha256=uquEM-WvBt2aV9GshgaI3UVhYd8sD0QQ-OmuNtvYUdU,798
|
|
28
28
|
exporter/markdown.py,sha256=_0mXQIhurGEZ0dO-eq9DbsuKNrgEDIblgtL3DAgYNo8,724
|
|
29
|
-
nginx_lens-0.3.
|
|
29
|
+
nginx_lens-0.3.3.dist-info/licenses/LICENSE,sha256=g8QXKdvZZC56rU8E12vIeYF6R4jeTWOsblOnYAda3K4,1073
|
|
30
30
|
parser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
31
31
|
parser/nginx_parser.py,sha256=Sa9FtGAkvTqNzoehBvgLUWPJHLLIZYWH9ugSHW50X8s,3699
|
|
32
32
|
upstream_checker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
|
-
upstream_checker/checker.py,sha256=
|
|
34
|
-
nginx_lens-0.3.
|
|
35
|
-
nginx_lens-0.3.
|
|
36
|
-
nginx_lens-0.3.
|
|
37
|
-
nginx_lens-0.3.
|
|
38
|
-
nginx_lens-0.3.
|
|
33
|
+
upstream_checker/checker.py,sha256=tyv6bVjoFdeGFJzASiamj4EoBppqyvM3gGc9aQSzwXo,8271
|
|
34
|
+
nginx_lens-0.3.3.dist-info/METADATA,sha256=EW_qvvG4Qz_ercZXKVX6xVGC4dBVNVvtYuGm41h7ZQ4,552
|
|
35
|
+
nginx_lens-0.3.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
36
|
+
nginx_lens-0.3.3.dist-info/entry_points.txt,sha256=qEcecjSyLqcJjbIVlNlTpqAhPqDyaujUV5ZcBTAr3po,48
|
|
37
|
+
nginx_lens-0.3.3.dist-info/top_level.txt,sha256=mxLJO4rZg0rbixVGhplF3fUNFs8vxDIL25ronZNvRy4,51
|
|
38
|
+
nginx_lens-0.3.3.dist-info/RECORD,,
|
upstream_checker/checker.py
CHANGED
|
@@ -80,14 +80,12 @@ def resolve_address(address: str) -> List[str]:
|
|
|
80
80
|
return []
|
|
81
81
|
host, port = parts
|
|
82
82
|
|
|
83
|
-
# Если это уже IPv4 адрес, возвращаем как есть
|
|
84
83
|
try:
|
|
85
84
|
socket.inet_aton(host)
|
|
86
85
|
return [host_port]
|
|
87
86
|
except socket.error:
|
|
88
87
|
pass
|
|
89
88
|
|
|
90
|
-
# Проверяем IPv6 (в квадратных скобках)
|
|
91
89
|
if host.startswith("[") and host.endswith("]"):
|
|
92
90
|
ipv6_host = host[1:-1]
|
|
93
91
|
try:
|
|
@@ -96,11 +94,9 @@ def resolve_address(address: str) -> List[str]:
|
|
|
96
94
|
except (socket.error, OSError):
|
|
97
95
|
pass
|
|
98
96
|
|
|
99
|
-
# Используем dnspython для детального DNS резолвинга
|
|
100
97
|
if DNS_AVAILABLE:
|
|
101
98
|
return _resolve_with_dns(host, port)
|
|
102
99
|
else:
|
|
103
|
-
# Fallback на стандартный socket, если dnspython недоступен
|
|
104
100
|
return _resolve_with_socket(host, port)
|
|
105
101
|
except (ValueError, IndexError, AttributeError):
|
|
106
102
|
return []
|
|
@@ -112,25 +108,21 @@ def _resolve_with_dns(host: str, port: str) -> List[str]:
|
|
|
112
108
|
cname_info = None
|
|
113
109
|
invalid_type = None
|
|
114
110
|
|
|
115
|
-
# Сначала проверяем CNAME для исходного хоста
|
|
116
111
|
try:
|
|
117
112
|
cname_answer = dns.resolver.resolve(host, 'CNAME', raise_on_no_answer=False)
|
|
118
113
|
if cname_answer:
|
|
119
114
|
cname_target = str(cname_answer[0].target).rstrip('.')
|
|
120
115
|
cname_info = cname_target
|
|
121
116
|
|
|
122
|
-
# Если есть CNAME, проверяем A записи для CNAME цели (не для исходного хоста)
|
|
123
117
|
try:
|
|
124
118
|
a_answer = dns.resolver.resolve(cname_target, 'A', raise_on_no_answer=False)
|
|
125
119
|
if a_answer:
|
|
126
|
-
# CNAME ведет на валидные A записи
|
|
127
120
|
resolved_ips = []
|
|
128
121
|
for rdata in a_answer:
|
|
129
122
|
ip = str(rdata.address)
|
|
130
123
|
resolved_ips.append(f"{ip}:{port} (via {cname_info})")
|
|
131
124
|
return resolved_ips
|
|
132
125
|
else:
|
|
133
|
-
# Нет A записей для CNAME цели, проверяем другие типы
|
|
134
126
|
try:
|
|
135
127
|
txt_answer = dns.resolver.resolve(cname_target, 'TXT', raise_on_no_answer=False)
|
|
136
128
|
if txt_answer:
|
|
@@ -145,7 +137,6 @@ def _resolve_with_dns(host: str, port: str) -> List[str]:
|
|
|
145
137
|
except:
|
|
146
138
|
pass
|
|
147
139
|
if not invalid_type:
|
|
148
|
-
# Проверяем другие невалидные типы
|
|
149
140
|
try:
|
|
150
141
|
ns_answer = dns.resolver.resolve(cname_target, 'NS', raise_on_no_answer=False)
|
|
151
142
|
if ns_answer:
|
|
@@ -161,7 +152,6 @@ def _resolve_with_dns(host: str, port: str) -> List[str]:
|
|
|
161
152
|
except Exception:
|
|
162
153
|
pass
|
|
163
154
|
|
|
164
|
-
# Если нет CNAME, получаем A записи для исходного хоста
|
|
165
155
|
try:
|
|
166
156
|
a_answer = dns.resolver.resolve(host, 'A', raise_on_no_answer=False)
|
|
167
157
|
if a_answer:
|
|
@@ -181,13 +171,10 @@ def _resolve_with_dns(host: str, port: str) -> List[str]:
|
|
|
181
171
|
def _resolve_with_socket(host: str, port: str) -> List[str]:
|
|
182
172
|
"""Fallback резолвинг через socket (без информации о CNAME)."""
|
|
183
173
|
try:
|
|
184
|
-
# gethostbyname_ex возвращает (hostname, aliaslist, ipaddrlist)
|
|
185
174
|
_, _, ipaddrlist = socket.gethostbyname_ex(host)
|
|
186
|
-
# Фильтруем только IPv4 адреса (IPv6 обрабатываются отдельно)
|
|
187
175
|
resolved_ips = []
|
|
188
176
|
for ip in ipaddrlist:
|
|
189
177
|
try:
|
|
190
|
-
# Проверяем, что это IPv4
|
|
191
178
|
socket.inet_aton(ip)
|
|
192
179
|
resolved_ips.append(f"{ip}:{port}")
|
|
193
180
|
except socket.error:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|