import { CreateTemplate, CreateTemplateGroup, CreateTemplateGroupResponse, ImportTemplateResponse, InputMaybe } from "../schema/generated/graphql.js"; import {logger} from "../logging/logger.js"; import { ZabbixCreateItemRequest, ZabbixCreateTemplateGroupRequest, ZabbixCreateTemplateRequest, ZabbixQueryTemplateGroupRequest, ZabbixQueryTemplatesRequest, ZabbixQueryTemplateResponse } from "../datasources/zabbix-templates.js"; import {isZabbixErrorResult, ParsedArgs, ZabbixErrorResult} from "../datasources/zabbix-request.js"; import {zabbixAPI} from "../datasources/zabbix-api.js"; /** * Handles importing templates and template groups into Zabbix. */ export class TemplateImporter { /** * Imports template groups into Zabbix. * @param templateGroups - The list of template groups to import. * @param zabbixAuthToken - Optional Zabbix authentication token. * @param cookie - Optional session cookie. * @returns A promise that resolves to an array of import responses. */ public static async importTemplateGroups(templateGroups: InputMaybe> | undefined, zabbixAuthToken?: string, cookie?: string) { if (!templateGroups) { return null } let result: CreateTemplateGroupResponse[] = [] for (let group of templateGroups) { let createGroupResult: { groupids: string[] } | ZabbixErrorResult | undefined = undefined; // Try to find if it exists by name first let groups = await new ZabbixQueryTemplateGroupRequest(zabbixAuthToken, cookie).executeRequestReturnError(zabbixAPI, new ParsedArgs({ filter_name: group.groupName })) let groupid = 0 let message: string | undefined = undefined if (!isZabbixErrorResult(groups) && groups?.length) { groupid = Number(groups[0].groupid) message = `Template group ${group.groupName} already exists with groupid=${groupid} - skipping` logger.debug(message) } else { createGroupResult = await new ZabbixCreateTemplateGroupRequest(zabbixAuthToken, cookie) .executeRequestReturnError(zabbixAPI, new ParsedArgs({ name: group.groupName, uuid: group.uuid })) if (isZabbixErrorResult(createGroupResult)) { let errorMessage = createGroupResult.error.message; if (createGroupResult.error.data) { errorMessage += " " + (typeof createGroupResult.error.data === 'string' ? createGroupResult.error.data : JSON.stringify(createGroupResult.error.data)); } result.push({ groupName: group.groupName, message: `Unable to create template group ${group.groupName}: ${errorMessage}`, error: createGroupResult.error }) continue } else if (createGroupResult?.groupids?.length) { groupid = Number(createGroupResult.groupids[0]) } } if (groupid) { result.push({ groupName: group.groupName, groupid: groupid, message: message }) } else { result.push({ groupName: group.groupName, message: `Unable to create template group ${group.groupName}: Unknown error`, error: { message: "Unknown error - no groupid returned" } }) } } return result } /** * Imports templates into Zabbix, including their items and linked templates. * @param templates - The list of templates to import. * @param zabbixAuthToken - Optional Zabbix authentication token. * @param cookie - Optional session cookie. * @returns A promise that resolves to an array of import responses. */ public static async importTemplates(templates: InputMaybe> | undefined, zabbixAuthToken?: string, cookie?: string) { if (!templates) { return null } let result: ImportTemplateResponse[] = [] for (let template of templates) { // 1. Resolve Group IDs let groupids = template.groupids if (!groupids || groupids.length === 0) { let groups = await new ZabbixQueryTemplateGroupRequest(zabbixAuthToken, cookie).executeRequestReturnError(zabbixAPI, new ParsedArgs({ filter_name: template.groupNames })) if (isZabbixErrorResult(groups) || !groups?.length) { result.push({ host: template.host, message: `Unable to find template groups=${template.groupNames}` }) continue } groupids = groups.map(g => Number(g.groupid)) } // 2. Resolve Linked Templates IDs let linkedTemplates: { templateid: string }[] = [] if (template.templates && template.templates.length > 0) { let templateNames = template.templates.map(t => t.name) let queryResult = await new ZabbixQueryTemplatesRequest(zabbixAuthToken, cookie).executeRequestReturnError(zabbixAPI, new ParsedArgs({ filter_host: templateNames }), ["templateid"]) if (isZabbixErrorResult(queryResult)) { let errorMessage = queryResult.error.message; if (queryResult.error.data) { errorMessage += " " + (typeof queryResult.error.data === 'string' ? queryResult.error.data : JSON.stringify(queryResult.error.data)); } result.push({ host: template.host, message: `Error querying linked templates: ${errorMessage}`, error: queryResult.error }) continue } linkedTemplates = queryResult.map((t: ZabbixQueryTemplateResponse) => ({ templateid: t.templateid })) } // 3. Create Template let templateCreateParams: any = { host: template.host, name: template.name || template.host, groups: groupids.map(id => ({ groupid: id })), uuid: template.uuid, templates: linkedTemplates, tags: template.tags?.map(t => ({ tag: t.tag, value: t.value || "" })), macros: template.macros } let templateImportResult = await new ZabbixCreateTemplateRequest(zabbixAuthToken, cookie) .executeRequestReturnError(zabbixAPI, new ParsedArgs(templateCreateParams)) if (isZabbixErrorResult(templateImportResult) || !templateImportResult?.templateids?.length) { let errorMessage = isZabbixErrorResult(templateImportResult) ? templateImportResult.error.message : "Unknown error"; if (isZabbixErrorResult(templateImportResult) && templateImportResult.error.data) { errorMessage += " " + (typeof templateImportResult.error.data === 'string' ? templateImportResult.error.data : JSON.stringify(templateImportResult.error.data)); } result.push({ host: template.host, message: `Unable to import template=${template.host}: ${errorMessage}`, error: isZabbixErrorResult(templateImportResult) ? templateImportResult.error : undefined }) continue } let templateid = templateImportResult.templateids[0] // 4. Create Items if any if (template.items && template.items.length > 0) { const createdItemKeyToId = new Map(); let itemsToCreate = [...template.items]; let retry = true; while (retry && itemsToCreate.length > 0) { retry = false; const remainingItems: typeof itemsToCreate = []; for (let item of itemsToCreate) { if (item.master_item && !createdItemKeyToId.has(item.master_item.key)) { remainingItems.push(item); continue; } let { key, master_item, ...itemData } = item; let itemCreateParams: any = { ...itemData, key_: key, hostid: templateid, preprocessing: item.preprocessing?.map(p => ({ type: p.type, params: p.params.join("\n"), error_handler: p.error_handler ?? 0, error_handler_params: p.error_handler_params ?? "" })), tags: item.tags?.map(t => ({ tag: t.tag, value: t.value || "" })) } if (master_item) { itemCreateParams.master_itemid = createdItemKeyToId.get(master_item.key); } let itemResult = await new ZabbixCreateItemRequest(zabbixAuthToken, cookie) .executeRequestReturnError(zabbixAPI, new ParsedArgs(itemCreateParams)) if (isZabbixErrorResult(itemResult)) { let errorMessage = itemResult.error.message; if (itemResult.error.data) { errorMessage += " " + (typeof itemResult.error.data === 'string' ? itemResult.error.data : JSON.stringify(itemResult.error.data)); } logger.error(`Unable to create item ${item.name} for template ${template.host}: ${errorMessage}`) } else if (itemResult?.itemids?.length) { createdItemKeyToId.set(key, itemResult.itemids[0]); retry = true; } } itemsToCreate = remainingItems; } if (itemsToCreate.length > 0) { logger.error(`Unable to create ${itemsToCreate.length} items for template ${template.host} due to missing master items: ${itemsToCreate.map(i => i.name).join(", ")}`); } } result.push({ host: template.host, templateid: templateid }) } return result } }