zabbix_manager 5.1.5 → 5.1.6

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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -9
  3. data/LICENSE +1 -1
  4. data/README.md +202 -8
  5. data/lib/zabbix_manager/basic/basic_alias.rb +25 -3
  6. data/lib/zabbix_manager/basic/basic_func.rb +32 -61
  7. data/lib/zabbix_manager/basic/basic_init.rb +28 -13
  8. data/lib/zabbix_manager/basic/basic_logic.rb +172 -128
  9. data/lib/zabbix_manager/classes/actions.rb +21 -11
  10. data/lib/zabbix_manager/classes/applications.rb +12 -17
  11. data/lib/zabbix_manager/classes/configurations.rb +20 -5
  12. data/lib/zabbix_manager/classes/drules.rb +11 -23
  13. data/lib/zabbix_manager/classes/errors.rb +16 -28
  14. data/lib/zabbix_manager/classes/events.rb +6 -2
  15. data/lib/zabbix_manager/classes/graphs.rb +42 -35
  16. data/lib/zabbix_manager/classes/hostgroups.rb +53 -3
  17. data/lib/zabbix_manager/classes/hostinterfaces.rb +172 -12
  18. data/lib/zabbix_manager/classes/hosts.rb +191 -81
  19. data/lib/zabbix_manager/classes/httptests.rb +18 -20
  20. data/lib/zabbix_manager/classes/items.rb +193 -63
  21. data/lib/zabbix_manager/classes/maintenance.rb +6 -2
  22. data/lib/zabbix_manager/classes/mediatypes.rb +7 -63
  23. data/lib/zabbix_manager/classes/problems.rb +75 -57
  24. data/lib/zabbix_manager/classes/proxies.rb +48 -7
  25. data/lib/zabbix_manager/classes/roles.rb +47 -36
  26. data/lib/zabbix_manager/classes/screens.rb +45 -14
  27. data/lib/zabbix_manager/classes/scripts.rb +17 -7
  28. data/lib/zabbix_manager/classes/server.rb +7 -1
  29. data/lib/zabbix_manager/classes/templates.rb +59 -21
  30. data/lib/zabbix_manager/classes/triggers.rb +253 -66
  31. data/lib/zabbix_manager/classes/usergroups.rb +28 -6
  32. data/lib/zabbix_manager/classes/usermacros.rb +119 -33
  33. data/lib/zabbix_manager/classes/users.rb +39 -7
  34. data/lib/zabbix_manager/classes/valuemaps.rb +13 -19
  35. data/lib/zabbix_manager/client.rb +308 -133
  36. data/lib/zabbix_manager/http_transport.rb +192 -0
  37. data/lib/zabbix_manager/log_sanitizer.rb +68 -0
  38. data/lib/zabbix_manager/monitoring.rb +691 -0
  39. data/lib/zabbix_manager/version.rb +1 -1
  40. data/lib/zabbix_manager.rb +118 -40
  41. data/zabbix_manager.gemspec +21 -8
  42. metadata +208 -22
  43. data/lib/zabbix_manager/classes/unusable.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72554dfff6fd4d60ac8be48bc766c9367e4b07f9fa2e3df7500cb21b49a6b033
4
- data.tar.gz: 01bea1ff565779f4ce5dab0b9a53d1832e80f9581b58dcc2e9bc943e83da9a46
3
+ metadata.gz: 37c70888e6fd6b0e27a4945f2672d460243584724c67eed4eadc4d69b88d6ad7
4
+ data.tar.gz: 6975d3b02322a81fe8923503e58b91f1888de4ec324f30846552305931fe6a59
5
5
  SHA512:
6
- metadata.gz: 28bfea0b7a7bd6d99d394a0168a3399275af50fe139609141d03a996e6f488f484e8601529a58bf8710c492edd401514d66771e3b1411a53500898a05e8b6974
7
- data.tar.gz: a25a5c306cffa53d2b601c6f281e5ab5afbfb72fd8cef106683668f7d4b907b047b5d4ab76fcc2aa1e62b9df979ba5129628443c53601effe0de95facb69dd90
6
+ metadata.gz: 875b98496cffef36b128f8038f007c8d9a0a9bdb6635c14df0380545ef495903970c73ffca1cb26105a3e382d14e88517308edd81b11b57d5be64e30e0b6f486
7
+ data.tar.gz: 9d2d60aa041e3e993b4c8aaf9c900570824a997537dca1f0fc34a88dbc7f2dd7286d86adc2ecda40e04b2ac0393fa9279cbbb2a29b65c92dab1a92463984d833
data/CHANGELOG.md CHANGED
@@ -1,11 +1,27 @@
1
1
  # CHANGELOG
2
2
 
3
- ## 5.1.1
4
- * 新增基类查询方法:
5
- * get_key_ids_by_identify:基于监控对象索引键(#{identify})查询 { "#{key}": id };
6
- * get_key_ids:基于监控对象索引建"#{identify}"查询 { "#{key}": id };
7
- * get_or_create_keys:批量创建或更新监控对象并返回 [{ "#{key}": id }];
8
- * 优化 Client 对象实例化逻辑:
9
- * 增加入参检查:必须提供 url、user和password,以及 @id 缓存;
10
- * 优化 debug 模式,接口请求入参和出参打印,均使用 JSON.pretty_unparse(data) 美化;
11
- * 完善项目注释,项目注释覆盖率90%;
3
+ ## Unreleased
4
+
5
+ * Add Zabbix 7.x API-token authentication through the Bearer header while retaining the legacy 4.x-6.x authentication body.
6
+ * Reuse a thread-safe persistent `Net::HTTP` session and add explicit `close` lifecycle handling.
7
+ * Add injectable, credential-filtered request logging and stable JSON-RPC error handling.
8
+ * Add idempotent device/interface monitoring workflows with bandwidth, error, and packet-loss hysteresis triggers.
9
+ * Remove experimental `mojo_*` host/trigger methods and unsafe hard-coded SNMP defaults.
10
+ * Remove environment-specific item lookup helpers with hard-coded host data; use `monitoring.reconcile_line` instead.
11
+ * Remove copied Role user-group methods and the hard-coded historical problem-closing workflow.
12
+ * Remove dormant live-Zabbix scripts that were not part of the RSpec test pattern and mutated remote systems by default.
13
+ * Use ActiveSupport for deep key normalization and blank-value semantics.
14
+ * Batch line reconciliation to reuse host/item discovery and reject ambiguous or dimensionally invalid traffic items.
15
+ * Simplify template reference lookup and fix partial final-row sizing in screen creation.
16
+ * Replace the inherited Rails RuboCop profile with project-scoped lint, security, performance, packaging, layout, and safe style gates.
17
+ * Keep HTTPS verification disabled by default for compatibility, with an opt-in `verify_ssl: true` mode.
18
+ * Remove the unused `http` runtime dependency and support the `logger` default gem on modern Ruby.
19
+ * Add two-phase batch reconciliation for devices and lines with full preflight validation, sanitized per-entry errors, and summaries.
20
+ * Add focused host-interface CRUD, item batch/status/delete, trigger status/delete, and current trigger dependency append/replace APIs.
21
+ * Replace legacy exception names with `Invalid`, `Conflict`, `ApiError`, and `TransportError`.
22
+ * Add CI jobs for tests, formatting, Gem packaging, and trusted tag-based RubyGems publishing.
23
+ * Move project metadata to `https://github.com/gatework/zabbix_manager/tree/master`.
24
+ * Scope destructive and dependency operations by host, serialize host/interface reconciliation, and expose uncertain writes as `ResultUnknown`.
25
+ * Validate current Zabbix item/interface create contracts before writes and publish the exact smoke-tested Gem artifact.
26
+
27
+ ### 5.0.7
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023 WENWU YAN
3
+ Copyright (c) 2022 WENWU YAN
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [gem]: https://rubygems.org/gems/zabbix_manager
6
6
 
7
- Most of the code in the project is based on rewriting the ZabbixApi
7
+ Most codes borrowed from zabbixapi, but fit for my everyday works well!
8
8
  Simple and lightweight ruby module for working with [Zabbix][Zabbix] via the [Zabbix API][Zabbix API]
9
9
 
10
10
  ## Installation
@@ -13,7 +13,7 @@ Simple and lightweight ruby module for working with [Zabbix][Zabbix] via the [Za
13
13
  gem install zabbix_manager
14
14
 
15
15
  # specific version
16
- gem install zabbix_manager -v 5.1.1
16
+ gem install zabbix_manager -v 4.2.0
17
17
  ```
18
18
 
19
19
  ## Documentation
@@ -23,15 +23,204 @@ gem install zabbix_manager -v 5.1.1
23
23
 
24
24
  ## Examples
25
25
 
26
+ ### API token (Zabbix 7.x)
27
+
28
+ The token can come from an application settings page or another secret store. Pass it directly to the client; do not copy it into request parameters or logs.
29
+
30
+ ```ruby
31
+ require "zabbix_manager"
32
+
33
+ zabbix = ZabbixManager.connect(
34
+ url: "https://zabbix.example.com/api_jsonrpc.php",
35
+ api_token: ENV.fetch("ZABBIX_API_TOKEN")
36
+ )
37
+
38
+ hosts = zabbix.hosts.get_raw(output: %w[hostid host])
39
+ zabbix.close
40
+ ```
41
+
42
+ Zabbix 7.x requests use the `Authorization: Bearer` header. Earlier supported servers use the JSON-RPC `auth` property. Supplying `api_token` skips `user.login`, and `logout` only closes the local connection because an API token is not a Zabbix user session. API tokens are rejected on plain HTTP unless `allow_insecure_http: true` is explicitly set.
43
+
44
+ ### Username and password
45
+
46
+ ```ruby
47
+ zabbix = ZabbixManager.connect(
48
+ url: "https://zabbix.example.com/api_jsonrpc.php",
49
+ username: ENV.fetch("ZABBIX_USERNAME"),
50
+ password: ENV.fetch("ZABBIX_PASSWORD")
51
+ )
52
+
53
+ begin
54
+ zabbix.query(method: "host.get", params: { output: %w[hostid host] })
55
+ ensure
56
+ zabbix.logout
57
+ end
58
+ ```
59
+
60
+ A client keeps one persistent `Net::HTTP` session and serializes access to it, so repeated API calls reuse the same TCP/TLS connection. Use one client per process or worker when parallel request throughput matters; a client deliberately permits only one in-flight request. Call `close` when the client is no longer needed. A failed HTTP request closes the connection; the next request establishes a fresh session without automatically replaying the failed JSON-RPC mutation.
61
+
62
+ ### Logging and HTTPS
63
+
64
+ Pass any Ruby Logger-compatible object to receive connection, request completion, duration, and failure events:
65
+
66
+ ```ruby
67
+ zabbix = ZabbixManager.connect(
68
+ url: "https://zabbix.example.com/api_jsonrpc.php",
69
+ api_token: ENV.fetch("ZABBIX_API_TOKEN"),
70
+ logger: Rails.logger
71
+ )
72
+ ```
73
+
74
+ Passwords, API tokens, authorization values, cookies, and session IDs are filtered. Request parameters and response bodies are not logged; debug events contain only operation metadata.
75
+
76
+ HTTPS certificate verification is disabled by default as required by this project. Set `verify_ssl: true` (and optionally `ca_file:`) to enable peer verification.
77
+
78
+ Zabbix 7 API-token requests need the `Authorization` header, so they cannot share that header with HTTP Basic authentication. The client rejects that combination instead of silently overwriting either credential.
79
+
80
+ Timeouts can be set together with `timeout:` or independently with `open_timeout:`, `read_timeout:`, and `write_timeout:`. `keep_alive_timeout:` controls persistent connection reuse.
81
+
82
+ ### Device and interface monitoring
83
+
84
+ `monitoring` provides idempotent workflows for frequent device and line updates. Item identity is the stable pair `hostid + key_`; managed triggers use a dedicated `zabbix_manager_id` tag. Missing remote objects are created and existing ones are updated. Omitted objects are never deleted.
85
+
86
+ For a line inventory that already has interface traffic items discovered by Zabbix, use `reconcile_line`. It accepts the field names from the historical `add_line_monitors.rb` importer, locates the host and the unique inbound/outbound items, then creates or updates one combined trigger. Use a stable, non-secret `line_id` so interface renames update the same trigger.
87
+
88
+ ```ruby
89
+ zabbix.monitoring.reconcile_line(
90
+ line_id: "line-42",
91
+ description: "Example upstream circuit",
92
+ capacity: 200, # Mbps
93
+ device1: "edge-switch-01",
94
+ ipaddr1: "192.0.2.10",
95
+ iface1: "Ten-GigabitEthernet1/0/49",
96
+ isp: "Example ISP",
97
+ high_water: 0.90,
98
+ recovery_water: 0.80,
99
+ problem_window: "5m",
100
+ recovery_window: "15m",
101
+ severity: 4
102
+ )
103
+ ```
104
+
105
+ The lookup accepts full and abbreviated interface names such as `Ten-GigabitEthernet1/0/49` and `Te1/0/49`. It refuses zero or multiple direction matches instead of selecting an item by response order. Existing triggers from the importer can be adopted when their description and `category=line_bandwidth` tag match.
106
+
107
+ Use `reconcile_lines(lines)` for imports. It reuses host and item discovery results within the batch, avoiding a full `item.get` scan for every line.
108
+
109
+ For a device-and-line batch, use `reconcile_network`. The whole input is structurally validated before the first device write. Devices are reconciled first, then lines, and the return value contains per-entry results plus a summary. Template linking and low-level discovery are asynchronous in Zabbix: if a new device's traffic items are not available yet, its line result is an error and the same batch can be safely rerun later.
110
+
111
+ ```ruby
112
+ result = zabbix.monitoring.reconcile_network(
113
+ devices: [
114
+ {
115
+ host: "edge-router-01",
116
+ name: "Example edge router",
117
+ groups: [{ groupid: 20 }],
118
+ interfaces: [{
119
+ type: 2, main: 1, useip: 1, ip: "192.0.2.10", dns: "", port: "161",
120
+ details: { version: 2, community: ENV.fetch("SNMP_COMMUNITY") }
121
+ }]
122
+ }
123
+ ],
124
+ lines: [
125
+ {
126
+ line_id: "line-42", device: "edge-router-01",
127
+ interface_name: "Ten-GigabitEthernet1/0/49", capacity_mbps: 200,
128
+ high_water: 0.90, recovery_water: 0.80
129
+ }
130
+ ]
131
+ )
132
+
133
+ result.fetch(:summary)
134
+ ```
135
+
136
+ ```ruby
137
+ hostid = zabbix.monitoring.reconcile_device(
138
+ host: "router-01",
139
+ name: "Core router 01",
140
+ groups: [{ groupid: 20 }],
141
+ interfaces: [{
142
+ type: 2,
143
+ main: 1,
144
+ useip: 1,
145
+ ip: "192.0.2.1",
146
+ dns: "",
147
+ port: "161",
148
+ details: { version: 2, community: ENV.fetch("SNMP_COMMUNITY") }
149
+ }]
150
+ )
151
+
152
+ zabbix.monitoring.reconcile_interface(
153
+ host: { hostid: hostid, host: "router-01" },
154
+ interface: { name: "GigabitEthernet1/0/1", interfaceid: 12 },
155
+ items: {
156
+ inbound_bps: {
157
+ key_: "if.hc.in.bps[1]", name: "WAN inbound", type: 20, value_type: 0,
158
+ snmp_oid: "get[1.3.6.1.2.1.31.1.1.1.6.1]", delay: "1m", units: "bps",
159
+ preprocessing: [
160
+ { type: 10, params: "", error_handler: 0, error_handler_params: "" },
161
+ { type: 1, params: "8", error_handler: 0, error_handler_params: "" }
162
+ ]
163
+ },
164
+ outbound_bps: {
165
+ key_: "if.hc.out.bps[1]", name: "WAN outbound", type: 20, value_type: 0,
166
+ snmp_oid: "get[1.3.6.1.2.1.31.1.1.1.10.1]", delay: "1m", units: "bps",
167
+ preprocessing: [
168
+ { type: 10, params: "", error_handler: 0, error_handler_params: "" },
169
+ { type: 1, params: "8", error_handler: 0, error_handler_params: "" }
170
+ ]
171
+ },
172
+ in_errors: {
173
+ key_: "if.in.errors.rate[1]", name: "WAN input errors", type: 20, value_type: 0,
174
+ snmp_oid: "get[1.3.6.1.2.1.2.2.1.14.1]", delay: "1m",
175
+ preprocessing: [{ type: 10, params: "", error_handler: 0, error_handler_params: "" }]
176
+ },
177
+ out_errors: {
178
+ key_: "if.out.errors.rate[1]", name: "WAN output errors", type: 20, value_type: 0,
179
+ snmp_oid: "get[1.3.6.1.2.1.2.2.1.20.1]", delay: "1m",
180
+ preprocessing: [{ type: 10, params: "", error_handler: 0, error_handler_params: "" }]
181
+ },
182
+ packet_loss: {
183
+ key_: "icmppingloss[198.51.100.1]", name: "WAN packet loss",
184
+ type: 3, value_type: 0, delay: "1m", units: "%"
185
+ }
186
+ },
187
+ thresholds: {
188
+ bandwidth: { capacity_bps: 1_000_000_000, high_percent: 80, recovery_percent: 70 },
189
+ errors: { high: 100, recovery: 20, function: "max", window: "5m" },
190
+ packet_loss: { high: 5, recovery: 2 }
191
+ }
192
+ )
193
+ ```
194
+
195
+ The library does not guess that SNMP discard/error counters equal packet-loss percentage. Supply an actual packet-loss item key (for example an ICMP loss item) and its item definition. Raw HC-octet traffic items must expose `bps` units and include change-per-second plus multiplier-8 preprocessing; otherwise line reconciliation refuses to build a dimensionally incorrect trigger. Thresholds use separate high and recovery values to avoid alert flapping.
196
+
197
+ Reconciliation is a sequence of remote API calls, not a transaction. Single-object methods raise immediately; batch methods return a sanitized error for each failed entry unless `fail_fast: true` is passed. A retry safely converges already-created items by stable keys. If a trigger create loses its response and cannot be confirmed by readback, `ResultUnknown` is raised and must not be automatically retried. The readback schedule can be set with `uncertain_write_delays:` (up to 60 seconds total). The trigger upsert is serialized within one client process. For multiple workers, inject a callable `upsert_lock` adapter that runs the block under an application-level distributed lock.
198
+
199
+ ```ruby
200
+ ZabbixManager.connect(
201
+ url: "https://zabbix.example.com/api_jsonrpc.php",
202
+ api_token: ENV.fetch("ZABBIX_API_TOKEN"),
203
+ upsert_lock: ->(key, &work) { MonitoringLock.with(key, &work) }
204
+ )
205
+ ```
206
+
207
+ Invalid caller input raises `ZabbixManager::Invalid`, ambiguous remote ownership raises `ZabbixManager::Conflict`, Zabbix JSON-RPC failures raise `ZabbixManager::ApiError`, HTTP/network failures raise `ZabbixManager::TransportError`, and uncertain remote writes raise `ZabbixManager::ResultUnknown`. Destructive/status/dependency methods require `hostid:` and verify ownership before writing. Dependencies default to the same host; cross-host dependencies require `allow_cross_host_dependencies: true`. Do not pass untrusted page parameters directly to raw `query` calls.
208
+
209
+ ### High-frequency API modules
210
+
211
+ The focused modules expose explicit current operations instead of compatibility aliases:
212
+
213
+ * `hosts.reconcile`, `hosts.find_by_id`, `hosts.find_by_candidates`, `hosts.set_status`
214
+ * `hostinterfaces.for_host`, `hostinterfaces.reconcile_for_host`, `hostinterfaces.delete_many`
215
+ * `items.for_host`, `items.upsert_by_key`, `items.upsert_many`, `items.set_status`, `items.delete_many`
216
+ * `triggers.for_host`, `triggers.upsert_for_host`, `triggers.add_dependencies`, `triggers.replace_dependencies`, `triggers.set_status`, `triggers.delete_many`
217
+
26
218
 
27
219
  ## Supported Ruby Versions
28
220
  This library aims to support and is [tested against][github-ci] the following Ruby
29
221
  versions:
30
222
 
31
- * Ruby 2.5
32
- * Ruby 2.6
33
- * Ruby 2.7
34
- * JRuby 9.2.10.0
223
+ * Ruby 2.7 and newer
35
224
 
36
225
  If something doesn't work on one of these versions, it's a bug.
37
226
 
@@ -49,8 +238,9 @@ dropped.
49
238
  ## Dependencies
50
239
 
51
240
  * net/http
241
+ * active_support
52
242
  * json
53
- * activesupport
243
+ * logger
54
244
 
55
245
  ## Contributing
56
246
 
@@ -60,10 +250,14 @@ dropped.
60
250
  * Commit, do not mess with rakefile, version.
61
251
  * Make a pull request.
62
252
 
253
+ ## CI and release
254
+
255
+ Pull requests and pushes to `master` run RSpec, documentation coverage, RuboCop, whitespace checks, and a built-Gem install smoke test. A `v<gem-version>` tag repeats the project gate, validates the tag/version, builds and installs a release candidate, then publishes that exact file through RubyGems Trusted Publishing. Configure the RubyGems trusted publisher for repository `gatework/zabbix_manager`, workflow `release.yml`, and environment `release` before pushing a release tag.
256
+
63
257
  ## Zabbix documentation
64
258
 
65
259
  * [Zabbix Project Homepage][Zabbix]
66
260
  * [Zabbix API docs][Zabbix API]
67
261
 
68
262
  [Zabbix]: https://www.zabbix.com
69
- [Zabbix API]: https://www.zabbix.com/documentation/5.2/manual/api
263
+ [Zabbix API]: https://www.zabbix.com/documentation/current/en/manual/api
@@ -2,19 +2,41 @@
2
2
 
3
3
  class ZabbixManager
4
4
  class Basic
5
- # 获取 Zabbix 对象数据
5
+ # 按标识字段从 Zabbix API 获取对象完整数据。
6
+ #
7
+ # @param data [Hash] 包含对象标识字段及其值
8
+ # @raise [ApiError] Zabbix API 调用失败时抛出
9
+ # @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
10
+ # @return [Hash] 对象完整数据
6
11
  def get(data)
7
12
  get_full_data(data)
8
13
  end
9
14
 
10
- # 新增 Zabbix 对象
15
+ # 通过 Zabbix API 创建对象。
16
+ #
17
+ # @param data [Hash] 待创建的对象属性
18
+ # @raise [ApiError] Zabbix API 调用失败时抛出
19
+ # @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
20
+ # @return [Integer] 创建单个对象时返回对象 ID
21
+ # @return [Boolean] 创建多个对象时返回操作结果
11
22
  def add(data)
12
23
  create(data)
13
24
  end
14
25
 
15
- # 删除 Zabbix 对象
26
+ # 通过 Zabbix API 删除对象。
27
+ #
28
+ # @param data [Hash] 包含对象标识字段及其值
29
+ # @raise [ApiError] Zabbix API 调用失败时抛出
30
+ # @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
31
+ # @return [Integer] 删除单个对象时返回对象 ID
32
+ # @return [Boolean] 删除多个对象时返回操作结果
16
33
  def destroy(data)
17
34
  delete(data)
18
35
  end
36
+
37
+ # 返回子类对应的 Zabbix API 方法名;由具体资源类实现。
38
+ #
39
+ # @return [String, nil] API 方法名
40
+ def method_name; end
19
41
  end
20
42
  end
@@ -2,83 +2,54 @@
2
2
 
3
3
  class ZabbixManager
4
4
  class Basic
5
- # 在调试模式下将日志消息记录到 stdout
5
+ # 将调试信息交给客户端结构化日志,并移除可能包含请求参数的片段。
6
+ #
7
+ # @param message [String] 待记录的调试信息
8
+ # @return [void]
6
9
  def log(message)
7
- puts message if @client.options[:debug]
10
+ return unless @client.options[:debug]
11
+
12
+ raw_message = message.to_s
13
+ safe_message = if raw_message.start_with?("[DEBUG]")
14
+ raw_message[/\A\[DEBUG\]\s+Call\s+[a-z_]+/i] || "[DEBUG] domain operation"
15
+ else
16
+ raw_message
17
+ end
18
+ @client.log(:debug, "domain.operation", message: safe_message)
8
19
  end
9
20
 
10
- # 比较两个哈希是否相等
11
- def hash_equals?(hash1, hash2)
12
- normalized_hash1 = normalize_hash(hash1)
13
- normalized_hash2 = normalize_hash(hash2)
14
-
15
- merged_hash1 = normalized_hash1.merge(normalized_hash2)
16
- merged_hash2 = normalized_hash2.merge(normalized_hash1)
17
-
18
- merged_hash1 == merged_hash2
21
+ # 比较实际哈希是否包含期望哈希中的全部键值。
22
+ #
23
+ # @param first_hash [Hash] 实际数据
24
+ # @param second_hash [Hash] 期望数据
25
+ # @return [Boolean] 是否匹配
26
+ def hash_equals?(first_hash, second_hash)
27
+ actual = normalize_hash(first_hash)
28
+ expected = normalize_hash(second_hash)
29
+ actual.slice(*expected.keys) == expected
19
30
  end
20
31
 
21
- # 将所有哈希/数组键转换为符号
22
- # &method(:symbolize_keys) 是 Ruby 中一种将方法转换为可传递给块或其他方法的 Proc 的方式
23
- def symbolize_keys(object)
24
- case object
25
- when Array
26
- object.map(&method(:symbolize_keys))
27
- when Hash
28
- object.transform_keys(&:to_sym).transform_values(&method(:symbolize_keys))
29
- else
30
- object
31
- end
32
- end
33
-
34
- # 将所有哈希值规范化为字符串
32
+ # 将哈希值递归规范为字符串,并忽略 hostid。
33
+ #
34
+ # @param hash [Hash] 待规范化的哈希
35
+ # @return [Hash] 规范化后的副本
35
36
  def normalize_hash(hash)
36
- result = hash.dup
37
-
38
- # 移除用于日志记录的 TODO 注释。TemplateID 和 HostID 具有不同的 ID
39
- result.delete(:hostid)
40
-
41
- result.transform_keys!(&:to_sym)
42
- result.transform_values! { |value| value.is_a?(Array) ? normalize_array(value) : value.to_s }
43
-
44
- result
37
+ hash.deep_symbolize_keys.except(:hostid).deep_transform_values(&:to_s)
45
38
  end
46
39
 
47
- # 将所有数组值规范化为字符串
48
- def normalize_array(array)
49
- result = []
50
-
51
- array.each do |e|
52
- if e.is_a?(Array)
53
- result.push(normalize_array(e))
54
- elsif e.is_a?(Hash)
55
- result.push(normalize_hash(e))
56
- else
57
- result.push(e.to_s)
58
- end
59
- end
60
-
61
- result
62
- end
63
-
64
- # 解析包含 ID 键或布尔值的数据哈希
40
+ # 从 API 结果中解析单个对象 ID,或透传布尔结果。
41
+ #
42
+ # @param data [Hash, Boolean] API 返回结果
43
+ # @return [Integer, Boolean, nil] 对象 ID、布尔结果或空值
65
44
  def parse_keys(data)
66
45
  case data
67
46
  when Hash
68
- data.empty? ? false : data[keys][0].to_i
47
+ data.empty? ? nil : data[keys][0].to_i
69
48
  when TrueClass
70
49
  true
71
50
  when FalseClass
72
51
  false
73
- else
74
- false
75
52
  end
76
53
  end
77
-
78
- # 合并两个哈希为一个新的哈希
79
- def merge_hashes(hash1, hash2)
80
- new_hash = hash1.dup
81
- new_hash.merge(hash2)
82
- end
83
54
  end
84
55
  end
@@ -2,34 +2,49 @@
2
2
 
3
3
  class ZabbixManager
4
4
  class Basic
5
- # 使用 ZabbixManager 客户端初始化一个新的 Basic 对象
5
+ # 使用 ZabbixManager 客户端初始化基础资源对象。
6
+ #
7
+ # @param client [ZabbixManager::Client] API 客户端
8
+ # @return [ZabbixManager::Basic] 基础资源对象
6
9
  def initialize(client)
7
10
  @client = client
8
11
  end
9
12
 
10
- # 在派生类中应该重写此方法以提供特定的方法名
13
+ # 定义资源对应的 API 方法名占位,要求子类覆盖。
14
+ #
15
+ # @raise [ApiError] 基础类不能直接提供方法名时抛出
16
+ # @return [String] API 方法名
11
17
  def method_name
12
- raise ZbxError, "子类需要自行实现 method_name"
18
+ raise Invalid, "Can't call method_name here"
13
19
  end
14
20
 
15
- # 在派生类中应该重写此方法以提供特定的 ID 字段名
16
- def identify
17
- raise ZbxError, "子类需要自行实现 identify"
18
- end
19
-
20
- # 派生类可以重写此方法以提供特定的默认选项
21
+ # 返回资源创建时使用的默认选项,子类可按需覆盖。
22
+ #
23
+ # @return [Hash] 默认选项
21
24
  def default_options
22
25
  {}
23
26
  end
24
27
 
25
- # 根据 method_name + id 返回对象的 ID 字段名(identify)
28
+ # 根据单数 ID 字段名生成 API 返回结果中的复数字段名。
29
+ #
30
+ # @return [String] 复数 ID 字段名
31
+ def keys
32
+ "#{key}s"
33
+ end
34
+
35
+ # 根据 API 方法名生成对象 ID 字段名。
36
+ #
37
+ # @return [String] 对象 ID 字段名
26
38
  def key
27
39
  "#{method_name}id"
28
40
  end
29
41
 
30
- # 根据 key 返回对象的复数 ID 字段名(identify)
31
- def keys
32
- "#{key}s"
42
+ # 定义资源业务标识字段占位,要求子类覆盖。
43
+ #
44
+ # @raise [ApiError] 基础类不能直接提供标识字段时抛出
45
+ # @return [String] 业务标识字段名
46
+ def identify
47
+ raise Invalid, "Can't call identify here"
33
48
  end
34
49
  end
35
50
  end