zabbix_manager 5.1.6 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -1
- data/README.md +69 -46
- 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 +135 -89
- data/lib/zabbix_manager/classes/{httptests.rb → http_tests.rb} +2 -8
- data/lib/zabbix_manager/classes/items.rb +91 -87
- 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 +5 -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 +42 -45
- data/lib/zabbix_manager/classes/user_groups.rb +63 -0
- data/lib/zabbix_manager/classes/user_macros.rb +110 -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 +148 -277
- data/lib/zabbix_manager/configuration.rb +107 -0
- data/lib/zabbix_manager/http_transport.rb +145 -97
- data/lib/zabbix_manager/log_sanitizer.rb +9 -19
- data/lib/zabbix_manager/monitoring/device.rb +393 -0
- data/lib/zabbix_manager/monitoring/expressions.rb +36 -0
- data/lib/zabbix_manager/monitoring/line.rb +175 -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 +132 -0
- data/lib/zabbix_manager/monitoring/validation.rb +92 -0
- data/lib/zabbix_manager/monitoring.rb +216 -642
- data/lib/zabbix_manager/resource.rb +235 -0
- data/lib/zabbix_manager/traffic.rb +238 -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,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class ZabbixManager
|
|
4
|
-
class Basic
|
|
5
|
-
# 按标识字段从 Zabbix API 获取对象完整数据。
|
|
6
|
-
#
|
|
7
|
-
# @param data [Hash] 包含对象标识字段及其值
|
|
8
|
-
# @raise [ApiError] Zabbix API 调用失败时抛出
|
|
9
|
-
# @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
|
|
10
|
-
# @return [Hash] 对象完整数据
|
|
11
|
-
def get(data)
|
|
12
|
-
get_full_data(data)
|
|
13
|
-
end
|
|
14
|
-
|
|
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] 创建多个对象时返回操作结果
|
|
22
|
-
def add(data)
|
|
23
|
-
create(data)
|
|
24
|
-
end
|
|
25
|
-
|
|
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] 删除多个对象时返回操作结果
|
|
33
|
-
def destroy(data)
|
|
34
|
-
delete(data)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# 返回子类对应的 Zabbix API 方法名;由具体资源类实现。
|
|
38
|
-
#
|
|
39
|
-
# @return [String, nil] API 方法名
|
|
40
|
-
def method_name; end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class ZabbixManager
|
|
4
|
-
class Basic
|
|
5
|
-
# 将调试信息交给客户端结构化日志,并移除可能包含请求参数的片段。
|
|
6
|
-
#
|
|
7
|
-
# @param message [String] 待记录的调试信息
|
|
8
|
-
# @return [void]
|
|
9
|
-
def log(message)
|
|
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)
|
|
19
|
-
end
|
|
20
|
-
|
|
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
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# 将哈希值递归规范为字符串,并忽略 hostid。
|
|
33
|
-
#
|
|
34
|
-
# @param hash [Hash] 待规范化的哈希
|
|
35
|
-
# @return [Hash] 规范化后的副本
|
|
36
|
-
def normalize_hash(hash)
|
|
37
|
-
hash.deep_symbolize_keys.except(:hostid).deep_transform_values(&:to_s)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# 从 API 结果中解析单个对象 ID,或透传布尔结果。
|
|
41
|
-
#
|
|
42
|
-
# @param data [Hash, Boolean] API 返回结果
|
|
43
|
-
# @return [Integer, Boolean, nil] 对象 ID、布尔结果或空值
|
|
44
|
-
def parse_keys(data)
|
|
45
|
-
case data
|
|
46
|
-
when Hash
|
|
47
|
-
data.empty? ? nil : data[keys][0].to_i
|
|
48
|
-
when TrueClass
|
|
49
|
-
true
|
|
50
|
-
when FalseClass
|
|
51
|
-
false
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
end
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class ZabbixManager
|
|
4
|
-
class Basic
|
|
5
|
-
# 使用 ZabbixManager 客户端初始化基础资源对象。
|
|
6
|
-
#
|
|
7
|
-
# @param client [ZabbixManager::Client] API 客户端
|
|
8
|
-
# @return [ZabbixManager::Basic] 基础资源对象
|
|
9
|
-
def initialize(client)
|
|
10
|
-
@client = client
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# 定义资源对应的 API 方法名占位,要求子类覆盖。
|
|
14
|
-
#
|
|
15
|
-
# @raise [ApiError] 基础类不能直接提供方法名时抛出
|
|
16
|
-
# @return [String] API 方法名
|
|
17
|
-
def method_name
|
|
18
|
-
raise Invalid, "Can't call method_name here"
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# 返回资源创建时使用的默认选项,子类可按需覆盖。
|
|
22
|
-
#
|
|
23
|
-
# @return [Hash] 默认选项
|
|
24
|
-
def default_options
|
|
25
|
-
{}
|
|
26
|
-
end
|
|
27
|
-
|
|
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 字段名
|
|
38
|
-
def key
|
|
39
|
-
"#{method_name}id"
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# 定义资源业务标识字段占位,要求子类覆盖。
|
|
43
|
-
#
|
|
44
|
-
# @raise [ApiError] 基础类不能直接提供标识字段时抛出
|
|
45
|
-
# @return [String] 业务标识字段名
|
|
46
|
-
def identify
|
|
47
|
-
raise Invalid, "Can't call identify here"
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class ZabbixManager
|
|
4
|
-
class Basic
|
|
5
|
-
# 合并默认选项后通过 Zabbix API 创建对象。
|
|
6
|
-
#
|
|
7
|
-
# @param data [Hash] 待创建的对象属性
|
|
8
|
-
# @raise [ApiError] Zabbix API 调用失败时抛出
|
|
9
|
-
# @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
|
|
10
|
-
# @return [Integer] 创建单个对象时返回对象 ID
|
|
11
|
-
# @return [Boolean] 创建多个对象时返回操作结果
|
|
12
|
-
def create(data)
|
|
13
|
-
log "[DEBUG] Call create with parameters: #{data.inspect}"
|
|
14
|
-
|
|
15
|
-
# 判断是否绑定默认选项并重新生成配置
|
|
16
|
-
data_with_default = default_options.empty? ? data : default_options.merge(data)
|
|
17
|
-
data_create = [data_with_default]
|
|
18
|
-
|
|
19
|
-
# 调用实例方法
|
|
20
|
-
result = @client.api_request(method: "#{method_name}.create", params: data_create)
|
|
21
|
-
# 判断是否执行成功并返回结果
|
|
22
|
-
parse_keys result
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# 通过 Zabbix API 删除对象。
|
|
26
|
-
#
|
|
27
|
-
# @param data [Hash] 包含待删除对象的 ID 字段和值
|
|
28
|
-
# @raise [ApiError] Zabbix API 调用失败时抛出
|
|
29
|
-
# @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
|
|
30
|
-
# @return [Integer] 删除单个对象时返回对象 ID
|
|
31
|
-
# @return [Boolean] 删除多个对象时返回操作结果
|
|
32
|
-
def delete(data)
|
|
33
|
-
log "[DEBUG] Call delete with parameters: #{data.inspect}"
|
|
34
|
-
|
|
35
|
-
data_delete = [data]
|
|
36
|
-
result = @client.api_request(method: "#{method_name}.delete", params: data_delete)
|
|
37
|
-
parse_keys result
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# 按业务标识查找对象,存在则更新,否则创建。
|
|
41
|
-
#
|
|
42
|
-
# @param data [Hash] 包含对象业务标识及待写入属性
|
|
43
|
-
# @raise [ApiError] Zabbix API 调用失败时抛出
|
|
44
|
-
# @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
|
|
45
|
-
# @return [Integer] 创建或更新后的对象 ID
|
|
46
|
-
# @return [Boolean] 批量操作时返回操作结果
|
|
47
|
-
def create_or_update(data)
|
|
48
|
-
log "[DEBUG] Call create_or_update with parameters: #{data.inspect}"
|
|
49
|
-
|
|
50
|
-
id = get_id(**identity_filter(data))
|
|
51
|
-
id ? update(data.merge(key.to_sym => id)) : create(data)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# 在属性发生变化或强制更新时通过 Zabbix API 更新对象。
|
|
55
|
-
#
|
|
56
|
-
# @param data [Hash] 包含对象 ID 及待更新属性
|
|
57
|
-
# @param force [Boolean] 属性一致时是否仍强制更新
|
|
58
|
-
# @raise [ApiError] Zabbix API 调用失败时抛出
|
|
59
|
-
# @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
|
|
60
|
-
# @return [Integer] 更新后的对象 ID
|
|
61
|
-
# @return [Boolean] 批量操作时返回操作结果
|
|
62
|
-
def update(data, force = false)
|
|
63
|
-
log "[DEBUG] Call update with parameters: #{data.inspect}"
|
|
64
|
-
dump = {}
|
|
65
|
-
dump_by_id(key.to_sym => data[key.to_sym]).each do |item|
|
|
66
|
-
dump = item.deep_symbolize_keys if item[key].to_i == data[key.to_sym].to_i
|
|
67
|
-
end
|
|
68
|
-
if hash_equals?(dump, data) && !force
|
|
69
|
-
log "[DEBUG] Equal keys #{dump} and #{data}, skip update"
|
|
70
|
-
data[key.to_sym].to_i
|
|
71
|
-
else
|
|
72
|
-
data_update = [data]
|
|
73
|
-
result = @client.api_request(method: "#{method_name}.update", params: data_update)
|
|
74
|
-
parse_keys result
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# 按业务标识从 Zabbix API 获取对象扩展数据。
|
|
79
|
-
#
|
|
80
|
-
# @param data [Hash] 包含对象业务标识字段及其值
|
|
81
|
-
# @raise [ApiError] Zabbix API 调用失败时抛出
|
|
82
|
-
# @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
|
|
83
|
-
# @return [Hash] 对象扩展数据
|
|
84
|
-
def get_full_data(data)
|
|
85
|
-
log "[DEBUG] Call get_full_data with parameters: #{data.inspect}"
|
|
86
|
-
|
|
87
|
-
@client.api_request(
|
|
88
|
-
method: "#{method_name}.get",
|
|
89
|
-
params: {
|
|
90
|
-
filter: {
|
|
91
|
-
identify.to_sym => data[identify.to_sym]
|
|
92
|
-
},
|
|
93
|
-
output: "extend"
|
|
94
|
-
}
|
|
95
|
-
)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# 将调用方参数直接传给对应的 Zabbix get 方法。
|
|
99
|
-
#
|
|
100
|
-
# @param data [Hash] 原始查询参数
|
|
101
|
-
# @raise [ApiError] Zabbix API 调用失败时抛出
|
|
102
|
-
# @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
|
|
103
|
-
# @return [Hash] API 返回数据
|
|
104
|
-
def get_raw(data)
|
|
105
|
-
log "[DEBUG] Call get_raw with parameters: #{data.inspect}"
|
|
106
|
-
|
|
107
|
-
@client.api_request(
|
|
108
|
-
method: "#{method_name}.get",
|
|
109
|
-
params: data
|
|
110
|
-
)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# 按对象 ID 字段从 Zabbix API 获取扩展数据。
|
|
114
|
-
#
|
|
115
|
-
# @param data [Hash] 包含对象 ID 字段及其值
|
|
116
|
-
# @raise [ApiError] Zabbix API 调用失败时抛出
|
|
117
|
-
# @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
|
|
118
|
-
# @return [Hash] 对象扩展数据
|
|
119
|
-
def dump_by_id(data)
|
|
120
|
-
log "[DEBUG] Call dump_by_id with parameters: #{data.inspect}"
|
|
121
|
-
|
|
122
|
-
@client.api_request(
|
|
123
|
-
method: "#{method_name}.get",
|
|
124
|
-
params: {
|
|
125
|
-
filter: {
|
|
126
|
-
key.to_sym => data[key.to_sym]
|
|
127
|
-
},
|
|
128
|
-
output: "extend"
|
|
129
|
-
}
|
|
130
|
-
)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
# 获取当前资源的全部对象,并返回业务标识到 ID 的映射。
|
|
134
|
-
#
|
|
135
|
-
# @raise [ApiError] Zabbix API 调用失败时抛出
|
|
136
|
-
# @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
|
|
137
|
-
# @return [Hash] 业务标识到对象 ID 的映射
|
|
138
|
-
def all
|
|
139
|
-
result = {}
|
|
140
|
-
@client.api_request(
|
|
141
|
-
method: "#{method_name}.get",
|
|
142
|
-
params: { output: "extend" }
|
|
143
|
-
).each do |item|
|
|
144
|
-
result[item[identify]] = item[key]
|
|
145
|
-
end
|
|
146
|
-
result
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
# 按业务标识精确查询对象 ID,并拒绝歧义结果。
|
|
150
|
-
#
|
|
151
|
-
# @param data [Hash] 业务标识过滤条件
|
|
152
|
-
# @raise [ApiError] API 调用失败、缺少标识字段或结果不唯一时抛出
|
|
153
|
-
# @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
|
|
154
|
-
# @return [Integer, nil] Zabbix 对象 ID,未找到时返回空值
|
|
155
|
-
def get_id(data)
|
|
156
|
-
log "[DEBUG] Call get_id with parameters: #{data.inspect}"
|
|
157
|
-
|
|
158
|
-
data = data.deep_symbolize_keys
|
|
159
|
-
# 缺少业务标识字段时立即终止查询
|
|
160
|
-
name = data[identify.to_sym]
|
|
161
|
-
raise Invalid, "#{identify} not supplied in call to get_id" if name.nil?
|
|
162
|
-
|
|
163
|
-
result = @client.api_request(
|
|
164
|
-
method: "#{method_name}.get",
|
|
165
|
-
params: {
|
|
166
|
-
filter: data,
|
|
167
|
-
output: [key, identify]
|
|
168
|
-
}
|
|
169
|
-
)
|
|
170
|
-
matches = result.select { |item| item[identify].to_s == name.to_s }
|
|
171
|
-
raise Conflict, "multiple #{method_name} objects match #{identify}=#{name}" if matches.length > 1
|
|
172
|
-
|
|
173
|
-
matches.first&.fetch(key, nil)&.to_i
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
# 按业务标识获取对象,不存在时创建。
|
|
177
|
-
#
|
|
178
|
-
# @param data [Hash] 包含对象业务标识及待创建属性
|
|
179
|
-
# @raise [ApiError] Zabbix API 调用失败时抛出
|
|
180
|
-
# @raise [TransportError] Zabbix 服务端返回非 200 状态时抛出
|
|
181
|
-
# @return [Integer] Zabbix 对象 ID
|
|
182
|
-
def get_or_create(data)
|
|
183
|
-
log "[DEBUG] Call get_or_create with parameters: #{data.inspect}"
|
|
184
|
-
|
|
185
|
-
unless (id = get_id(**identity_filter(data)))
|
|
186
|
-
id = create(data)
|
|
187
|
-
end
|
|
188
|
-
id
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
# 提取通用获取或写入操作使用的远端业务标识。
|
|
192
|
-
#
|
|
193
|
-
# @param data [Hash] 对象属性
|
|
194
|
-
# @return [Hash] 业务标识过滤条件
|
|
195
|
-
def identity_filter(data)
|
|
196
|
-
attributes = data.deep_symbolize_keys
|
|
197
|
-
{ identify.to_sym => attributes.fetch(identify.to_sym) }
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
# 使用原始参数直接创建 Zabbix 对象。
|
|
201
|
-
#
|
|
202
|
-
# @param data [Hash, Array] 原始创建参数
|
|
203
|
-
# @return [Object] API 返回结果
|
|
204
|
-
def create_raw(data)
|
|
205
|
-
log "[DEBUG] Call create_raw with parameters: #{data.inspect}"
|
|
206
|
-
# 请求创建数据
|
|
207
|
-
@client.api_request(
|
|
208
|
-
method: "#{method_name}.create",
|
|
209
|
-
params: data
|
|
210
|
-
)
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
# 使用原始参数直接更新 Zabbix 对象。
|
|
214
|
-
#
|
|
215
|
-
# @param data [Hash, Array] 原始更新参数
|
|
216
|
-
# @return [Object] API 返回结果
|
|
217
|
-
def update_raw(data)
|
|
218
|
-
log "[DEBUG] Call update_raw with parameters: #{data.inspect}"
|
|
219
|
-
# 请求创建数据
|
|
220
|
-
@client.api_request(
|
|
221
|
-
method: "#{method_name}.update",
|
|
222
|
-
params: data
|
|
223
|
-
)
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
# 使用原始参数直接删除 Zabbix 对象。
|
|
227
|
-
#
|
|
228
|
-
# @param data [Hash, Array] 原始删除参数
|
|
229
|
-
# @return [Object] API 返回结果
|
|
230
|
-
def delete_raw(data)
|
|
231
|
-
log "[DEBUG] Call delete_raw with parameters: #{data.inspect}"
|
|
232
|
-
# 请求创建数据
|
|
233
|
-
@client.api_request(
|
|
234
|
-
method: "#{method_name}.delete",
|
|
235
|
-
params: data
|
|
236
|
-
)
|
|
237
|
-
end
|
|
238
|
-
end
|
|
239
|
-
end
|
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class ZabbixManager
|
|
4
|
-
# 封装高频使用的 Zabbix 主机接口查询与幂等更新。
|
|
5
|
-
class HostInterfaces < Basic
|
|
6
|
-
# 返回对应的 Zabbix API 模块名。
|
|
7
|
-
# @return [String]
|
|
8
|
-
def method_name
|
|
9
|
-
"hostinterface"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# 返回接口对象的主键字段。
|
|
13
|
-
# @return [String]
|
|
14
|
-
def key
|
|
15
|
-
"interfaceid"
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# 使用接口 ID 作为通用查询标识。
|
|
19
|
-
# @return [String]
|
|
20
|
-
def identify
|
|
21
|
-
"interfaceid"
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# 查询指定主机的全部接口,可选择同时返回关联监控项。
|
|
25
|
-
# @return [Array<Hash>]
|
|
26
|
-
def for_host(hostid, select_items: nil)
|
|
27
|
-
raise Invalid, "hostid is required" if hostid.blank?
|
|
28
|
-
|
|
29
|
-
params = { hostids: hostid, output: "extend" }
|
|
30
|
-
params[:selectItems] = select_items if select_items
|
|
31
|
-
@client.api_request(method: "hostinterface.get", params: params)
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# 规范化并校验接口定义,不执行远端查询或写入。
|
|
35
|
-
# @return [Array<Hash>]
|
|
36
|
-
def validate(interfaces)
|
|
37
|
-
desired = Array.wrap(interfaces).map { |interface| normalize_definition(interface) }
|
|
38
|
-
validate_definitions!(desired)
|
|
39
|
-
desired
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# 校验 host.create 中全部接口的创建必填合同。
|
|
43
|
-
# @return [Array<Hash>]
|
|
44
|
-
def validate_for_create(interfaces)
|
|
45
|
-
validate(interfaces).each { |attributes| validate_create_definition!(attributes) }
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# 幂等创建或更新一个主机的接口集合。
|
|
49
|
-
# @return [Array<Integer>]
|
|
50
|
-
def reconcile_for_host(hostid:, interfaces:)
|
|
51
|
-
@client.with_upsert_lock("host-interfaces:#{hostid}") do
|
|
52
|
-
plan = plan_for_host(hostid: hostid, interfaces: interfaces)
|
|
53
|
-
apply_plan(hostid: hostid, plan: plan)
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# 删除明确指定的主机接口;关联监控项由 Zabbix 按官方规则处理。
|
|
58
|
-
# @return [Array<Integer>]
|
|
59
|
-
def delete_many(hostid:, interfaceids:)
|
|
60
|
-
ids = Array(interfaceids).filter_map { |value| value.to_s.strip.presence }.uniq
|
|
61
|
-
raise Invalid, "interfaceids are required" if ids.empty?
|
|
62
|
-
|
|
63
|
-
owned_ids = for_host(hostid).map { |interface| interface.fetch("interfaceid").to_s }
|
|
64
|
-
foreign_ids = ids - owned_ids
|
|
65
|
-
raise Conflict, "interfaces do not belong to host #{hostid}: #{foreign_ids.join(", ")}" if foreign_ids.any?
|
|
66
|
-
|
|
67
|
-
result = @client.api_request(method: "hostinterface.delete", params: ids)
|
|
68
|
-
Array(result.fetch("interfaceids")).map(&:to_i)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
private
|
|
72
|
-
|
|
73
|
-
# 预先校验并生成仅供当前对象执行的接口变更计划。
|
|
74
|
-
def plan_for_host(hostid:, interfaces:)
|
|
75
|
-
desired = validate(interfaces)
|
|
76
|
-
existing = for_host(hostid)
|
|
77
|
-
desired.map { |attributes| [attributes, matching_interface(existing, attributes)] }
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# 执行内部生成的接口变更计划,避免调用方伪造跨主机接口 ID。
|
|
81
|
-
def apply_plan(hostid:, plan:)
|
|
82
|
-
plan.map do |attributes, current|
|
|
83
|
-
current ? update_interface(attributes, current) : create_interface(hostid, attributes)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# 把接口字段递归转换为统一符号键。
|
|
88
|
-
def normalize_definition(interface)
|
|
89
|
-
interface.deep_symbolize_keys
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# 校验新接口的通用字段及 SNMP 条件字段。
|
|
93
|
-
def validate_create_definition!(attributes)
|
|
94
|
-
attributes[:ip] = "" unless attributes.key?(:ip)
|
|
95
|
-
attributes[:dns] = "" unless attributes.key?(:dns)
|
|
96
|
-
interface_identity(attributes)
|
|
97
|
-
validate_snmp_details!(attributes) if attributes[:type].to_i == 2
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# 校验 SNMP 版本和 v1/v2c community 必填合同。
|
|
101
|
-
def validate_snmp_details!(attributes)
|
|
102
|
-
details = attributes[:details]&.deep_symbolize_keys
|
|
103
|
-
raise Invalid, "SNMP interface details are required" unless details
|
|
104
|
-
|
|
105
|
-
version = Integer(details[:version])
|
|
106
|
-
raise Invalid, "SNMP interface version must be 1, 2, or 3" unless [1, 2, 3].include?(version)
|
|
107
|
-
if [1, 2].include?(version) && details[:community].blank?
|
|
108
|
-
raise Invalid, "SNMP v1/v2 interface community is required"
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
attributes[:details] = details
|
|
112
|
-
rescue ArgumentError, TypeError
|
|
113
|
-
raise Invalid, "SNMP interface version must be 1, 2, or 3"
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
# 校验期望接口是否包含重复身份。
|
|
117
|
-
# @return [void]
|
|
118
|
-
# @api private
|
|
119
|
-
def validate_definitions!(interfaces)
|
|
120
|
-
identities = interfaces.map { |interface| interface_identity(interface) }
|
|
121
|
-
duplicate = identities.tally.find { |_identity, count| count > 1 }&.first
|
|
122
|
-
raise Invalid, "duplicate desired interface identity #{duplicate}" if duplicate
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# 按显式 ID 或稳定端点身份匹配已有接口。
|
|
126
|
-
# @return [Hash, nil]
|
|
127
|
-
# @api private
|
|
128
|
-
def matching_interface(existing, attributes)
|
|
129
|
-
if attributes[:interfaceid]
|
|
130
|
-
match = existing.find { |item| item["interfaceid"].to_s == attributes[:interfaceid].to_s }
|
|
131
|
-
raise Invalid, "interfaceid #{attributes[:interfaceid]} does not belong to this host" unless match
|
|
132
|
-
|
|
133
|
-
return match
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
candidates = existing.select { |item| endpoint_identity(item) == endpoint_identity(attributes) }
|
|
137
|
-
raise Conflict, "interface identity is ambiguous; provide interfaceid" if candidates.length > 1
|
|
138
|
-
|
|
139
|
-
candidates.first
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# 生成不依赖数组顺序的接口身份。
|
|
143
|
-
# @return [String]
|
|
144
|
-
# @api private
|
|
145
|
-
def interface_identity(attributes)
|
|
146
|
-
values = attributes.with_indifferent_access
|
|
147
|
-
return "id:#{values[:interfaceid]}" if values[:interfaceid].present?
|
|
148
|
-
|
|
149
|
-
endpoint_identity(values)
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
# 使用类型、端点和端口匹配接口,不把可变的 main 或远端 ID 作为端点身份。
|
|
153
|
-
def endpoint_identity(attributes)
|
|
154
|
-
values = attributes.with_indifferent_access
|
|
155
|
-
|
|
156
|
-
%i[type main useip port].each do |field|
|
|
157
|
-
raise Invalid, "interface #{field} is required" if values[field].blank?
|
|
158
|
-
end
|
|
159
|
-
endpoint_field = values[:useip].to_i == 1 ? :ip : :dns
|
|
160
|
-
raise Invalid, "interface #{endpoint_field} is required" if values[endpoint_field].blank?
|
|
161
|
-
|
|
162
|
-
"endpoint:#{values[:type]}:#{values[:useip]}:#{values[endpoint_field]}:#{values[:port]}"
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
# 更新已属于目标主机的接口。
|
|
166
|
-
# @return [Integer]
|
|
167
|
-
# @api private
|
|
168
|
-
def update_interface(attributes, current)
|
|
169
|
-
interfaceid = current.fetch("interfaceid")
|
|
170
|
-
@client.api_request(
|
|
171
|
-
method: "hostinterface.update",
|
|
172
|
-
params: attributes.except(:hostid).merge(interfaceid: interfaceid)
|
|
173
|
-
)
|
|
174
|
-
interfaceid.to_i
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
# 为目标主机创建缺失接口。
|
|
178
|
-
# @return [Integer]
|
|
179
|
-
# @api private
|
|
180
|
-
def create_interface(hostid, attributes)
|
|
181
|
-
validate_create_definition!(attributes)
|
|
182
|
-
result = @client.api_request(
|
|
183
|
-
method: "hostinterface.create",
|
|
184
|
-
params: attributes.except(:interfaceid).merge(hostid: hostid)
|
|
185
|
-
)
|
|
186
|
-
result.fetch("interfaceids").first.to_i
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
end
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
class ZabbixManager
|
|
4
|
-
class Usergroups < Basic
|
|
5
|
-
# 返回 Zabbix API 中用户组对象的方法名前缀。
|
|
6
|
-
#
|
|
7
|
-
# @return [String] 用户组对象的方法名前缀
|
|
8
|
-
def method_name
|
|
9
|
-
"usergroup"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
# 返回用户组对象的主键字段名。
|
|
13
|
-
#
|
|
14
|
-
# @return [String] 用户组对象的主键字段名
|
|
15
|
-
def key
|
|
16
|
-
"usrgrpid"
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# 返回用于唯一识别用户组的业务字段名。
|
|
20
|
-
#
|
|
21
|
-
# @return [String] 用户组对象的业务标识字段名
|
|
22
|
-
def identify
|
|
23
|
-
"name"
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# 更新用户组对主机组的访问权限。
|
|
27
|
-
#
|
|
28
|
-
# @param data [Hash] 包含 usrgrpid、hostgroupids 及可选 permission
|
|
29
|
-
# @raise [ApiError] Zabbix API 返回业务错误时抛出
|
|
30
|
-
# @raise [TransportError] Zabbix 服务返回非成功 HTTP 状态时抛出
|
|
31
|
-
# @return [Integer, nil] 已更新用户组的 ID
|
|
32
|
-
def permissions(data)
|
|
33
|
-
permission = data[:permission] || 2
|
|
34
|
-
result = @client.api_request(
|
|
35
|
-
method: "usergroup.update",
|
|
36
|
-
params: {
|
|
37
|
-
usrgrpid: data[:usrgrpid],
|
|
38
|
-
rights: data[:hostgroupids].map { |t| { permission: permission, id: t } }
|
|
39
|
-
}
|
|
40
|
-
)
|
|
41
|
-
result ? result["usrgrpids"][0].to_i : nil
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# 将用户加入用户组;兼容旧调用并委托给 update_users。
|
|
45
|
-
#
|
|
46
|
-
# @deprecated Zabbix 已移除 massAdd,请使用 update_users。
|
|
47
|
-
# @param data [Hash] 包含 userids 和 usrgrpids
|
|
48
|
-
# @raise [ApiError] Zabbix API 返回业务错误时抛出
|
|
49
|
-
# @raise [TransportError] Zabbix 服务返回非成功 HTTP 状态时抛出
|
|
50
|
-
# @return [Integer, nil] 已更新用户组的 ID
|
|
51
|
-
def add_user(data)
|
|
52
|
-
update_users(data)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# 批量替换指定用户组中的用户列表。
|
|
56
|
-
#
|
|
57
|
-
# @param data [Hash] 包含 userids 和 usrgrpids
|
|
58
|
-
# @raise [ApiError] Zabbix API 返回业务错误时抛出
|
|
59
|
-
# @raise [TransportError] Zabbix 服务返回非成功 HTTP 状态时抛出
|
|
60
|
-
# @return [Integer, nil] 首个已更新用户组的 ID
|
|
61
|
-
def update_users(data)
|
|
62
|
-
user_groups = data[:usrgrpids].map do |t|
|
|
63
|
-
{
|
|
64
|
-
usrgrpid: t,
|
|
65
|
-
userids: data[:userids]
|
|
66
|
-
}
|
|
67
|
-
end
|
|
68
|
-
result = @client.api_request(
|
|
69
|
-
method: "usergroup.update",
|
|
70
|
-
params: user_groups
|
|
71
|
-
)
|
|
72
|
-
result ? result["usrgrpids"][0].to_i : nil
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|