Class: ZabbixManager::Client
- Inherits:
-
Object
- Object
- ZabbixManager::Client
- Defined in:
- lib/zabbix_manager/client.rb
Constant Summary collapse
- SUPPORTED_MAJOR_VERSIONS =
(4..7).freeze
- UNAUTHENTICATED_METHODS =
%w[apiinfo.version user.login].freeze
- BLANK_NORMALIZED_OPTIONS =
%i[api_token username user password http_user http_password].freeze
- UPSERT_MUTEX_STRIPES =
64- DEFAULT_UNCERTAIN_WRITE_DELAYS =
[0, 0.25, 1, 2].freeze
Instance Attribute Summary collapse
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#sanitized_options ⇒ Object
readonly
Returns the value of attribute sanitized_options.
Instance Method Summary collapse
-
#_request(body) ⇒ Object
解析 JSON-RPC 响应并统一转换协议错误。.
-
#api_request(body) ⇒ Object
(also: #manager_request)
执行 Zabbix JSON-RPC 方法并记录脱敏耗时日志。.
-
#api_version ⇒ String
返回首次查询后缓存的远端 Zabbix API 版本。.
-
#auth ⇒ String
使用用户名和密码创建 Zabbix 会话。.
-
#close ⇒ Object
关闭持久 HTTP 连接。.
-
#debug? ⇒ Boolean
判断是否启用调试日志。.
-
#http_request(body) ⇒ String
通过持久连接发送请求,并按版本加入 Bearer 令牌。.
-
#id ⇒ Integer
分配线程安全的 JSON-RPC 请求编号。.
-
#initialize(options = {}) ⇒ Client
constructor
构建按服务端版本选择认证方式并复用 HTTP 会话的客户端。.
-
#inspect ⇒ String
返回不包含凭据的客户端摘要,避免对象检查时泄漏配置.
-
#log(level, event, data = {}) ⇒ void
输出结构化且已脱敏的客户端事件。.
-
#logout ⇒ Object
注销用户名会话并关闭持久连接;API 令牌无需远端注销。.
-
#message_json(body) ⇒ String
序列化 JSON-RPC 请求并按版本加入请求体认证。.
-
#pretty_body(body) ⇒ String
格式化请求摘要并隐藏全部参数值。.
-
#with_upsert_lock(key, &block) ⇒ Object
以业务键串行执行幂等写入,并可接入跨进程锁实现.
Constructor Details
#initialize(options = {}) ⇒ Client
构建按服务端版本选择认证方式并复用 HTTP 会话的客户端。
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/zabbix_manager/client.rb', line 19 def initialize( = {}) @raw_options = () validate_credentials! validate_uncertain_write_delays! @sanitized_options = (@raw_options).freeze @options = @sanitized_options @logger = build_logger @id_mutex = Mutex.new @next_id = 0 @upsert_mutexes = Array.new(UPSERT_MUTEX_STRIPES) { Mutex.new } validate_upsert_lock! @transport = HttpTransport.new(@raw_options) validate_token_transport! @api_version = api_version validate_api_version! validate_http_auth_compatibility! @credential_type = @raw_options[:api_token] ? :api_token : :user_session @auth_token = @raw_options[:api_token] || auth log(:info, "client.connected", version: @api_version, credential_type: @credential_type) log(:warn, "tls.verification_disabled", url: @transport.safe_url) if insecure_https? log(:warn, "token.sent_over_http", url: @transport.safe_url) if insecure_token_transport? rescue StandardError @transport&.close raise end |
Instance Attribute Details
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
14 15 16 |
# File 'lib/zabbix_manager/client.rb', line 14 def logger @logger end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
14 15 16 |
# File 'lib/zabbix_manager/client.rb', line 14 def @options end |
#sanitized_options ⇒ Object (readonly)
Returns the value of attribute sanitized_options.
14 15 16 |
# File 'lib/zabbix_manager/client.rb', line 14 def @sanitized_options end |
Instance Method Details
#_request(body) ⇒ Object
解析 JSON-RPC 响应并统一转换协议错误。
105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/zabbix_manager/client.rb', line 105 def _request(body) parsed = JSON.parse(http_request(body)) raise_api_error(parsed, body) if parsed["error"] unless parsed.key?("result") raise ApiError.new("Invalid JSON-RPC response: missing result", LogSanitizer.sanitize(parsed)) end parsed["result"] rescue JSON::ParserError => e raise ApiError, "Invalid JSON response: #{e.}" end |
#api_request(body) ⇒ Object Also known as: manager_request
执行 Zabbix JSON-RPC 方法并记录脱敏耗时日志。
129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/zabbix_manager/client.rb', line 129 def api_request(body) method = fetch_body_value(body, :method) started_at = monotonic_time log(:debug, "request.started", method: method) result = _request((body)) log(:info, "request.completed", method: method, duration_ms: elapsed_ms(started_at)) result rescue StandardError => e log(:warn, "request.failed", method: method, duration_ms: elapsed_ms(started_at), error: e.class.name) raise end |
#api_version ⇒ String
返回首次查询后缓存的远端 Zabbix API 版本。
55 56 57 |
# File 'lib/zabbix_manager/client.rb', line 55 def api_version @api_version ||= api_request(method: "apiinfo.version", params: {}) end |
#auth ⇒ String
使用用户名和密码创建 Zabbix 会话。
62 63 64 65 66 67 68 69 70 |
# File 'lib/zabbix_manager/client.rb', line 62 def auth api_request( method: "user.login", params: { login_parameter => username, password: @raw_options[:password] } ) end |
#close ⇒ Object
关闭持久 HTTP 连接。
156 157 158 |
# File 'lib/zabbix_manager/client.rb', line 156 def close @transport.close end |
#debug? ⇒ Boolean
判断是否启用调试日志。
75 76 77 |
# File 'lib/zabbix_manager/client.rb', line 75 def debug? @raw_options[:debug] == true end |
#http_request(body) ⇒ String
通过持久连接发送请求,并按版本加入 Bearer 令牌。
97 98 99 100 |
# File 'lib/zabbix_manager/client.rb', line 97 def http_request(body) method = JSON.parse(body).fetch("method") @transport.request(body, bearer_token: bearer_token_for(method)) end |
#id ⇒ Integer
分配线程安全的 JSON-RPC 请求编号。
48 49 50 |
# File 'lib/zabbix_manager/client.rb', line 48 def id @id_mutex.synchronize { @next_id += 1 } end |
#inspect ⇒ String
返回不包含凭据的客户端摘要,避免对象检查时泄漏配置
174 175 176 |
# File 'lib/zabbix_manager/client.rb', line 174 def inspect "#<#{self.class} options=#{@sanitized_options.inspect}>" end |
#log(level, event, data = {}) ⇒ void
This method returns an undefined value.
输出结构化且已脱敏的客户端事件。
163 164 165 166 167 168 169 |
# File 'lib/zabbix_manager/client.rb', line 163 def log(level, event, data = {}) return unless @logger sanitized = LogSanitizer.sanitize(data) details = sanitized.map { |key, value| "#{key}=#{value.inspect}" }.join(" ") @logger.public_send(level, ["[zabbix_manager]", event, details].reject(&:empty?).join(" ")) end |
#logout ⇒ Object
注销用户名会话并关闭持久连接;API 令牌无需远端注销。
145 146 147 148 149 150 151 |
# File 'lib/zabbix_manager/client.rb', line 145 def logout result = @credential_type == :user_session && @auth_token ? api_request(method: "user.logout", params: []) : true result ensure @auth_token = nil close end |
#message_json(body) ⇒ String
序列化 JSON-RPC 请求并按版本加入请求体认证。
82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/zabbix_manager/client.rb', line 82 def (body) method = fetch_body_value(body, :method) = { method: method, params: fetch_body_value(body, :params) || {}, id: id, jsonrpc: "2.0" } [:auth] = @auth_token if @auth_token && body_authentication?(method) JSON.generate() end |
#pretty_body(body) ⇒ String
格式化请求摘要并隐藏全部参数值。
120 121 122 123 124 |
# File 'lib/zabbix_manager/client.rb', line 120 def pretty_body(body) parsed = JSON.parse(body) parsed["params"] = LogSanitizer::REDACTED if parsed.key?("params") JSON.pretty_generate(LogSanitizer.sanitize(parsed)) end |
#with_upsert_lock(key, &block) ⇒ Object
以业务键串行执行幂等写入,并可接入跨进程锁实现
181 182 183 184 185 186 187 |
# File 'lib/zabbix_manager/client.rb', line 181 def with_upsert_lock(key, &block) mutex = @upsert_mutexes[key.hash % UPSERT_MUTEX_STRIPES] mutex.synchronize do coordinator = @raw_options[:upsert_lock] coordinator ? coordinator.call(key, &block) : yield end end |