This update enhances compatibility across multiple Zabbix versions and introduces tools for easier local development and testing. Key improvements and verified version support: - Verified Zabbix version support: 6.2, 6.4, 7.0, and 7.4. - Version-specific feature handling: - `history.push` is enabled only for Zabbix 7.0+; older versions skip it with a clear error or notice. - Conditional JSON-RPC authentication: the `auth` field is automatically added to the request body for versions older than 6.4. - Implemented static Zabbix version caching in the datasource to minimize redundant API calls. - Query optimization refinements: - Added mapping for implied fields (e.g., `state` -> `items`, `deviceType` -> `tags`). - Automatically prune unnecessary Zabbix parameters (like `selectItems` or `selectTags`) when not requested. - Local development environment: - Added a new `zabbix-local` Docker Compose profile that includes PostgreSQL, Zabbix Server, and Zabbix Web. - Supports testing different versions by passing the `ZABBIX_VERSION` environment variable (e.g., 6.2, 6.4, 7.0, 7.4). - Provided a sample environment file at `samples/zabbix-local.env`. - Documentation and Roadmap: - Updated README with a comprehensive version compatibility matrix and local environment instructions. - Created a new guide: `docs/howtos/local_development.md`. - Updated maintenance guides and added "Local Development Environment" as an achieved milestone in the roadmap. - Test suite enhancements: - Improved Smoketest and RegressionTest executors with more reliable resource cleanup and error reporting. - Made tests version-aware to prevent failures on older Zabbix instances. BREAKING CHANGE: Dropped Zabbix 6.0 specific workarounds; the minimum supported version is now 6.2.
114 lines
4.1 KiB
TypeScript
114 lines
4.1 KiB
TypeScript
import {ApiError, SortOrder, StorageItemType} from "../schema/generated/graphql.js";
|
|
import {isZabbixErrorResult, ParsedArgs, ZabbixErrorResult, ZabbixParams, ZabbixRequest, ZabbixResult} from "./zabbix-request.js";
|
|
import {ZabbixAPI} from "./zabbix-api.js";
|
|
import {GraphQLError} from "graphql";
|
|
|
|
export interface ZabbixValue {
|
|
itemid?: string,
|
|
key?: string,
|
|
host?: string,
|
|
value: string,
|
|
clock: number,
|
|
ns: number
|
|
}
|
|
|
|
export interface ZabbixExportValue extends ZabbixValue, ZabbixResult {
|
|
itemid?: string
|
|
}
|
|
|
|
export class ZabbixHistoryGetParams extends ParsedArgs {
|
|
time_from_ms: number | undefined
|
|
time_till_ms: number | undefined
|
|
|
|
constructor(public itemids: number[] | number | string | string[],
|
|
public output: string[] = ["value", "itemid", "clock", "ns"],
|
|
public limit: number | null = Array.isArray(itemids) ? itemids.length : 1,
|
|
public history: StorageItemType | string = StorageItemType.Text,
|
|
time_from?: Date,
|
|
time_until?: Date,
|
|
public sortfield: string[] = ["clock", "ns"],
|
|
public sortorder: SortOrder | null = SortOrder.Desc,
|
|
) {
|
|
super();
|
|
this.time_from_ms = time_from ? Math.floor(new Date(time_from).getTime() / 1000) : undefined
|
|
this.time_till_ms = time_until ? Math.floor(new Date(time_until).getTime() / 1000) : undefined
|
|
}
|
|
}
|
|
|
|
export class ZabbixQueryHistoryRequest extends ZabbixRequest<ZabbixExportValue[], ZabbixHistoryGetParams> {
|
|
constructor(authToken?: string | null, cookie?: string | null) {
|
|
super("history.get", authToken, cookie);
|
|
}
|
|
|
|
createZabbixParams(args?: ZabbixHistoryGetParams): ZabbixParams {
|
|
return {
|
|
itemids: args?.itemids,
|
|
output: args?.output,
|
|
limit: args?.limit,
|
|
history: args?.history?.valueOf(),
|
|
sortfield: args?.sortfield,
|
|
sortorder: args?.sortorder == SortOrder.Asc ? "ASC" : "DESC",
|
|
time_from: args?.time_from_ms,
|
|
time_till: args?.time_till_ms,
|
|
}
|
|
}
|
|
}
|
|
|
|
export interface ZabbixHistoryPushInput {
|
|
timestamp: string
|
|
value: any,
|
|
}
|
|
|
|
export interface ZabbixHistoryPushResult {
|
|
response: string,
|
|
data: { itemid: string, error?: string[] | ApiError }[],
|
|
error?: ApiError | string[]
|
|
}
|
|
|
|
export class ZabbixHistoryPushParams extends ParsedArgs {
|
|
constructor(public values: ZabbixHistoryPushInput[], public itemid?: string,
|
|
public key?: string,
|
|
public host?: string,) {
|
|
super();
|
|
}
|
|
}
|
|
|
|
export class ZabbixHistoryPushRequest extends ZabbixRequest<ZabbixHistoryPushResult, ZabbixHistoryPushParams> {
|
|
constructor(authToken?: string | null, cookie?: string) {
|
|
super("history.push", authToken, cookie);
|
|
}
|
|
|
|
async prepare(zabbixAPI: ZabbixAPI, args?: ZabbixHistoryPushParams): Promise<ZabbixHistoryPushResult | ZabbixErrorResult | undefined> {
|
|
if (!args) return undefined;
|
|
|
|
const version = await zabbixAPI.getVersion();
|
|
if (version < "7.0.0") {
|
|
throw new GraphQLError(`history.push is only supported in Zabbix 7.0.0 and newer. Current version is ${version}. For older versions, please use Zabbix trapper items and zabbix_sender protocol.`);
|
|
}
|
|
|
|
if (!args.itemid && (!args.key || !args.host)) {
|
|
throw new GraphQLError("if itemid is empty both key and host must be filled");
|
|
}
|
|
|
|
return super.prepare(zabbixAPI, args);
|
|
}
|
|
|
|
createZabbixParams(args?: ZabbixHistoryPushParams): ZabbixParams {
|
|
if (!args) return [];
|
|
return args.values.map(v => {
|
|
const date = new Date(v.timestamp);
|
|
const result: any = {
|
|
value: typeof v.value === 'string' ? v.value : JSON.stringify(v.value),
|
|
clock: Math.floor(date.getTime() / 1000),
|
|
ns: (date.getTime() % 1000) * 1000000
|
|
};
|
|
if (args.itemid) {
|
|
result.itemid = args.itemid;
|
|
} else {
|
|
result.host = args.host;
|
|
result.key = args.key;
|
|
}
|
|
return result as ZabbixValue;
|
|
});
|
|
}
|
|
}
|