feat: add template and template group management via GraphQL
- Implemented GraphQL endpoints for importing, querying, and deleting Zabbix templates and template groups. - Added support for full template data import, including items, preprocessing steps, tags, and linked templates. - Implemented dependent item support by deferred creation logic in the template importer. - Added ability to query templates and template groups with name pattern filtering (supporting Zabbix wildcards). - Implemented batch deletion for templates and template groups by ID or name pattern. - Improved error reporting by including detailed Zabbix API error data in GraphQL responses. - Added comprehensive unit and integration tests covering all new functionality. - Provided GraphQL sample queries and mutations in the 'docs' directory for all new endpoints.
This commit is contained in:
parent
e641f8e610
commit
a3ed4886a3
22 changed files with 2450 additions and 20 deletions
2
.idea/runConfigurations/index_ts.xml
generated
2
.idea/runConfigurations/index_ts.xml
generated
|
|
@ -1,5 +1,5 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="index.ts" type="NodeJSConfigurationType" path-to-node="wsl://Ubuntu@/home/ahilbig/.nvm/versions/node/v24.12.0/bin/node" nameIsGenerated="true" path-to-js-file="src/index.ts" typescript-loader="bundled" working-dir="$PROJECT_DIR$">
|
<configuration default="false" name="index.ts" type="NodeJSConfigurationType" path-to-node="wsl://Ubuntu@/home/ahilbig/.nvm/versions/node/v24.12.0/bin/node" nameIsGenerated="true" path-to-js-file="src/index.ts" node-parameters="--import tsx" working-dir="$PROJECT_DIR$">
|
||||||
<envs>
|
<envs>
|
||||||
<env name="ADDITIONAL_RESOLVERS" value="SinglePanelDevice,FourPanelDevice,DistanceTrackerDevice" />
|
<env name="ADDITIONAL_RESOLVERS" value="SinglePanelDevice,FourPanelDevice,DistanceTrackerDevice" />
|
||||||
<env name="ADDITIONAL_SCHEMAS" value="./schema/extensions/display_devices.graphql,./schema/extensions/location_tracker_devices.graphql,./schema/extensions/location_tracker_commons.graphql" />
|
<env name="ADDITIONAL_SCHEMAS" value="./schema/extensions/display_devices.graphql,./schema/extensions/location_tracker_devices.graphql,./schema/extensions/location_tracker_commons.graphql" />
|
||||||
|
|
|
||||||
47
.idea/workspace.xml
generated
47
.idea/workspace.xml
generated
|
|
@ -4,13 +4,16 @@
|
||||||
<option name="autoReloadType" value="SELECTIVE" />
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="d7a71994-2699-4ae4-9fd2-ee13b7f33d35" name="Changes" comment="chore: Enhance schema with `DeviceConfig` tags resolver and update IntelliJ workspace adjustments">
|
<list default="true" id="d7a71994-2699-4ae4-9fd2-ee13b7f33d35" name="Changes" comment="chore: Add `allDevices` query resolver, update Zabbix device query handling, and enhance schema with `DeviceConfig` and `WidgetPreview` types">
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/testdata/templates/zbx_default_templates_vcr.yaml" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/.idea/runConfigurations/index_ts.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/runConfigurations/index_ts.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/schema/devices.graphql" beforeDir="false" afterPath="$PROJECT_DIR$/schema/devices.graphql" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/schema/mutations.graphql" beforeDir="false" afterPath="$PROJECT_DIR$/schema/mutations.graphql" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/schema/queries.graphql" beforeDir="false" afterPath="$PROJECT_DIR$/schema/queries.graphql" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/schema/queries.graphql" beforeDir="false" afterPath="$PROJECT_DIR$/schema/queries.graphql" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/api/resolvers.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/api/resolvers.ts" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/api/resolvers.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/api/resolvers.ts" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/datasources/zabbix-hosts.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/datasources/zabbix-hosts.ts" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/datasources/zabbix-request.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/datasources/zabbix-request.ts" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/datasources/zabbix-request.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/datasources/zabbix-request.ts" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/src/datasources/zabbix-templates.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/datasources/zabbix-templates.ts" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/schema/generated/graphql.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/schema/generated/graphql.ts" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/schema/generated/graphql.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/schema/generated/graphql.ts" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
|
@ -22,7 +25,7 @@
|
||||||
<execution />
|
<execution />
|
||||||
</component>
|
</component>
|
||||||
<component name="EmbeddingIndexingInfo">
|
<component name="EmbeddingIndexingInfo">
|
||||||
<option name="cachedIndexableFilesCount" value="57" />
|
<option name="cachedIndexableFilesCount" value="70" />
|
||||||
<option name="fileBasedEmbeddingIndicesEnabled" value="true" />
|
<option name="fileBasedEmbeddingIndicesEnabled" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="Git.Settings">
|
<component name="Git.Settings">
|
||||||
|
|
@ -52,7 +55,7 @@
|
||||||
"NIXITCH_NIX_PROFILES": "",
|
"NIXITCH_NIX_PROFILES": "",
|
||||||
"NIXITCH_NIX_REMOTE": "",
|
"NIXITCH_NIX_REMOTE": "",
|
||||||
"NIXITCH_NIX_USER_PROFILE_DIR": "",
|
"NIXITCH_NIX_USER_PROFILE_DIR": "",
|
||||||
"Node.js.index.ts.executor": "Debug",
|
"Node.js.index.ts.executor": "Run",
|
||||||
"RunOnceActivity.MCP Project settings loaded": "true",
|
"RunOnceActivity.MCP Project settings loaded": "true",
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||||
|
|
@ -63,7 +66,7 @@
|
||||||
"go.import.settings.migrated": "true",
|
"go.import.settings.migrated": "true",
|
||||||
"javascript.preferred.runtime.type.id": "node",
|
"javascript.preferred.runtime.type.id": "node",
|
||||||
"junie.onboarding.icon.badge.shown": "true",
|
"junie.onboarding.icon.badge.shown": "true",
|
||||||
"last_opened_file_path": "//wsl.localhost/Ubuntu/home/ahilbig/git/vcr/zabbix-graphql-api/src/test",
|
"last_opened_file_path": "//wsl.localhost/Ubuntu/home/ahilbig/git/vcr/zabbix-graphql-api/src/testdata/templates",
|
||||||
"node.js.detected.package.eslint": "true",
|
"node.js.detected.package.eslint": "true",
|
||||||
"node.js.detected.package.tslint": "true",
|
"node.js.detected.package.tslint": "true",
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
|
|
@ -74,7 +77,7 @@
|
||||||
"npm.compile.executor": "Run",
|
"npm.compile.executor": "Run",
|
||||||
"npm.copy-schema.executor": "Run",
|
"npm.copy-schema.executor": "Run",
|
||||||
"npm.prod.executor": "Run",
|
"npm.prod.executor": "Run",
|
||||||
"settings.editor.selected.configurable": "preferences.sourceCode.TypeScript",
|
"settings.editor.selected.configurable": "settings.javascript.runtime",
|
||||||
"to.speed.mode.migration.done": "true",
|
"to.speed.mode.migration.done": "true",
|
||||||
"ts.external.directory.path": "\\\\wsl.localhost\\Ubuntu\\home\\ahilbig\\git\\vcr\\zabbix-graphql-api\\node_modules\\typescript\\lib",
|
"ts.external.directory.path": "\\\\wsl.localhost\\Ubuntu\\home\\ahilbig\\git\\vcr\\zabbix-graphql-api\\node_modules\\typescript\\lib",
|
||||||
"vue.rearranger.settings.migration": "true"
|
"vue.rearranger.settings.migration": "true"
|
||||||
|
|
@ -89,6 +92,7 @@
|
||||||
</component>
|
</component>
|
||||||
<component name="RecentsManager">
|
<component name="RecentsManager">
|
||||||
<key name="CopyFile.RECENT_KEYS">
|
<key name="CopyFile.RECENT_KEYS">
|
||||||
|
<recent name="\\wsl.localhost\Ubuntu\home\ahilbig\git\vcr\zabbix-graphql-api\src\testdata\templates" />
|
||||||
<recent name="\\wsl.localhost\Ubuntu\home\ahilbig\git\vcr\zabbix-graphql-api\src\test" />
|
<recent name="\\wsl.localhost\Ubuntu\home\ahilbig\git\vcr\zabbix-graphql-api\src\test" />
|
||||||
<recent name="\\wsl.localhost\Ubuntu\home\ahilbig\git\vcr\zabbix-graphql-api\.forgejo\workflows" />
|
<recent name="\\wsl.localhost\Ubuntu\home\ahilbig\git\vcr\zabbix-graphql-api\.forgejo\workflows" />
|
||||||
<recent name="\\wsl.localhost\Ubuntu\home\ahilbig\git\vcr\zabbix-graphql-api" />
|
<recent name="\\wsl.localhost\Ubuntu\home\ahilbig\git\vcr\zabbix-graphql-api" />
|
||||||
|
|
@ -160,7 +164,9 @@
|
||||||
<workItem from="1768273025985" duration="11343000" />
|
<workItem from="1768273025985" duration="11343000" />
|
||||||
<workItem from="1768380302361" duration="9751000" />
|
<workItem from="1768380302361" duration="9751000" />
|
||||||
<workItem from="1768551040782" duration="6556000" />
|
<workItem from="1768551040782" duration="6556000" />
|
||||||
<workItem from="1768913192173" duration="7156000" />
|
<workItem from="1768913192173" duration="14627000" />
|
||||||
|
<workItem from="1769095609607" duration="1390000" />
|
||||||
|
<workItem from="1769256682556" duration="8928000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="chore: Update IntelliJ workspace settings and add GitHub Actions workflow for Docker deployment">
|
<task id="LOCAL-00001" summary="chore: Update IntelliJ workspace settings and add GitHub Actions workflow for Docker deployment">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
|
|
@ -274,7 +280,15 @@
|
||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1768592274523</updated>
|
<updated>1768592274523</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="15" />
|
<task id="LOCAL-00015" summary="chore: Add `allDevices` query resolver, update Zabbix device query handling, and enhance schema with `DeviceConfig` and `WidgetPreview` types">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1768925413032</created>
|
||||||
|
<option name="number" value="00015" />
|
||||||
|
<option name="presentableId" value="LOCAL-00015" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1768925413032</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="16" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
|
@ -308,16 +322,23 @@
|
||||||
<MESSAGE value="chore: Use DeviceConfig type instead of JSONObject scalar for tags - attribute of devices " />
|
<MESSAGE value="chore: Use DeviceConfig type instead of JSONObject scalar for tags - attribute of devices " />
|
||||||
<MESSAGE value="chore: Update `tags` field schema to use `DeviceConfig`, enhance `isDevice` type check, and adjust IntelliJ workspace" />
|
<MESSAGE value="chore: Update `tags` field schema to use `DeviceConfig`, enhance `isDevice` type check, and adjust IntelliJ workspace" />
|
||||||
<MESSAGE value="chore: Enhance schema with `DeviceConfig` tags resolver and update IntelliJ workspace adjustments" />
|
<MESSAGE value="chore: Enhance schema with `DeviceConfig` tags resolver and update IntelliJ workspace adjustments" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="chore: Enhance schema with `DeviceConfig` tags resolver and update IntelliJ workspace adjustments" />
|
<MESSAGE value="chore: Add `allDevices` query resolver, update Zabbix device query handling, and enhance schema with `DeviceConfig` and `WidgetPreview` types" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="chore: Add `allDevices` query resolver, update Zabbix device query handling, and enhance schema with `DeviceConfig` and `WidgetPreview` types" />
|
||||||
</component>
|
</component>
|
||||||
<component name="XDebuggerManager">
|
<component name="XDebuggerManager">
|
||||||
<breakpoint-manager>
|
<breakpoint-manager>
|
||||||
<breakpoints>
|
<breakpoints>
|
||||||
<line-breakpoint enabled="true" type="javascript">
|
<line-breakpoint enabled="true" type="javascript">
|
||||||
<url>file://$PROJECT_DIR$/src/datasources/zabbix-hosts.ts</url>
|
<url>file://$PROJECT_DIR$/src/datasources/zabbix-request.ts</url>
|
||||||
<line>149</line>
|
<line>133</line>
|
||||||
<properties lambdaOrdinal="-1" />
|
<properties lambdaOrdinal="-1" />
|
||||||
<option name="timeStamp" value="1" />
|
<option name="timeStamp" value="5" />
|
||||||
|
</line-breakpoint>
|
||||||
|
<line-breakpoint enabled="true" type="javascript">
|
||||||
|
<url>file://$PROJECT_DIR$/src/datasources/zabbix-request.ts</url>
|
||||||
|
<line>213</line>
|
||||||
|
<properties lambdaOrdinal="-1" />
|
||||||
|
<option name="timeStamp" value="6" />
|
||||||
</line-breakpoint>
|
</line-breakpoint>
|
||||||
</breakpoints>
|
</breakpoints>
|
||||||
</breakpoint-manager>
|
</breakpoint-manager>
|
||||||
|
|
|
||||||
18
docs/sample_all_template_groups_query.graphql
Normal file
18
docs/sample_all_template_groups_query.graphql
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
### Query
|
||||||
|
Use this query to list all template groups.
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query AllTemplateGroups($name_pattern: String) {
|
||||||
|
allTemplateGroups(name_pattern: $name_pattern) {
|
||||||
|
groupid
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variables
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name_pattern": "Templates/Roadwork/*"
|
||||||
|
}
|
||||||
|
```
|
||||||
30
docs/sample_delete_template_groups_mutation.graphql
Normal file
30
docs/sample_delete_template_groups_mutation.graphql
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
### Mutation
|
||||||
|
Use this mutation to delete template groups by their numeric IDs or by a name pattern.
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
mutation DeleteTemplateGroups($groupids: [Int!], $name_pattern: String) {
|
||||||
|
deleteTemplateGroups(groupids: $groupids, name_pattern: $name_pattern) {
|
||||||
|
id
|
||||||
|
message
|
||||||
|
error {
|
||||||
|
message
|
||||||
|
code
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variables (by ID)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"groupids": [201]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variables (by name pattern)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name_pattern": "Templates/Roadwork/%"
|
||||||
|
}
|
||||||
|
```
|
||||||
30
docs/sample_delete_templates_mutation.graphql
Normal file
30
docs/sample_delete_templates_mutation.graphql
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
### Mutation
|
||||||
|
Use this mutation to delete templates by their numeric IDs or by a name pattern.
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
mutation DeleteTemplates($templateids: [Int!], $name_pattern: String) {
|
||||||
|
deleteTemplates(templateids: $templateids, name_pattern: $name_pattern) {
|
||||||
|
id
|
||||||
|
message
|
||||||
|
error {
|
||||||
|
message
|
||||||
|
code
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variables (by ID)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"templateids": [501]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variables (by name pattern)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name_pattern": "BT_DEVICE_TRACKER%"
|
||||||
|
}
|
||||||
|
```
|
||||||
59
docs/sample_import_template_groups_mutation.graphql
Normal file
59
docs/sample_import_template_groups_mutation.graphql
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
### Mutation
|
||||||
|
Use this mutation to import template groups.
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
mutation ImportTemplateGroups($templateGroups: [CreateTemplateGroup!]!) {
|
||||||
|
importTemplateGroups(templateGroups: $templateGroups) {
|
||||||
|
groupName
|
||||||
|
groupid
|
||||||
|
message
|
||||||
|
error {
|
||||||
|
message
|
||||||
|
code
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variables
|
||||||
|
This sample data is based on the `template_groups` from `src/testdata/templates/zbx_default_templates_vcr.yaml`.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"templateGroups": [
|
||||||
|
{
|
||||||
|
"uuid": "43aab460fe444f18886b19948413b7e3",
|
||||||
|
"groupName": "Permissions/ConstructionSite"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uuid": "376524057e094c07aaa0cf7f524849dc",
|
||||||
|
"groupName": "Templates/Roadwork/Controller"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uuid": "7d83c76454564390bb0e34600780eaec",
|
||||||
|
"groupName": "Templates/Roadwork/Device-Capabilities"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uuid": "48d5d2a18a08448c96a931b63bb2c97d",
|
||||||
|
"groupName": "Templates/Roadwork/Device-Capabilities/FLASH_ATTACHABLE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uuid": "785986b84892468ea2e92d912747b1d3",
|
||||||
|
"groupName": "Templates/Roadwork/Device-Capabilities/GEOLOCALIZABLE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uuid": "a4b79479e97a4b48972dcb476d45e55a",
|
||||||
|
"groupName": "Templates/Roadwork/Device-Capabilities/HAS_OPERATIONAL_DATA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uuid": "3604af8102644bee9dcaf0f9c1ee93a1",
|
||||||
|
"groupName": "Templates/Roadwork/Devices"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uuid": "5ad0bd9e42a4487e869e9e41b38fe553",
|
||||||
|
"groupName": "Templates/Roadwork/DisplayLibrary"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
97
docs/sample_import_templates_mutation.graphql
Normal file
97
docs/sample_import_templates_mutation.graphql
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
### Mutation
|
||||||
|
Use this mutation to import templates along with their items, tags, and linked templates.
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
mutation ImportTemplates($templates: [CreateTemplate!]!) {
|
||||||
|
importTemplates(templates: $templates) {
|
||||||
|
host
|
||||||
|
templateid
|
||||||
|
message
|
||||||
|
error {
|
||||||
|
message
|
||||||
|
code
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variables
|
||||||
|
This sample data is based on the `BT_DEVICE_TRACKER` template from `src/testdata/templates/zbx_default_templates_vcr.yaml`.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"templates": [
|
||||||
|
{
|
||||||
|
"uuid": "27474f627cb344b782a81c16d7e0c7d1",
|
||||||
|
"host": "BT_DEVICE_TRACKER",
|
||||||
|
"name": "BT_DEVICE_TRACKER",
|
||||||
|
"groupNames": ["Templates/Roadwork/Devices"],
|
||||||
|
"templates": [
|
||||||
|
{ "name": "ROADWORK_DEVICE" }
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
{ "tag": "class", "value": "roadwork" },
|
||||||
|
{ "tag": "deviceType", "value": "bt_device_tracker_generic" }
|
||||||
|
],
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"uuid": "d4d3ec9f3ca940a39a721b6cfd2f3471",
|
||||||
|
"name": "location",
|
||||||
|
"type": 18,
|
||||||
|
"key": "location",
|
||||||
|
"value_type": 4,
|
||||||
|
"history": "2d",
|
||||||
|
"preprocessing": [
|
||||||
|
{
|
||||||
|
"type": 21,
|
||||||
|
"params": [
|
||||||
|
"var obj=JSON.parse(value);\n\nif (obj[\"isFiltered\"]) {\n throw \"Result is filtered\";\n return \"filtered\";\n}\n\nreturn value;"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 15,
|
||||||
|
"params": ["filtered"],
|
||||||
|
"error_handler": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"master_item": {
|
||||||
|
"key": "mqtt.trap[deviceValue/location]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uuid": "380c4a7d752848cba3b5a59a0f9b13c0",
|
||||||
|
"name": "MQTT_LOCATION",
|
||||||
|
"type": 2,
|
||||||
|
"key": "mqtt.trap[deviceValue/location]",
|
||||||
|
"value_type": 4,
|
||||||
|
"history": "0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mapping Reference
|
||||||
|
When converting from Zabbix YAML/XML exports, use the following numeric mappings for items and preprocessing:
|
||||||
|
|
||||||
|
#### Item Type (`type`)
|
||||||
|
- `2`: ZABBIX_TRAP (TRAP)
|
||||||
|
- `18`: DEPENDANT_ITEM (DEPENDENT)
|
||||||
|
- `21`: SIMULATOR_JAVASCRIPT (JAVASCRIPT)
|
||||||
|
|
||||||
|
#### Value Type (`value_type`)
|
||||||
|
- `0`: Float
|
||||||
|
- `3`: Int (Numeric unsigned)
|
||||||
|
- `4`: Text
|
||||||
|
|
||||||
|
#### Preprocessing Type (`type`)
|
||||||
|
- `12`: JSONPATH
|
||||||
|
- `15`: NOT_MATCHES_REGEX
|
||||||
|
- `21`: JAVASCRIPT
|
||||||
|
|
||||||
|
#### Error Handler (`error_handler`)
|
||||||
|
- `1`: DISCARD_VALUE
|
||||||
|
- `2`: SET_VALUE
|
||||||
|
- `3`: SET_ERROR
|
||||||
18
docs/sample_templates_query.graphql
Normal file
18
docs/sample_templates_query.graphql
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
### Query
|
||||||
|
Use this query to verify the results of the template import.
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
query GetTemplates($name_pattern: String) {
|
||||||
|
templates(name_pattern: $name_pattern) {
|
||||||
|
templateid
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variables
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name_pattern": "BT_DEVICE_TRACKER"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"compile": "tsc",
|
"compile": "tsc",
|
||||||
"start": "nodemon --watch \"src/**\" --watch \"schema.graphql\" --ext \"ts,json\" --exec \"tsc & node --require ts-node/register --inspect --import tsx/esm ./src/index.ts\"",
|
"start": "nodemon --watch \"src/**\" --watch \"schema.graphql\" --ext \"ts,json\" --exec \"node --import tsx ./src/index.ts\"",
|
||||||
"prod": "npm run copy-schema && node ./dist/index.js",
|
"prod": "npm run copy-schema && node ./dist/index.js",
|
||||||
"test": "jest --detectOpenHandles --forceExit --bail",
|
"test": "jest --detectOpenHandles --forceExit --bail",
|
||||||
"codegen": "graphql-codegen --config codegen.ts --watch \"schema.graphql\"",
|
"codegen": "graphql-codegen --config codegen.ts --watch \"schema.graphql\"",
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,152 @@ type Mutation {
|
||||||
importHosts(hosts: [CreateHost!]!):[ImportHostResponse!]
|
importHosts(hosts: [CreateHost!]!):[ImportHostResponse!]
|
||||||
|
|
||||||
importUserRights(input: UserRightsInput!, dryRun: Boolean! = true): ImportUserRightsResult
|
importUserRights(input: UserRightsInput!, dryRun: Boolean! = true): ImportUserRightsResult
|
||||||
|
|
||||||
|
"""
|
||||||
|
(Mass) Import template groups
|
||||||
|
and assign them by groupid or name.
|
||||||
|
|
||||||
|
Return value: If no error occurs a groupid be returned for each created group,
|
||||||
|
otherwise the return object will contain an error message
|
||||||
|
|
||||||
|
Authentication: By zbx_session - cookie or zabbix-auth-token - header
|
||||||
|
"""
|
||||||
|
importTemplateGroups(templateGroups: [CreateTemplateGroup!]!):[CreateTemplateGroupResponse!]
|
||||||
|
|
||||||
|
"""
|
||||||
|
(Mass) Import templates.
|
||||||
|
|
||||||
|
Return value: If no error occurs a templateid will be returned for each created template,
|
||||||
|
otherwise the return object will contain an error message.
|
||||||
|
|
||||||
|
Authentication: By zbx_session - cookie or zabbix-auth-token - header
|
||||||
|
"""
|
||||||
|
importTemplates(templates: [CreateTemplate!]!):[ImportTemplateResponse!]
|
||||||
|
|
||||||
|
"""
|
||||||
|
Delete templates.
|
||||||
|
|
||||||
|
Authentication: By zbx_session - cookie or zabbix-auth-token - header
|
||||||
|
"""
|
||||||
|
deleteTemplates(templateids: [Int!], name_pattern: String): [DeleteResponse!]
|
||||||
|
|
||||||
|
"""
|
||||||
|
Delete template groups.
|
||||||
|
|
||||||
|
Authentication: By zbx_session - cookie or zabbix-auth-token - header
|
||||||
|
"""
|
||||||
|
deleteTemplateGroups(groupids: [Int!], name_pattern: String): [DeleteResponse!]
|
||||||
}
|
}
|
||||||
|
|
||||||
####################################################################
|
####################################################################
|
||||||
# Input types used for importXXX - and storeXXX - Mutations
|
# Input types used for importXXX - and storeXXX - Mutations
|
||||||
####################################################################
|
####################################################################
|
||||||
|
|
||||||
|
type DeleteResponse {
|
||||||
|
id: Int!
|
||||||
|
message: String
|
||||||
|
error: ApiError
|
||||||
|
}
|
||||||
|
|
||||||
|
input CreateTemplateGroup {
|
||||||
|
"""
|
||||||
|
Name of the template group
|
||||||
|
"""
|
||||||
|
groupName: String!
|
||||||
|
"""
|
||||||
|
Internally used unique id
|
||||||
|
(will be assigned by Zabbix if empty)
|
||||||
|
"""
|
||||||
|
uuid: String
|
||||||
|
}
|
||||||
|
|
||||||
|
input CreateTemplate {
|
||||||
|
"""
|
||||||
|
Name of the template
|
||||||
|
"""
|
||||||
|
host: String!
|
||||||
|
"""
|
||||||
|
Visible name of the template
|
||||||
|
"""
|
||||||
|
name: String
|
||||||
|
"""
|
||||||
|
groupNames is used to assign the created object
|
||||||
|
to a template group.
|
||||||
|
"""
|
||||||
|
groupNames: [String!]!
|
||||||
|
"""
|
||||||
|
Optionally the internal groupids can be passed - in this case the
|
||||||
|
groupName is ignored
|
||||||
|
"""
|
||||||
|
groupids: [Int]
|
||||||
|
"""
|
||||||
|
Internally used unique id
|
||||||
|
(will be assigned by Zabbix if empty)
|
||||||
|
"""
|
||||||
|
uuid: String
|
||||||
|
"""
|
||||||
|
Template items
|
||||||
|
"""
|
||||||
|
items: [CreateTemplateItem!]
|
||||||
|
"""
|
||||||
|
Linked templates
|
||||||
|
"""
|
||||||
|
templates: [CreateLinkedTemplate!]
|
||||||
|
"""
|
||||||
|
Template tags
|
||||||
|
"""
|
||||||
|
tags: [CreateTag!]
|
||||||
|
}
|
||||||
|
|
||||||
|
input CreateTemplateItem {
|
||||||
|
uuid: String
|
||||||
|
name: String!
|
||||||
|
type: Int
|
||||||
|
key: String!
|
||||||
|
value_type: Int
|
||||||
|
history: String
|
||||||
|
units: String
|
||||||
|
delay: String
|
||||||
|
description: String
|
||||||
|
preprocessing: [CreateItemPreprocessing!]
|
||||||
|
tags: [CreateTag!]
|
||||||
|
master_item: CreateMasterItem
|
||||||
|
}
|
||||||
|
|
||||||
|
input CreateMasterItem {
|
||||||
|
key: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
input CreateItemPreprocessing {
|
||||||
|
type: Int!
|
||||||
|
params: [String!]!
|
||||||
|
error_handler: Int
|
||||||
|
error_handler_params: String
|
||||||
|
}
|
||||||
|
|
||||||
|
input CreateLinkedTemplate {
|
||||||
|
name: String!
|
||||||
|
}
|
||||||
|
|
||||||
|
input CreateTag {
|
||||||
|
tag: String!
|
||||||
|
value: String
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImportTemplateResponse {
|
||||||
|
host: String!
|
||||||
|
templateid: String
|
||||||
|
message: String
|
||||||
|
error: ApiError
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateTemplateGroupResponse {
|
||||||
|
groupName: String!
|
||||||
|
groupid: Int
|
||||||
|
message: String
|
||||||
|
error: ApiError
|
||||||
|
}
|
||||||
|
|
||||||
input CreateHostGroup {
|
input CreateHostGroup {
|
||||||
"""
|
"""
|
||||||
Name of the host group
|
Name of the host group
|
||||||
|
|
|
||||||
|
|
@ -113,5 +113,15 @@ type Query {
|
||||||
exclude_groups_pattern: Regex allowing to exclude all matching hostgroups from group permissions
|
exclude_groups_pattern: Regex allowing to exclude all matching hostgroups from group permissions
|
||||||
"""
|
"""
|
||||||
exportUserRights(name_pattern: String = "" exclude_hostgroups_pattern: String = ""): UserRights
|
exportUserRights(name_pattern: String = "" exclude_hostgroups_pattern: String = ""): UserRights
|
||||||
|
|
||||||
|
"""
|
||||||
|
Get templates.
|
||||||
|
"""
|
||||||
|
templates(hostids: [Int], name_pattern: String): [Template]
|
||||||
|
|
||||||
|
"""
|
||||||
|
Get template groups.
|
||||||
|
"""
|
||||||
|
allTemplateGroups(name_pattern: String): [HostGroup]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,10 @@ import {
|
||||||
MutationCreateHostArgs,
|
MutationCreateHostArgs,
|
||||||
MutationImportHostGroupsArgs,
|
MutationImportHostGroupsArgs,
|
||||||
MutationImportHostsArgs,
|
MutationImportHostsArgs,
|
||||||
|
MutationImportTemplateGroupsArgs,
|
||||||
|
MutationImportTemplatesArgs,
|
||||||
|
MutationDeleteTemplatesArgs,
|
||||||
|
MutationDeleteTemplateGroupsArgs,
|
||||||
MutationImportUserRightsArgs,
|
MutationImportUserRightsArgs,
|
||||||
Permission, QueryAllDevicesArgs,
|
Permission, QueryAllDevicesArgs,
|
||||||
QueryAllHostGroupsArgs,
|
QueryAllHostGroupsArgs,
|
||||||
|
|
@ -13,12 +17,15 @@ import {
|
||||||
QueryExportHostValueHistoryArgs,
|
QueryExportHostValueHistoryArgs,
|
||||||
QueryExportUserRightsArgs,
|
QueryExportUserRightsArgs,
|
||||||
QueryHasPermissionsArgs,
|
QueryHasPermissionsArgs,
|
||||||
|
QueryTemplatesArgs,
|
||||||
QueryUserPermissionsArgs,
|
QueryUserPermissionsArgs,
|
||||||
Resolvers,
|
Resolvers,
|
||||||
StorageItemType,
|
StorageItemType,
|
||||||
} from "../schema/generated/graphql.js";
|
} from "../schema/generated/graphql.js";
|
||||||
|
|
||||||
import {HostImporter} from "../execution/host_importer.js";
|
import {HostImporter} from "../execution/host_importer.js";
|
||||||
|
import {TemplateImporter} from "../execution/template_importer.js";
|
||||||
|
import {TemplateDeleter} from "../execution/template_deleter.js";
|
||||||
import {HostValueExporter} from "../execution/host_exporter.js";
|
import {HostValueExporter} from "../execution/host_exporter.js";
|
||||||
import {logger} from "../logging/logger.js";
|
import {logger} from "../logging/logger.js";
|
||||||
import {ParsedArgs, ZabbixRequest} from "../datasources/zabbix-request.js";
|
import {ParsedArgs, ZabbixRequest} from "../datasources/zabbix-request.js";
|
||||||
|
|
@ -39,6 +46,14 @@ import {
|
||||||
ZabbixImportUserRolesRequest,
|
ZabbixImportUserRolesRequest,
|
||||||
ZabbixQueryUserRolesRequest
|
ZabbixQueryUserRolesRequest
|
||||||
} from "../datasources/zabbix-userroles.js";
|
} from "../datasources/zabbix-userroles.js";
|
||||||
|
import {
|
||||||
|
ZabbixCreateItemRequest,
|
||||||
|
ZabbixCreateTemplateGroupRequest,
|
||||||
|
ZabbixCreateTemplateRequest,
|
||||||
|
ZabbixQueryItemRequest,
|
||||||
|
ZabbixQueryTemplateGroupRequest,
|
||||||
|
ZabbixQueryTemplatesRequest
|
||||||
|
} from "../datasources/zabbix-templates.js";
|
||||||
import {ZABBIX_EDGE_DEVICE_BASE_GROUP, zabbixAPI} from "../datasources/zabbix-api.js";
|
import {ZABBIX_EDGE_DEVICE_BASE_GROUP, zabbixAPI} from "../datasources/zabbix-api.js";
|
||||||
import {GraphQLInterfaceType, GraphQLList} from "graphql/type/index.js";
|
import {GraphQLInterfaceType, GraphQLList} from "graphql/type/index.js";
|
||||||
import {isDevice} from "./resolver_helpers.js";
|
import {isDevice} from "./resolver_helpers.js";
|
||||||
|
|
@ -129,6 +144,37 @@ export function createResolvers(): Resolvers {
|
||||||
userGroups: groups,
|
userGroups: groups,
|
||||||
userRoles: roles
|
userRoles: roles
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
templates: async (_parent: any, args: QueryTemplatesArgs, {
|
||||||
|
zabbixAuthToken,
|
||||||
|
cookie
|
||||||
|
}: any) => {
|
||||||
|
let params: any = {}
|
||||||
|
if (args.hostids) {
|
||||||
|
params.templateids = args.hostids
|
||||||
|
}
|
||||||
|
if (args.name_pattern) {
|
||||||
|
params.search = {
|
||||||
|
name: args.name_pattern
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return await new ZabbixQueryTemplatesRequest(zabbixAuthToken, cookie)
|
||||||
|
.executeRequestThrowError(zabbixAPI, new ParsedArgs(params));
|
||||||
|
},
|
||||||
|
|
||||||
|
allTemplateGroups: async (_parent: any, args: any, {
|
||||||
|
zabbixAuthToken,
|
||||||
|
cookie
|
||||||
|
}: any) => {
|
||||||
|
let params: any = {}
|
||||||
|
if (args.name_pattern) {
|
||||||
|
params.search = {
|
||||||
|
name: args.name_pattern
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return await new ZabbixQueryTemplateGroupRequest(zabbixAuthToken, cookie)
|
||||||
|
.executeRequestThrowError(zabbixAPI, new ParsedArgs(params));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Mutation: {
|
Mutation: {
|
||||||
|
|
@ -172,6 +218,30 @@ export function createResolvers(): Resolvers {
|
||||||
userRoles: userRolesImport,
|
userRoles: userRolesImport,
|
||||||
userGroups: userGroupsImport
|
userGroups: userGroupsImport
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
importTemplateGroups: async (_parent: any, args: MutationImportTemplateGroupsArgs, {
|
||||||
|
zabbixAuthToken,
|
||||||
|
cookie
|
||||||
|
}: any) => {
|
||||||
|
return TemplateImporter.importTemplateGroups(args.templateGroups, zabbixAuthToken, cookie)
|
||||||
|
},
|
||||||
|
importTemplates: async (_parent: any, args: MutationImportTemplatesArgs, {
|
||||||
|
zabbixAuthToken,
|
||||||
|
cookie
|
||||||
|
}: any) => {
|
||||||
|
return TemplateImporter.importTemplates(args.templates, zabbixAuthToken, cookie)
|
||||||
|
},
|
||||||
|
deleteTemplates: async (_parent: any, args: MutationDeleteTemplatesArgs, {
|
||||||
|
zabbixAuthToken,
|
||||||
|
cookie
|
||||||
|
}: any) => {
|
||||||
|
return TemplateDeleter.deleteTemplates(args.templateids, args.name_pattern, zabbixAuthToken, cookie)
|
||||||
|
},
|
||||||
|
deleteTemplateGroups: async (_parent: any, args: MutationDeleteTemplateGroupsArgs, {
|
||||||
|
zabbixAuthToken,
|
||||||
|
cookie
|
||||||
|
}: any) => {
|
||||||
|
return TemplateDeleter.deleteTemplateGroups(args.groupids, args.name_pattern, zabbixAuthToken, cookie)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ export class ParsedArgs {
|
||||||
constructor(params?: any) {
|
constructor(params?: any) {
|
||||||
if (Array.isArray(params)) {
|
if (Array.isArray(params)) {
|
||||||
this.zabbix_params = params.map(arg => this.parseArgObject(arg))
|
this.zabbix_params = params.map(arg => this.parseArgObject(arg))
|
||||||
} else if (params instanceof Object) {
|
} else {
|
||||||
this.zabbix_params = this.parseArgObject(params)
|
this.zabbix_params = this.parseArgObject(params)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,9 +52,12 @@ export class ParsedArgs {
|
||||||
return paramName in this.zabbix_params ? this.zabbix_params[paramName] : undefined
|
return paramName in this.zabbix_params ? this.zabbix_params[paramName] : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
parseArgObject(args?: Object) {
|
parseArgObject(args?: any) {
|
||||||
|
if (args && (typeof args !== 'object' || args.constructor !== Object)) {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
let result: ZabbixParams
|
let result: ZabbixParams
|
||||||
if (args) {
|
if (args && typeof args === 'object' && args.constructor === Object) {
|
||||||
if ("name_pattern" in args && typeof args["name_pattern"] == "string") {
|
if ("name_pattern" in args && typeof args["name_pattern"] == "string") {
|
||||||
if (args["name_pattern"]) {
|
if (args["name_pattern"]) {
|
||||||
this.name_pattern = args["name_pattern"]
|
this.name_pattern = args["name_pattern"]
|
||||||
|
|
@ -159,7 +162,10 @@ export class ZabbixRequest<T extends ZabbixResult, A extends ParsedArgs = Parsed
|
||||||
let params: ZabbixParams
|
let params: ZabbixParams
|
||||||
if (Array.isArray(args?.zabbix_params)) {
|
if (Array.isArray(args?.zabbix_params)) {
|
||||||
params = args?.zabbix_params.map(paramsObj => {
|
params = args?.zabbix_params.map(paramsObj => {
|
||||||
return {...this.requestBodyTemplate.params, ...paramsObj}
|
if (paramsObj !== null && typeof paramsObj === 'object' && paramsObj.constructor === Object) {
|
||||||
|
return {...this.requestBodyTemplate.params, ...paramsObj}
|
||||||
|
}
|
||||||
|
return paramsObj;
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
params = {...this.requestBodyTemplate.params, ...zabbixParams ?? this.createZabbixParams(args)}
|
params = {...this.requestBodyTemplate.params, ...zabbixParams ?? this.createZabbixParams(args)}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
|
||||||
import { ZabbixRequest } from "./zabbix-request.js";
|
import {isZabbixErrorResult, ParsedArgs, ZabbixRequest} from "./zabbix-request.js";
|
||||||
|
import {ZabbixAPI} from "./zabbix-api.js";
|
||||||
|
import {logger} from "../logging/logger.js";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -30,3 +32,40 @@ export class ZabbixQueryTemplateGroupRequest extends ZabbixRequest<ZabbixQueryTe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class ZabbixCreateTemplateGroupRequest extends ZabbixRequest<{ groupids: string[] }> {
|
||||||
|
constructor(authToken?: string | null, cookie?: string | null) {
|
||||||
|
super("templategroup.create", authToken, cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ZabbixCreateTemplateRequest extends ZabbixRequest<{ templateids: string[] }> {
|
||||||
|
constructor(authToken?: string | null, cookie?: string | null) {
|
||||||
|
super("template.create", authToken, cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ZabbixQueryItemRequest extends ZabbixRequest<any[]> {
|
||||||
|
constructor(authToken?: string | null, cookie?: string | null) {
|
||||||
|
super("item.get", authToken, cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ZabbixCreateItemRequest extends ZabbixRequest<{ itemids: string[] }> {
|
||||||
|
constructor(authToken?: string | null, cookie?: string | null) {
|
||||||
|
super("item.create", authToken, cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ZabbixDeleteTemplatesRequest extends ZabbixRequest<{ templateids: string[] }> {
|
||||||
|
constructor(authToken?: string | null, cookie?: string | null) {
|
||||||
|
super("template.delete", authToken, cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ZabbixDeleteTemplateGroupsRequest extends ZabbixRequest<{ groupids: string[] }> {
|
||||||
|
constructor(authToken?: string | null, cookie?: string | null) {
|
||||||
|
super("templategroup.delete", authToken, cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
107
src/execution/template_deleter.ts
Normal file
107
src/execution/template_deleter.ts
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
|
||||||
|
import {DeleteResponse} from "../schema/generated/graphql.js";
|
||||||
|
import {
|
||||||
|
ZabbixDeleteTemplateGroupsRequest,
|
||||||
|
ZabbixDeleteTemplatesRequest,
|
||||||
|
ZabbixQueryTemplateGroupRequest,
|
||||||
|
ZabbixQueryTemplatesRequest
|
||||||
|
} from "../datasources/zabbix-templates.js";
|
||||||
|
import {isZabbixErrorResult, ParsedArgs} from "../datasources/zabbix-request.js";
|
||||||
|
import {zabbixAPI} from "../datasources/zabbix-api.js";
|
||||||
|
|
||||||
|
export class TemplateDeleter {
|
||||||
|
|
||||||
|
public static async deleteTemplates(templateids: number[] | null | undefined, name_pattern?: string | null, zabbixAuthToken?: string, cookie?: string): Promise<DeleteResponse[]> {
|
||||||
|
const result: DeleteResponse[] = [];
|
||||||
|
let idsToDelete = templateids ? [...templateids] : [];
|
||||||
|
|
||||||
|
if (name_pattern) {
|
||||||
|
const queryResult = await new ZabbixQueryTemplatesRequest(zabbixAuthToken, cookie)
|
||||||
|
.executeRequestReturnError(zabbixAPI, new ParsedArgs({ name_pattern: name_pattern }));
|
||||||
|
|
||||||
|
if (!isZabbixErrorResult(queryResult) && Array.isArray(queryResult)) {
|
||||||
|
const foundIds = queryResult.map(t => Number(t.templateid));
|
||||||
|
// Merge and deduplicate
|
||||||
|
idsToDelete = Array.from(new Set([...idsToDelete, ...foundIds]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idsToDelete.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zabbix template.delete accepts an array of template IDs
|
||||||
|
const deleteResult = await new ZabbixDeleteTemplatesRequest(zabbixAuthToken, cookie)
|
||||||
|
.executeRequestReturnError(zabbixAPI, new ParsedArgs(idsToDelete));
|
||||||
|
|
||||||
|
if (isZabbixErrorResult(deleteResult)) {
|
||||||
|
let errorMessage = deleteResult.error.message;
|
||||||
|
if (deleteResult.error.data) {
|
||||||
|
errorMessage += " " + (typeof deleteResult.error.data === 'string' ? deleteResult.error.data : JSON.stringify(deleteResult.error.data));
|
||||||
|
}
|
||||||
|
// If the whole batch fails, we report the error for each ID
|
||||||
|
for (const id of idsToDelete) {
|
||||||
|
result.push({
|
||||||
|
id: id,
|
||||||
|
message: errorMessage,
|
||||||
|
error: deleteResult.error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (deleteResult?.templateids) {
|
||||||
|
for (const id of idsToDelete) {
|
||||||
|
result.push({
|
||||||
|
id: id,
|
||||||
|
message: `Template ${id} deleted successfully`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async deleteTemplateGroups(groupids: number[] | null | undefined, name_pattern?: string | null, zabbixAuthToken?: string, cookie?: string): Promise<DeleteResponse[]> {
|
||||||
|
const result: DeleteResponse[] = [];
|
||||||
|
let idsToDelete = groupids ? [...groupids] : [];
|
||||||
|
|
||||||
|
if (name_pattern) {
|
||||||
|
const queryResult = await new ZabbixQueryTemplateGroupRequest(zabbixAuthToken, cookie)
|
||||||
|
.executeRequestReturnError(zabbixAPI, new ParsedArgs({ name_pattern: name_pattern }));
|
||||||
|
|
||||||
|
if (!isZabbixErrorResult(queryResult) && Array.isArray(queryResult)) {
|
||||||
|
const foundIds = queryResult.map(g => Number(g.groupid));
|
||||||
|
// Merge and deduplicate
|
||||||
|
idsToDelete = Array.from(new Set([...idsToDelete, ...foundIds]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idsToDelete.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteResult = await new ZabbixDeleteTemplateGroupsRequest(zabbixAuthToken, cookie)
|
||||||
|
.executeRequestReturnError(zabbixAPI, new ParsedArgs(idsToDelete));
|
||||||
|
|
||||||
|
if (isZabbixErrorResult(deleteResult)) {
|
||||||
|
let errorMessage = deleteResult.error.message;
|
||||||
|
if (deleteResult.error.data) {
|
||||||
|
errorMessage += " " + (typeof deleteResult.error.data === 'string' ? deleteResult.error.data : JSON.stringify(deleteResult.error.data));
|
||||||
|
}
|
||||||
|
for (const id of idsToDelete) {
|
||||||
|
result.push({
|
||||||
|
id: id,
|
||||||
|
message: errorMessage,
|
||||||
|
error: deleteResult.error
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (deleteResult?.groupids) {
|
||||||
|
for (const id of idsToDelete) {
|
||||||
|
result.push({
|
||||||
|
id: id,
|
||||||
|
message: `Template group ${id} deleted successfully`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
220
src/execution/template_importer.ts
Normal file
220
src/execution/template_importer.ts
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
|
||||||
|
import {
|
||||||
|
CreateTemplate,
|
||||||
|
CreateTemplateGroup,
|
||||||
|
CreateTemplateGroupResponse,
|
||||||
|
ImportTemplateResponse,
|
||||||
|
InputMaybe
|
||||||
|
} from "../schema/generated/graphql.js";
|
||||||
|
import {logger} from "../logging/logger.js";
|
||||||
|
import {
|
||||||
|
ZabbixCreateItemRequest,
|
||||||
|
ZabbixCreateTemplateGroupRequest,
|
||||||
|
ZabbixCreateTemplateRequest,
|
||||||
|
ZabbixQueryItemRequest,
|
||||||
|
ZabbixQueryTemplateGroupRequest,
|
||||||
|
ZabbixQueryTemplatesRequest
|
||||||
|
} from "../datasources/zabbix-templates.js";
|
||||||
|
import {isZabbixErrorResult, ParsedArgs, ZabbixErrorResult} from "../datasources/zabbix-request.js";
|
||||||
|
import {zabbixAPI} from "../datasources/zabbix-api.js";
|
||||||
|
|
||||||
|
export class TemplateImporter {
|
||||||
|
|
||||||
|
public static async importTemplateGroups(templateGroups: InputMaybe<Array<CreateTemplateGroup>> | 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
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async importTemplates(templates: InputMaybe<Array<CreateTemplate>> | 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
|
||||||
|
}))
|
||||||
|
|
||||||
|
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 => ({ 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 || "" }))
|
||||||
|
}
|
||||||
|
|
||||||
|
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<string, string>();
|
||||||
|
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,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -81,6 +81,94 @@ export interface CreateHostResponse {
|
||||||
itemids?: Maybe<Array<Maybe<Scalars['Int']['output']>>>;
|
itemids?: Maybe<Array<Maybe<Scalars['Int']['output']>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CreateItemPreprocessing {
|
||||||
|
error_handler?: InputMaybe<Scalars['Int']['input']>;
|
||||||
|
error_handler_params?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
params: Array<Scalars['String']['input']>;
|
||||||
|
type: Scalars['Int']['input'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateLinkedTemplate {
|
||||||
|
name: Scalars['String']['input'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateMasterItem {
|
||||||
|
key: Scalars['String']['input'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateTag {
|
||||||
|
tag: Scalars['String']['input'];
|
||||||
|
value?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateTemplate {
|
||||||
|
/**
|
||||||
|
* groupNames is used to assign the created object
|
||||||
|
* to a template group.
|
||||||
|
*/
|
||||||
|
groupNames: Array<Scalars['String']['input']>;
|
||||||
|
/**
|
||||||
|
* Optionally the internal groupids can be passed - in this case the
|
||||||
|
* groupName is ignored
|
||||||
|
*/
|
||||||
|
groupids?: InputMaybe<Array<InputMaybe<Scalars['Int']['input']>>>;
|
||||||
|
/** Name of the template */
|
||||||
|
host: Scalars['String']['input'];
|
||||||
|
/** Template items */
|
||||||
|
items?: InputMaybe<Array<CreateTemplateItem>>;
|
||||||
|
/** Visible name of the template */
|
||||||
|
name?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
/** Template tags */
|
||||||
|
tags?: InputMaybe<Array<CreateTag>>;
|
||||||
|
/** Linked templates */
|
||||||
|
templates?: InputMaybe<Array<CreateLinkedTemplate>>;
|
||||||
|
/**
|
||||||
|
* Internally used unique id
|
||||||
|
* (will be assigned by Zabbix if empty)
|
||||||
|
*/
|
||||||
|
uuid?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateTemplateGroup {
|
||||||
|
/** Name of the template group */
|
||||||
|
groupName: Scalars['String']['input'];
|
||||||
|
/**
|
||||||
|
* Internally used unique id
|
||||||
|
* (will be assigned by Zabbix if empty)
|
||||||
|
*/
|
||||||
|
uuid?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateTemplateGroupResponse {
|
||||||
|
__typename?: 'CreateTemplateGroupResponse';
|
||||||
|
error?: Maybe<ApiError>;
|
||||||
|
groupName: Scalars['String']['output'];
|
||||||
|
groupid?: Maybe<Scalars['Int']['output']>;
|
||||||
|
message?: Maybe<Scalars['String']['output']>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateTemplateItem {
|
||||||
|
delay?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
description?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
history?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
key: Scalars['String']['input'];
|
||||||
|
master_item?: InputMaybe<CreateMasterItem>;
|
||||||
|
name: Scalars['String']['input'];
|
||||||
|
preprocessing?: InputMaybe<Array<CreateItemPreprocessing>>;
|
||||||
|
tags?: InputMaybe<Array<CreateTag>>;
|
||||||
|
type?: InputMaybe<Scalars['Int']['input']>;
|
||||||
|
units?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
uuid?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
value_type?: InputMaybe<Scalars['Int']['input']>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DeleteResponse {
|
||||||
|
__typename?: 'DeleteResponse';
|
||||||
|
error?: Maybe<ApiError>;
|
||||||
|
id: Scalars['Int']['output'];
|
||||||
|
message?: Maybe<Scalars['String']['output']>;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (IoT / Edge - ) Devices are hosts having a state containing the "output" / the business data which is exposed
|
* (IoT / Edge - ) Devices are hosts having a state containing the "output" / the business data which is exposed
|
||||||
* besides monitoring information.
|
* besides monitoring information.
|
||||||
|
|
@ -232,6 +320,14 @@ export interface ImportHostResponse {
|
||||||
message?: Maybe<Scalars['String']['output']>;
|
message?: Maybe<Scalars['String']['output']>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ImportTemplateResponse {
|
||||||
|
__typename?: 'ImportTemplateResponse';
|
||||||
|
error?: Maybe<ApiError>;
|
||||||
|
host: Scalars['String']['output'];
|
||||||
|
message?: Maybe<Scalars['String']['output']>;
|
||||||
|
templateid?: Maybe<Scalars['String']['output']>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ImportUserRightResult {
|
export interface ImportUserRightResult {
|
||||||
__typename?: 'ImportUserRightResult';
|
__typename?: 'ImportUserRightResult';
|
||||||
errors?: Maybe<Array<ApiError>>;
|
errors?: Maybe<Array<ApiError>>;
|
||||||
|
|
@ -268,6 +364,18 @@ export interface Mutation {
|
||||||
__typename?: 'Mutation';
|
__typename?: 'Mutation';
|
||||||
/** Authentication: By zbx_session - cookie or zabbix-auth-token - header */
|
/** Authentication: By zbx_session - cookie or zabbix-auth-token - header */
|
||||||
createHost?: Maybe<CreateHostResponse>;
|
createHost?: Maybe<CreateHostResponse>;
|
||||||
|
/**
|
||||||
|
* Delete template groups.
|
||||||
|
*
|
||||||
|
* Authentication: By zbx_session - cookie or zabbix-auth-token - header
|
||||||
|
*/
|
||||||
|
deleteTemplateGroups?: Maybe<Array<DeleteResponse>>;
|
||||||
|
/**
|
||||||
|
* Delete templates.
|
||||||
|
*
|
||||||
|
* Authentication: By zbx_session - cookie or zabbix-auth-token - header
|
||||||
|
*/
|
||||||
|
deleteTemplates?: Maybe<Array<DeleteResponse>>;
|
||||||
/**
|
/**
|
||||||
* (Mass) Import zabbix groups
|
* (Mass) Import zabbix groups
|
||||||
* and assign them to the corresponding hosts by groupid or groupName.
|
* and assign them to the corresponding hosts by groupid or groupName.
|
||||||
|
|
@ -287,6 +395,25 @@ export interface Mutation {
|
||||||
* Authentication: By zbx_session - cookie or zabbix-auth-token - header
|
* Authentication: By zbx_session - cookie or zabbix-auth-token - header
|
||||||
*/
|
*/
|
||||||
importHosts?: Maybe<Array<ImportHostResponse>>;
|
importHosts?: Maybe<Array<ImportHostResponse>>;
|
||||||
|
/**
|
||||||
|
* (Mass) Import template groups
|
||||||
|
* and assign them by groupid or name.
|
||||||
|
*
|
||||||
|
* Return value: If no error occurs a groupid be returned for each created group,
|
||||||
|
* otherwise the return object will contain an error message
|
||||||
|
*
|
||||||
|
* Authentication: By zbx_session - cookie or zabbix-auth-token - header
|
||||||
|
*/
|
||||||
|
importTemplateGroups?: Maybe<Array<CreateTemplateGroupResponse>>;
|
||||||
|
/**
|
||||||
|
* (Mass) Import templates.
|
||||||
|
*
|
||||||
|
* Return value: If no error occurs a templateid will be returned for each created template,
|
||||||
|
* otherwise the return object will contain an error message.
|
||||||
|
*
|
||||||
|
* Authentication: By zbx_session - cookie or zabbix-auth-token - header
|
||||||
|
*/
|
||||||
|
importTemplates?: Maybe<Array<ImportTemplateResponse>>;
|
||||||
importUserRights?: Maybe<ImportUserRightsResult>;
|
importUserRights?: Maybe<ImportUserRightsResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -299,6 +426,18 @@ export interface MutationCreateHostArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface MutationDeleteTemplateGroupsArgs {
|
||||||
|
groupids?: InputMaybe<Array<Scalars['Int']['input']>>;
|
||||||
|
name_pattern?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface MutationDeleteTemplatesArgs {
|
||||||
|
name_pattern?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
templateids?: InputMaybe<Array<Scalars['Int']['input']>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface MutationImportHostGroupsArgs {
|
export interface MutationImportHostGroupsArgs {
|
||||||
hostGroups: Array<CreateHostGroup>;
|
hostGroups: Array<CreateHostGroup>;
|
||||||
}
|
}
|
||||||
|
|
@ -309,6 +448,16 @@ export interface MutationImportHostsArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface MutationImportTemplateGroupsArgs {
|
||||||
|
templateGroups: Array<CreateTemplateGroup>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface MutationImportTemplatesArgs {
|
||||||
|
templates: Array<CreateTemplate>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface MutationImportUserRightsArgs {
|
export interface MutationImportUserRightsArgs {
|
||||||
dryRun?: Scalars['Boolean']['input'];
|
dryRun?: Scalars['Boolean']['input'];
|
||||||
input: UserRightsInput;
|
input: UserRightsInput;
|
||||||
|
|
@ -359,6 +508,8 @@ export interface Query {
|
||||||
* Authentication: By zbx_session - cookie or zabbix-auth-token - header
|
* Authentication: By zbx_session - cookie or zabbix-auth-token - header
|
||||||
*/
|
*/
|
||||||
allHosts?: Maybe<Array<Maybe<Host>>>;
|
allHosts?: Maybe<Array<Maybe<Host>>>;
|
||||||
|
/** Get template groups. */
|
||||||
|
allTemplateGroups?: Maybe<Array<Maybe<HostGroup>>>;
|
||||||
/** Get api (build) version */
|
/** Get api (build) version */
|
||||||
apiVersion: Scalars['String']['output'];
|
apiVersion: Scalars['String']['output'];
|
||||||
/**
|
/**
|
||||||
|
|
@ -401,6 +552,8 @@ export interface Query {
|
||||||
* operation. Returns true on success
|
* operation. Returns true on success
|
||||||
*/
|
*/
|
||||||
logout?: Maybe<Scalars['Boolean']['output']>;
|
logout?: Maybe<Scalars['Boolean']['output']>;
|
||||||
|
/** Get templates. */
|
||||||
|
templates?: Maybe<Array<Maybe<Template>>>;
|
||||||
/**
|
/**
|
||||||
* Return all user permissions. If objectNames is provided return only the permissions related to the objects within
|
* Return all user permissions. If objectNames is provided return only the permissions related to the objects within
|
||||||
* the objectNames - list
|
* the objectNames - list
|
||||||
|
|
@ -439,6 +592,11 @@ export interface QueryAllHostsArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface QueryAllTemplateGroupsArgs {
|
||||||
|
name_pattern?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface QueryExportHostValueHistoryArgs {
|
export interface QueryExportHostValueHistoryArgs {
|
||||||
host_filter?: InputMaybe<Array<Scalars['String']['input']>>;
|
host_filter?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||||
itemKey_filter?: InputMaybe<Array<Scalars['String']['input']>>;
|
itemKey_filter?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||||
|
|
@ -474,6 +632,12 @@ export interface QueryLoginArgs {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface QueryTemplatesArgs {
|
||||||
|
hostids?: InputMaybe<Array<InputMaybe<Scalars['Int']['input']>>>;
|
||||||
|
name_pattern?: InputMaybe<Scalars['String']['input']>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface QueryUserPermissionsArgs {
|
export interface QueryUserPermissionsArgs {
|
||||||
objectNames?: InputMaybe<Array<Scalars['String']['input']>>;
|
objectNames?: InputMaybe<Array<Scalars['String']['input']>>;
|
||||||
}
|
}
|
||||||
|
|
@ -749,7 +913,16 @@ export type ResolversTypes = {
|
||||||
CreateHostGroup: CreateHostGroup;
|
CreateHostGroup: CreateHostGroup;
|
||||||
CreateHostGroupResponse: ResolverTypeWrapper<CreateHostGroupResponse>;
|
CreateHostGroupResponse: ResolverTypeWrapper<CreateHostGroupResponse>;
|
||||||
CreateHostResponse: ResolverTypeWrapper<CreateHostResponse>;
|
CreateHostResponse: ResolverTypeWrapper<CreateHostResponse>;
|
||||||
|
CreateItemPreprocessing: CreateItemPreprocessing;
|
||||||
|
CreateLinkedTemplate: CreateLinkedTemplate;
|
||||||
|
CreateMasterItem: CreateMasterItem;
|
||||||
|
CreateTag: CreateTag;
|
||||||
|
CreateTemplate: CreateTemplate;
|
||||||
|
CreateTemplateGroup: CreateTemplateGroup;
|
||||||
|
CreateTemplateGroupResponse: ResolverTypeWrapper<CreateTemplateGroupResponse>;
|
||||||
|
CreateTemplateItem: CreateTemplateItem;
|
||||||
DateTime: ResolverTypeWrapper<Scalars['DateTime']['output']>;
|
DateTime: ResolverTypeWrapper<Scalars['DateTime']['output']>;
|
||||||
|
DeleteResponse: ResolverTypeWrapper<DeleteResponse>;
|
||||||
Device: ResolverTypeWrapper<ResolversInterfaceTypes<ResolversTypes>['Device']>;
|
Device: ResolverTypeWrapper<ResolversInterfaceTypes<ResolversTypes>['Device']>;
|
||||||
DeviceCommunicationType: DeviceCommunicationType;
|
DeviceCommunicationType: DeviceCommunicationType;
|
||||||
DeviceConfig: ResolverTypeWrapper<DeviceConfig>;
|
DeviceConfig: ResolverTypeWrapper<DeviceConfig>;
|
||||||
|
|
@ -769,6 +942,7 @@ export type ResolversTypes = {
|
||||||
HostGroup: ResolverTypeWrapper<HostGroup>;
|
HostGroup: ResolverTypeWrapper<HostGroup>;
|
||||||
ID: ResolverTypeWrapper<Scalars['ID']['output']>;
|
ID: ResolverTypeWrapper<Scalars['ID']['output']>;
|
||||||
ImportHostResponse: ResolverTypeWrapper<ImportHostResponse>;
|
ImportHostResponse: ResolverTypeWrapper<ImportHostResponse>;
|
||||||
|
ImportTemplateResponse: ResolverTypeWrapper<ImportTemplateResponse>;
|
||||||
ImportUserRightResult: ResolverTypeWrapper<ImportUserRightResult>;
|
ImportUserRightResult: ResolverTypeWrapper<ImportUserRightResult>;
|
||||||
ImportUserRightsResult: ResolverTypeWrapper<ImportUserRightsResult>;
|
ImportUserRightsResult: ResolverTypeWrapper<ImportUserRightsResult>;
|
||||||
Int: ResolverTypeWrapper<Scalars['Int']['output']>;
|
Int: ResolverTypeWrapper<Scalars['Int']['output']>;
|
||||||
|
|
@ -814,7 +988,16 @@ export type ResolversParentTypes = {
|
||||||
CreateHostGroup: CreateHostGroup;
|
CreateHostGroup: CreateHostGroup;
|
||||||
CreateHostGroupResponse: CreateHostGroupResponse;
|
CreateHostGroupResponse: CreateHostGroupResponse;
|
||||||
CreateHostResponse: CreateHostResponse;
|
CreateHostResponse: CreateHostResponse;
|
||||||
|
CreateItemPreprocessing: CreateItemPreprocessing;
|
||||||
|
CreateLinkedTemplate: CreateLinkedTemplate;
|
||||||
|
CreateMasterItem: CreateMasterItem;
|
||||||
|
CreateTag: CreateTag;
|
||||||
|
CreateTemplate: CreateTemplate;
|
||||||
|
CreateTemplateGroup: CreateTemplateGroup;
|
||||||
|
CreateTemplateGroupResponse: CreateTemplateGroupResponse;
|
||||||
|
CreateTemplateItem: CreateTemplateItem;
|
||||||
DateTime: Scalars['DateTime']['output'];
|
DateTime: Scalars['DateTime']['output'];
|
||||||
|
DeleteResponse: DeleteResponse;
|
||||||
Device: ResolversInterfaceTypes<ResolversParentTypes>['Device'];
|
Device: ResolversInterfaceTypes<ResolversParentTypes>['Device'];
|
||||||
DeviceConfig: DeviceConfig;
|
DeviceConfig: DeviceConfig;
|
||||||
DeviceState: ResolversInterfaceTypes<ResolversParentTypes>['DeviceState'];
|
DeviceState: ResolversInterfaceTypes<ResolversParentTypes>['DeviceState'];
|
||||||
|
|
@ -832,6 +1015,7 @@ export type ResolversParentTypes = {
|
||||||
HostGroup: HostGroup;
|
HostGroup: HostGroup;
|
||||||
ID: Scalars['ID']['output'];
|
ID: Scalars['ID']['output'];
|
||||||
ImportHostResponse: ImportHostResponse;
|
ImportHostResponse: ImportHostResponse;
|
||||||
|
ImportTemplateResponse: ImportTemplateResponse;
|
||||||
ImportUserRightResult: ImportUserRightResult;
|
ImportUserRightResult: ImportUserRightResult;
|
||||||
ImportUserRightsResult: ImportUserRightsResult;
|
ImportUserRightsResult: ImportUserRightsResult;
|
||||||
Int: Scalars['Int']['output'];
|
Int: Scalars['Int']['output'];
|
||||||
|
|
@ -890,10 +1074,25 @@ export type CreateHostResponseResolvers<ContextType = any, ParentType extends Re
|
||||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CreateTemplateGroupResponseResolvers<ContextType = any, ParentType extends ResolversParentTypes['CreateTemplateGroupResponse'] = ResolversParentTypes['CreateTemplateGroupResponse']> = {
|
||||||
|
error?: Resolver<Maybe<ResolversTypes['ApiError']>, ParentType, ContextType>;
|
||||||
|
groupName?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||||
|
groupid?: Resolver<Maybe<ResolversTypes['Int']>, ParentType, ContextType>;
|
||||||
|
message?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||||
|
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||||
|
};
|
||||||
|
|
||||||
export interface DateTimeScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['DateTime'], any> {
|
export interface DateTimeScalarConfig extends GraphQLScalarTypeConfig<ResolversTypes['DateTime'], any> {
|
||||||
name: 'DateTime';
|
name: 'DateTime';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type DeleteResponseResolvers<ContextType = any, ParentType extends ResolversParentTypes['DeleteResponse'] = ResolversParentTypes['DeleteResponse']> = {
|
||||||
|
error?: Resolver<Maybe<ResolversTypes['ApiError']>, ParentType, ContextType>;
|
||||||
|
id?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
|
||||||
|
message?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||||
|
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||||
|
};
|
||||||
|
|
||||||
export type DeviceResolvers<ContextType = any, ParentType extends ResolversParentTypes['Device'] = ResolversParentTypes['Device']> = {
|
export type DeviceResolvers<ContextType = any, ParentType extends ResolversParentTypes['Device'] = ResolversParentTypes['Device']> = {
|
||||||
__resolveType: TypeResolveFn<'GenericDevice', ParentType, ContextType>;
|
__resolveType: TypeResolveFn<'GenericDevice', ParentType, ContextType>;
|
||||||
deviceType?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
deviceType?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||||
|
|
@ -1011,6 +1210,14 @@ export type ImportHostResponseResolvers<ContextType = any, ParentType extends Re
|
||||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ImportTemplateResponseResolvers<ContextType = any, ParentType extends ResolversParentTypes['ImportTemplateResponse'] = ResolversParentTypes['ImportTemplateResponse']> = {
|
||||||
|
error?: Resolver<Maybe<ResolversTypes['ApiError']>, ParentType, ContextType>;
|
||||||
|
host?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||||
|
message?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||||
|
templateid?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||||
|
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||||
|
};
|
||||||
|
|
||||||
export type ImportUserRightResultResolvers<ContextType = any, ParentType extends ResolversParentTypes['ImportUserRightResult'] = ResolversParentTypes['ImportUserRightResult']> = {
|
export type ImportUserRightResultResolvers<ContextType = any, ParentType extends ResolversParentTypes['ImportUserRightResult'] = ResolversParentTypes['ImportUserRightResult']> = {
|
||||||
errors?: Resolver<Maybe<Array<ResolversTypes['ApiError']>>, ParentType, ContextType>;
|
errors?: Resolver<Maybe<Array<ResolversTypes['ApiError']>>, ParentType, ContextType>;
|
||||||
id?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
id?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||||
|
|
@ -1043,8 +1250,12 @@ export type LocationResolvers<ContextType = any, ParentType extends ResolversPar
|
||||||
|
|
||||||
export type MutationResolvers<ContextType = any, ParentType extends ResolversParentTypes['Mutation'] = ResolversParentTypes['Mutation']> = {
|
export type MutationResolvers<ContextType = any, ParentType extends ResolversParentTypes['Mutation'] = ResolversParentTypes['Mutation']> = {
|
||||||
createHost?: Resolver<Maybe<ResolversTypes['CreateHostResponse']>, ParentType, ContextType, RequireFields<MutationCreateHostArgs, 'host' | 'hostgroupids' | 'templateids'>>;
|
createHost?: Resolver<Maybe<ResolversTypes['CreateHostResponse']>, ParentType, ContextType, RequireFields<MutationCreateHostArgs, 'host' | 'hostgroupids' | 'templateids'>>;
|
||||||
|
deleteTemplateGroups?: Resolver<Maybe<Array<ResolversTypes['DeleteResponse']>>, ParentType, ContextType, Partial<MutationDeleteTemplateGroupsArgs>>;
|
||||||
|
deleteTemplates?: Resolver<Maybe<Array<ResolversTypes['DeleteResponse']>>, ParentType, ContextType, Partial<MutationDeleteTemplatesArgs>>;
|
||||||
importHostGroups?: Resolver<Maybe<Array<ResolversTypes['CreateHostGroupResponse']>>, ParentType, ContextType, RequireFields<MutationImportHostGroupsArgs, 'hostGroups'>>;
|
importHostGroups?: Resolver<Maybe<Array<ResolversTypes['CreateHostGroupResponse']>>, ParentType, ContextType, RequireFields<MutationImportHostGroupsArgs, 'hostGroups'>>;
|
||||||
importHosts?: Resolver<Maybe<Array<ResolversTypes['ImportHostResponse']>>, ParentType, ContextType, RequireFields<MutationImportHostsArgs, 'hosts'>>;
|
importHosts?: Resolver<Maybe<Array<ResolversTypes['ImportHostResponse']>>, ParentType, ContextType, RequireFields<MutationImportHostsArgs, 'hosts'>>;
|
||||||
|
importTemplateGroups?: Resolver<Maybe<Array<ResolversTypes['CreateTemplateGroupResponse']>>, ParentType, ContextType, RequireFields<MutationImportTemplateGroupsArgs, 'templateGroups'>>;
|
||||||
|
importTemplates?: Resolver<Maybe<Array<ResolversTypes['ImportTemplateResponse']>>, ParentType, ContextType, RequireFields<MutationImportTemplatesArgs, 'templates'>>;
|
||||||
importUserRights?: Resolver<Maybe<ResolversTypes['ImportUserRightsResult']>, ParentType, ContextType, RequireFields<MutationImportUserRightsArgs, 'dryRun' | 'input'>>;
|
importUserRights?: Resolver<Maybe<ResolversTypes['ImportUserRightsResult']>, ParentType, ContextType, RequireFields<MutationImportUserRightsArgs, 'dryRun' | 'input'>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1064,6 +1275,7 @@ export type QueryResolvers<ContextType = any, ParentType extends ResolversParent
|
||||||
allDevices?: Resolver<Maybe<Array<Maybe<ResolversTypes['Device']>>>, ParentType, ContextType, RequireFields<QueryAllDevicesArgs, 'filter_host' | 'groupids' | 'name_pattern' | 'tag_deviceType' | 'with_items'>>;
|
allDevices?: Resolver<Maybe<Array<Maybe<ResolversTypes['Device']>>>, ParentType, ContextType, RequireFields<QueryAllDevicesArgs, 'filter_host' | 'groupids' | 'name_pattern' | 'tag_deviceType' | 'with_items'>>;
|
||||||
allHostGroups?: Resolver<Maybe<Array<Maybe<ResolversTypes['HostGroup']>>>, ParentType, ContextType, RequireFields<QueryAllHostGroupsArgs, 'with_hosts'>>;
|
allHostGroups?: Resolver<Maybe<Array<Maybe<ResolversTypes['HostGroup']>>>, ParentType, ContextType, RequireFields<QueryAllHostGroupsArgs, 'with_hosts'>>;
|
||||||
allHosts?: Resolver<Maybe<Array<Maybe<ResolversTypes['Host']>>>, ParentType, ContextType, RequireFields<QueryAllHostsArgs, 'filter_host' | 'groupids' | 'name_pattern' | 'tag_deviceType' | 'with_items'>>;
|
allHosts?: Resolver<Maybe<Array<Maybe<ResolversTypes['Host']>>>, ParentType, ContextType, RequireFields<QueryAllHostsArgs, 'filter_host' | 'groupids' | 'name_pattern' | 'tag_deviceType' | 'with_items'>>;
|
||||||
|
allTemplateGroups?: Resolver<Maybe<Array<Maybe<ResolversTypes['HostGroup']>>>, ParentType, ContextType, Partial<QueryAllTemplateGroupsArgs>>;
|
||||||
apiVersion?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
apiVersion?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||||
exportHostValueHistory?: Resolver<Maybe<ResolversTypes['GenericResponse']>, ParentType, ContextType, RequireFields<QueryExportHostValueHistoryArgs, 'sortOrder' | 'type'>>;
|
exportHostValueHistory?: Resolver<Maybe<ResolversTypes['GenericResponse']>, ParentType, ContextType, RequireFields<QueryExportHostValueHistoryArgs, 'sortOrder' | 'type'>>;
|
||||||
exportUserRights?: Resolver<Maybe<ResolversTypes['UserRights']>, ParentType, ContextType, RequireFields<QueryExportUserRightsArgs, 'exclude_hostgroups_pattern' | 'name_pattern'>>;
|
exportUserRights?: Resolver<Maybe<ResolversTypes['UserRights']>, ParentType, ContextType, RequireFields<QueryExportUserRightsArgs, 'exclude_hostgroups_pattern' | 'name_pattern'>>;
|
||||||
|
|
@ -1071,6 +1283,7 @@ export type QueryResolvers<ContextType = any, ParentType extends ResolversParent
|
||||||
locations?: Resolver<Maybe<Array<Maybe<ResolversTypes['Location']>>>, ParentType, ContextType, RequireFields<QueryLocationsArgs, 'distinct_by_name' | 'name_pattern' | 'templateids'>>;
|
locations?: Resolver<Maybe<Array<Maybe<ResolversTypes['Location']>>>, ParentType, ContextType, RequireFields<QueryLocationsArgs, 'distinct_by_name' | 'name_pattern' | 'templateids'>>;
|
||||||
login?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType, RequireFields<QueryLoginArgs, 'password' | 'username'>>;
|
login?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType, RequireFields<QueryLoginArgs, 'password' | 'username'>>;
|
||||||
logout?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
|
logout?: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
|
||||||
|
templates?: Resolver<Maybe<Array<Maybe<ResolversTypes['Template']>>>, ParentType, ContextType, Partial<QueryTemplatesArgs>>;
|
||||||
userPermissions?: Resolver<Maybe<Array<ResolversTypes['UserPermission']>>, ParentType, ContextType, Partial<QueryUserPermissionsArgs>>;
|
userPermissions?: Resolver<Maybe<Array<ResolversTypes['UserPermission']>>, ParentType, ContextType, Partial<QueryUserPermissionsArgs>>;
|
||||||
zabbixVersion?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
zabbixVersion?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||||
};
|
};
|
||||||
|
|
@ -1193,7 +1406,9 @@ export type Resolvers<ContextType = any> = {
|
||||||
ApiError?: ApiErrorResolvers<ContextType>;
|
ApiError?: ApiErrorResolvers<ContextType>;
|
||||||
CreateHostGroupResponse?: CreateHostGroupResponseResolvers<ContextType>;
|
CreateHostGroupResponse?: CreateHostGroupResponseResolvers<ContextType>;
|
||||||
CreateHostResponse?: CreateHostResponseResolvers<ContextType>;
|
CreateHostResponse?: CreateHostResponseResolvers<ContextType>;
|
||||||
|
CreateTemplateGroupResponse?: CreateTemplateGroupResponseResolvers<ContextType>;
|
||||||
DateTime?: GraphQLScalarType;
|
DateTime?: GraphQLScalarType;
|
||||||
|
DeleteResponse?: DeleteResponseResolvers<ContextType>;
|
||||||
Device?: DeviceResolvers<ContextType>;
|
Device?: DeviceResolvers<ContextType>;
|
||||||
DeviceCommunicationType?: DeviceCommunicationTypeResolvers;
|
DeviceCommunicationType?: DeviceCommunicationTypeResolvers;
|
||||||
DeviceConfig?: DeviceConfigResolvers<ContextType>;
|
DeviceConfig?: DeviceConfigResolvers<ContextType>;
|
||||||
|
|
@ -1211,6 +1426,7 @@ export type Resolvers<ContextType = any> = {
|
||||||
Host?: HostResolvers<ContextType>;
|
Host?: HostResolvers<ContextType>;
|
||||||
HostGroup?: HostGroupResolvers<ContextType>;
|
HostGroup?: HostGroupResolvers<ContextType>;
|
||||||
ImportHostResponse?: ImportHostResponseResolvers<ContextType>;
|
ImportHostResponse?: ImportHostResponseResolvers<ContextType>;
|
||||||
|
ImportTemplateResponse?: ImportTemplateResponseResolvers<ContextType>;
|
||||||
ImportUserRightResult?: ImportUserRightResultResolvers<ContextType>;
|
ImportUserRightResult?: ImportUserRightResultResolvers<ContextType>;
|
||||||
ImportUserRightsResult?: ImportUserRightsResultResolvers<ContextType>;
|
ImportUserRightsResult?: ImportUserRightsResultResolvers<ContextType>;
|
||||||
Inventory?: InventoryResolvers<ContextType>;
|
Inventory?: InventoryResolvers<ContextType>;
|
||||||
|
|
|
||||||
162
src/test/template_deleter.test.ts
Normal file
162
src/test/template_deleter.test.ts
Normal file
|
|
@ -0,0 +1,162 @@
|
||||||
|
|
||||||
|
import {TemplateDeleter} from "../execution/template_deleter.js";
|
||||||
|
import {zabbixAPI} from "../datasources/zabbix-api.js";
|
||||||
|
|
||||||
|
// Mocking ZabbixAPI
|
||||||
|
jest.mock("../datasources/zabbix-api.js", () => ({
|
||||||
|
zabbixAPI: {
|
||||||
|
executeRequest: jest.fn(),
|
||||||
|
post: jest.fn()
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("TemplateDeleter", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("deleteTemplates - success", async () => {
|
||||||
|
const templateids = [1, 2];
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ templateids: ["1", "2"] });
|
||||||
|
|
||||||
|
const result = await TemplateDeleter.deleteTemplates(templateids, null, "token");
|
||||||
|
|
||||||
|
expect(result).toHaveLength(2);
|
||||||
|
expect(result[0].id).toBe(1);
|
||||||
|
expect(result[0].message).toContain("deleted successfully");
|
||||||
|
expect(result[1].id).toBe(2);
|
||||||
|
|
||||||
|
expect(zabbixAPI.post).toHaveBeenCalledWith("template.delete", expect.objectContaining({
|
||||||
|
body: expect.objectContaining({
|
||||||
|
params: [1, 2]
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("deleteTemplates - error", async () => {
|
||||||
|
const templateids = [1];
|
||||||
|
const zabbixError = {
|
||||||
|
error: {
|
||||||
|
code: -32602,
|
||||||
|
message: "Invalid params.",
|
||||||
|
data: "Template does not exist"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce(zabbixError);
|
||||||
|
|
||||||
|
const result = await TemplateDeleter.deleteTemplates(templateids, null, "token");
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result[0].error).toBeDefined();
|
||||||
|
expect(result[0].message).toContain("Invalid params.");
|
||||||
|
expect(result[0].message).toContain("Template does not exist");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("deleteTemplates - by name_pattern", async () => {
|
||||||
|
// Mock template.get
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([
|
||||||
|
{ templateid: "10", host: "PatternTemplate 1" },
|
||||||
|
{ templateid: "11", host: "PatternTemplate 2" }
|
||||||
|
]);
|
||||||
|
// Mock template.delete
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ templateids: ["10", "11"] });
|
||||||
|
|
||||||
|
const result = await TemplateDeleter.deleteTemplates(null, "PatternTemplate%", "token");
|
||||||
|
|
||||||
|
expect(result).toHaveLength(2);
|
||||||
|
expect(result.map(r => r.id)).toContain(10);
|
||||||
|
expect(result.map(r => r.id)).toContain(11);
|
||||||
|
|
||||||
|
expect(zabbixAPI.post).toHaveBeenCalledWith("template.get", expect.objectContaining({
|
||||||
|
body: expect.objectContaining({
|
||||||
|
params: expect.objectContaining({
|
||||||
|
search: { name: "PatternTemplate%" }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
expect(zabbixAPI.post).toHaveBeenCalledWith("template.delete", expect.objectContaining({
|
||||||
|
body: expect.objectContaining({
|
||||||
|
params: expect.arrayContaining([10, 11])
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("deleteTemplates - merged IDs and name_pattern", async () => {
|
||||||
|
// Mock template.get
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([
|
||||||
|
{ templateid: "10", host: "PatternTemplate 1" },
|
||||||
|
{ templateid: "12", host: "PatternTemplate 3" }
|
||||||
|
]);
|
||||||
|
// Mock template.delete
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ templateids: ["10", "11", "12"] });
|
||||||
|
|
||||||
|
const result = await TemplateDeleter.deleteTemplates([11], "PatternTemplate%", "token");
|
||||||
|
|
||||||
|
expect(result).toHaveLength(3);
|
||||||
|
expect(result.map(r => r.id)).toContain(10);
|
||||||
|
expect(result.map(r => r.id)).toContain(11);
|
||||||
|
expect(result.map(r => r.id)).toContain(12);
|
||||||
|
|
||||||
|
expect(zabbixAPI.post).toHaveBeenCalledWith("template.delete", expect.objectContaining({
|
||||||
|
body: expect.objectContaining({
|
||||||
|
params: expect.arrayContaining([10, 11, 12])
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("deleteTemplateGroups - success", async () => {
|
||||||
|
const groupids = [101];
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ groupids: ["101"] });
|
||||||
|
|
||||||
|
const result = await TemplateDeleter.deleteTemplateGroups(groupids, null, "token");
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result[0].id).toBe(101);
|
||||||
|
expect(result[0].message).toContain("deleted successfully");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("deleteTemplateGroups - error", async () => {
|
||||||
|
const groupids = [101];
|
||||||
|
const zabbixError = {
|
||||||
|
error: {
|
||||||
|
code: -32602,
|
||||||
|
message: "Invalid params.",
|
||||||
|
data: "Group is in use"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce(zabbixError);
|
||||||
|
|
||||||
|
const result = await TemplateDeleter.deleteTemplateGroups(groupids, null, "token");
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result[0].error).toBeDefined();
|
||||||
|
expect(result[0].message).toContain("Group is in use");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("deleteTemplateGroups - by name_pattern", async () => {
|
||||||
|
// Mock templategroup.get
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([
|
||||||
|
{ groupid: "201", name: "PatternGroup 1" }
|
||||||
|
]);
|
||||||
|
// Mock templategroup.delete
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ groupids: ["201"] });
|
||||||
|
|
||||||
|
const result = await TemplateDeleter.deleteTemplateGroups(null, "PatternGroup%", "token");
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result[0].id).toBe(201);
|
||||||
|
|
||||||
|
expect(zabbixAPI.post).toHaveBeenCalledWith("templategroup.get", expect.objectContaining({
|
||||||
|
body: expect.objectContaining({
|
||||||
|
params: expect.objectContaining({
|
||||||
|
search: { name: "PatternGroup%" }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
expect(zabbixAPI.post).toHaveBeenCalledWith("templategroup.delete", expect.objectContaining({
|
||||||
|
body: expect.objectContaining({
|
||||||
|
params: [201]
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
176
src/test/template_importer.test.ts
Normal file
176
src/test/template_importer.test.ts
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
|
||||||
|
import {TemplateImporter} from "../execution/template_importer.js";
|
||||||
|
import {zabbixAPI} from "../datasources/zabbix-api.js";
|
||||||
|
import {
|
||||||
|
ZabbixCreateItemRequest,
|
||||||
|
ZabbixCreateTemplateGroupRequest,
|
||||||
|
ZabbixCreateTemplateRequest,
|
||||||
|
ZabbixQueryItemRequest,
|
||||||
|
ZabbixQueryTemplateGroupRequest,
|
||||||
|
ZabbixQueryTemplatesRequest
|
||||||
|
} from "../datasources/zabbix-templates.js";
|
||||||
|
import {ZabbixErrorResult} from "../datasources/zabbix-request.js";
|
||||||
|
|
||||||
|
// Mocking ZabbixAPI.executeRequest
|
||||||
|
jest.mock("../datasources/zabbix-api.js", () => ({
|
||||||
|
zabbixAPI: {
|
||||||
|
executeRequest: jest.fn(),
|
||||||
|
post: jest.fn()
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("TemplateImporter", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("importTemplateGroups - create new group", async () => {
|
||||||
|
const templateGroups = [{ groupName: "New Group", uuid: "uuid1" }];
|
||||||
|
|
||||||
|
// Mocking group.get to return empty (group doesn't exist)
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([]);
|
||||||
|
// Mocking group.create
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ groupids: ["101"] });
|
||||||
|
|
||||||
|
const result = await TemplateImporter.importTemplateGroups(templateGroups, "token");
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result![0].groupid).toBe(101);
|
||||||
|
expect(result![0].groupName).toBe("New Group");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("importTemplateGroups - group already exists", async () => {
|
||||||
|
const templateGroups = [{ groupName: "Existing Group" }];
|
||||||
|
|
||||||
|
// Mocking group.get to return existing group
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ groupid: "102", name: "Existing Group" }]);
|
||||||
|
|
||||||
|
const result = await TemplateImporter.importTemplateGroups(templateGroups, "token");
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result![0].groupid).toBe(102);
|
||||||
|
expect(result![0].message).toContain("already exists");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("importTemplates - basic template", async () => {
|
||||||
|
const templates = [{
|
||||||
|
host: "Test Template",
|
||||||
|
groupNames: ["Group1"]
|
||||||
|
}];
|
||||||
|
|
||||||
|
// Mocking group.get for Group1
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ groupid: "201", name: "Group1" }]);
|
||||||
|
// Mocking template.create
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ templateids: ["301"] });
|
||||||
|
|
||||||
|
const result = await TemplateImporter.importTemplates(templates, "token");
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result![0].templateid).toBe("301");
|
||||||
|
expect(result![0].host).toBe("Test Template");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("importTemplates - with items, linked templates and dependent items", async () => {
|
||||||
|
const templates = [{
|
||||||
|
host: "Complex Template",
|
||||||
|
groupNames: ["Group1"],
|
||||||
|
templates: [{ name: "Linked Template" }],
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: "Dependent Item",
|
||||||
|
key: "dependent.key",
|
||||||
|
type: 18,
|
||||||
|
value_type: 3,
|
||||||
|
master_item: { key: "master.key" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Master Item",
|
||||||
|
key: "master.key",
|
||||||
|
type: 0,
|
||||||
|
value_type: 3,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}];
|
||||||
|
|
||||||
|
// Mocking group.get
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ groupid: "201", name: "Group1" }]);
|
||||||
|
// Mocking template.get for linked template
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ templateid: "401", host: "Linked Template" }]);
|
||||||
|
// Mocking template.create
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ templateids: ["501"] });
|
||||||
|
|
||||||
|
// Mocking item.create for Master Item (first pass will pick Master Item because Dependent Item is missing its master)
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ itemids: ["601"] });
|
||||||
|
// Mocking item.create for Dependent Item (second pass)
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ itemids: ["602"] });
|
||||||
|
|
||||||
|
const result = await TemplateImporter.importTemplates(templates, "token");
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result![0].templateid).toBe("501");
|
||||||
|
|
||||||
|
// Check template.create params
|
||||||
|
const templateCreateCall = (zabbixAPI.post as jest.Mock).mock.calls.find(call => call[1].body.method === "template.create");
|
||||||
|
expect(templateCreateCall[1].body.params.templates).toContainEqual({ templateid: "401" });
|
||||||
|
|
||||||
|
// Check item.create calls
|
||||||
|
const itemCreateCalls = (zabbixAPI.post as jest.Mock).mock.calls.filter(call => call[1].body.method === "item.create");
|
||||||
|
expect(itemCreateCalls).toHaveLength(2);
|
||||||
|
|
||||||
|
const masterCall = itemCreateCalls.find(c => c[1].body.params.name === "Master Item");
|
||||||
|
const dependentCall = itemCreateCalls.find(c => c[1].body.params.name === "Dependent Item");
|
||||||
|
|
||||||
|
expect(masterCall[1].body.params.key_).toBe("master.key");
|
||||||
|
expect(dependentCall[1].body.params.key_).toBe("dependent.key");
|
||||||
|
expect(dependentCall[1].body.params.master_itemid).toBe("601");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("importTemplates - template query", async () => {
|
||||||
|
// This tests the template.get functionality used during import
|
||||||
|
const templates = [{
|
||||||
|
host: "Template A",
|
||||||
|
groupNames: ["Group1"],
|
||||||
|
templates: [{ name: "Template B" }]
|
||||||
|
}];
|
||||||
|
|
||||||
|
// Mock Group
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ groupid: "1", name: "Group1" }]);
|
||||||
|
// Mock Template B lookup
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ templateid: "2", host: "Template B" }]);
|
||||||
|
// Mock Template A creation
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ templateids: ["3"] });
|
||||||
|
|
||||||
|
await TemplateImporter.importTemplates(templates, "token");
|
||||||
|
|
||||||
|
// Verify that template.get was called for Template B
|
||||||
|
const templateQueryCall = (zabbixAPI.post as jest.Mock).mock.calls.find(call => call[1].body.method === "template.get");
|
||||||
|
expect(templateQueryCall).toBeDefined();
|
||||||
|
expect(templateQueryCall[1].body.params.filter.host).toContain("Template B");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("importTemplates - error message includes data field", async () => {
|
||||||
|
const templates = [{
|
||||||
|
host: "Error Template",
|
||||||
|
groupNames: ["Group1"]
|
||||||
|
}];
|
||||||
|
|
||||||
|
// Mocking group.get
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ groupid: "201", name: "Group1" }]);
|
||||||
|
|
||||||
|
// Mocking template.create with an error including data
|
||||||
|
const zabbixError = {
|
||||||
|
error: {
|
||||||
|
code: -32602,
|
||||||
|
message: "Invalid params.",
|
||||||
|
data: "Invalid parameter \"/1\": the parameter \"key_\" is missing."
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce(zabbixError);
|
||||||
|
|
||||||
|
const result = await TemplateImporter.importTemplates(templates, "token");
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result![0].message).toContain("Invalid params.");
|
||||||
|
expect(result![0].message).toContain("the parameter \"key_\" is missing.");
|
||||||
|
});
|
||||||
|
});
|
||||||
229
src/test/template_integration.test.ts
Normal file
229
src/test/template_integration.test.ts
Normal file
|
|
@ -0,0 +1,229 @@
|
||||||
|
import { ApolloServer } from '@apollo/server';
|
||||||
|
import { schema_loader } from '../api/schema.js';
|
||||||
|
import { readFileSync } from 'fs';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { zabbixAPI } from '../datasources/zabbix-api.js';
|
||||||
|
|
||||||
|
// Mocking ZabbixAPI.post
|
||||||
|
jest.mock("../datasources/zabbix-api.js", () => ({
|
||||||
|
zabbixAPI: {
|
||||||
|
post: jest.fn(),
|
||||||
|
executeRequest: jest.fn(),
|
||||||
|
baseURL: 'http://localhost/zabbix'
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("Template Integration Tests", () => {
|
||||||
|
let server: ApolloServer;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const schema = await schema_loader();
|
||||||
|
server = new ApolloServer({
|
||||||
|
schema,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Import templates using sample query and variables", async () => {
|
||||||
|
const sampleFile = readFileSync(join(process.cwd(), 'docs', 'sample_import_templates_mutation.graphql'), 'utf-8').replace(/\r\n/g, '\n');
|
||||||
|
|
||||||
|
// Extract mutation and variables from the doc file
|
||||||
|
const mutationMatch = sampleFile.match(/```graphql\n([\s\S]*?)\n```/);
|
||||||
|
const variablesMatch = sampleFile.match(/```json\n([\s\S]*?)\n```/);
|
||||||
|
|
||||||
|
const mutation = mutationMatch![1];
|
||||||
|
const variables = JSON.parse(variablesMatch![1]);
|
||||||
|
|
||||||
|
// Mock Zabbix API calls
|
||||||
|
// 1. Group lookup
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ groupid: "201", name: "Templates/Roadwork/Devices" }]);
|
||||||
|
// 2. Linked template lookup
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ templateid: "401", host: "ROADWORK_DEVICE" }]);
|
||||||
|
// 3. Template creation
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ templateids: ["501"] });
|
||||||
|
// 4. Item creation (location)
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ itemids: ["601"] });
|
||||||
|
// 5. Item creation (MQTT_LOCATION)
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ itemids: ["602"] });
|
||||||
|
|
||||||
|
const response = await server.executeOperation({
|
||||||
|
query: mutation,
|
||||||
|
variables: variables,
|
||||||
|
}, {
|
||||||
|
contextValue: {
|
||||||
|
zabbixAuthToken: 'test-token'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.body.kind).toBe('single');
|
||||||
|
// @ts-ignore
|
||||||
|
const result = response.body.singleResult;
|
||||||
|
expect(result.errors).toBeUndefined();
|
||||||
|
expect(result.data.importTemplates).toHaveLength(1);
|
||||||
|
expect(result.data.importTemplates[0].host).toBe("BT_DEVICE_TRACKER");
|
||||||
|
expect(result.data.importTemplates[0].templateid).toBe("501");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Import and Export templates comparison", async () => {
|
||||||
|
// 1. Import
|
||||||
|
const importSample = readFileSync(join(process.cwd(), 'docs', 'sample_import_templates_mutation.graphql'), 'utf-8').replace(/\r\n/g, '\n');
|
||||||
|
const importMutation = importSample.match(/```graphql\n([\s\S]*?)\n```/)![1];
|
||||||
|
const importVariables = JSON.parse(importSample.match(/```json\n([\s\S]*?)\n```/)![1]);
|
||||||
|
|
||||||
|
// Mock for import
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ groupid: "201", name: "Templates/Roadwork/Devices" }]);
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ templateid: "401", host: "ROADWORK_DEVICE" }]);
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ templateids: ["501"] });
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ itemids: ["601"] });
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ itemids: ["602"] });
|
||||||
|
|
||||||
|
await server.executeOperation({
|
||||||
|
query: importMutation,
|
||||||
|
variables: importVariables,
|
||||||
|
}, {
|
||||||
|
contextValue: { zabbixAuthToken: 'test-token' }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Export (Query)
|
||||||
|
const querySample = readFileSync(join(process.cwd(), 'docs', 'sample_templates_query.graphql'), 'utf-8').replace(/\r\n/g, '\n');
|
||||||
|
const query = querySample.match(/```graphql\n([\s\S]*?)\n```/)![1];
|
||||||
|
const queryVariables = JSON.parse(querySample.match(/```json\n([\s\S]*?)\n```/)![1]);
|
||||||
|
|
||||||
|
// Mock for query
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ templateid: "501", host: "BT_DEVICE_TRACKER", name: "BT_DEVICE_TRACKER" }]);
|
||||||
|
|
||||||
|
const queryResponse = await server.executeOperation({
|
||||||
|
query: query,
|
||||||
|
variables: queryVariables,
|
||||||
|
}, {
|
||||||
|
contextValue: { zabbixAuthToken: 'test-token' }
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(queryResponse.body.kind).toBe('single');
|
||||||
|
// @ts-ignore
|
||||||
|
const queryResult = queryResponse.body.singleResult;
|
||||||
|
expect(queryResult.errors).toBeUndefined();
|
||||||
|
expect(queryResult.data.templates).toHaveLength(1);
|
||||||
|
expect(queryResult.data.templates[0].name).toBe(importVariables.templates[0].name);
|
||||||
|
expect(queryResult.data.templates[0].templateid).toBe("501");
|
||||||
|
|
||||||
|
// 3. Delete
|
||||||
|
const deleteMutation = `
|
||||||
|
mutation DeleteTemplates($templateids: [Int!], $name_pattern: String) {
|
||||||
|
deleteTemplates(templateids: $templateids, name_pattern: $name_pattern) {
|
||||||
|
id
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
// Mock for query (to find ID for name_pattern deletion)
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ templateid: "501", host: "BT_DEVICE_TRACKER" }]);
|
||||||
|
// Mock for delete
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ templateids: ["501"] });
|
||||||
|
|
||||||
|
const deleteResponse = await server.executeOperation({
|
||||||
|
query: deleteMutation,
|
||||||
|
variables: { name_pattern: "BT_DEVICE_TRACKER" },
|
||||||
|
}, {
|
||||||
|
contextValue: { zabbixAuthToken: 'test-token' }
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(deleteResponse.body.kind).toBe('single');
|
||||||
|
// @ts-ignore
|
||||||
|
const deleteResult = deleteResponse.body.singleResult;
|
||||||
|
expect(deleteResult.errors).toBeUndefined();
|
||||||
|
expect(deleteResult.data.deleteTemplates).toHaveLength(1);
|
||||||
|
expect(deleteResult.data.deleteTemplates[0].message).toContain("deleted successfully");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Import and Export template groups comparison", async () => {
|
||||||
|
// 1. Import
|
||||||
|
const importSample = readFileSync(join(process.cwd(), 'docs', 'sample_import_template_groups_mutation.graphql'), 'utf-8').replace(/\r\n/g, '\n');
|
||||||
|
const importMutation = importSample.match(/```graphql\n([\s\S]*?)\n```/)![1];
|
||||||
|
const importVariables = JSON.parse(importSample.match(/```json\n([\s\S]*?)\n```/)![1]);
|
||||||
|
|
||||||
|
// Mock for import (8 groups in sample)
|
||||||
|
for (const group of importVariables.templateGroups) {
|
||||||
|
// Mock lookup (not found)
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([]);
|
||||||
|
// Mock creation
|
||||||
|
const mockGroupId = Math.floor(Math.random() * 1000).toString();
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ groupids: [mockGroupId] });
|
||||||
|
}
|
||||||
|
|
||||||
|
const importResponse = await server.executeOperation({
|
||||||
|
query: importMutation,
|
||||||
|
variables: importVariables,
|
||||||
|
}, {
|
||||||
|
contextValue: { zabbixAuthToken: 'test-token' }
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(importResponse.body.kind).toBe('single');
|
||||||
|
// @ts-ignore
|
||||||
|
const importResult = importResponse.body.singleResult;
|
||||||
|
expect(importResult.errors).toBeUndefined();
|
||||||
|
expect(importResult.data.importTemplateGroups).toHaveLength(importVariables.templateGroups.length);
|
||||||
|
|
||||||
|
// 2. Export (Query)
|
||||||
|
const querySample = readFileSync(join(process.cwd(), 'docs', 'sample_all_template_groups_query.graphql'), 'utf-8').replace(/\r\n/g, '\n');
|
||||||
|
const query = querySample.match(/```graphql\n([\s\S]*?)\n```/)![1];
|
||||||
|
const queryVariables = JSON.parse(querySample.match(/```json\n([\s\S]*?)\n```/)![1]);
|
||||||
|
|
||||||
|
// Mock for query
|
||||||
|
const mockGroupsResponse = importVariables.templateGroups.map((g: any, index: number) => ({
|
||||||
|
groupid: (index + 1000).toString(),
|
||||||
|
name: g.groupName
|
||||||
|
}));
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce(mockGroupsResponse);
|
||||||
|
|
||||||
|
const queryResponse = await server.executeOperation({
|
||||||
|
query: query,
|
||||||
|
variables: queryVariables,
|
||||||
|
}, {
|
||||||
|
contextValue: { zabbixAuthToken: 'test-token' }
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(queryResponse.body.kind).toBe('single');
|
||||||
|
// @ts-ignore
|
||||||
|
const queryResult = queryResponse.body.singleResult;
|
||||||
|
expect(queryResult.errors).toBeUndefined();
|
||||||
|
expect(queryResult.data.allTemplateGroups).toHaveLength(importVariables.templateGroups.length);
|
||||||
|
|
||||||
|
// Verify names match
|
||||||
|
const importedNames = importVariables.templateGroups.map((g: any) => g.groupName).sort();
|
||||||
|
const exportedNames = queryResult.data.allTemplateGroups.map((g: any) => g.name).sort();
|
||||||
|
expect(exportedNames).toEqual(importedNames);
|
||||||
|
|
||||||
|
// 3. Delete Template Groups
|
||||||
|
const groupidsToDelete = queryResult.data.allTemplateGroups.map((g: any) => parseInt(g.groupid));
|
||||||
|
// Mock for query (for name_pattern)
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce(queryResult.data.allTemplateGroups.map((g: any) => ({ groupid: g.groupid, name: g.name })));
|
||||||
|
// Mock for delete
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ groupids: groupidsToDelete.map((id: number) => id.toString()) });
|
||||||
|
|
||||||
|
const deleteMutation = `
|
||||||
|
mutation DeleteTemplateGroups($groupids: [Int!], $name_pattern: String) {
|
||||||
|
deleteTemplateGroups(groupids: $groupids, name_pattern: $name_pattern) {
|
||||||
|
id
|
||||||
|
message
|
||||||
|
error {
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const deleteResponse = await server.executeOperation({
|
||||||
|
query: deleteMutation,
|
||||||
|
variables: { name_pattern: "Templates/Roadwork/%" },
|
||||||
|
}, {
|
||||||
|
contextValue: { zabbixAuthToken: 'test-token' }
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(deleteResponse.body.kind).toBe('single');
|
||||||
|
// @ts-ignore
|
||||||
|
const deleteResult = deleteResponse.body.singleResult;
|
||||||
|
expect(deleteResult.errors).toBeUndefined();
|
||||||
|
expect(deleteResult.data.deleteTemplateGroups).toHaveLength(groupidsToDelete.length);
|
||||||
|
expect(deleteResult.data.deleteTemplateGroups[0].message).toContain("deleted successfully");
|
||||||
|
});
|
||||||
|
});
|
||||||
112
src/test/template_query.test.ts
Normal file
112
src/test/template_query.test.ts
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
|
||||||
|
import {createResolvers} from "../api/resolvers.js";
|
||||||
|
import {zabbixAPI} from "../datasources/zabbix-api.js";
|
||||||
|
import {QueryTemplatesArgs} from "../schema/generated/graphql.js";
|
||||||
|
|
||||||
|
// Mocking ZabbixAPI
|
||||||
|
jest.mock("../datasources/zabbix-api.js", () => ({
|
||||||
|
zabbixAPI: {
|
||||||
|
executeRequest: jest.fn(),
|
||||||
|
post: jest.fn(),
|
||||||
|
baseURL: "http://mock-zabbix"
|
||||||
|
},
|
||||||
|
ZABBIX_EDGE_DEVICE_BASE_GROUP: "Baustellen-Devices"
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("Template Resolver", () => {
|
||||||
|
let resolvers: any;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
resolvers = createResolvers();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("templates query - returns all templates", async () => {
|
||||||
|
const mockTemplates = [
|
||||||
|
{ templateid: "1", name: "Template 1", uuid: "uuid1" },
|
||||||
|
{ templateid: "2", name: "Template 2", uuid: "uuid2" }
|
||||||
|
];
|
||||||
|
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce(mockTemplates);
|
||||||
|
|
||||||
|
const args: QueryTemplatesArgs = {};
|
||||||
|
const context = { zabbixAuthToken: "test-token" };
|
||||||
|
|
||||||
|
const result = await resolvers.Query.templates(null, args, context);
|
||||||
|
|
||||||
|
expect(result).toEqual(mockTemplates);
|
||||||
|
expect(zabbixAPI.post).toHaveBeenCalledWith("template.get", expect.objectContaining({
|
||||||
|
body: expect.objectContaining({
|
||||||
|
method: "template.get",
|
||||||
|
params: {}
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("templates query - filters by hostids", async () => {
|
||||||
|
const mockTemplates = [{ templateid: "1", name: "Template 1" }];
|
||||||
|
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce(mockTemplates);
|
||||||
|
|
||||||
|
const args: QueryTemplatesArgs = { hostids: [1] };
|
||||||
|
const context = { zabbixAuthToken: "test-token" };
|
||||||
|
|
||||||
|
const result = await resolvers.Query.templates(null, args, context);
|
||||||
|
|
||||||
|
expect(result).toEqual(mockTemplates);
|
||||||
|
expect(zabbixAPI.post).toHaveBeenCalledWith("template.get", expect.objectContaining({
|
||||||
|
body: expect.objectContaining({
|
||||||
|
method: "template.get",
|
||||||
|
params: expect.objectContaining({
|
||||||
|
templateids: [1]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("templates query - filters by name_pattern", async () => {
|
||||||
|
const mockTemplates = [{ templateid: "1", name: "Template 1" }];
|
||||||
|
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce(mockTemplates);
|
||||||
|
|
||||||
|
const args: QueryTemplatesArgs = { name_pattern: "Template" };
|
||||||
|
const context = { zabbixAuthToken: "test-token" };
|
||||||
|
|
||||||
|
const result = await resolvers.Query.templates(null, args, context);
|
||||||
|
|
||||||
|
expect(result).toEqual(mockTemplates);
|
||||||
|
expect(zabbixAPI.post).toHaveBeenCalledWith("template.get", expect.objectContaining({
|
||||||
|
body: expect.objectContaining({
|
||||||
|
method: "template.get",
|
||||||
|
params: expect.objectContaining({
|
||||||
|
search: {
|
||||||
|
name: "Template"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("templates query - filters by name_pattern with % wildcard", async () => {
|
||||||
|
const mockTemplates = [{ templateid: "1", name: "Template 1" }];
|
||||||
|
|
||||||
|
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce(mockTemplates);
|
||||||
|
|
||||||
|
const args: QueryTemplatesArgs = { name_pattern: "Temp%1" };
|
||||||
|
const context = { zabbixAuthToken: "test-token" };
|
||||||
|
|
||||||
|
const result = await resolvers.Query.templates(null, args, context);
|
||||||
|
|
||||||
|
expect(result).toEqual(mockTemplates);
|
||||||
|
expect(zabbixAPI.post).toHaveBeenCalledWith("template.get", expect.objectContaining({
|
||||||
|
body: expect.objectContaining({
|
||||||
|
method: "template.get",
|
||||||
|
params: expect.objectContaining({
|
||||||
|
search: {
|
||||||
|
name: "Temp%1"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
670
src/testdata/templates/zbx_default_templates_vcr.yaml
vendored
Normal file
670
src/testdata/templates/zbx_default_templates_vcr.yaml
vendored
Normal file
|
|
@ -0,0 +1,670 @@
|
||||||
|
zabbix_export:
|
||||||
|
version: '7.4'
|
||||||
|
template_groups:
|
||||||
|
- uuid: 43aab460fe444f18886b19948413b7e3
|
||||||
|
name: Permissions/ConstructionSite
|
||||||
|
- uuid: 376524057e094c07aaa0cf7f524849dc
|
||||||
|
name: Templates/Roadwork/Controller
|
||||||
|
- uuid: 7d83c76454564390bb0e34600780eaec
|
||||||
|
name: Templates/Roadwork/Device-Capabilities
|
||||||
|
- uuid: 48d5d2a18a08448c96a931b63bb2c97d
|
||||||
|
name: Templates/Roadwork/Device-Capabilities/FLASH_ATTACHABLE
|
||||||
|
- uuid: 785986b84892468ea2e92d912747b1d3
|
||||||
|
name: Templates/Roadwork/Device-Capabilities/GEOLOCALIZABLE
|
||||||
|
- uuid: a4b79479e97a4b48972dcb476d45e55a
|
||||||
|
name: Templates/Roadwork/Device-Capabilities/HAS_OPERATIONAL_DATA
|
||||||
|
- uuid: 3604af8102644bee9dcaf0f9c1ee93a1
|
||||||
|
name: Templates/Roadwork/Devices
|
||||||
|
- uuid: 5ad0bd9e42a4487e869e9e41b38fe553
|
||||||
|
name: Templates/Roadwork/DisplayLibrary
|
||||||
|
templates:
|
||||||
|
- uuid: 27474f627cb344b782a81c16d7e0c7d1
|
||||||
|
template: BT_DEVICE_TRACKER
|
||||||
|
name: BT_DEVICE_TRACKER
|
||||||
|
vendor:
|
||||||
|
name: 'Hilbig IT GmbH'
|
||||||
|
version: 2.1.1
|
||||||
|
templates:
|
||||||
|
- name: ROADWORK_DEVICE
|
||||||
|
groups:
|
||||||
|
- name: Templates/Roadwork/Devices
|
||||||
|
items:
|
||||||
|
- uuid: d4d3ec9f3ca940a39a721b6cfd2f3471
|
||||||
|
name: location
|
||||||
|
type: DEPENDENT
|
||||||
|
key: location
|
||||||
|
history: 2d
|
||||||
|
value_type: TEXT
|
||||||
|
preprocessing:
|
||||||
|
- type: JAVASCRIPT
|
||||||
|
parameters:
|
||||||
|
- |
|
||||||
|
var obj=JSON.parse(value);
|
||||||
|
|
||||||
|
if (obj["isFiltered"]) {
|
||||||
|
throw "Result is filtered";
|
||||||
|
return "filtered";
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
- type: NOT_MATCHES_REGEX
|
||||||
|
parameters:
|
||||||
|
- filtered
|
||||||
|
error_handler: DISCARD_VALUE
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[deviceValue/location]'
|
||||||
|
- uuid: 380c4a7d752848cba3b5a59a0f9b13c0
|
||||||
|
name: MQTT_LOCATION
|
||||||
|
type: TRAP
|
||||||
|
key: 'mqtt.trap[deviceValue/location]'
|
||||||
|
history: '0'
|
||||||
|
value_type: TEXT
|
||||||
|
- uuid: 29faf53c033840c0b1405f8240e30312
|
||||||
|
name: coords
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.current.values.coords
|
||||||
|
history: 2d
|
||||||
|
value_type: TEXT
|
||||||
|
preprocessing:
|
||||||
|
- type: JAVASCRIPT
|
||||||
|
parameters:
|
||||||
|
- |
|
||||||
|
var obj=JSON.parse(value);
|
||||||
|
var location = obj["location"];
|
||||||
|
var coords = location["coords"];
|
||||||
|
return JSON.stringify({
|
||||||
|
"btDeviceKey": obj["btDeviceKey"],
|
||||||
|
"timestamp": location["timestamp"],
|
||||||
|
"deviceName": obj["deviceName"],
|
||||||
|
"latitude": coords[1],
|
||||||
|
"longitude": coords[0],
|
||||||
|
"coords": coords
|
||||||
|
});
|
||||||
|
master_item:
|
||||||
|
key: location
|
||||||
|
tags:
|
||||||
|
- tag: hasValue
|
||||||
|
value: 'true'
|
||||||
|
- uuid: 1ae9486c18394e56b114c9cb4546deaf
|
||||||
|
name: geojson
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.current.values.geojson
|
||||||
|
history: 2d
|
||||||
|
value_type: TEXT
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.location.setup
|
||||||
|
master_item:
|
||||||
|
key: location
|
||||||
|
tags:
|
||||||
|
- tag: hasValue
|
||||||
|
value: 'true'
|
||||||
|
tags:
|
||||||
|
- tag: class
|
||||||
|
value: roadwork
|
||||||
|
- tag: deviceType
|
||||||
|
value: bt_device_tracker_generic
|
||||||
|
- uuid: e6905dc6122944f3829ad28a9739e269
|
||||||
|
template: BT_TRACKER
|
||||||
|
name: BT_TRACKER
|
||||||
|
vendor:
|
||||||
|
name: 'Hilbig IT GmbH'
|
||||||
|
version: 2.1.1
|
||||||
|
templates:
|
||||||
|
- name: ROADWORK_DEVICE
|
||||||
|
groups:
|
||||||
|
- name: Templates/Roadwork/Devices
|
||||||
|
items:
|
||||||
|
- uuid: b1e3062d67f94f7c8d064eff36a58b13
|
||||||
|
name: MQTT_STATE
|
||||||
|
type: DEPENDENT
|
||||||
|
key: currentstate
|
||||||
|
value_type: TEXT
|
||||||
|
preprocessing:
|
||||||
|
- type: JAVASCRIPT
|
||||||
|
parameters:
|
||||||
|
- |
|
||||||
|
var v = JSON.parse(value);
|
||||||
|
return JSON.stringify({
|
||||||
|
"count": v.count,
|
||||||
|
"timeFrom": v.timeFrom,
|
||||||
|
"timeUntil": v.timeUntil
|
||||||
|
});
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[deviceValue/count]'
|
||||||
|
- uuid: 905c5f1b6e524bd2b227769a59f4df1b
|
||||||
|
name: MQTT_COUNT
|
||||||
|
type: TRAP
|
||||||
|
key: 'mqtt.trap[deviceValue/count]'
|
||||||
|
history: '0'
|
||||||
|
value_type: TEXT
|
||||||
|
- uuid: 6fa441872c3140f4adecf39956245603
|
||||||
|
name: MQTT_DISTANCE
|
||||||
|
type: TRAP
|
||||||
|
key: 'mqtt.trap[deviceValue/distance]'
|
||||||
|
value_type: TEXT
|
||||||
|
- uuid: 69d2afa4a0324d818150e9473c3264f3
|
||||||
|
name: MQTT_NAME
|
||||||
|
type: TRAP
|
||||||
|
key: 'mqtt.trap[deviceValue/name]'
|
||||||
|
value_type: TEXT
|
||||||
|
- uuid: 45ff9430d27f47a492c98fce03fc7962
|
||||||
|
name: MQTT_SERVICE_DATA
|
||||||
|
type: TRAP
|
||||||
|
key: 'mqtt.trap[deviceValue/ServiceData]'
|
||||||
|
value_type: TEXT
|
||||||
|
- uuid: 3bf0d3017ea54e1da2a764c3f96bf97e
|
||||||
|
name: count
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.current.values.count
|
||||||
|
trends: '0'
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.count
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[deviceValue/count]'
|
||||||
|
- uuid: f0d1fc72e2154613b349be86c6bdcfd6
|
||||||
|
name: timeFrom
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.current.values.timeFrom
|
||||||
|
value_type: TEXT
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.timeFrom
|
||||||
|
- type: REGEX
|
||||||
|
parameters:
|
||||||
|
- 'T(\d\d:\d\d:\d\d):'
|
||||||
|
- \1
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[deviceValue/count]'
|
||||||
|
- uuid: e55bf604808f4eb4a964ebeefdd9eb9e
|
||||||
|
name: timeUntil
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.current.values.timeUntil
|
||||||
|
value_type: TEXT
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.timeUntil
|
||||||
|
- type: REGEX
|
||||||
|
parameters:
|
||||||
|
- 'T(\d\d:\d\d:\d\d):'
|
||||||
|
- \1
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[deviceValue/count]'
|
||||||
|
tags:
|
||||||
|
- tag: class
|
||||||
|
value: roadwork
|
||||||
|
- tag: deviceType
|
||||||
|
value: bt_tracker_generic
|
||||||
|
- tag: deviceWidgetPreview.BOTTOM_LEFT.key
|
||||||
|
value: timeFrom
|
||||||
|
- tag: deviceWidgetPreview.BOTTOM_LEFT.unit
|
||||||
|
value: Startzeit
|
||||||
|
- tag: deviceWidgetPreview.BOTTOM_LEFT.unit_font_size
|
||||||
|
value: '8'
|
||||||
|
- tag: deviceWidgetPreview.BOTTOM_LEFT.value_font_size
|
||||||
|
value: '16'
|
||||||
|
- tag: deviceWidgetPreview.BOTTOM_RIGHT.key
|
||||||
|
value: timeUntil
|
||||||
|
- tag: deviceWidgetPreview.BOTTOM_RIGHT.unit
|
||||||
|
value: Endezeit
|
||||||
|
- tag: deviceWidgetPreview.BOTTOM_RIGHT.unit_font_size
|
||||||
|
value: '8'
|
||||||
|
- tag: deviceWidgetPreview.BOTTOM_RIGHT.value_font_size
|
||||||
|
value: '16'
|
||||||
|
- tag: deviceWidgetPreview.TOP_LEFT.key
|
||||||
|
value: count
|
||||||
|
- tag: deviceWidgetPreview.TOP_LEFT.unit
|
||||||
|
value: Geräte
|
||||||
|
- tag: deviceWidgetPreview.TOP_LEFT.unit_font_size
|
||||||
|
value: '8'
|
||||||
|
- tag: deviceWidgetPreview.TOP_LEFT.value_font_size
|
||||||
|
value: '24'
|
||||||
|
- uuid: 6490907a74964d0797c7acd1938bc553
|
||||||
|
template: GEOLOCATION
|
||||||
|
name: GEOLOCATION
|
||||||
|
vendor:
|
||||||
|
name: 'Hilbig IT GmbH'
|
||||||
|
version: 2.1.1
|
||||||
|
groups:
|
||||||
|
- name: Templates/Roadwork/Device-Capabilities
|
||||||
|
- name: Templates/Roadwork/Device-Capabilities/GEOLOCALIZABLE
|
||||||
|
items:
|
||||||
|
- uuid: 4ad4d9a769744615816d190c34cb49c7
|
||||||
|
name: GPS_LOCATION_MQTT
|
||||||
|
type: TRAP
|
||||||
|
key: 'mqtt.trap[operationalValue/location]'
|
||||||
|
history: '0'
|
||||||
|
value_type: TEXT
|
||||||
|
description: 'old value: mqtt.get["rabbitmq","operationalValue/{$DEVICETYPE}/{HOST.HOST}/location","voltra_dev:voltradev","rabbit4voltra"]'
|
||||||
|
- uuid: 0e0012933b2345d4b119fdc50c526c73
|
||||||
|
name: GPS_LOCATION
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.location.json
|
||||||
|
history: 90d
|
||||||
|
value_type: TEXT
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[operationalValue/location]'
|
||||||
|
tags:
|
||||||
|
- tag: attributeName
|
||||||
|
value: location
|
||||||
|
- tag: hasValue
|
||||||
|
value: 'true'
|
||||||
|
- tag: topicType
|
||||||
|
value: operationalValue
|
||||||
|
- uuid: e9dcf0279afc4ed4a23e274df4c98356
|
||||||
|
name: LATITUDE
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.location.latitude
|
||||||
|
history: 90d
|
||||||
|
value_type: FLOAT
|
||||||
|
inventory_link: LOCATION_LAT
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.latitude
|
||||||
|
master_item:
|
||||||
|
key: state.operational.location.json
|
||||||
|
- uuid: 49d1677d3a4a4cfab23b2e8e50533833
|
||||||
|
name: LONGITUDE
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.location.longitude
|
||||||
|
history: 90d
|
||||||
|
value_type: FLOAT
|
||||||
|
inventory_link: LOCATION_LON
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.longitude
|
||||||
|
master_item:
|
||||||
|
key: state.operational.location.json
|
||||||
|
- uuid: d7203eaab36749798014b6d3b1a43e24
|
||||||
|
name: LOCATION_NAME
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.location.name
|
||||||
|
history: 90d
|
||||||
|
value_type: TEXT
|
||||||
|
inventory_link: LOCATION
|
||||||
|
preprocessing:
|
||||||
|
- type: JAVASCRIPT
|
||||||
|
parameters:
|
||||||
|
- |
|
||||||
|
var json = JSON.parse(value);
|
||||||
|
var lat = "lat=" + json.latitude;
|
||||||
|
var lon = "lon=" + json.longitude;
|
||||||
|
|
||||||
|
return lon + ", " + lat;
|
||||||
|
var geocoderURL = "https://photon.komoot.io/reverse?" + lon + "&" + lat;
|
||||||
|
|
||||||
|
var req = new HttpRequest();
|
||||||
|
|
||||||
|
req.addHeader('Content-Type: application/json');
|
||||||
|
|
||||||
|
resp = req.get(geocoderURL);
|
||||||
|
|
||||||
|
if (req.getStatus() != 200) {
|
||||||
|
throw 'Response code: '+req.getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultJson = JSON.parse(resp);
|
||||||
|
|
||||||
|
var features = resultJson.features;
|
||||||
|
if (features.length && features[0].properties) {
|
||||||
|
var props = features[0].properties;
|
||||||
|
return props.postcode + " " + props.city;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
master_item:
|
||||||
|
key: state.operational.location.json
|
||||||
|
tags:
|
||||||
|
- tag: class
|
||||||
|
value: roadwork
|
||||||
|
macros:
|
||||||
|
- macro: '{$DEVICEKEY}'
|
||||||
|
value: '{HOST.HOST}'
|
||||||
|
- uuid: fe8bac9ac30f411cb5a322817760e71d
|
||||||
|
template: OPERATIONAL_DATA
|
||||||
|
name: OPERATIONAL_DATA
|
||||||
|
vendor:
|
||||||
|
name: 'Hilbig IT GmbH'
|
||||||
|
version: 2.1.1
|
||||||
|
groups:
|
||||||
|
- name: Templates/Roadwork/Device-Capabilities
|
||||||
|
- name: Templates/Roadwork/Device-Capabilities/HAS_OPERATIONAL_DATA
|
||||||
|
items:
|
||||||
|
- uuid: 602290e9f42f4135b548e1cd45abe135
|
||||||
|
name: DENSITY_MQTT
|
||||||
|
type: TRAP
|
||||||
|
key: 'mqtt.trap[operationalValue/density]'
|
||||||
|
history: '0'
|
||||||
|
value_type: TEXT
|
||||||
|
- uuid: 87e0a14266984247b81fdc757dea5bde
|
||||||
|
name: ERROR_MQTT
|
||||||
|
type: TRAP
|
||||||
|
key: 'mqtt.trap[operationalValue/error]'
|
||||||
|
history: '0'
|
||||||
|
value_type: TEXT
|
||||||
|
- uuid: 644b0ec2e3d9448da1a69561ec10d19d
|
||||||
|
name: SIGNALSTRENGTH_MQTT
|
||||||
|
type: TRAP
|
||||||
|
key: 'mqtt.trap[operationalValue/signalstrength]'
|
||||||
|
history: '0'
|
||||||
|
value_type: TEXT
|
||||||
|
- uuid: 67c01d7334a24823832bba74073cf356
|
||||||
|
name: TEMPERATURE_MQTT
|
||||||
|
type: TRAP
|
||||||
|
key: 'mqtt.trap[operationalValue/temperature]'
|
||||||
|
history: '0'
|
||||||
|
value_type: TEXT
|
||||||
|
tags:
|
||||||
|
- tag: attributeName
|
||||||
|
value: temperature
|
||||||
|
- tag: GRAPHQL_TYPE
|
||||||
|
value: Int
|
||||||
|
- tag: hasValue
|
||||||
|
value: 'true'
|
||||||
|
- tag: subscribeMqtt
|
||||||
|
value: 'true'
|
||||||
|
- tag: topicType
|
||||||
|
value: operationalValue
|
||||||
|
- uuid: 0352c80c749d4d91b386dab9c74ef3c6
|
||||||
|
name: VOLTAGE_MQTT
|
||||||
|
type: TRAP
|
||||||
|
key: 'mqtt.trap[operationalValue/voltage]'
|
||||||
|
history: '0'
|
||||||
|
value_type: TEXT
|
||||||
|
- uuid: 7aac8212c94044d28ada982c422f2bf7
|
||||||
|
name: DENSITY
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.density
|
||||||
|
units: Kfz/Min
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.density
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[operationalValue/density]'
|
||||||
|
tags:
|
||||||
|
- tag: attributeName
|
||||||
|
value: density
|
||||||
|
- tag: hasValue
|
||||||
|
value: 'true'
|
||||||
|
- tag: topicType
|
||||||
|
value: operationalValue
|
||||||
|
- uuid: 6c8c2f4cdc304b019d02026e7c3225ce
|
||||||
|
name: ERROR_HIGH
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.errorHigh
|
||||||
|
value_type: TEXT
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- '$[?(@.code>=1000)]'
|
||||||
|
error_handler: CUSTOM_VALUE
|
||||||
|
master_item:
|
||||||
|
key: state.operational.json_error
|
||||||
|
triggers:
|
||||||
|
- uuid: bc381851c3d84534866f3262828817a9
|
||||||
|
expression: 'last(/OPERATIONAL_DATA/state.operational.errorHigh)<>""'
|
||||||
|
name: DEVICE_ERROR_HIGH
|
||||||
|
event_name: DEVICE_ERROR_HIGH
|
||||||
|
priority: HIGH
|
||||||
|
manual_close: 'YES'
|
||||||
|
- uuid: 7634372683af42e7bb807bd2ee0e600a
|
||||||
|
name: ERROR_INFO
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.errorInfo
|
||||||
|
value_type: TEXT
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- '$[?(@.code=0)]'
|
||||||
|
error_handler: CUSTOM_VALUE
|
||||||
|
master_item:
|
||||||
|
key: state.operational.json_error
|
||||||
|
triggers:
|
||||||
|
- uuid: 201be3f4fd484651a0d2bb34586b408b
|
||||||
|
expression: 'last(/OPERATIONAL_DATA/state.operational.errorInfo)<>""'
|
||||||
|
name: DEVICE_ERROR_INFO
|
||||||
|
event_name: DEVICE_ERROR_INFO
|
||||||
|
priority: INFO
|
||||||
|
manual_close: 'YES'
|
||||||
|
- uuid: 58beaf63a07c44bd918f3f7c93be6d16
|
||||||
|
name: ERROR_WARNING
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.errorWarning
|
||||||
|
value_type: TEXT
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- '$[?(@.code>0&&@.code<1000)]'
|
||||||
|
error_handler: CUSTOM_VALUE
|
||||||
|
master_item:
|
||||||
|
key: state.operational.json_error
|
||||||
|
triggers:
|
||||||
|
- uuid: 208ef0feec0b469c8b3a8edc3ef12680
|
||||||
|
expression: 'last(/OPERATIONAL_DATA/state.operational.errorWarning)<>""'
|
||||||
|
name: DEVICE_ERROR_WARNING
|
||||||
|
event_name: DEVICE_ERROR_WARNING
|
||||||
|
priority: WARNING
|
||||||
|
manual_close: 'YES'
|
||||||
|
- uuid: cf7b08cec47a46ddb7ea110feab42c94
|
||||||
|
name: ERROR
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.json_error
|
||||||
|
history: '0'
|
||||||
|
value_type: TEXT
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.error
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[operationalValue/error]'
|
||||||
|
tags:
|
||||||
|
- tag: attributeName
|
||||||
|
value: error
|
||||||
|
- tag: hasValue
|
||||||
|
value: 'true'
|
||||||
|
- tag: topicType
|
||||||
|
value: operationalValue
|
||||||
|
- uuid: a711e858297e4c80a61952b9848dd217
|
||||||
|
name: SIGNALSTRENGTH
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.signalstrength
|
||||||
|
history: 90d
|
||||||
|
value_type: FLOAT
|
||||||
|
trends: '0'
|
||||||
|
units: dBm
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.signalstrength
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[operationalValue/signalstrength]'
|
||||||
|
tags:
|
||||||
|
- tag: attributeName
|
||||||
|
value: signalstrength
|
||||||
|
- tag: hasValue
|
||||||
|
value: 'true'
|
||||||
|
triggers:
|
||||||
|
- uuid: 610d7f2cd5db4dc8938a61ffe81eb8e3
|
||||||
|
expression: 'nodata(/OPERATIONAL_DATA/state.operational.signalstrength,70s)=1'
|
||||||
|
name: NO_OPERATIONAL_VALUE
|
||||||
|
priority: WARNING
|
||||||
|
- uuid: 93df1a6ad1d640c883f446c85a220bd3
|
||||||
|
name: TEMPERATURE
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.temperature
|
||||||
|
history: 90d
|
||||||
|
value_type: FLOAT
|
||||||
|
trends: '0'
|
||||||
|
units: °C
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.temperature
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[operationalValue/temperature]'
|
||||||
|
tags:
|
||||||
|
- tag: attributeName
|
||||||
|
value: temperature
|
||||||
|
- tag: hasValue
|
||||||
|
value: 'true'
|
||||||
|
triggers:
|
||||||
|
- uuid: 8bc17b97d7fe4e4f9ac236e90d0b315d
|
||||||
|
expression: 'last(/OPERATIONAL_DATA/state.operational.temperature,#3)>60'
|
||||||
|
recovery_mode: RECOVERY_EXPRESSION
|
||||||
|
recovery_expression: 'last(/OPERATIONAL_DATA/state.operational.temperature,#3)<=60'
|
||||||
|
name: TEMPERATURE_HIGH
|
||||||
|
event_name: TEMPERATURE_HIGH
|
||||||
|
priority: HIGH
|
||||||
|
dependencies:
|
||||||
|
- name: TEMPERATURE_WARNING
|
||||||
|
expression: 'last(/OPERATIONAL_DATA/state.operational.temperature,#3)>50'
|
||||||
|
recovery_expression: 'last(/OPERATIONAL_DATA/state.operational.temperature,#3)<=50'
|
||||||
|
- uuid: 086f026b15e5410793d0604b4c7d51f6
|
||||||
|
expression: 'last(/OPERATIONAL_DATA/state.operational.temperature,#3)>50'
|
||||||
|
recovery_mode: RECOVERY_EXPRESSION
|
||||||
|
recovery_expression: 'last(/OPERATIONAL_DATA/state.operational.temperature,#3)<=50'
|
||||||
|
name: TEMPERATURE_WARNING
|
||||||
|
event_name: TEMPERATURE_WARNING
|
||||||
|
priority: AVERAGE
|
||||||
|
- uuid: cbc60c96e65d4111b902e3b133681067
|
||||||
|
name: TIMESTAMP
|
||||||
|
type: CALCULATED
|
||||||
|
key: state.operational.timestamp
|
||||||
|
value_type: TEXT
|
||||||
|
params: 'max(last(/{HOST.HOST}/state.operational.timestampSignalstrength),last(/{HOST.HOST}/state.operational.timestampVoltage))'
|
||||||
|
inventory_link: POC_2_NOTES
|
||||||
|
- uuid: ca1a1397f1aa458b88e531f699cacfeb
|
||||||
|
name: TIMESTAMP_SIGNALSTRENGTH
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.timestampSignalstrength
|
||||||
|
history: '0'
|
||||||
|
value_type: TEXT
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.timestamp
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[operationalValue/signalstrength]'
|
||||||
|
tags:
|
||||||
|
- tag: attributeName
|
||||||
|
value: timestamp
|
||||||
|
- tag: hasValue
|
||||||
|
value: 'true'
|
||||||
|
- tag: subscribeMqtt
|
||||||
|
value: 'false'
|
||||||
|
- uuid: 919a09b55b304fc391bcd569f444b979
|
||||||
|
name: TIMESTAMP_VOLTAGE
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.timestampVoltage
|
||||||
|
history: '0'
|
||||||
|
value_type: TEXT
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.timestamp
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[operationalValue/voltage]'
|
||||||
|
tags:
|
||||||
|
- tag: attributeName
|
||||||
|
value: timestamp
|
||||||
|
- tag: hasValue
|
||||||
|
value: 'true'
|
||||||
|
- tag: subscribeMqtt
|
||||||
|
value: 'false'
|
||||||
|
- uuid: 3363ed4409b545b48ae7c6197a56aae2
|
||||||
|
name: VOLTAGE
|
||||||
|
type: DEPENDENT
|
||||||
|
key: state.operational.voltage
|
||||||
|
history: 90d
|
||||||
|
value_type: FLOAT
|
||||||
|
trends: '0'
|
||||||
|
units: V
|
||||||
|
preprocessing:
|
||||||
|
- type: JSONPATH
|
||||||
|
parameters:
|
||||||
|
- $.voltage
|
||||||
|
master_item:
|
||||||
|
key: 'mqtt.trap[operationalValue/voltage]'
|
||||||
|
tags:
|
||||||
|
- tag: attributeName
|
||||||
|
value: voltage
|
||||||
|
- tag: hasValue
|
||||||
|
value: 'true'
|
||||||
|
- tag: topicType
|
||||||
|
value: operationalValue
|
||||||
|
triggers:
|
||||||
|
- uuid: b411e1c0527a470184cac731c072fec2
|
||||||
|
expression: 'last(/OPERATIONAL_DATA/state.operational.voltage,#3)<=12'
|
||||||
|
recovery_mode: RECOVERY_EXPRESSION
|
||||||
|
recovery_expression: 'last(/OPERATIONAL_DATA/state.operational.voltage,#3)>=12'
|
||||||
|
name: VOLTAGE_LOW
|
||||||
|
event_name: VOLTAGE_LOW
|
||||||
|
priority: WARNING
|
||||||
|
description: |
|
||||||
|
warning if voltage < 24 of last 3 values
|
||||||
|
recovery if voltage >=24 of last 3 values
|
||||||
|
- uuid: f5c351920d544fc6abcf00fd9b26f51b
|
||||||
|
expression: 'last(/OPERATIONAL_DATA/state.operational.voltage,#3)<=11'
|
||||||
|
recovery_mode: RECOVERY_EXPRESSION
|
||||||
|
recovery_expression: 'last(/OPERATIONAL_DATA/state.operational.voltage,#3)>=11'
|
||||||
|
name: VOLTAGE_TOO_LOW
|
||||||
|
priority: DISASTER
|
||||||
|
tags:
|
||||||
|
- tag: class
|
||||||
|
value: roadwork
|
||||||
|
macros:
|
||||||
|
- macro: '{$DEVICEKEY}'
|
||||||
|
value: '{HOST.HOST}'
|
||||||
|
- uuid: 2b814a4751b745bcb08b5ee98f295dc9
|
||||||
|
template: ROADWORK_DEVICE
|
||||||
|
name: ROADWORK_DEVICE
|
||||||
|
vendor:
|
||||||
|
name: 'Hilbig IT GmbH'
|
||||||
|
version: 2.1.1
|
||||||
|
groups:
|
||||||
|
- name: Templates/Roadwork/Devices
|
||||||
|
tags:
|
||||||
|
- tag: class
|
||||||
|
value: roadwork
|
||||||
|
- tag: hostType
|
||||||
|
value: Roadwork/Devices
|
||||||
|
- uuid: c53977cb7c6a45b18700502fd841db56
|
||||||
|
template: TEMPLATEGROUP_EXPORT_DUMMY_TEMPLATE
|
||||||
|
name: TEMPLATEGROUP_EXPORT_DUMMY_TEMPLATE
|
||||||
|
description: 'This template is linked to all template group which shall be part of the export templates - action because empty template groups will not be exported'
|
||||||
|
vendor:
|
||||||
|
name: 'Hilbig IT GmbH'
|
||||||
|
version: 2.1.1
|
||||||
|
groups:
|
||||||
|
- name: Permissions/Automatism
|
||||||
|
- name: Permissions/Automatism/Status
|
||||||
|
- name: Permissions/ConstructionSite
|
||||||
|
- name: Permissions/Library
|
||||||
|
- name: Permissions/Library/Item
|
||||||
|
- name: Templates/Roadwork/Controller
|
||||||
|
- name: Templates/Roadwork/Device-Capabilities
|
||||||
|
- name: Templates/Roadwork/Device-Capabilities/FLASH_ATTACHABLE
|
||||||
|
- name: Templates/Roadwork/Device-Capabilities/GEOLOCALIZABLE
|
||||||
|
- name: Templates/Roadwork/Device-Capabilities/HAS_OPERATIONAL_DATA
|
||||||
|
- name: Templates/Roadwork/Devices
|
||||||
|
- name: Templates/Roadwork/DisplayLibrary
|
||||||
|
tags:
|
||||||
|
- tag: class
|
||||||
|
value: roadwork
|
||||||
|
graphs:
|
||||||
|
- uuid: 2c8b16c6937a4d07912b6485ac8a1339
|
||||||
|
name: 'Mac address count'
|
||||||
|
graph_items:
|
||||||
|
- drawtype: GRADIENT_LINE
|
||||||
|
color: 1A7C11
|
||||||
|
calc_fnc: ALL
|
||||||
|
item:
|
||||||
|
host: BT_TRACKER
|
||||||
|
key: state.current.values.count
|
||||||
Loading…
Add table
Add a link
Reference in a new issue