feat: optimize Zabbix queries and enhance specialized device support

- Implement query optimization (reduced output, parameter skipping) to minimize Zabbix API traffic.

- Add indirect dependency handling: deviceType implies tags and state implies items.

- Move schema extensions to samples/extensions/ to clarify their role as samples.

- Enhance DistanceTrackerDevice with String time fields to support optional date portions.

- Ensure allDevices strictly filters by deviceType and populates the field in results.

- Refactor runAllRegressionTests mutation to use internal unique names and improve stability.

- Fix unnecessary Zabbix API calls for item preprocessing during template and host imports.

- Update documentation including cookbook recipes, test specifications, and optimization guides.

- Add extensive unit, integration, and regression tests covering all implemented changes.

- Update docker-compose.yml to mount the samples/ directory as a volume.

- Update IntelliJ .idea run configurations to reflect the new sample extension paths.
This commit is contained in:
Andreas Hilbig 2026-02-02 13:20:06 +01:00
parent 97a0f70fd6
commit b646b8c606
28 changed files with 551 additions and 74 deletions

View file

@ -73,12 +73,14 @@ Compare the GraphQL response with the expected output described in the Zabbix do
This recipe shows how to add support for a new specialized device type without modifying the core API code. We will use the `DistanceTrackerDevice` as an example.
> **Important**: Schema extensions are not part of the core API source code. They are loaded dynamically at runtime via environment variables. The extensions provided in the `samples/extensions/` directory of this repository are **samples** to demonstrate how to use this mechanism. You can place your own extension files in any directory accessible by the API server.
### 📋 Prerequisites
- Zabbix Template Group `Templates/Roadwork/Devices` exists.
- Zabbix GraphQL API is running.
### 🛠️ Step 1: Define the Schema Extension
Create a new `.graphql` file in `schema/extensions/` (e.g. `distance_tracker.graphql`).
Create a new `.graphql` file in `samples/extensions/` (e.g. `distance_tracker.graphql`).
> **Advice**: A new device type must always implement both the `Host` and `Device` interfaces to ensure compatibility with the API's core logic and resolvers.
@ -102,20 +104,20 @@ type DistanceTrackerState implements DeviceState {
}
type DistanceTrackerValues {
timeFrom: Time
timeUntil: Time
timeFrom: String
timeUntil: String
count: Int
# The distances are modelled using a type which is already defined in location_tracker_commons.graphql
distances: [SensorDistanceValue!]
}
```
> **Reference**: This example is based on the already prepared sample: [location_tracker_devices.graphql](../../schema/extensions/location_tracker_devices.graphql).
> **Reference**: This example is based on the already prepared sample: [location_tracker_devices.graphql](../../samples/extensions/location_tracker_devices.graphql).
### ⚙️ Step 2: Configure Environment Variables
Add the new schema and resolver to your `.env` file:
```env
ADDITIONAL_SCHEMAS=./schema/extensions/distance_tracker.graphql,./schema/extensions/location_tracker_commons.graphql
ADDITIONAL_SCHEMAS=./samples/extensions/distance_tracker.graphql,./samples/extensions/location_tracker_commons.graphql
ADDITIONAL_RESOLVERS=DistanceTrackerDevice
```
Restart the API server.
@ -203,7 +205,7 @@ This recipe demonstrates how to extend the schema with new device types that ret
- The device has geo-coordinates set via user macros (e.g. `{$LAT}` and `{$LON}`).
### 🛠️ Step 1: Define the Schema Extension
Create a new `.graphql` file in `schema/extensions/` (e.g. `weather_sensor.graphql` or `ground_value_checker.graphql`).
Create a new `.graphql` file in `samples/extensions/` (e.g. `weather_sensor.graphql` or `ground_value_checker.graphql`).
**Sample: Weather Sensor**
```graphql
@ -262,7 +264,7 @@ type GroundValues {
### ⚙️ Step 2: Register the Resolver
Add the new types and schemas to your `.env` file to enable the dynamic resolver:
```env
ADDITIONAL_SCHEMAS=./schema/extensions/weather_sensor.graphql,./schema/extensions/ground_value_checker.graphql
ADDITIONAL_SCHEMAS=./samples/extensions/weather_sensor.graphql,./samples/extensions/ground_value_checker.graphql
ADDITIONAL_RESOLVERS=WeatherSensorDevice,GroundValueChecker
```
Restart the API server to apply the changes.
@ -344,6 +346,30 @@ Create a host, assign it macros for coordinates, and query its state.
---
## 🍳 Recipe: Testing Specialized Device Types
This recipe shows how to execute a comprehensive query to verify the state and configuration of specialized device types, such as the `DistanceTrackerDevice`. This is useful for validating that your schema extensions and hierarchical mappings are working correctly.
### 📋 Prerequisites
- Zabbix GraphQL API is running.
- The schema has been extended with the `DistanceTrackerDevice` type (see [Recipe: Extending Schema with a New Device Type](#-recipe-extending-schema-with-a-new-device-type)). Sample extensions can be found in the `samples/extensions` directory.
- At least one host with `deviceType` set to `DistanceTrackerDevice` exists in Zabbix.
### 🛠️ Step 1: Get the Sample Query
1. **Open the Sample**: Open [docs/queries/sample_distance_tracker_test_query.graphql](../queries/sample_distance_tracker_test_query.graphql).
2. **Copy the Query**: Copy the GraphQL code block under the `### Query` header.
### 🚀 Step 2: Execution/Action
Execute the query against your GraphQL endpoint. This query retrieves information from `allHostGroups`, `allDevices`, and `allHosts`, using inline fragments to access fields specific to `DistanceTrackerDevice`.
### ✅ Step 3: Verification
Check the response for the following:
- **apiVersion** and **zabbixVersion** are returned.
- **allHostGroups** contains the expected groups.
- **allDevices** and **allHosts** include your `DistanceTrackerDevice` with its specialized `state` (count, timeFrom, timeUntil) and `tags` (deviceWidgetPreview).
---
## 🍳 Recipe: Provisioning a New Host
### 📋 Prerequisites

View file

@ -22,7 +22,7 @@ The `GraphqlParamsToNeededZabbixOutput` class provides static methods to map Gra
### 3. Resolver Integration
Resolvers use the mapper to determine the required output and pass it to the datasource:
```typescript
const output = GraphqlParamsToNeededZabbixOutput.mapAllHosts(args, info);
const output = GraphqlParamsToNeededZabbixOutput.mapAllHosts(info);
return await new ZabbixQueryHostsRequestWithItemsAndInventory(...)
.executeRequestThrowError(dataSources.zabbixAPI, new ParsedArgs(args), output);
```
@ -30,6 +30,7 @@ return await new ZabbixQueryHostsRequestWithItemsAndInventory(...)
### 4. Indirect Dependencies
Some GraphQL fields are not directly returned by Zabbix but are computed from other data. The optimization logic ensures these dependencies are handled:
- **`state`**: Requesting the `state` field on a `Device` requires Zabbix `items`. The mapper automatically adds `items` to the requested output if `state` is present.
- **`deviceType`**: Requesting `deviceType` requires Zabbix `tags` (or `inheritedTags`). This is needed because the `deviceType` is resolved from a Zabbix tag and will be empty otherwise. The optimization logic ensures that `selectTags` and `selectInheritedTags` are not skipped when `deviceType` is requested.
## 🛠️ Configuration
Optimization rules are defined in the constructor of specialized `ZabbixRequest` classes.
@ -37,7 +38,7 @@ Optimization rules are defined in the constructor of specialized `ZabbixRequest`
### 📋 Supported Optimizations
- **Hosts & Devices**:
- `selectParentTemplates` skipped if `parentTemplates` not requested.
- `selectTags` and `selectInheritedTags` skipped if `tags` not requested.
- `selectTags` and `selectInheritedTags` skipped if `tags` (or `deviceType`) not requested.
- `selectHostGroups` skipped if `hostgroups` not requested.
- `selectItems` skipped if `items` (or `state`) not requested.
- `selectInventory` skipped if `inventory` not requested.

View file

@ -10,7 +10,7 @@ The GraphQL schema is located in the `../../schema/` directory and consists of:
- `zabbix.graphql` - Zabbix-specific types (see detailed documentation in file comments)
- `device_value_commons.graphql` - Common value types (see detailed documentation in file comments)
- `api_commons.graphql` - Common API types and permission system (see detailed documentation in file comments)
- `extensions/` - Custom device type extensions
- `samples/extensions/` - Sample device type extensions (not part of the core source)
For comprehensive understanding of each operation, read the detailed comments in the respective schema files.
@ -38,7 +38,8 @@ The `Location` type represents geographical information from Zabbix host invento
Extend the schema without code changes using environment variables:
```bash
ADDITIONAL_SCHEMAS=./schema/extensions/display_devices.graphql,./schema/extensions/location_tracker_devices.graphql
# Extensions can be located anywhere; samples are provided in samples/extensions/
ADDITIONAL_SCHEMAS=./samples/extensions/display_devices.graphql,./samples/extensions/location_tracker_devices.graphql
ADDITIONAL_RESOLVERS=SinglePanelDevice,FourPanelDevice,DistanceTrackerDevice
```