zabbix_manager 5.1.6 → 6.0.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -1
- data/README.md +73 -45
- data/lib/zabbix_manager/classes/actions.rb +3 -11
- data/lib/zabbix_manager/classes/applications.rb +2 -8
- data/lib/zabbix_manager/classes/configurations.rb +4 -9
- data/lib/zabbix_manager/classes/{drules.rb → discovery_rules.rb} +2 -8
- data/lib/zabbix_manager/classes/errors.rb +3 -0
- data/lib/zabbix_manager/classes/events.rb +2 -1
- data/lib/zabbix_manager/classes/graphs.rb +19 -15
- data/lib/zabbix_manager/classes/{hostgroups.rb → host_groups.rb} +5 -11
- data/lib/zabbix_manager/classes/host_interfaces.rb +261 -0
- data/lib/zabbix_manager/classes/hosts.rb +139 -89
- data/lib/zabbix_manager/classes/{httptests.rb → http_tests.rb} +2 -8
- data/lib/zabbix_manager/classes/items.rb +139 -92
- data/lib/zabbix_manager/classes/maintenance.rb +2 -1
- data/lib/zabbix_manager/classes/{mediatypes.rb → media_types.rb} +2 -7
- data/lib/zabbix_manager/classes/problems.rb +11 -40
- data/lib/zabbix_manager/classes/proxies.rb +7 -15
- data/lib/zabbix_manager/classes/proxy_groups.rb +16 -0
- data/lib/zabbix_manager/classes/roles.rb +13 -19
- data/lib/zabbix_manager/classes/screens.rb +11 -30
- data/lib/zabbix_manager/classes/scripts.rb +2 -8
- data/lib/zabbix_manager/classes/server.rb +1 -0
- data/lib/zabbix_manager/classes/templates.rb +2 -65
- data/lib/zabbix_manager/classes/triggers.rb +62 -53
- data/lib/zabbix_manager/classes/user_groups.rb +63 -0
- data/lib/zabbix_manager/classes/user_macros.rb +111 -0
- data/lib/zabbix_manager/classes/users.rb +15 -54
- data/lib/zabbix_manager/classes/value_maps.rb +52 -0
- data/lib/zabbix_manager/client.rb +162 -279
- data/lib/zabbix_manager/configuration.rb +115 -0
- data/lib/zabbix_manager/http_transport.rb +145 -97
- data/lib/zabbix_manager/log_sanitizer.rb +18 -29
- data/lib/zabbix_manager/monitoring/device.rb +394 -0
- data/lib/zabbix_manager/monitoring/expressions.rb +36 -0
- data/lib/zabbix_manager/monitoring/line.rb +176 -0
- data/lib/zabbix_manager/monitoring/line_items.rb +110 -0
- data/lib/zabbix_manager/monitoring/line_lifecycle.rb +169 -0
- data/lib/zabbix_manager/monitoring/line_plan.rb +113 -0
- data/lib/zabbix_manager/monitoring/thresholds.rb +182 -0
- data/lib/zabbix_manager/monitoring/traffic_items.rb +133 -0
- data/lib/zabbix_manager/monitoring/validation.rb +92 -0
- data/lib/zabbix_manager/monitoring.rb +216 -642
- data/lib/zabbix_manager/resource.rb +262 -0
- data/lib/zabbix_manager/traffic.rb +239 -0
- data/lib/zabbix_manager/version.rb +1 -1
- data/lib/zabbix_manager.rb +66 -179
- data/zabbix_manager.gemspec +6 -22
- metadata +41 -190
- data/lib/zabbix_manager/basic/basic_alias.rb +0 -42
- data/lib/zabbix_manager/basic/basic_func.rb +0 -55
- data/lib/zabbix_manager/basic/basic_init.rb +0 -50
- data/lib/zabbix_manager/basic/basic_logic.rb +0 -239
- data/lib/zabbix_manager/classes/hostinterfaces.rb +0 -189
- data/lib/zabbix_manager/classes/usergroups.rb +0 -75
- data/lib/zabbix_manager/classes/usermacros.rb +0 -222
- data/lib/zabbix_manager/classes/valuemaps.rb +0 -26
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class ZabbixManager
|
|
4
|
-
|
|
4
|
+
# 监控项查询与写入;通用 CRUD 使用名称,专用 upsert 使用 hostid + key_。
|
|
5
|
+
class Items < Resource
|
|
5
6
|
DEFAULT_OPTIONS = {
|
|
6
7
|
delay: "1m",
|
|
7
8
|
history: "1h",
|
|
@@ -19,13 +20,6 @@ class ZabbixManager
|
|
|
19
20
|
"item"
|
|
20
21
|
end
|
|
21
22
|
|
|
22
|
-
# 使用名称作为通用 CRUD 的业务标识。
|
|
23
|
-
#
|
|
24
|
-
# @return [String]
|
|
25
|
-
def identify
|
|
26
|
-
"name"
|
|
27
|
-
end
|
|
28
|
-
|
|
29
23
|
# 返回创建监控项时的克制默认值。
|
|
30
24
|
#
|
|
31
25
|
# @return [Hash]
|
|
@@ -35,10 +29,10 @@ class ZabbixManager
|
|
|
35
29
|
|
|
36
30
|
# 使用主机和名称组成通用 CRUD 的查询边界。
|
|
37
31
|
#
|
|
38
|
-
# @param data [Hash]
|
|
39
|
-
# @raise [ApiError]
|
|
40
|
-
# @raise [TransportError]
|
|
41
|
-
# @return [
|
|
32
|
+
# @param data [Hash] 包含 name 和 hostid 的监控项属性
|
|
33
|
+
# @raise [ApiError] Zabbix API 明确返回业务错误
|
|
34
|
+
# @raise [TransportError] HTTP 或网络请求失败,可能无法确认远端结果
|
|
35
|
+
# @return [Hash] 名称和所属主机组成的精确过滤条件
|
|
42
36
|
def identity_filter(data)
|
|
43
37
|
attributes = data.deep_symbolize_keys
|
|
44
38
|
{ name: attributes.fetch(:name), hostid: attributes.fetch(:hostid) }
|
|
@@ -47,87 +41,88 @@ class ZabbixManager
|
|
|
47
41
|
# 查询主机监控项,可按稳定 key 集合过滤并选择关联对象。
|
|
48
42
|
# @return [Array<Hash>]
|
|
49
43
|
def for_host(hostid, keys: nil, output: "extend", select_preprocessing: nil, select_tags: nil)
|
|
50
|
-
|
|
44
|
+
positive_id_attribute(hostid, "hostid")
|
|
51
45
|
|
|
52
46
|
params = { hostids: hostid, output: output }
|
|
53
47
|
params[:filter] = { key_: keys } if keys.present?
|
|
54
48
|
params[:selectPreprocessing] = select_preprocessing if select_preprocessing
|
|
55
49
|
params[:selectTags] = select_tags if select_tags
|
|
56
|
-
@client.api_request(method: "item.get", params: params)
|
|
50
|
+
response_objects(@client.api_request(method: "item.get", params: params))
|
|
57
51
|
end
|
|
58
52
|
|
|
59
53
|
# 按主机和稳定 key 查询唯一监控项。
|
|
60
54
|
# @return [Hash, nil]
|
|
61
55
|
def find_by_key(hostid:, key:)
|
|
62
|
-
result = for_host(hostid, keys: key, output:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
result.first
|
|
56
|
+
result = for_host(hostid, keys: key, output: "extend", select_preprocessing: "extend")
|
|
57
|
+
index_items(result, hostid, [key])[key]
|
|
66
58
|
end
|
|
67
59
|
|
|
68
60
|
# 按 hostid + key_ 幂等创建或更新监控项。
|
|
69
61
|
# @return [Integer]
|
|
70
62
|
def upsert_by_key(data)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
current = find_by_key(hostid: attributes[:hostid], key: attributes[:key_])
|
|
74
|
-
if current
|
|
75
|
-
itemid = current.fetch("itemid")
|
|
76
|
-
@client.api_request(
|
|
77
|
-
method: "item.update",
|
|
78
|
-
params: attributes.except(:hostid).merge(itemid: itemid)
|
|
79
|
-
)
|
|
80
|
-
itemid.to_i
|
|
81
|
-
else
|
|
82
|
-
create_attributes = default_options.merge(attributes)
|
|
83
|
-
validate_create_item!(create_attributes)
|
|
84
|
-
result = @client.api_request(method: "item.create", params: create_attributes)
|
|
85
|
-
result.fetch("itemids").first.to_i
|
|
86
|
-
end
|
|
63
|
+
apply_item(*plan_item(validate_item!(data)))
|
|
87
64
|
end
|
|
88
65
|
|
|
89
66
|
# 先校验整批数据,再按稳定 key 逐项幂等写入。
|
|
67
|
+
# @yieldparam effective [Array<Hash>] 合并已有配置或创建默认值后的有效属性;块失败时不写入
|
|
90
68
|
# @return [Array<Integer>]
|
|
91
69
|
def upsert_many(collection)
|
|
92
70
|
items = Array(collection).map { |data| validate_item!(data) }
|
|
93
|
-
identities = items.map { |item| [item[:hostid].to_s, item[:key_]
|
|
71
|
+
identities = items.map { |item| [positive_id_attribute(item[:hostid], "hostid").to_s, item[:key_]] }
|
|
94
72
|
duplicate = identities.tally.find { |_identity, count| count > 1 }&.first
|
|
95
73
|
raise Invalid, "duplicate hostid + key_ identity #{duplicate.join(":")}" if duplicate
|
|
96
74
|
|
|
97
|
-
|
|
75
|
+
existing = batch_items(items)
|
|
76
|
+
plans = items.map do |item|
|
|
77
|
+
identity = [positive_id_attribute(item[:hostid], "hostid").to_s, item[:key_]]
|
|
78
|
+
plan_item(item, existing[identity])
|
|
79
|
+
end
|
|
80
|
+
if block_given?
|
|
81
|
+
effective = plans.map do |attributes, current|
|
|
82
|
+
if current && !%w[type value_type].all? { |field| current.key?(field) }
|
|
83
|
+
raise ProtocolError, "item.get must include type and value_type for effective configuration validation"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
current ? current.deep_symbolize_keys.merge(attributes).deep_dup : attributes.deep_dup
|
|
87
|
+
end
|
|
88
|
+
yield effective
|
|
89
|
+
end
|
|
90
|
+
plans.map { |attributes, current| apply_item(attributes, current) }
|
|
98
91
|
end
|
|
99
92
|
|
|
100
93
|
# 批量启用或停用监控项。
|
|
101
94
|
# @return [Array<Integer>]
|
|
102
95
|
def set_status(hostid:, itemids:, enabled:)
|
|
103
|
-
|
|
96
|
+
validate_boolean!(enabled, "enabled")
|
|
97
|
+
ids = normalized_ids(itemids)
|
|
104
98
|
verify_host_ownership!(hostid, ids)
|
|
105
99
|
result = @client.api_request(
|
|
106
100
|
method: "item.update",
|
|
107
101
|
params: ids.map { |itemid| { itemid: itemid, status: enabled ? 0 : 1 } }
|
|
108
102
|
)
|
|
109
|
-
|
|
103
|
+
response_ids(result, expected: ids)
|
|
110
104
|
end
|
|
111
105
|
|
|
112
106
|
# 批量删除明确指定的监控项。
|
|
113
107
|
# @return [Array<Integer>]
|
|
114
108
|
def delete_many(hostid:, itemids:)
|
|
115
|
-
ids = normalized_ids(itemids
|
|
109
|
+
ids = normalized_ids(itemids)
|
|
116
110
|
verify_host_ownership!(hostid, ids)
|
|
117
111
|
result = @client.api_request(method: "item.delete", params: ids)
|
|
118
|
-
|
|
112
|
+
response_ids(result, expected: ids)
|
|
119
113
|
end
|
|
120
114
|
|
|
121
115
|
# 返回主机中可能表示接口流量的已启用监控项。
|
|
122
116
|
# 方向和接口精确匹配由 Monitoring 业务层负责。
|
|
123
117
|
# @return [Array<Hash>]
|
|
124
118
|
def monitored_traffic_candidates(hostid)
|
|
119
|
+
positive_id_attribute(hostid, "hostid")
|
|
125
120
|
@client.api_request(
|
|
126
121
|
method: "item.get",
|
|
127
122
|
params: {
|
|
128
123
|
hostids: [hostid],
|
|
129
124
|
monitored: true,
|
|
130
|
-
output: %w[itemid hostid name key_ snmp_oid value_type status units],
|
|
125
|
+
output: %w[itemid hostid name key_ type snmp_oid value_type status units],
|
|
131
126
|
selectPreprocessing: "extend",
|
|
132
127
|
sortfield: "name",
|
|
133
128
|
sortorder: "ASC"
|
|
@@ -143,7 +138,7 @@ class ZabbixManager
|
|
|
143
138
|
raise Invalid, "dns_name is required" if name.blank?
|
|
144
139
|
raise Invalid, "dns_name contains unsupported item key delimiters" if name.match?(/[\[\],]/)
|
|
145
140
|
|
|
146
|
-
|
|
141
|
+
upsert_by_key(
|
|
147
142
|
hostid: hostid,
|
|
148
143
|
interfaceid: interfaceid,
|
|
149
144
|
name: "【DNS域名解析监控】#{name}",
|
|
@@ -154,72 +149,124 @@ class ZabbixManager
|
|
|
154
149
|
history: "90d",
|
|
155
150
|
timeout: "3s"
|
|
156
151
|
)
|
|
157
|
-
log "Ensured DNS monitoring item for #{name}"
|
|
158
|
-
itemid
|
|
159
|
-
rescue StandardError => e
|
|
160
|
-
log "Failed to ensure DNS monitoring item: #{e.class}"
|
|
161
|
-
raise
|
|
162
152
|
end
|
|
163
153
|
|
|
164
154
|
private
|
|
165
155
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
156
|
+
# 每个主机只读取一次期望 key 集合,全部发现和校验完成后才开始写入。
|
|
157
|
+
def batch_items(items)
|
|
158
|
+
groups = items.group_by { |item| positive_id_attribute(item[:hostid], "hostid").to_s }
|
|
159
|
+
ids = {}
|
|
160
|
+
groups.each_with_object({}) do |(owner, definitions), result|
|
|
161
|
+
hostid = definitions.first[:hostid]
|
|
162
|
+
keys = definitions.map { |item| item[:key_] }
|
|
163
|
+
rows = for_host(hostid, keys: keys, select_preprocessing: "extend")
|
|
164
|
+
index_items(rows, hostid, keys).each do |key, row|
|
|
165
|
+
id = response_identifier(row["itemid"])
|
|
166
|
+
raise ProtocolError, "item.get returned duplicate item IDs across hosts" if ids.key?(id)
|
|
174
167
|
|
|
175
|
-
|
|
168
|
+
ids[id] = true
|
|
169
|
+
result[[owner, key]] = row
|
|
170
|
+
end
|
|
176
171
|
end
|
|
172
|
+
end
|
|
177
173
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
raise Invalid, "interfaceid is required for item type #{type}"
|
|
188
|
-
end
|
|
189
|
-
if REQUIRED_PARAMS_TYPES.include?(type) && attributes[:params].blank?
|
|
190
|
-
raise Invalid, "params is required for item type #{type}"
|
|
174
|
+
# 不信任服务端过滤器:返回项必须位于所请求的主机和 key 集合中。
|
|
175
|
+
def index_items(rows, hostid, keys)
|
|
176
|
+
owner = positive_id_attribute(hostid, "hostid")
|
|
177
|
+
requested = keys.to_h { |key| [key, true] }
|
|
178
|
+
ids = {}
|
|
179
|
+
response_objects(rows).each_with_object({}) do |row, result|
|
|
180
|
+
id = response_identifier(row["itemid"])
|
|
181
|
+
unless response_identifier(row["hostid"], "hostid") == owner && requested.key?(row["key_"])
|
|
182
|
+
raise ProtocolError, "item.get returned an item outside the requested host and keys"
|
|
191
183
|
end
|
|
184
|
+
raise Conflict, "multiple items use the same key on host #{hostid}" if result.key?(row["key_"])
|
|
185
|
+
raise ProtocolError, "item.get returned duplicate item IDs" if ids.key?(id)
|
|
192
186
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
187
|
+
ids[id] = true
|
|
188
|
+
result[row["key_"]] = row
|
|
189
|
+
end
|
|
190
|
+
end
|
|
197
191
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
192
|
+
# 创建必填字段必须在整批写入开始前校验。
|
|
193
|
+
def plan_item(attributes, current = find_by_key(hostid: attributes[:hostid], key: attributes[:key_]))
|
|
194
|
+
validate_item_type!(attributes[:type]) if attributes.key?(:type)
|
|
195
|
+
response_identifier(current["itemid"]) if current
|
|
196
|
+
unless current
|
|
197
|
+
attributes = default_options.merge(attributes)
|
|
198
|
+
validate_create_item!(attributes)
|
|
201
199
|
end
|
|
200
|
+
[attributes, current]
|
|
201
|
+
end
|
|
202
202
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
203
|
+
def apply_item(attributes, current)
|
|
204
|
+
if current
|
|
205
|
+
itemid = current.fetch("itemid")
|
|
206
|
+
result = @client.api_request(method: "item.update", params: attributes.except(:hostid).merge(itemid: itemid))
|
|
207
|
+
response_id(result, expected: [itemid])
|
|
208
|
+
else
|
|
209
|
+
result = @client.api_request(method: "item.create", params: attributes)
|
|
210
|
+
response_id(result)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# 规范化并校验幂等写入所需字段。
|
|
215
|
+
# @return [Hash]
|
|
216
|
+
# @api private
|
|
217
|
+
def validate_item!(data)
|
|
218
|
+
raise Invalid, "item must be a hash" unless data.is_a?(Hash)
|
|
206
219
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
220
|
+
attributes = data.deep_symbolize_keys.deep_dup
|
|
221
|
+
positive_id_attribute(attributes[:hostid], "hostid")
|
|
222
|
+
%i[key_ name].each do |field|
|
|
223
|
+
unless attributes[field].is_a?(String) && attributes[field].present?
|
|
224
|
+
raise Invalid, "#{field} must be a non-empty string"
|
|
225
|
+
end
|
|
213
226
|
end
|
|
214
227
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
228
|
+
attributes
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# 校验 item.create 的通用必填字段和 SNMP 条件字段。
|
|
232
|
+
def validate_create_item!(attributes)
|
|
233
|
+
raise Invalid, "type is required when creating an item" if attributes[:type].blank?
|
|
234
|
+
raise Invalid, "value_type is required when creating an item" if attributes[:value_type].blank?
|
|
221
235
|
|
|
222
|
-
|
|
236
|
+
type = validate_item_type!(attributes[:type])
|
|
237
|
+
|
|
238
|
+
if REQUIRED_INTERFACE_TYPES.include?(type) && attributes[:interfaceid].blank?
|
|
239
|
+
raise Invalid, "interfaceid is required for item type #{type}"
|
|
240
|
+
end
|
|
241
|
+
if REQUIRED_PARAMS_TYPES.include?(type) && attributes[:params].blank?
|
|
242
|
+
raise Invalid, "params is required for item type #{type}"
|
|
223
243
|
end
|
|
244
|
+
|
|
245
|
+
raise Invalid,
|
|
246
|
+
"master_itemid is required for a dependent item" if type == 18 && attributes[:master_itemid].blank?
|
|
247
|
+
raise Invalid, "url is required for an HTTP item" if type == 19 && attributes[:url].blank?
|
|
248
|
+
return unless type == 20
|
|
249
|
+
|
|
250
|
+
raise Invalid, "snmp_oid is required for an SNMP item" if attributes[:snmp_oid].blank?
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def validate_item_type!(value)
|
|
254
|
+
type = integer_attribute(value, "type")
|
|
255
|
+
raise Invalid, "unsupported item type #{type}" unless ITEM_TYPES.include?(type)
|
|
256
|
+
|
|
257
|
+
type
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# 回查监控项归属,阻止共享高权限令牌跨主机修改。
|
|
261
|
+
def verify_host_ownership!(hostid, ids)
|
|
262
|
+
positive_id_attribute(hostid, "hostid")
|
|
263
|
+
|
|
264
|
+
result = @client.api_request(
|
|
265
|
+
method: "item.get", params: { hostids: hostid, itemids: ids, output: ["itemid"] }
|
|
266
|
+
)
|
|
267
|
+
owned_ids = response_objects(result).map { |item| response_identifier(item["itemid"]).to_s }
|
|
268
|
+
foreign_ids = ids - owned_ids
|
|
269
|
+
raise Conflict, "items do not belong to host #{hostid}: #{foreign_ids.join(", ")}" if foreign_ids.any?
|
|
270
|
+
end
|
|
224
271
|
end
|
|
225
272
|
end
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class ZabbixManager
|
|
4
|
-
|
|
4
|
+
# 原生通知媒介资源;仅提供最小默认值,不推断端点、凭据或版本字段。
|
|
5
|
+
class MediaTypes < Resource
|
|
5
6
|
# 返回媒介类型对象对应的 Zabbix API 方法前缀。
|
|
6
7
|
# @return [String] API 方法前缀
|
|
7
8
|
def method_name
|
|
8
9
|
"mediatype"
|
|
9
10
|
end
|
|
10
11
|
|
|
11
|
-
# 返回媒介类型用于业务识别的字段名。
|
|
12
|
-
# @return [String] 识别字段名
|
|
13
|
-
def identify
|
|
14
|
-
"name"
|
|
15
|
-
end
|
|
16
|
-
|
|
17
12
|
# 返回媒介类型的最小默认属性;端点和凭据等版本相关字段由调用方显式提供。
|
|
18
13
|
# @return [Hash] 媒介类型默认属性
|
|
19
14
|
def default_options
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class ZabbixManager
|
|
4
|
-
|
|
4
|
+
# 原生问题查询与事件确认;问题身份使用 eventid,确认动作属于远端写入。
|
|
5
|
+
class Problems < Resource
|
|
5
6
|
# 返回问题对象对应的 Zabbix API 方法前缀。
|
|
6
7
|
#
|
|
7
8
|
# @return [String]
|
|
@@ -9,45 +10,18 @@ class ZabbixManager
|
|
|
9
10
|
"problem"
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# @return [String]
|
|
15
|
-
def identify
|
|
16
|
-
"name"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# 返回问题对象的兼容 ID 字段名;问题对象本身没有独立的唯一标识。
|
|
13
|
+
# 使用触发问题的事件 ID 作为对象身份。
|
|
20
14
|
#
|
|
21
15
|
# @return [String]
|
|
22
16
|
def key
|
|
23
|
-
"
|
|
17
|
+
"eventid"
|
|
24
18
|
end
|
|
25
19
|
|
|
26
|
-
#
|
|
20
|
+
# 返回事件 ID 集合字段名。
|
|
27
21
|
#
|
|
28
22
|
# @return [String]
|
|
29
23
|
def keys
|
|
30
|
-
"
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# 按识别字段查询问题对象的完整数据。
|
|
34
|
-
#
|
|
35
|
-
# @param data [Hash] 包含问题识别字段及其值的查询条件
|
|
36
|
-
# @raise [ApiError] Zabbix API 返回业务错误时抛出
|
|
37
|
-
# @raise [TransportError] Zabbix 服务端返回非成功 HTTP 状态时抛出
|
|
38
|
-
# @return [Hash] 匹配的问题数据
|
|
39
|
-
def dump_by_id(data)
|
|
40
|
-
log "[DEBUG] Call dump_by_id with parameters: #{data.inspect}"
|
|
41
|
-
|
|
42
|
-
@client.api_request(
|
|
43
|
-
method: "problem.get",
|
|
44
|
-
params: {
|
|
45
|
-
filter: {
|
|
46
|
-
identify.to_sym => data[identify.to_sym]
|
|
47
|
-
},
|
|
48
|
-
output: "extend"
|
|
49
|
-
}
|
|
50
|
-
)
|
|
24
|
+
"eventids"
|
|
51
25
|
end
|
|
52
26
|
|
|
53
27
|
# 获取问题及其确认、标签和抑制信息,并支持附加查询参数。
|
|
@@ -55,10 +29,8 @@ class ZabbixManager
|
|
|
55
29
|
# @param data [Hash] 问题过滤条件及附加 API 参数
|
|
56
30
|
# @raise [ApiError] Zabbix API 返回业务错误时抛出
|
|
57
31
|
# @raise [TransportError] Zabbix 服务端返回非成功 HTTP 状态时抛出
|
|
58
|
-
# @return [Hash] 匹配的问题完整数据
|
|
32
|
+
# @return [Array<Hash>] 匹配的问题完整数据
|
|
59
33
|
def get_full_data(data)
|
|
60
|
-
log "[DEBUG] Call get_full_data with parameters: #{data.inspect}"
|
|
61
|
-
|
|
62
34
|
data = data.deep_symbolize_keys
|
|
63
35
|
params = {
|
|
64
36
|
recent: false,
|
|
@@ -92,15 +64,14 @@ class ZabbixManager
|
|
|
92
64
|
# @param message [String, nil] 可选确认消息
|
|
93
65
|
# @return [Hash] 事件确认结果
|
|
94
66
|
def acknowledge_events(eventids, action: 2, message: nil)
|
|
95
|
-
ids =
|
|
96
|
-
raise Invalid, "eventids are required" if ids.empty?
|
|
67
|
+
ids = normalized_ids(eventids)
|
|
97
68
|
|
|
98
|
-
@client.api_request(
|
|
69
|
+
result = @client.api_request(
|
|
99
70
|
method: "event.acknowledge",
|
|
100
71
|
params: { eventids: ids, action: action, message: message }.compact
|
|
101
72
|
)
|
|
73
|
+
response_ids(result, expected: ids)
|
|
74
|
+
result
|
|
102
75
|
end
|
|
103
|
-
|
|
104
|
-
alias ack_event acknowledge_events
|
|
105
76
|
end
|
|
106
77
|
end
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class ZabbixManager
|
|
4
|
-
|
|
4
|
+
# 原生代理资源;按服务器版本选择 name 或 host 作为名称字段。
|
|
5
|
+
class Proxies < Resource
|
|
5
6
|
# 返回 Zabbix API 中代理对象的方法名前缀。
|
|
6
7
|
#
|
|
7
8
|
# @return [String] 代理对象的方法名前缀
|
|
@@ -13,18 +14,7 @@ class ZabbixManager
|
|
|
13
14
|
#
|
|
14
15
|
# @return [String] 代理对象的标识字段名
|
|
15
16
|
def identify
|
|
16
|
-
"host"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# 通过 Zabbix API 删除指定代理,并返回首个已删除代理的 ID。
|
|
20
|
-
#
|
|
21
|
-
# @param data [Array] 要删除的 proxyid 数组
|
|
22
|
-
# @raise [ApiError] Zabbix API 返回业务错误时抛出
|
|
23
|
-
# @raise [TransportError] Zabbix 服务返回非成功 HTTP 状态时抛出
|
|
24
|
-
# @return [Integer, nil] 已删除代理的 ID,无结果时返回 nil
|
|
25
|
-
def delete(data)
|
|
26
|
-
result = @client.api_request(method: "proxy.delete", params: data)
|
|
27
|
-
result.empty? ? nil : result["proxyids"][0].to_i
|
|
17
|
+
Gem::Version.new(@client.api_version) >= Gem::Version.new("7.0") ? "name" : "host"
|
|
28
18
|
end
|
|
29
19
|
|
|
30
20
|
# 检查当前凭证是否可读取指定代理。
|
|
@@ -58,12 +48,14 @@ class ZabbixManager
|
|
|
58
48
|
result = @client.api_request(
|
|
59
49
|
method: "proxy.get",
|
|
60
50
|
params: {
|
|
61
|
-
output:
|
|
51
|
+
output: ["proxyid", identify],
|
|
62
52
|
filter: {
|
|
63
|
-
|
|
53
|
+
identify.to_sym => proxy
|
|
64
54
|
}
|
|
65
55
|
}
|
|
66
56
|
)
|
|
57
|
+
result = response_objects(result)
|
|
58
|
+
result.each { |proxy_data| response_identifier(proxy_data["proxyid"]) }
|
|
67
59
|
raise Conflict, "proxy lookup is ambiguous for #{proxy}" if result.length > 1
|
|
68
60
|
|
|
69
61
|
result.first&.fetch("proxyid", nil)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class ZabbixManager
|
|
4
|
+
# Zabbix 7.0 起提供的原生代理组资源。
|
|
5
|
+
class ProxyGroups < Resource
|
|
6
|
+
# @return [String] 原生 API 方法前缀
|
|
7
|
+
def method_name
|
|
8
|
+
"proxygroup"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @return [String] 原生代理组 ID 字段
|
|
12
|
+
def key
|
|
13
|
+
"proxy_groupid"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class ZabbixManager
|
|
4
|
-
|
|
4
|
+
# 角色查询与权限规则更新;权限内容由调用方定义,服务端负责权限校验。
|
|
5
|
+
class Roles < Resource
|
|
5
6
|
# 返回 Zabbix API 中角色对象的方法名前缀。
|
|
6
7
|
#
|
|
7
8
|
# @return [String] 角色对象的方法名前缀
|
|
@@ -9,20 +10,6 @@ class ZabbixManager
|
|
|
9
10
|
"role"
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
# 返回角色对象的主键字段名。
|
|
13
|
-
#
|
|
14
|
-
# @return [String] 角色对象的主键字段名
|
|
15
|
-
def key
|
|
16
|
-
"roleid"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# 返回用于唯一识别角色的业务字段名。
|
|
20
|
-
#
|
|
21
|
-
# @return [String] 角色对象的业务标识字段名
|
|
22
|
-
def identify
|
|
23
|
-
"name"
|
|
24
|
-
end
|
|
25
|
-
|
|
26
13
|
# 更新指定角色的权限规则。
|
|
27
14
|
#
|
|
28
15
|
# @param data [Hash] 包含 roleid 和 rules 的角色规则数据
|
|
@@ -34,6 +21,8 @@ class ZabbixManager
|
|
|
34
21
|
raise Invalid, "roleid is required" if attributes[:roleid].blank?
|
|
35
22
|
raise Invalid, "rules is required" if attributes[:rules].blank?
|
|
36
23
|
|
|
24
|
+
normalized_ids([attributes[:roleid]])
|
|
25
|
+
|
|
37
26
|
result = @client.api_request(
|
|
38
27
|
method: "role.update",
|
|
39
28
|
params: {
|
|
@@ -41,24 +30,29 @@ class ZabbixManager
|
|
|
41
30
|
rules: attributes[:rules]
|
|
42
31
|
}
|
|
43
32
|
)
|
|
44
|
-
result
|
|
33
|
+
response_id(result, expected: [attributes[:roleid]])
|
|
45
34
|
end
|
|
46
35
|
|
|
47
36
|
# 按角色 ID 获取角色详情及完整规则。
|
|
48
37
|
#
|
|
49
|
-
# @param data [Hash] 包含 id
|
|
38
|
+
# @param data [Hash] 包含 roleid 的查询参数;旧 id 引用仍可使用,但不得矛盾
|
|
50
39
|
# @raise [ApiError] Zabbix API 返回业务错误时抛出
|
|
51
40
|
# @raise [TransportError] Zabbix 服务返回非成功 HTTP 状态时抛出
|
|
52
41
|
# @return [Array<Hash>] 匹配的角色详情
|
|
53
42
|
def dump_by_id(data)
|
|
54
|
-
|
|
43
|
+
attributes = data.deep_symbolize_keys
|
|
44
|
+
if attributes.key?(:roleid) && attributes.key?(:id) &&
|
|
45
|
+
normalized_ids([attributes[:roleid]]) != normalized_ids([attributes[:id]])
|
|
46
|
+
raise Invalid, "roleid and id disagree"
|
|
47
|
+
end
|
|
55
48
|
|
|
49
|
+
id = normalized_ids([attributes.fetch(:roleid) { attributes[:id] }]).first
|
|
56
50
|
@client.api_request(
|
|
57
51
|
method: "role.get",
|
|
58
52
|
params: {
|
|
59
53
|
output: "extend",
|
|
60
54
|
selectRules: "extend",
|
|
61
|
-
roleids:
|
|
55
|
+
roleids: id
|
|
62
56
|
}
|
|
63
57
|
)
|
|
64
58
|
end
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class ZabbixManager
|
|
4
|
-
|
|
4
|
+
# 旧版聚合图形的网格创建入口;目标服务器须提供 screen API。
|
|
5
|
+
class Screens < Resource
|
|
5
6
|
# 以下资源类型取自 frontends/php/include/defines.inc.php。
|
|
6
7
|
# SCREEN_RESOURCE_GRAPH => 0,
|
|
7
8
|
# SCREEN_RESOURCE_SIMPLE_GRAPH => 1,
|
|
@@ -28,24 +29,6 @@ class ZabbixManager
|
|
|
28
29
|
"screen"
|
|
29
30
|
end
|
|
30
31
|
|
|
31
|
-
# 返回用于唯一识别聚合图形的业务字段名。
|
|
32
|
-
#
|
|
33
|
-
# @return [String] 聚合图形的业务标识字段名
|
|
34
|
-
def identify
|
|
35
|
-
"name"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# 删除指定聚合图形并返回首个已删除对象的 ID。
|
|
39
|
-
#
|
|
40
|
-
# @param data [String, Array] 要删除的聚合图形 ID
|
|
41
|
-
# @raise [ApiError] Zabbix API 返回业务错误时抛出
|
|
42
|
-
# @raise [TransportError] Zabbix 服务返回非成功 HTTP 状态时抛出
|
|
43
|
-
# @return [Integer, nil] 已删除聚合图形的 ID,无结果时返回 nil
|
|
44
|
-
def delete(data)
|
|
45
|
-
result = @client.api_request(method: "screen.delete", params: [data])
|
|
46
|
-
result.empty? ? nil : result["screenids"][0].to_i
|
|
47
|
-
end
|
|
48
|
-
|
|
49
32
|
# 按名称获取聚合图形,不存在时按图形 ID 网格化创建。
|
|
50
33
|
#
|
|
51
34
|
# @param data [Hash] 包含 screen_name、graphids 及可选布局参数
|
|
@@ -97,17 +80,15 @@ class ZabbixManager
|
|
|
97
80
|
|
|
98
81
|
private
|
|
99
82
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
83
|
+
# 将横向格数转换为正整数,非法值直接拒绝。
|
|
84
|
+
#
|
|
85
|
+
# @param value [Object] 待校验的横向格数
|
|
86
|
+
# @return [Integer] 正整数横向格数
|
|
87
|
+
def positive_hsize(value)
|
|
88
|
+
size = integer_attribute(value, "hsize")
|
|
89
|
+
raise Invalid, "hsize must be a positive integer" unless size.positive?
|
|
107
90
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
raise Invalid, "hsize must be a positive integer"
|
|
111
|
-
end
|
|
91
|
+
size
|
|
92
|
+
end
|
|
112
93
|
end
|
|
113
94
|
end
|