UNPKG

zabbix-utils

Version:

TypeScript port of zabbix-utils - Python library for working with Zabbix API, Sender, and Getter protocols

377 lines 15.8 kB
"use strict"; // zabbix_utils // // Copyright (C) 2001-2023 Zabbix SIA (Original Python library) // Copyright (C) 2024-2025 Han Yong Lim <hanyong.lim@gmail.com> (TypeScript adaptation) // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, // merge, publish, distribute, sublicense, and/or sell copies // of the Software, and to permit persons to whom the Software // is furnished to do so, subject to the following conditions: var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ZabbixAPI = exports.APIObject = void 0; // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. const axios_1 = __importDefault(require("axios")); const https = __importStar(require("https")); const uuid_1 = require("uuid"); const types_1 = require("./types"); const common_1 = require("./common"); const exceptions_1 = require("./exceptions"); const version_1 = require("./version"); class APIObject { constructor(name, parent) { this.object = name; this.parent = parent; } } exports.APIObject = APIObject; class ZabbixAPI { constructor(options = {}) { this.__useToken = false; const { url = process.env.ZABBIX_URL || 'http://localhost/zabbix/api_jsonrpc.php', token = process.env.ZABBIX_TOKEN, user = process.env.ZABBIX_USER, password = process.env.ZABBIX_PASSWORD, httpUser, httpPassword, skipVersionCheck = false, validateCerts = true, timeout = 30 } = options; this.url = common_1.ModuleUtils.checkUrl(url); this.validateCerts = validateCerts; this.timeout = timeout * 1000; // Convert to milliseconds // HTTP Auth unsupported since Zabbix 7.2 if (httpUser && httpPassword) { this.__basicAuth(httpUser, httpPassword); } this.__checkVersion(skipVersionCheck); // HTTP Auth unsupported since Zabbix 7.2 - but we can't check version yet // This will be checked later when version is available // Note: login() is async and cannot be called from constructor // Users should call login() manually after creating the instance // Return a proxy to handle dynamic method calls return new Proxy(this, { get(target, prop) { if (typeof prop === 'string' && !(prop in target) && !prop.startsWith('__')) { return new Proxy(new APIObject(prop, target), { get(apiObj, method) { if (typeof method === 'string') { return target.__createMethod(prop, method); } return apiObj[method]; } }); } return target[prop]; } }); } __createMethod(objectName, methodName) { return (...args) => { const hasKwargs = args.length > 0 && typeof args[args.length - 1] === 'object' && !Array.isArray(args[args.length - 1]) && args[args.length - 1] !== null; if (args.length > 1 && hasKwargs) { throw new TypeError("Only args or kwargs should be used."); } // Support '_' suffix to avoid conflicts with JavaScript keywords const cleanObjectName = objectName.endsWith('_') ? objectName.slice(0, -1) : objectName; const cleanMethodName = methodName.endsWith('_') ? methodName.slice(0, -1) : methodName; const method = `${cleanObjectName}.${cleanMethodName}`; // Support passing list of ids and params as a dict let params; if (hasKwargs) { params = args[args.length - 1]; } else if (args.length === 1 && (Array.isArray(args[0]) || typeof args[0] === 'object')) { params = args[0]; } else if (args.length > 0) { params = args; } else { params = null; } console.debug(`Executing ${method} method`); const needAuth = !common_1.ModuleUtils.UNAUTH_METHODS.includes(method); return this.sendApiRequest(method, params, needAuth).then(response => response.result); }; } __basicAuth(user, password) { /** * Enable Basic Authentication using. * * @param user - Basic Authentication username. * @param password - Basic Authentication password. */ console.debug(`Enable Basic Authentication with username:${user} password:${common_1.ModuleUtils.HIDING_MASK}`); this.__basicCred = Buffer.from(`${user}:${password}`).toString('base64'); } /** * Return object of Zabbix API version. * * @returns Object of Zabbix API version */ async apiVersion() { if (!this.__version) { const versionResponse = await this.sendApiRequest('apiinfo.version', null, false); this.__version = new types_1.APIVersion(versionResponse.result); } return this.__version; } /** * Return object of Zabbix API version. * * @returns Object of Zabbix API version. */ get version() { if (!this.__version) { throw new exceptions_1.ProcessingError("Version not initialized. Call apiVersion() first."); } return this.__version; } /** * Login to Zabbix API. * * @param token - Zabbix API token. Defaults to `null`. * @param user - Zabbix API username. Defaults to `null`. * @param password - Zabbix API user's password. Defaults to `null`. */ async login(token, user, password) { // Ensure version is fetched first if (!this.__version) { await this.apiVersion(); } // Check if HTTP auth is supported for this version if (this.version.greaterThan(7.0) && this.__basicCred) { throw new exceptions_1.APINotSupported("HTTP authentication unsupported since Zabbix 7.2."); } if (token) { if (this.version.lessThan(5.4)) { throw new exceptions_1.APINotSupported("Token usage", this.version.toString()); } if (user || password) { throw new exceptions_1.ProcessingError("Token cannot be used with username and password"); } this.__useToken = true; this.__sessionId = token; return; } if (!user) { throw new exceptions_1.ProcessingError("Username is missing"); } if (!password) { throw new exceptions_1.ProcessingError("User password is missing"); } let userCred; if (this.version.lessThan(5.4)) { userCred = { user: user, password: password }; } else { userCred = { username: user, password: password }; } console.debug(`Login to Zabbix API using username:${user} password:${common_1.ModuleUtils.HIDING_MASK}`); this.__useToken = false; const loginResponse = await this.sendApiRequest('user.login', userCred, false); this.__sessionId = loginResponse.result; console.debug(`Connected to Zabbix API version ${this.version}: ${this.url}`); } /** * Logout from Zabbix API. */ async logout() { if (this.__sessionId) { if (this.__useToken) { this.__sessionId = undefined; this.__useToken = false; return; } console.debug("Logout from Zabbix API"); await this.sendApiRequest('user.logout', {}, true); this.__sessionId = undefined; } else { console.debug("You're not logged in Zabbix API"); } } /** * Check authentication status in Zabbix API. * * @returns User authentication status (`true`, `false`) */ async checkAuth() { if (!this.__sessionId) { console.debug("You're not logged in Zabbix API"); return false; } let refreshResp; if (this.__useToken) { console.debug("Check auth session using token in Zabbix API"); refreshResp = await this.sendApiRequest('user.checkAuthentication', { token: this.__sessionId }, false); } else { console.debug("Check auth session using sessionid in Zabbix API"); refreshResp = await this.sendApiRequest('user.checkAuthentication', { sessionid: this.__sessionId }, false); } return Boolean(refreshResp.result?.userid); } /** * Function for sending request to Zabbix API. * * @param method - Zabbix API method name. * @param params - Params for request body. Defaults to `null`. * @param needAuth - Authorization using flag. Defaults to `false`. * @returns Dictionary with Zabbix API response. */ async sendApiRequest(method, params = null, needAuth = true) { const requestJson = { jsonrpc: '2.0', method: method, params: params || {}, id: (0, uuid_1.v4)(), }; const headers = { 'Accept': 'application/json', 'Content-Type': 'application/json-rpc', 'User-Agent': `zabbix-utils/${version_1.__version__}` }; if (needAuth) { if (!this.__sessionId) { throw new exceptions_1.ProcessingError("You're not logged in Zabbix API"); } // Ensure version is available for auth logic if (!this.__version) { await this.apiVersion(); } // For Zabbix 7.2+, always use Authorization header if (this.version.greaterThanOrEqual(7.2)) { headers["Authorization"] = `Bearer ${this.__sessionId}`; } // For token-based authentication, use Bearer header (Zabbix 6.4+) else if (this.__useToken) { headers["Authorization"] = `Bearer ${this.__sessionId}`; } // For session-based authentication on older versions, use auth field else { requestJson.auth = this.__sessionId; } } if (this.__basicCred) { headers["Authorization"] = `Basic ${this.__basicCred}`; } console.debug(`Sending request to ${this.url} with body:`, requestJson); const config = { method: 'POST', url: this.url, data: requestJson, headers: headers, timeout: this.timeout, }; // Disable SSL certificate validation if needed. if (!this.validateCerts) { config.httpsAgent = new https.Agent({ rejectUnauthorized: false }); } try { const response = await (0, axios_1.default)(config); const respJson = response.data; if (!common_1.ModuleUtils.FILES_METHODS.includes(method)) { console.debug("Received response body:", respJson); } else { const debugJson = { ...respJson }; if (debugJson.result) { debugJson.result = debugJson.result.length > 200 ? debugJson.result.slice(0, 197) + '...' : debugJson.result; } console.debug("Received response body (clipped):", JSON.stringify(debugJson, null, 4)); } if ('error' in respJson) { const err = { ...respJson.error }; err.body = { ...requestJson }; throw new exceptions_1.APIRequestError(err); } return respJson; } catch (error) { if (error instanceof exceptions_1.APIRequestError) { throw error; } if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND') { throw new exceptions_1.ProcessingError(`Unable to connect to ${this.url}:`, error.message); } if (error.response?.data) { throw new exceptions_1.ProcessingError("Unable to parse json:", error.response.data); } throw new exceptions_1.ProcessingError("Request failed:", error.message); } } __checkVersion(skipCheck) { const skipCheckHelp = "If you're sure zabbix_utils will work properly with your current " + "Zabbix version you can skip this check by " + "specifying skipVersionCheck=true when create ZabbixAPI object."; // Skip version check if requested or if version not yet fetched if (skipCheck || !this.__version) { return; } if (this.version.lessThan(version_1.__min_supported__)) { console.debug(`Version of Zabbix API [${this.version}] is less than the library supports. ` + "Further library use at your own risk!"); } if (this.version.greaterThan(version_1.__max_supported__)) { console.debug(`Version of Zabbix API [${this.version}] is more than the library was tested on. ` + "Recommended to update the library. Further library use at your own risk!"); } } } exports.ZabbixAPI = ZabbixAPI; //# sourceMappingURL=api.js.map