zabbix_manager 5.1.5 → 6.0.0

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -9
  3. data/LICENSE +1 -1
  4. data/README.md +241 -24
  5. data/lib/zabbix_manager/classes/actions.rb +19 -17
  6. data/lib/zabbix_manager/classes/applications.rb +11 -22
  7. data/lib/zabbix_manager/classes/configurations.rb +20 -10
  8. data/lib/zabbix_manager/classes/discovery_rules.rb +23 -0
  9. data/lib/zabbix_manager/classes/errors.rb +18 -27
  10. data/lib/zabbix_manager/classes/events.rb +8 -3
  11. data/lib/zabbix_manager/classes/graphs.rb +48 -37
  12. data/lib/zabbix_manager/classes/host_groups.rb +64 -0
  13. data/lib/zabbix_manager/classes/host_interfaces.rb +261 -0
  14. data/lib/zabbix_manager/classes/hosts.rb +232 -76
  15. data/lib/zabbix_manager/classes/http_tests.rb +32 -0
  16. data/lib/zabbix_manager/classes/items.rb +206 -72
  17. data/lib/zabbix_manager/classes/maintenance.rb +8 -3
  18. data/lib/zabbix_manager/classes/media_types.rb +18 -0
  19. data/lib/zabbix_manager/classes/problems.rb +51 -62
  20. data/lib/zabbix_manager/classes/proxies.rb +45 -14
  21. data/lib/zabbix_manager/classes/proxy_groups.rb +16 -0
  22. data/lib/zabbix_manager/classes/roles.rb +46 -41
  23. data/lib/zabbix_manager/classes/screens.rb +36 -24
  24. data/lib/zabbix_manager/classes/scripts.rb +16 -12
  25. data/lib/zabbix_manager/classes/server.rb +8 -1
  26. data/lib/zabbix_manager/classes/templates.rb +26 -51
  27. data/lib/zabbix_manager/classes/triggers.rb +251 -67
  28. data/lib/zabbix_manager/classes/user_groups.rb +63 -0
  29. data/lib/zabbix_manager/classes/user_macros.rb +110 -0
  30. data/lib/zabbix_manager/classes/users.rb +16 -23
  31. data/lib/zabbix_manager/classes/value_maps.rb +52 -0
  32. data/lib/zabbix_manager/client.rb +183 -137
  33. data/lib/zabbix_manager/configuration.rb +107 -0
  34. data/lib/zabbix_manager/http_transport.rb +240 -0
  35. data/lib/zabbix_manager/log_sanitizer.rb +58 -0
  36. data/lib/zabbix_manager/monitoring/device.rb +393 -0
  37. data/lib/zabbix_manager/monitoring/expressions.rb +36 -0
  38. data/lib/zabbix_manager/monitoring/line.rb +175 -0
  39. data/lib/zabbix_manager/monitoring/line_items.rb +110 -0
  40. data/lib/zabbix_manager/monitoring/line_lifecycle.rb +169 -0
  41. data/lib/zabbix_manager/monitoring/line_plan.rb +113 -0
  42. data/lib/zabbix_manager/monitoring/thresholds.rb +182 -0
  43. data/lib/zabbix_manager/monitoring/traffic_items.rb +132 -0
  44. data/lib/zabbix_manager/monitoring/validation.rb +92 -0
  45. data/lib/zabbix_manager/monitoring.rb +265 -0
  46. data/lib/zabbix_manager/resource.rb +235 -0
  47. data/lib/zabbix_manager/traffic.rb +238 -0
  48. data/lib/zabbix_manager/version.rb +1 -1
  49. data/lib/zabbix_manager.rb +110 -145
  50. data/zabbix_manager.gemspec +12 -15
  51. metadata +67 -30
  52. data/lib/zabbix_manager/basic/basic_alias.rb +0 -20
  53. data/lib/zabbix_manager/basic/basic_func.rb +0 -84
  54. data/lib/zabbix_manager/basic/basic_init.rb +0 -35
  55. data/lib/zabbix_manager/basic/basic_logic.rb +0 -195
  56. data/lib/zabbix_manager/classes/drules.rb +0 -41
  57. data/lib/zabbix_manager/classes/hostgroups.rb +0 -20
  58. data/lib/zabbix_manager/classes/hostinterfaces.rb +0 -29
  59. data/lib/zabbix_manager/classes/httptests.rb +0 -40
  60. data/lib/zabbix_manager/classes/mediatypes.rb +0 -79
  61. data/lib/zabbix_manager/classes/unusable.rb +0 -11
  62. data/lib/zabbix_manager/classes/usergroups.rb +0 -53
  63. data/lib/zabbix_manager/classes/usermacros.rb +0 -136
  64. data/lib/zabbix_manager/classes/valuemaps.rb +0 -32
@@ -1,95 +1,229 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ZabbixManager
4
- class Items < Basic
5
- # 用于通过 Zabbix API 与 Items 交互的方法名称
4
+ # 监控项查询与写入;通用 CRUD 使用名称,专用 upsert 使用 hostid + key_。
5
+ class Items < Resource
6
+ DEFAULT_OPTIONS = {
7
+ delay: "1m",
8
+ history: "1h",
9
+ status: 0,
10
+ value_type: 3
11
+ }.freeze
12
+ ITEM_TYPES = [0, 2, 3, 5, 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22].freeze
13
+ REQUIRED_INTERFACE_TYPES = [0, 12, 16, 17, 20].freeze
14
+ REQUIRED_PARAMS_TYPES = [11, 13, 14, 15, 21, 22].freeze
15
+
16
+ # 返回监控项对应的 Zabbix API 模块名。
17
+ #
18
+ # @return [String]
6
19
  def method_name
7
20
  "item"
8
21
  end
9
22
 
10
- # 用于通过 Zabbix API 标识特定 Item 对象的 id 字段名称
11
- def identify
12
- "name"
23
+ # 返回创建监控项时的克制默认值。
24
+ #
25
+ # @return [Hash]
26
+ def default_options
27
+ DEFAULT_OPTIONS.dup
13
28
  end
14
29
 
15
- # 通过 Zabbix API 创建 Item 对象时使用的默认选项
16
- def default_options
17
- {
18
- name: nil,
19
- key_: nil,
20
- hostid: nil,
21
- delay: 60,
22
- history: 3600,
23
- status: 0,
24
- type: 7,
25
- snmp_community: "",
26
- snmp_oid: "",
27
- value_type: 3,
28
- data_type: 0,
29
- trapper_hosts: "localhost",
30
- snmp_port: 161,
31
- units: "",
32
- multiplier: 0,
33
- delta: 0,
34
- snmpv3_securityname: "",
35
- snmpv3_securitylevel: 0,
36
- snmpv3_authpassphrase: "",
37
- snmpv3_privpassphrase: "",
38
- formula: 0,
39
- trends: 86_400,
40
- logtimefmt: "",
41
- valuemapid: 0,
42
- delay_flex: "",
43
- authtype: 0,
44
- username: "",
45
- password: "",
46
- publickey: "",
47
- privatekey: "",
48
- params: "",
49
- ipmi_sensor: ""
50
- }
51
- end
52
-
53
- # 通过 Zabbix API 获取或创建 Item 对象
54
- def get_or_create(data)
55
- log "[DEBUG] 调用 #{method_name}.get_or_create 方法,参数: #{data.inspect}"
56
-
57
- if (id = get_id(name: data[:name], hostid: data[:hostid]))
58
- id
59
- else
60
- create(data)
61
- end
30
+ # 使用主机和名称组成通用 CRUD 的查询边界。
31
+ #
32
+ # @param data [Hash] 包含 name 和 hostid 的监控项属性
33
+ # @raise [ApiError] Zabbix API 明确返回业务错误
34
+ # @raise [TransportError] HTTP 或网络请求失败,可能无法确认远端结果
35
+ # @return [Hash] 名称和所属主机组成的精确过滤条件
36
+ def identity_filter(data)
37
+ attributes = data.deep_symbolize_keys
38
+ { name: attributes.fetch(:name), hostid: attributes.fetch(:hostid) }
39
+ end
40
+
41
+ # 查询主机监控项,可按稳定 key 集合过滤并选择关联对象。
42
+ # @return [Array<Hash>]
43
+ def for_host(hostid, keys: nil, output: "extend", select_preprocessing: nil, select_tags: nil)
44
+ raise Invalid, "hostid is required" if hostid.blank?
45
+
46
+ params = { hostids: hostid, output: output }
47
+ params[:filter] = { key_: keys } if keys.present?
48
+ params[:selectPreprocessing] = select_preprocessing if select_preprocessing
49
+ params[:selectTags] = select_tags if select_tags
50
+ @client.api_request(method: "item.get", params: params)
51
+ end
52
+
53
+ # 按主机和稳定 key 查询唯一监控项。
54
+ # @return [Hash, nil]
55
+ def find_by_key(hostid:, key:)
56
+ result = for_host(hostid, keys: key, output: "extend", select_preprocessing: "extend")
57
+ raise Conflict, "multiple items use key #{key} on host #{hostid}" if result.length > 1
58
+
59
+ result.first
60
+ end
61
+
62
+ # 按 hostid + key_ 幂等创建或更新监控项。
63
+ # @return [Integer]
64
+ def upsert_by_key(data)
65
+ apply_item(*plan_item(validate_item!(data)))
62
66
  end
63
67
 
64
- # 通过 Zabbix API 创建或更新 Item 对象
65
- def create_or_update(data)
66
- itemid = get_id(name: data[:name], hostid: data[:hostid])
67
- itemid ? update(data.merge(itemid: itemid)) : create(data)
68
+ # 先校验整批数据,再按稳定 key 逐项幂等写入。
69
+ # @yieldparam effective [Array<Hash>] 合并已有配置或创建默认值后的有效属性;块失败时不写入
70
+ # @return [Array<Integer>]
71
+ def upsert_many(collection)
72
+ items = Array(collection).map { |data| validate_item!(data) }
73
+ identities = items.map { |item| [item[:hostid].to_s, item[:key_].to_s] }
74
+ duplicate = identities.tally.find { |_identity, count| count > 1 }&.first
75
+ raise Invalid, "duplicate hostid + key_ identity #{duplicate.join(":")}" if duplicate
76
+
77
+ plans = items.map { |item| plan_item(item) }
78
+ if block_given?
79
+ effective = plans.map do |attributes, current|
80
+ if current && !%w[type value_type].all? { |field| current.key?(field) }
81
+ raise ProtocolError, "item.get must include type and value_type for effective configuration validation"
82
+ end
83
+
84
+ current ? current.deep_symbolize_keys.merge(attributes).deep_dup : attributes.deep_dup
85
+ end
86
+ yield effective
87
+ end
88
+ plans.map { |attributes, current| apply_item(attributes, current) }
68
89
  end
69
90
 
70
- # 通过 Zabbix API 获取特定主机和接口下的监控项
71
- def get_interface_items(hostid, name)
72
- # 记录调试信息,标识方法调用以及传递的参数
73
- log "[DEBUG] 调用 #{method_name}.get_interface_items,参数:hostid #{hostid.inspect},name #{name.inspect}"
91
+ # 批量启用或停用监控项。
92
+ # @return [Array<Integer>]
93
+ def set_status(hostid:, itemids:, enabled:)
94
+ validate_boolean!(enabled, "enabled")
95
+ ids = normalized_ids(itemids)
96
+ verify_host_ownership!(hostid, ids)
97
+ result = @client.api_request(
98
+ method: "item.update",
99
+ params: ids.map { |itemid| { itemid: itemid, status: enabled ? 0 : 1 } }
100
+ )
101
+ response_ids(result, expected: ids)
102
+ end
74
103
 
75
- # 自动剔除收尾空白字符,规范化接口名
76
- _name = name&.gsub(%r{[^/0-9]}, "")&.strip
77
- iface = "#{_name}("
104
+ # 批量删除明确指定的监控项。
105
+ # @return [Array<Integer>]
106
+ def delete_many(hostid:, itemids:)
107
+ ids = normalized_ids(itemids)
108
+ verify_host_ownership!(hostid, ids)
109
+ result = @client.api_request(method: "item.delete", params: ids)
110
+ response_ids(result, expected: ids)
111
+ end
78
112
 
79
- # 使用 Zabbix API 进行模糊查询,获取特定主机和接口下的监控项
80
- result = get_raw(
81
- {
82
- output: "extend",
113
+ # 返回主机中可能表示接口流量的已启用监控项。
114
+ # 方向和接口精确匹配由 Monitoring 业务层负责。
115
+ # @return [Array<Hash>]
116
+ def monitored_traffic_candidates(hostid)
117
+ @client.api_request(
118
+ method: "item.get",
119
+ params: {
83
120
  hostids: [hostid],
84
- search: { name: iface }
121
+ monitored: true,
122
+ output: %w[itemid hostid name key_ type snmp_oid value_type status units],
123
+ selectPreprocessing: "extend",
124
+ sortfield: "name",
125
+ sortorder: "ASC"
85
126
  }
86
127
  )
128
+ end
129
+
130
+ # 按主机接口幂等创建或更新 DNS 解析监控项,并返回监控项 ID。
131
+ # DNS 名称会进入 item key,因此拒绝可能改变 key 参数结构的分隔符。
132
+ # @return [Integer]
133
+ def upsert_dns_item(hostid:, interfaceid:, dns_name:)
134
+ name = dns_name.to_s.strip
135
+ raise Invalid, "dns_name is required" if name.blank?
136
+ raise Invalid, "dns_name contains unsupported item key delimiters" if name.match?(/[\[\],]/)
137
+
138
+ upsert_by_key(
139
+ hostid: hostid,
140
+ interfaceid: interfaceid,
141
+ name: "【DNS域名解析监控】#{name}",
142
+ key_: "net.dns.record[,#{name},A,2,2]",
143
+ type: 0,
144
+ value_type: 1,
145
+ delay: "1m",
146
+ history: "90d",
147
+ timeout: "3s"
148
+ )
149
+ end
87
150
 
88
- # 过滤结果,只保留符合正则表达式的项
89
- filtered_result = result.select { |item| item["snmp_oid"].match?(/(1.3.6.1.2.1.31.1.1.1.(6|10|15)|1.3.6.1.2.1.2.2.1.8)./) }
151
+ private
90
152
 
91
- # 如果结果为空,则返回 nil;否则,返回排序后的结果
92
- filtered_result.empty? ? nil : filtered_result.sort_by { |item| item["key_"] }
153
+ # 创建必填字段必须在整批写入开始前校验。
154
+ def plan_item(attributes)
155
+ current = find_by_key(hostid: attributes[:hostid], key: attributes[:key_])
156
+ validate_item_type!(attributes[:type]) if attributes.key?(:type)
157
+ response_identifier(current["itemid"]) if current
158
+ unless current
159
+ attributes = default_options.merge(attributes)
160
+ validate_create_item!(attributes)
161
+ end
162
+ [attributes, current]
163
+ end
164
+
165
+ def apply_item(attributes, current)
166
+ if current
167
+ itemid = current.fetch("itemid")
168
+ result = @client.api_request(method: "item.update", params: attributes.except(:hostid).merge(itemid: itemid))
169
+ response_id(result, expected: [itemid])
170
+ else
171
+ result = @client.api_request(method: "item.create", params: attributes)
172
+ response_id(result)
173
+ end
174
+ end
175
+
176
+ # 规范化并校验幂等写入所需字段。
177
+ # @return [Hash]
178
+ # @api private
179
+ def validate_item!(data)
180
+ attributes = data.deep_symbolize_keys
181
+ raise Invalid, "hostid is required" if attributes[:hostid].blank?
182
+ raise Invalid, "key_ is required" if attributes[:key_].blank?
183
+ raise Invalid, "name is required" if attributes[:name].blank?
184
+
185
+ attributes
186
+ end
187
+
188
+ # 校验 item.create 的通用必填字段和 SNMP 条件字段。
189
+ def validate_create_item!(attributes)
190
+ raise Invalid, "type is required when creating an item" if attributes[:type].blank?
191
+ raise Invalid, "value_type is required when creating an item" if attributes[:value_type].blank?
192
+
193
+ type = validate_item_type!(attributes[:type])
194
+
195
+ if REQUIRED_INTERFACE_TYPES.include?(type) && attributes[:interfaceid].blank?
196
+ raise Invalid, "interfaceid is required for item type #{type}"
197
+ end
198
+ if REQUIRED_PARAMS_TYPES.include?(type) && attributes[:params].blank?
199
+ raise Invalid, "params is required for item type #{type}"
200
+ end
201
+
202
+ raise Invalid,
203
+ "master_itemid is required for a dependent item" if type == 18 && attributes[:master_itemid].blank?
204
+ raise Invalid, "url is required for an HTTP item" if type == 19 && attributes[:url].blank?
205
+ return unless type == 20
206
+
207
+ raise Invalid, "snmp_oid is required for an SNMP item" if attributes[:snmp_oid].blank?
208
+ end
209
+
210
+ def validate_item_type!(value)
211
+ type = integer_attribute(value, "type")
212
+ raise Invalid, "unsupported item type #{type}" unless ITEM_TYPES.include?(type)
213
+
214
+ type
215
+ end
216
+
217
+ # 回查监控项归属,阻止共享高权限令牌跨主机修改。
218
+ def verify_host_ownership!(hostid, ids)
219
+ raise Invalid, "hostid is required" if hostid.blank?
220
+
221
+ result = @client.api_request(
222
+ method: "item.get", params: { hostids: hostid, itemids: ids, output: ["itemid"] }
223
+ )
224
+ owned_ids = result.map { |item| item.fetch("itemid").to_s }
225
+ foreign_ids = ids - owned_ids
226
+ raise Conflict, "items do not belong to host #{hostid}: #{foreign_ids.join(", ")}" if foreign_ids.any?
93
227
  end
94
228
  end
95
229
  end
@@ -1,13 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ZabbixManager
4
- class Maintenance < Basic
5
- # 用于通过 Zabbix API 与维护窗口对象交互的方法名称
4
+ # 原生维护期资源;时间段、目标主机和群组由调用方显式定义。
5
+ class Maintenance < Resource
6
+ # 返回维护期对象对应的 Zabbix API 方法前缀。
7
+ #
8
+ # @return [String]
6
9
  def method_name
7
10
  "maintenance"
8
11
  end
9
12
 
10
- # 用于通过 Zabbix API 识别特定维护窗口对象的 id 字段名称
13
+ # 返回维护期对象用于业务识别的字段名。
14
+ #
15
+ # @return [String]
11
16
  def identify
12
17
  "name"
13
18
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ZabbixManager
4
+ # 原生通知媒介资源;仅提供最小默认值,不推断端点、凭据或版本字段。
5
+ class MediaTypes < Resource
6
+ # 返回媒介类型对象对应的 Zabbix API 方法前缀。
7
+ # @return [String] API 方法前缀
8
+ def method_name
9
+ "mediatype"
10
+ end
11
+
12
+ # 返回媒介类型的最小默认属性;端点和凭据等版本相关字段由调用方显式提供。
13
+ # @return [Hash] 媒介类型默认属性
14
+ def default_options
15
+ { type: 0 }
16
+ end
17
+ end
18
+ end
@@ -1,88 +1,77 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ZabbixManager
4
- class Problems < Basic
5
- require "active_support"
6
- require "active_support/core_ext/date/calculations"
7
-
8
- # 与 Zabbix API 交互的问题方法名称
4
+ # 原生问题查询与事件确认;问题身份使用 eventid,确认动作属于远端写入。
5
+ class Problems < Resource
6
+ # 返回问题对象对应的 Zabbix API 方法前缀。
7
+ #
8
+ # @return [String]
9
9
  def method_name
10
10
  "problem"
11
11
  end
12
12
 
13
- # 识别特定问题对象的 id 字段名称
14
- def identify
15
- "name"
13
+ # 使用触发问题的事件 ID 作为对象身份。
14
+ #
15
+ # @return [String]
16
+ def key
17
+ "eventid"
16
18
  end
17
19
 
18
- # 通过键值对从 Zabbix API 转储问题对象数据
19
- def dump_by_id(data)
20
- log "[DEBUG] 调用 #{method_name}.dump_by_id 方法,参数: #{data.inspect}"
21
-
22
- get_raw({
23
- filter: {
24
- identify.to_sym => data[identify.to_sym]
25
- },
26
- output: "extend"
27
- })
20
+ # 返回事件 ID 集合字段名。
21
+ #
22
+ # @return [String]
23
+ def keys
24
+ "eventids"
28
25
  end
29
26
 
30
- # 从 Zabbix API 获取完整/扩展的问题数据
27
+ # 获取问题及其确认、标签和抑制信息,并支持附加查询参数。
28
+ #
29
+ # @param data [Hash] 问题过滤条件及附加 API 参数
30
+ # @raise [ApiError] Zabbix API 返回业务错误时抛出
31
+ # @raise [TransportError] Zabbix 服务端返回非成功 HTTP 状态时抛出
32
+ # @return [Array<Hash>] 匹配的问题完整数据
31
33
  def get_full_data(data)
32
- log "[DEBUG] 调用 #{method_name}.get_full_data 方法,参数: #{data.inspect}"
33
-
34
- data = symbolize_keys(data)
34
+ data = data.deep_symbolize_keys
35
+ params = {
36
+ recent: false,
37
+ sortfield: ["eventid"],
38
+ sortorder: "DESC",
39
+ output: "extend",
40
+ selectAcknowledges: "extend",
41
+ selectTags: "extend",
42
+ selectSuppressionData: "extend"
43
+ }.merge(data.except(:name).compact)
44
+ params[:filter] = { identify.to_sym => data[identify.to_sym] } if data[identify.to_sym].present?
35
45
 
36
- get_raw({
37
- filter: {
38
- identify.to_sym => data[identify.to_sym]
39
- },
40
- eventids: data[:eventids] || nil,
41
- groupids: data[:groupids] || nil,
42
- hostids: data[:hostids] || nil,
43
- objectids: data[:objectids] || nil,
44
- applicationids: data[:applicationids] || nil,
45
- tags: data[:tags] || nil,
46
- time_from: data[:time_from] || nil,
47
- time_till: data[:time_till] || nil,
48
- eventid_from: data[:eventid_from] || nil,
49
- eventid_till: data[:eventid_till] || nil,
50
- recent: data[:recent] || false,
51
- sortfield: data[:sortfield] || ["eventid"],
52
- sortorder: data[:sortorder] || "DESC",
53
- countOutput: data[:countOutput] || nil,
54
- output: "extend",
55
- selectAcknowledges: "extend",
56
- selectTags: "extend",
57
- selectSuppressionData: "extend"
58
- })
46
+ @client.api_request(
47
+ method: "#{method_name}.get",
48
+ params: params
49
+ )
59
50
  end
60
51
 
61
- # 获取所有问题对象的完整/扩展 Zabbix 数据
52
+ # 获取全部问题对象的完整数据。
53
+ #
54
+ # @raise [ApiError] Zabbix API 返回业务错误时抛出
55
+ # @raise [TransportError] Zabbix 服务端返回非成功 HTTP 状态时抛出
56
+ # @return [Array<Hash>] 匹配的问题对象列表
62
57
  def all
63
58
  get_full_data({})
64
59
  end
65
60
 
66
- # 根据给定参数自动确认问题
67
- def ack_problem
68
- time_from = 90.days.ago.at_beginning_of_day.to_i
69
- time_till = 7.days.ago.at_beginning_of_day.to_i
70
- event_ids = []
71
-
72
- get_full_data(time_from: time_from, time_till: time_till).each do |item|
73
- event_ids << item["eventid"]
74
- end
75
- return if event_ids.empty?
61
+ # 批量确认事件,可指定确认动作和附加消息。
62
+ # @param eventids [Array<String, Integer>, String, Integer] 待确认的事件 ID
63
+ # @param action [Integer] Zabbix 确认动作位掩码
64
+ # @param message [String, nil] 可选确认消息
65
+ # @return [Hash] 事件确认结果
66
+ def acknowledge_events(eventids, action: 2, message: nil)
67
+ ids = normalized_ids(eventids)
76
68
 
77
69
  result = @client.api_request(
78
70
  method: "event.acknowledge",
79
- params: {
80
- eventids: event_ids,
81
- action: 2,
82
- message: "本次告警符合自动刷新规则,已通过接口处理且刷新时间为:#{Time.now}"
83
- }
71
+ params: { eventids: ids, action: action, message: message }.compact
84
72
  )
85
- result.empty? ? nil : result.map { |i| { eventids: i["eventids"] } }
73
+ response_ids(result, expected: ids)
74
+ result
86
75
  end
87
76
  end
88
77
  end
@@ -1,31 +1,62 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ZabbixManager
4
- class Proxies < Basic
5
- # 与 Zabbix API 交互的代理方法名称
4
+ # 原生代理资源;按服务器版本选择 name 或 host 作为名称字段。
5
+ class Proxies < Resource
6
+ # 返回 Zabbix API 中代理对象的方法名前缀。
7
+ #
8
+ # @return [String] 代理对象的方法名前缀
6
9
  def method_name
7
10
  "proxy"
8
11
  end
9
12
 
10
- # 识别特定代理对象的 id 字段名称
13
+ # 返回用于唯一识别代理对象的字段名。
14
+ #
15
+ # @return [String] 代理对象的标识字段名
11
16
  def identify
12
- "host"
17
+ Gem::Version.new(@client.api_version) >= Gem::Version.new("7.0") ? "name" : "host"
13
18
  end
14
19
 
15
- # 使用 Zabbix API 删除代理对象
16
- def delete(data)
17
- result = @client.api_request(method: "proxy.delete", params: data)
18
- result.empty? ? nil : result["proxyids"][0].to_i
19
- end
20
-
21
- # 检查代理对象是否可读
22
- def is_readable(data)
20
+ # 检查当前凭证是否可读取指定代理。
21
+ #
22
+ # @param data [Array] 要检查的 proxyid 数组
23
+ # @raise [ApiError] Zabbix API 返回业务错误时抛出
24
+ # @raise [TransportError] Zabbix 服务返回非成功 HTTP 状态时抛出
25
+ # @return [Boolean] 指定代理是否可读
26
+ def isreadable(data)
23
27
  @client.api_request(method: "proxy.isreadable", params: data)
24
28
  end
25
29
 
26
- # 检查代理对象是否可写
27
- def is_writable(data)
30
+ # 检查当前凭证是否可写入指定代理。
31
+ #
32
+ # @param data [Array] 要检查的 proxyid 数组
33
+ # @raise [ApiError] Zabbix API 返回业务错误时抛出
34
+ # @raise [TransportError] Zabbix 服务返回非成功 HTTP 状态时抛出
35
+ # @return [Boolean] 指定代理是否可写
36
+ def iswritable(data)
28
37
  @client.api_request(method: "proxy.iswritable", params: data)
29
38
  end
39
+
40
+ # 按代理名称查询唯一代理 ID,空名称返回 nil,重名时拒绝选择。
41
+ #
42
+ # @param proxy [String] 代理名称
43
+ # @return [String, nil] 唯一代理 ID,未找到时返回 nil
44
+ def get_proxy_id(proxy)
45
+ return nil if proxy.blank?
46
+
47
+ # 请求后端接口,只支持单个代理节点
48
+ result = @client.api_request(
49
+ method: "proxy.get",
50
+ params: {
51
+ output: ["proxyid", identify],
52
+ filter: {
53
+ identify.to_sym => proxy
54
+ }
55
+ }
56
+ )
57
+ raise Conflict, "proxy lookup is ambiguous for #{proxy}" if result.length > 1
58
+
59
+ result.first&.fetch("proxyid", nil)
60
+ end
30
61
  end
31
62
  end
@@ -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