commit a033dfa9702d9d28c6b0bbe839c49c9c84487953 Author: Yoshihiro OKUMURA Date: Tue Nov 3 14:40:19 2026 +0900 feat: bootstrap Zabbix template repository Set up a repository for custom Zabbix templates and add the first template for Dell PowerVault ME storage systems. - Add conventions, version policy, and release documentation. - Add validation, index, packaging, export, and import-test scripts. - Add a disposable Zabbix test stack with version-aware imports. - Add PowerVault ME SNMP exports for Zabbix 7.0 and 8.0. - Cover system information, unit health, sensors, ports, and firmware revisions. diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..2e0d78c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[*.py] +indent_size = 4 + +[Makefile] +indent_style = tab diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..d3a8b4a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ +* text=auto eol=lf + +*.sh text eol=lf +*.py text eol=lf +*.yaml text eol=lf +*.yml text eol=lf +*.md text eol=lf +*.txt text eol=lf +Makefile text eol=lf + +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.zip binary diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..14b6cc4 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,37 @@ +name: Validate + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: pip + cache-dependency-path: requirements-dev.txt + - name: Install dependencies + run: pip install -r requirements-dev.txt + - name: Lint YAML + run: yamllint . + - name: Validate manifests + run: python3 scripts/validate.py + - name: Check README index + run: python3 scripts/gen_index.py --check + + import-test: + runs-on: ubuntu-latest + needs: lint + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + - name: Import templates into disposable Zabbix + run: ./scripts/import_test.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..67aa345 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Generated artifacts +dist/ +*.zip + +# Python +.venv/ +venv/ +__pycache__/ +*.py[cod] + +# Local settings and secrets +.env +tests/.env + +# Local scratch files (for example, vendor MIB files) +tmp/ + +# Editors +.vscode/ +.idea/ +.DS_Store diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..75fac3a --- /dev/null +++ b/.yamllint @@ -0,0 +1,22 @@ +extends: default + +ignore: | + tmp/ + dist/ + .venv/ + +rules: + line-length: disable + document-start: disable + truthy: + allowed-values: ["true", "false", "yes", "no", "on", "off"] + comments: + min-spaces-from-content: 1 + braces: + max-spaces-inside: 1 + brackets: + max-spaces-inside: 1 + indentation: + spaces: 2 + indent-sequences: true + check-multi-line-strings: false diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..beaab49 --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +SHELL := /bin/bash +PYTHON ?= python3 + +.PHONY: help lint validate index index-check package import-test new clean + +help: + @echo "make lint YAML lint and manifest validation" + @echo "make index Update the template list in README.md" + @echo "make index-check Check whether the template list is up to date" + @echo "make package Create distribution zips in dist/" + @echo "make import-test Import templates into a disposable Zabbix instance" + @echo "make new CATEGORY=app PRODUCT=apache NAME='Apache by HTTP' METHOD=http" + @echo "make clean Remove dist/" + +lint: + yamllint . + $(PYTHON) scripts/validate.py + +validate: lint + +index: + $(PYTHON) scripts/gen_index.py + +index-check: + $(PYTHON) scripts/gen_index.py --check + +package: + ./scripts/package.sh + +import-test: + ./scripts/import_test.sh + +new: + ./scripts/new_template.sh "$(CATEGORY)" "$(PRODUCT)" "$(NAME)" "$(METHOD)" + +clean: + rm -rf dist diff --git a/README.md b/README.md new file mode 100644 index 0000000..d0d2e32 --- /dev/null +++ b/README.md @@ -0,0 +1,109 @@ +# Zabbix Custom Templates + +A collection of custom Zabbix templates targeting Zabbix 7.0 LTS and 8.0 LTS. + +## Supported Versions + +| Zabbix | Status | +|---|---| +| 7.0 LTS | Primary | +| 8.0 LTS | Export added (tested with 8.0.0 development build) | + +See [docs/versioning.md](docs/versioning.md) for the version directory policy. + +## Templates + + +| ID | Template | Version | Zabbix | Tested | Description | +|---|---|---|---|---|---| +| [san/dell_powervault_me](templates/san/dell_powervault_me/) | Dell PowerVault ME by SNMP | 1.0.0 | 7.0+ | 7.0, 8.0 | Monitors Dell PowerVault ME storage systems via SNMP, including system information, unit health, sensors, ports, and firmware revisions. | + + +## Repository Layout + +```text +templates/// +├── README.md +├── CHANGELOG.md +├── manifest.yaml +├── 7.0/ +│ └── template_....yaml +└── assets/ # optional +``` + +- `templates/`: Template packages. One directory is one import unit. +- `global/`: Shared configuration that is not included in template exports, such as global scripts and media types. +- `docs/`: Conventions, version policy, and release process. +- `scripts/`: Scaffolding, validation, export, and packaging scripts. +- `tests/`: Disposable Zabbix and PostgreSQL stack for import tests. + +## Requirements + +- Python 3.10 or later +- PyYAML and yamllint +- Docker and Docker Compose (for import tests) +- curl, jq, and zip + +```bash +python3 -m venv .venv +. .venv/bin/activate +pip install -r requirements-dev.txt +``` + +## Adding a Template + +```bash +make new \ + CATEGORY=app \ + PRODUCT=apache \ + NAME="Apache by HTTP" \ + METHOD=http +``` + +`METHOD` defaults to `agent`. Use `PRODUCT=cisco/ios` when vendor grouping is needed. + +After scaffolding, export the template from the matching Zabbix version as YAML and place it under `templates/app/apache/7.0/` or `templates/app/apache/8.0/`. Remove the `.gitkeep` file once the export is in place. + +```bash +make lint # YAML lint and manifest validation +make index # Update the template list in README.md +make import-test # Import into a disposable Zabbix instance +``` + +`make import-test` requires access to the Docker daemon. The test Zabbix stack is defined in `tests/compose.yaml` and is removed on exit. To keep the stack running, use `KEEP_STACK=1 make import-test`. + +The import test detects the Zabbix server version and imports only the matching version directory. To test Zabbix 8.0, override the image tags: + +```bash +ZBX_SERVER_IMAGE=alpine-8.0-latest \ +ZBX_WEB_IMAGE=alpine-8.0-latest \ +ZBX_TEST_PROJECT=zabbix-templates-test-8 \ +make import-test +``` + +If the 8.0 image is not published yet, use `alpine-trunk` for the development build. + +## Importing a Template + +Open **Data collection > Templates** in Zabbix, choose **Import**, and select the YAML file under `templates/<...>/7.0/` or `templates/<...>/8.0/` depending on your Zabbix version. Exports include linked templates, so a single import is normally sufficient. + +## Packaging + +```bash +make package +``` + +Distribution zips are written to `dist/`. The `dist/` directory is not tracked by Git. + +## Documentation + +- [Naming, macros, and trigger conventions](docs/conventions.md) +- [Zabbix version policy](docs/versioning.md) +- [Release process](docs/release.md) +- [Template README scaffold](docs/template-README.md) + +## Notes + +- Never commit secrets such as SNMP communities, API tokens, or passwords. +- When a template is derived from an official or community template, record the upstream URL in `manifest.yaml` under `source` and comply with the original license. +- This repository does not have a repository-wide license yet. Add a `LICENSE` file before publishing. diff --git a/docs/conventions.md b/docs/conventions.md new file mode 100644 index 0000000..c027c2a --- /dev/null +++ b/docs/conventions.md @@ -0,0 +1,166 @@ +# Conventions + +## Directory Layout + +```text +templates/// +├── README.md +├── CHANGELOG.md +├── manifest.yaml +├── / +│ └── template_....yaml +└── assets/ # optional +``` + +- One directory is one import unit (a package). +- Place linked and dependent templates in the same package and version directory. +- Use a third level such as `network/cisco/ios/` only when vendor grouping is necessary. + +## Categories + +| Category | Purpose | Example `class` tag | +|---|---|---| +| `app` | Applications | `application` | +| `db` | Databases | `database` | +| `network` | Network devices | `network` | +| `os` | Operating systems | `os` | +| `hardware` | Server hardware | `hardware` | +| `san` | SAN and storage arrays | `storage` | +| `cloud` | Cloud services | `cloud` | +| `container` | Containers and orchestration | `container` | +| `web` | Web servers and web monitoring | `web` | +| `virtualization` | Virtualization platforms | `virtualization` | +| `power` | UPS and PDU devices | `power` | +| `printer` | Printers | `printer` | +| `custom` | Custom monitoring that fits no other category | `custom` | + +## Naming + +- Template technical name: ` by ` + - Examples: `Dell PowerVault ME by SNMP`, `Huawei OceanStor Dorado by SNMP` + - Follow the naming used by official Zabbix templates. Do not add a `Template` prefix. +- Directory: lowercase snake_case, without the `template_` prefix. + - Examples: `templates/app/apache/`, `templates/network/cisco_ios/` +- Export file: keep the default filename produced by Zabbix. + - Example: `template_app_apache.yaml` +- Git tag: `-v`, replacing `/` with `-`. + - Example: `app-apache-v1.2.0` + +## manifest.yaml + +`manifest.yaml` is the single source of metadata for a package. The top-level template list and distribution zips are generated from it. + +| Field | Required | Description | +|---|---|---| +| `id` | Yes | `category/product`. Must match the directory path. | +| `name` | Yes | Template technical name. Must match the name in the export. | +| `description` | Yes | One-line description shown in the template list. | +| `version` | Yes | SemVer (for example, `1.0.0`). | +| `category` | Yes | One of the categories above. | +| `vendor` | No | Vendor name. | +| `method` | No | `agent`, `agent2`, `snmp`, `http`, `ipmi`, `jmx`, `ssh`, `telnet`, `odbc`, `external`, `script`, `calculated`, `dependent`, or `other` | +| `zabbix.min` | Yes | Minimum supported Zabbix version (for example, `"7.0"`). | +| `zabbix.max` | No | Maximum supported Zabbix version, or `null` when unbounded. | +| `zabbix.tested` | No | List of tested Zabbix versions. | +| `depends_on` | No | IDs of other packages this package depends on. | +| `source` | No | `original` or the upstream URL for derived templates. | +| `maintainer` | Yes | Maintainer name. | + +Example: + +```yaml +id: app/apache +name: Apache by HTTP +description: Monitors Apache availability and performance. +version: 1.0.0 +category: app +vendor: Apache +method: http + +zabbix: + min: "7.0" + max: null + tested: ["7.0", "8.0"] + +depends_on: [] +source: original +maintainer: okumura +``` + +## Version Directories + +- Directory names use Zabbix `major.minor` versions (for example, `7.0` and `8.0`). +- Start with the directory for the minimum supported version only. +- Add a newer version directory only when the template uses features specific to that version or the exported content differs. +- If the same export also works on a newer version, keep one directory and add the newer version to `zabbix.tested` in `manifest.yaml`. + +See [versioning.md](versioning.md) for details. + +## Export Procedure + +1. Prepare a dedicated Zabbix server for template development. A clean server with no hosts is preferred. +2. Select the templates and export them in YAML format. +3. Include linked templates so that a single import is sufficient. +4. Verify that hosts, local IDs, and secrets are not included. +5. Place the export under `templates////`. +6. `scripts/export.sh` can export templates directly through the API. + +## Tags + +Follow the tags used by official Zabbix templates and add at least the following. + +| Tag | Example values | Description | +|---|---|---| +| `class` | `application`, `database`, `network`, `os` | High-level category | +| `target` | `apache`, `postgresql`, `cisco_ios` | Monitored target | + +Document the meaning of any additional tags in the package `README.md`. + +## Macros + +- User macros use uppercase `{$SECTION.NAME}` names. + - Examples: `{$APACHE.PORT}`, `{$APACHE.TIMEOUT}` +- Do not hardcode thresholds. Expose them as macros with defaults. +- LLD macros use the `{#SECTION.NAME}` format. +- Store passwords and API tokens in secret user macros and never commit their real values. + +## Items and Triggers + +- Item names use the `Component [{#MACRO}]: Metric` form. Do not add the template name prefix. +- Trigger names use the `: : ` form. Include `{HOST.NAME}` for host-level events. +- Prefix item and trigger descriptions with `MIB: ` and a short explanation, following the official Zabbix templates. +- For SNMP discovery, prefer a master SNMP walk item with dependent LLD rules and `SNMP_WALK_TO_JSON` / `SNMP_WALK_VALUE` preprocessing. +- Use user macros for discovery filters, for example `{$DELL.POWERVAULT.ME.DISCOVERY.PORT.TYPE.NOT_MATCHES}`. +- Use `DISCARD_UNCHANGED_HEARTBEAT` 6h for static or health items and 1h for discovery rules. +- Use vendor-prefixed macro names, for example `{$DELL.POWERVAULT.ME.UPTIME.WARN}`. +- Expose thresholds as macros and document their defaults and meanings in `README.md`. +- Always define recovery conditions. +- When dependencies become complex, prefer tags and event correlation over trigger dependencies. +- Filter unnecessary entities in LLD rules to avoid excessive item counts. + +## README + +Each package `README.md` must cover the following. + +1. Overview and what is monitored +2. Supported and tested Zabbix versions +3. Requirements such as agents, SNMP, external scripts, and open ports +4. Import procedure +5. Macro reference +6. Item, LLD, and trigger overview +7. Known limitations and troubleshooting +8. Link to the changelog + +The scaffold is available at [template-README.md](template-README.md). + +## Security + +- Never commit SNMP communities, API tokens, passwords, or private keys. +- Before exporting, check for host-specific values and internal IP addresses. +- For external scripts, review execution permissions and input handling. + +## Source and Licensing + +- When a template is derived from an official or community template, record the upstream URL in `manifest.yaml` under `source`. +- Follow the original license and add its full text to `LICENSES/` or `NOTICE` when required. +- This repository does not have a repository-wide license yet. Decide on one before publishing. diff --git a/docs/release.md b/docs/release.md new file mode 100644 index 0000000..f2434ee --- /dev/null +++ b/docs/release.md @@ -0,0 +1,48 @@ +# Release Process + +## Checklist + +1. Update `CHANGELOG.md`. +2. Update `version` in `manifest.yaml`. +3. Confirm that `make lint` passes. +4. Confirm that `make import-test` passes. +5. If an 8.0 export exists, run `make import-test` with the 8.0 image tags (see [versioning.md](versioning.md)). +6. Run `make index` to update the template list in `README.md`. +7. Commit the changes. +8. Tag the release per template. +9. Run `make package` and attach the zips to the release. + +```bash +make lint +make import-test +make index +git add . +git commit -m "apache: add HTTP template" +git tag app-apache-v1.0.0 +make package +``` + +## Artifacts + +`make package` creates zips in `dist/` using the following naming pattern. + +```text +dist/app_apache-1.0.0-zbx7.0.zip +dist/app_apache-1.0.0-zbx8.0.zip +``` + +Zip contents: + +```text +README.md +CHANGELOG.md +manifest.yaml +template_app_apache.yaml +assets/... +``` + +The `dist/` directory is not tracked by Git. Attach the zips to a release page or upload them to a file server. + +## Versioning + +See [versioning.md](versioning.md). diff --git a/docs/template-README.md b/docs/template-README.md new file mode 100644 index 0000000..f09c8dc --- /dev/null +++ b/docs/template-README.md @@ -0,0 +1,52 @@ +# {{TEMPLATE_NAME}} + +- ID: `{{ID}}` +- Supported Zabbix: {{ZABBIX_MIN}} or later +- Collection method: {{METHOD}} +- Vendor: {{VENDOR}} + +## Overview + +TODO: Describe what this template monitors. + +## Requirements + +- Zabbix {{ZABBIX_MIN}} or later +- TODO: Agent, SNMP, HTTP, external script, and other prerequisites + +## Import + +1. Open **Data collection > Templates** in Zabbix. +2. Choose **Import**. +3. Select the YAML file under `{{ZABBIX_MIN}}/`. +4. If linked templates are included in the export, a single import completes the setup. + +## Macros + +| Macro | Default | Description | +|---|---|---| +| `{$EXAMPLE.PORT}` | `80` | Example: monitored port | + +TODO: Replace this table with the actual macros. + +## Monitored Resources + +### Items + +TODO + +### Discovery Rules + +TODO + +### Triggers + +TODO + +## Known Limitations and Troubleshooting + +TODO + +## Changelog + +[CHANGELOG.md](CHANGELOG.md) diff --git a/docs/versioning.md b/docs/versioning.md new file mode 100644 index 0000000..ab61893 --- /dev/null +++ b/docs/versioning.md @@ -0,0 +1,79 @@ +# Zabbix Version Policy + +## Current Support + +| Zabbix | Status | Directory | +|---|---|---| +| 7.0 LTS | Primary | `7.0/` | +| 8.0 LTS | Export added (tested with 8.0.0) | `8.0/` | + +The `8.0/` export was imported into Zabbix 8.0.0 (development build) and linked to a test host. Re-validate it after the official 8.0 GA release. + +## Principles + +- For each package, create only the directory for the minimum supported version. +- A YAML export from Zabbix 7.0 can normally be imported into 7.0 and later versions. +- Add an `8.0/` directory only when the template uses features specific to 8.0 or the 8.0 export differs from the 7.0 export. +- If the same export also works on 8.0, keep only the existing directory and add `"8.0"` to `zabbix.tested` in `manifest.yaml`. + +To scaffold a package that supports 8.0 only, run `ZABBIX_MIN=8.0 make new ...`. + +## Adding Zabbix 8.0 LTS + +The `8.0/` export is already included. The steps below describe how it was added and how to add future versions. + +1. Import the template into an 8.0 test environment. +2. Check whether the 7.0 export still works. +3. If it works without changes: + - Add `"8.0"` to `zabbix.tested` in `manifest.yaml`. + - Leave `zabbix.max` as `null`. +4. If 8.0 requires changes: + - Create `templates///8.0/` and place the export from 8.0 there. + - Document any 8.0-specific notes in `README.md`. + - Leave `zabbix.max` as `null` and add `"8.0"` to `tested`. + +### Testing a specific version + +`scripts/import_test.sh` detects the server version from `apiinfo.version` and imports only the matching version directory. Use environment variables to select the image tags: + +```bash +ZBX_SERVER_IMAGE=alpine-8.0-latest \ +ZBX_WEB_IMAGE=alpine-8.0-latest \ +ZBX_TEST_PROJECT=zabbix-templates-test-8 \ +make import-test +``` + +If the 8.0 image is not published yet, use `alpine-trunk` for the development build. + +## Choosing a Version Directory + +Consumers use the newest directory that is less than or equal to their Zabbix version. + +| Consumer Zabbix | When `7.0/` and `8.0/` exist | +|---|---| +| 7.0 | `7.0/` | +| 7.4 | `7.0/` | +| 8.0 | `8.0/` | + +## Template Versions + +The `version` field in `manifest.yaml` follows SemVer. + +- MAJOR: Template rename, macro removal, or another incompatible change +- MINOR: New items, triggers, or LLD rules +- PATCH: Threshold, description, or bug fixes + +## Git Tags + +Tag each template independently. + +```bash +git tag app-apache-v1.2.0 +git push origin app-apache-v1.2.0 +``` + +Use a collection-wide tag such as `v2026.11.0` only when a repository-level release is needed. + +## End of Support + +- To drop 7.0 support, remove `7.0/`, update `zabbix.min` to `"8.0"`, and increment the MAJOR version because the change is breaking. diff --git a/global/README.md b/global/README.md new file mode 100644 index 0000000..beba4ce --- /dev/null +++ b/global/README.md @@ -0,0 +1,8 @@ +# global + +Shared configuration that is not included in template exports. + +- `scripts/`: Global scripts +- `mediatypes/`: Media types such as webhooks + +These objects cannot be imported together with Zabbix templates. Record the change procedure and deployment steps in each directory's README. Do not store secrets here. diff --git a/global/mediatypes/README.md b/global/mediatypes/README.md new file mode 100644 index 0000000..b401fea --- /dev/null +++ b/global/mediatypes/README.md @@ -0,0 +1,9 @@ +# global/mediatypes + +Zabbix media types such as webhooks. + +- Exported YAML +- A `README.md` describing deployment steps +- Required macro definitions + +Never commit API tokens or secret parts of webhook URLs. diff --git a/global/scripts/README.md b/global/scripts/README.md new file mode 100644 index 0000000..fe91051 --- /dev/null +++ b/global/scripts/README.md @@ -0,0 +1,9 @@ +# global/scripts + +Global Zabbix scripts. + +- Script sources (`.js`, `.sh`, and so on) +- A `README.md` describing deployment steps +- Required macros and permissions + +Keep script names consistent with their display names in Zabbix, and record changes over time. diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..a9f4d6d --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,2 @@ +PyYAML>=6.0 +yamllint>=1.35 diff --git a/scripts/export.sh b/scripts/export.sh new file mode 100755 index 0000000..8b527d3 --- /dev/null +++ b/scripts/export.sh @@ -0,0 +1,125 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <<'EOF' +Usage: + ZBX_URL=https://zabbix.example.com ZBX_TOKEN=xxxx \ + scripts/export.sh [--force] [ ...] + +Specifying multiple template names exports them into a single YAML file. +To include linked templates, list their names explicitly. + +Environment variables: + ZBX_URL Zabbix URL (for example, https://zabbix.example.com) + ZBX_TOKEN API token +EOF +} + +force=0 +if [[ "${1:-}" == "--force" ]]; then + force=1 + shift +fi + +if [[ $# -lt 2 ]]; then + usage + exit 1 +fi + +out="$1" +shift +names=("$@") + +if [[ -z "${ZBX_URL:-}" || -z "${ZBX_TOKEN:-}" ]]; then + echo "ERROR: Set ZBX_URL and ZBX_TOKEN." >&2 + exit 1 +fi + +command -v curl >/dev/null 2>&1 || { + echo "ERROR: curl is required." >&2 + exit 1 +} +command -v jq >/dev/null 2>&1 || { + echo "ERROR: jq is required." >&2 + exit 1 +} + +api_url="${ZBX_URL%/}" +if [[ "$api_url" != */api_jsonrpc.php ]]; then + api_url="$api_url/api_jsonrpc.php" +fi + +if [[ -e "$out" && $force -eq 0 ]]; then + echo "ERROR: Output already exists: $out (use --force to overwrite)" >&2 + exit 1 +fi + +api_call() { + local payload="$1" + curl -sS --fail-with-body \ + -H "Authorization: Bearer ${ZBX_TOKEN}" \ + -H 'Content-Type: application/json' \ + -d "$payload" \ + "$api_url" +} + +ids=() +for name in "${names[@]}"; do + payload="$(jq -n --arg name "$name" '{ + jsonrpc: "2.0", + method: "template.get", + params: { + output: ["templateid", "host"], + filter: {host: $name} + }, + id: 1 + }')" + + if ! response="$(api_call "$payload")"; then + echo "ERROR: API request failed: $api_url" >&2 + exit 1 + fi + + if jq -e '.error' >/dev/null 2>&1 <<<"$response"; then + echo "ERROR: template.get failed: $name" >&2 + jq -r '.error.data // .error.message' <<<"$response" >&2 + exit 1 + fi + + id="$(jq -r '.result[0].templateid // empty' <<<"$response")" + if [[ -z "$id" ]]; then + echo "ERROR: Template not found: $name" >&2 + exit 1 + fi + + ids+=("$id") + echo "Resolved: $name -> $id" >&2 +done + +ids_json="$(printf '%s\n' "${ids[@]}" | jq -R . | jq -s .)" +payload="$(jq -n --argjson ids "$ids_json" '{ + jsonrpc: "2.0", + method: "configuration.export", + params: { + options: {templates: $ids}, + format: "yaml" + }, + id: 1 +}')" + +if ! response="$(api_call "$payload")"; then + echo "ERROR: API request failed: $api_url" >&2 + exit 1 +fi + +if jq -e '.error' >/dev/null 2>&1 <<<"$response"; then + echo "ERROR: configuration.export failed" >&2 + jq -r '.error.data // .error.message' <<<"$response" >&2 + exit 1 +fi + +yaml="$(jq -r '.result' <<<"$response")" +mkdir -p "$(dirname "$out")" +printf '%s\n' "$yaml" > "$out" +echo "Created: $out" diff --git a/scripts/gen_index.py b/scripts/gen_index.py new file mode 100755 index 0000000..d27490d --- /dev/null +++ b/scripts/gen_index.py @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 +"""Generate the template index in README.md from manifest.yaml files.""" + +from __future__ import annotations + +import argparse +import difflib +import sys +from pathlib import Path + +import yaml + +ROOT = Path(__file__).resolve().parent.parent +TEMPLATES_DIR = ROOT / "templates" +README = ROOT / "README.md" +START = "" +END = "" + + +def load_manifests() -> list[dict]: + rows: list[dict] = [] + for path in sorted(TEMPLATES_DIR.rglob("manifest.yaml")): + try: + with path.open(encoding="utf-8") as fh: + data = yaml.safe_load(fh) or {} + except yaml.YAMLError as exc: + print(f"WARN {path}: Could not parse YAML: {exc}", file=sys.stderr) + continue + + if not isinstance(data, dict): + continue + + zabbix = data.get("zabbix") + if not isinstance(zabbix, dict): + zabbix = {} + + rows.append( + { + "id": str(data.get("id") or ""), + "name": str(data.get("name") or ""), + "version": str(data.get("version") or ""), + "description": " ".join( + str(data.get("description") or "").split() + ), + "zabbix": zabbix, + "path": path.parent.relative_to(ROOT).as_posix(), + } + ) + + rows.sort(key=lambda row: row["id"]) + return rows + + +def zabbix_range(zabbix: dict) -> str: + minimum = str(zabbix.get("min") or "") + maximum = zabbix.get("max") + if not minimum: + return "-" + if maximum: + return f"{minimum} - {maximum}" + return f"{minimum}+" + + +def tested(zabbix: dict) -> str: + values = zabbix.get("tested") or [] + if not isinstance(values, list): + return "-" + return ", ".join(str(value) for value in values) or "-" + + +def escape_cell(value: str) -> str: + return value.replace("|", "\\|") + + +def render(rows: list[dict]) -> str: + if not rows: + return "_No templates yet. Add one with `make new`._\n" + + lines = [ + "| ID | Template | Version | Zabbix | Tested | Description |", + "|---|---|---|---|---|---|", + ] + for row in rows: + lines.append( + "| [{id}]({path}/) | {name} | {version} | {zabbix} | {tested} | {description} |".format( + id=escape_cell(row["id"]), + path=row["path"], + name=escape_cell(row["name"]), + version=escape_cell(row["version"]), + zabbix=escape_cell(zabbix_range(row["zabbix"])), + tested=escape_cell(tested(row["zabbix"])), + description=escape_cell(row["description"]) or "-", + ) + ) + return "\n".join(lines) + "\n" + + +def replace_section(readme: str, body: str) -> str: + start = readme.find(START) + end = readme.find(END) + if start == -1 or end == -1 or end < start: + raise ValueError(f"README.md is missing {START} and/or {END}") + return readme[: start + len(START)] + "\n" + body + readme[end:] + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Generate the template index in README.md from manifest.yaml files." + ) + parser.add_argument( + "--check", + action="store_true", + help="Check whether README.md is up to date without modifying it", + ) + args = parser.parse_args() + + if not README.is_file(): + print(f"ERROR README.md not found: {README}", file=sys.stderr) + return 1 + + original = README.read_text(encoding="utf-8") + rows = load_manifests() + body = render(rows) + + try: + updated = replace_section(original, body) + except ValueError as exc: + print(f"ERROR {exc}", file=sys.stderr) + return 1 + + if args.check: + if original != updated: + print( + "ERROR The template index in README.md is not up to date. " + "Run `make index`.", + file=sys.stderr, + ) + diff = difflib.unified_diff( + original.splitlines(), + updated.splitlines(), + fromfile="README.md", + tofile="README.md (generated)", + lineterm="", + ) + print("\n".join(diff), file=sys.stderr) + return 1 + print("The template index in README.md is up to date.") + return 0 + + README.write_text(updated, encoding="utf-8") + print(f"Updated README.md ({len(rows)} package(s)).") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/import_test.sh b/scripts/import_test.sh new file mode 100755 index 0000000..20a120e --- /dev/null +++ b/scripts/import_test.sh @@ -0,0 +1,194 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +COMPOSE_FILE="$ROOT/tests/compose.yaml" + +env_value() { + local key="$1" + local default="$2" + local value="${!key:-}" + if [[ -z "$value" && -f "$ROOT/tests/.env" ]]; then + value="$(sed -n "s/^${key}=//p" "$ROOT/tests/.env" | tail -n 1)" + fi + printf '%s' "${value:-$default}" +} + +PROJECT="$(env_value ZBX_TEST_PROJECT zabbix-templates-test)" +WEB_PORT="$(env_value ZBX_WEB_PORT 8080)" +API_URL="http://127.0.0.1:${WEB_PORT}/api_jsonrpc.php" + +command -v docker >/dev/null 2>&1 || { + echo "ERROR: docker is required." >&2 + exit 1 +} +docker compose version >/dev/null 2>&1 || { + echo "ERROR: docker compose is required." >&2 + exit 1 +} +command -v curl >/dev/null 2>&1 || { + echo "ERROR: curl is required." >&2 + exit 1 +} +command -v jq >/dev/null 2>&1 || { + echo "ERROR: jq is required." >&2 + exit 1 +} + +mapfile -t files < <( + find "$ROOT/templates" -type f \( -name '*.yaml' -o -name '*.yml' \) \ + | grep -E '/[0-9]+\.[0-9]+/' || true +) + +if [[ ${#files[@]} -eq 0 ]]; then + echo "No YAML files to import." + exit 0 +fi + +compose=( + docker compose + --project-directory "$ROOT/tests" + -f "$COMPOSE_FILE" + -p "$PROJECT" +) +if [[ -f "$ROOT/tests/.env" ]]; then + compose+=(--env-file "$ROOT/tests/.env") +fi + +cleanup() { + local status=$? + if [[ "${KEEP_STACK:-0}" == "1" ]]; then + echo "Zabbix stack left running (KEEP_STACK=1)." + echo "To stop it: docker compose --project-directory \"$ROOT/tests\" -f \"$COMPOSE_FILE\" -p \"$PROJECT\" down -v" + else + "${compose[@]}" down -v >/dev/null 2>&1 || true + fi + exit "$status" +} +trap cleanup EXIT + +echo "Starting the Zabbix test stack..." +"${compose[@]}" up -d + +echo "Waiting for the API..." +ready=0 +server_version="" +for _ in {1..90}; do + response="$(curl -sS -m 5 -H 'Content-Type: application/json' \ + -d '{"jsonrpc":"2.0","method":"apiinfo.version","params":{},"id":1}' \ + "$API_URL" 2>/dev/null || true)" + server_version="$(jq -r '.result // empty' <<<"$response" 2>/dev/null || true)" + if [[ -n "$server_version" ]]; then + ready=1 + break + fi + sleep 2 +done + +if [[ $ready -ne 1 ]]; then + echo "ERROR: The Zabbix API did not become ready." >&2 + echo "Logs: docker compose --project-directory \"$ROOT/tests\" -f \"$COMPOSE_FILE\" -p \"$PROJECT\" logs" >&2 + exit 1 +fi + +server_minor="$(cut -d. -f1-2 <<<"$server_version")" +echo "Zabbix version: $server_version" + +mapfile -t versions < <( + printf '%s\n' "${files[@]}" | grep -oE '/[0-9]+\.[0-9]+/' | tr -d '/' | sort -u +) +server_major="${server_minor%%.*}" +server_patch="${server_minor##*.}" +server_key=$((10#$server_major * 100 + 10#$server_patch)) +selected_version="" +selected_key=-1 +for version in "${versions[@]}"; do + major="${version%%.*}" + minor="${version##*.}" + key=$((10#$major * 100 + 10#$minor)) + if (( key <= server_key && key > selected_key )); then + selected_version="$version" + selected_key=$key + fi +done + +if [[ -z "$selected_version" ]]; then + echo "No YAML files compatible with Zabbix $server_version." + exit 0 +fi + +echo "Using version directory: $selected_version" +mapfile -t version_files < <( + printf '%s\n' "${files[@]}" | grep -F "/$selected_version/" || true +) +files=("${version_files[@]}") + +echo "Logging in..." +login_response="$( + jq -n \ + --arg user "$(env_value ZBX_USER Admin)" \ + --arg password "$(env_value ZBX_PASSWORD zabbix)" \ + '{ + jsonrpc: "2.0", + method: "user.login", + params: {username: $user, password: $password}, + id: 1 + }' \ + | curl -sS --fail-with-body \ + -H 'Content-Type: application/json' \ + --data-binary @- \ + "$API_URL" +)" +token="$(jq -r '.result // empty' <<<"$login_response")" +if [[ -z "$token" ]]; then + echo "ERROR: Login failed." >&2 + jq . <<<"$login_response" >&2 + exit 1 +fi + +rules="$(jq -n '{ + templates: {createMissing: true, updateExisting: true}, + template_groups: {createMissing: true, updateExisting: true}, + templateLinkage: {createMissing: true, deleteMissing: false}, + items: {createMissing: true, updateExisting: true, deleteMissing: false}, + discoveryRules: {createMissing: true, updateExisting: true, deleteMissing: false}, + triggers: {createMissing: true, updateExisting: true, deleteMissing: false}, + graphs: {createMissing: true, updateExisting: true, deleteMissing: false}, + httptests: {createMissing: true, updateExisting: true, deleteMissing: false}, + templateDashboards: {createMissing: true, updateExisting: true, deleteMissing: false}, + valueMaps: {createMissing: true, updateExisting: true, deleteMissing: false} +}')" + +for file in "${files[@]}"; do + rel="${file#"$ROOT/"}" + echo "Importing: $rel" + + response="$( + jq -n \ + --rawfile source "$file" \ + --argjson rules "$rules" \ + '{ + jsonrpc: "2.0", + method: "configuration.import", + params: { + format: "yaml", + rules: $rules, + source: $source + }, + id: 1 + }' \ + | curl -sS --fail-with-body \ + -H "Authorization: Bearer ${token}" \ + -H 'Content-Type: application/json' \ + --data-binary @- \ + "$API_URL" + )" + + if ! jq -e '.result == true' >/dev/null 2>&1 <<<"$response"; then + echo "ERROR: Import failed: $rel" >&2 + jq . <<<"$response" >&2 + exit 1 + fi +done + +echo "Import test passed: ${#files[@]} file(s)" diff --git a/scripts/new_template.sh b/scripts/new_template.sh new file mode 100755 index 0000000..9eb2735 --- /dev/null +++ b/scripts/new_template.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +usage() { + cat <<'EOF' +Usage: + scripts/new_template.sh [method] + +Examples: + scripts/new_template.sh app apache "Apache by HTTP" http + scripts/new_template.sh network cisco/ios "Cisco IOS by SNMP" snmp + +Arguments: + category app / db / network / os / hardware / cloud / container / web / + virtualization / power / printer / custom + product Directory name in lowercase snake_case. Use vendor/product + when grouping by vendor. + template-name Zabbix template technical name. + method Collection method (default: agent). +EOF +} + +if [[ $# -lt 3 || $# -gt 4 ]]; then + usage + exit 1 +fi + +category="$1" +product="$2" +name="$3" +method="${4:-agent}" + +allowed_categories="app db network os hardware cloud container web virtualization power printer san custom" +if ! [[ " $allowed_categories " == *" $category "* ]]; then + echo "ERROR: Unknown category: $category" >&2 + usage + exit 1 +fi + +if ! [[ "$product" =~ ^[a-z0-9][a-z0-9_]*(/[a-z0-9][a-z0-9_]*)?$ ]]; then + echo "ERROR: product must use lowercase letters, digits, and _: $product" >&2 + exit 1 +fi + +allowed_methods="agent agent2 snmp http ipmi jmx ssh telnet odbc external script calculated dependent other" +if ! [[ " $allowed_methods " == *" $method "* ]]; then + echo "ERROR: Unknown method: $method" >&2 + exit 1 +fi + +if [[ "$name" == *$'\n'* || "$name" == *$'\r'* ]]; then + echo "ERROR: template-name must not contain line breaks." >&2 + exit 1 +fi + +if [[ "$name" != *" by "* ]]; then + echo "WARN: Template names should include 'by ': $name" >&2 +fi + +package_dir="$ROOT/templates/$category/$product" +if [[ -e "$package_dir" ]]; then + echo "ERROR: Already exists: ${package_dir#"$ROOT/"}" >&2 + exit 1 +fi + +maintainer="${MAINTAINER:-$(git -C "$ROOT" config user.name 2>/dev/null || true)}" +maintainer="${maintainer:-unknown}" +vendor="${VENDOR:-${product%%/*}}" +zabbix_min="${ZABBIX_MIN:-7.0}" + +if ! [[ "$zabbix_min" =~ ^[0-9]+\.[0-9]+$ ]]; then + echo "ERROR: ZABBIX_MIN must use the 7.0 format: $zabbix_min" >&2 + exit 1 +fi + +mkdir -p "$package_dir/$zabbix_min" + +# Escape sed replacement characters. +escape_sed() { + printf '%s' "$1" | sed -e 's/[\\&|]/\\&/g' +} + +sed \ + -e "s|{{TEMPLATE_NAME}}|$(escape_sed "$name")|g" \ + -e "s|{{ID}}|$(escape_sed "$category/$product")|g" \ + -e "s|{{CATEGORY}}|$(escape_sed "$category")|g" \ + -e "s|{{VENDOR}}|$(escape_sed "$vendor")|g" \ + -e "s|{{METHOD}}|$(escape_sed "$method")|g" \ + -e "s|{{ZABBIX_MIN}}|$(escape_sed "$zabbix_min")|g" \ + "$ROOT/docs/template-README.md" > "$package_dir/README.md" + +cat > "$package_dir/CHANGELOG.md" < "$package_dir/manifest.yaml" </dev/null 2>&1 && python3 -c 'import yaml' >/dev/null 2>&1; then + if ! python3 "$ROOT/scripts/gen_index.py" >/dev/null; then + echo "WARN: Could not update the template index in README.md. Run 'make index'." >&2 + fi +fi + +echo "Created: ${package_dir#"$ROOT/"}" +echo +echo "Next steps:" +echo " 1. Export the template as YAML from Zabbix $zabbix_min." +echo " 2. Place the export in ${package_dir#"$ROOT/"}/$zabbix_min/ and remove .gitkeep." +echo " 3. Replace the TODO entries in README.md and manifest.yaml." +echo " 4. Run 'make lint'." diff --git a/scripts/package.sh b/scripts/package.sh new file mode 100755 index 0000000..4aca8aa --- /dev/null +++ b/scripts/package.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +DIST="$ROOT/dist" + +usage() { + cat <<'EOF' +Usage: + scripts/package.sh [package-id] + +If package-id is omitted, all packages are packaged. +Example: + scripts/package.sh app/apache +EOF +} + +if [[ $# -gt 1 ]]; then + usage + exit 1 +fi + +target="${1:-}" +target="${target%/}" + +command -v zip >/dev/null 2>&1 || { + echo "ERROR: zip is required." >&2 + exit 1 +} +python3 -c 'import yaml' >/dev/null 2>&1 || { + echo "ERROR: PyYAML is required (pip install -r requirements-dev.txt)." >&2 + exit 1 +} + +mkdir -p "$DIST" +tmp_root="$(mktemp -d)" +cleanup() { + rm -rf "$tmp_root" +} +trap cleanup EXIT + +created=0 + +while IFS= read -r manifest; do + package_dir="$(dirname "$manifest")" + rel="${package_dir#"$ROOT/templates/"}" + if [[ -n "$target" && "$rel" != "$target" ]]; then + continue + fi + + meta="$( + python3 - "$manifest" <<'PY' +import sys + +import yaml + +with open(sys.argv[1], encoding="utf-8") as fh: + data = yaml.safe_load(fh) or {} + +print(data.get("id") or "") +print(data.get("version") or "") +PY + )" + id="$(sed -n '1p' <<<"$meta")" + version="$(sed -n '2p' <<<"$meta")" + + if [[ -z "$id" || -z "$version" ]]; then + echo "WARN: id or version is empty: ${manifest#"$ROOT/"}" >&2 + continue + fi + + for version_dir in "$package_dir"/*/; do + [[ -d "$version_dir" ]] || continue + + zbx_version="$(basename "$version_dir")" + [[ "$zbx_version" =~ ^[0-9]+\.[0-9]+$ ]] || continue + + mapfile -t yaml_files < <( + find "$version_dir" -maxdepth 1 -type f \ + \( -name '*.yaml' -o -name '*.yml' \) | sort + ) + if [[ ${#yaml_files[@]} -eq 0 ]]; then + echo "SKIP: No YAML files in ${version_dir#"$ROOT/"}" >&2 + continue + fi + + safe_id="${id//\//_}" + staging="$tmp_root/${safe_id}-${version}-${zbx_version}" + mkdir -p "$staging" + + cp "$package_dir/README.md" "$package_dir/CHANGELOG.md" \ + "$package_dir/manifest.yaml" "$staging/" + cp "${yaml_files[@]}" "$staging/" + if [[ -d "$package_dir/assets" ]]; then + cp -R "$package_dir/assets" "$staging/" + fi + + out="$DIST/${safe_id}-${version}-zbx${zbx_version}.zip" + rm -f "$out" + (cd "$staging" && zip -q -r "$out" .) + rm -rf "$staging" + + echo "Created: ${out#"$ROOT/"}" + created=$((created + 1)) + done +done < <(find "$ROOT/templates" -name manifest.yaml -type f | sort) + +if [[ $created -eq 0 ]]; then + if [[ -n "$target" ]]; then + echo "ERROR: Package not found or it has no distributable YAML: $target" >&2 + exit 1 + fi + echo "No artifacts were created." +fi diff --git a/scripts/validate.py b/scripts/validate.py new file mode 100755 index 0000000..49656a7 --- /dev/null +++ b/scripts/validate.py @@ -0,0 +1,354 @@ +#!/usr/bin/env python3 +"""Validate template package structure and manifest.yaml.""" + +from __future__ import annotations + +import argparse +import re +import sys +from pathlib import Path + +import yaml + +ROOT = Path(__file__).resolve().parent.parent +TEMPLATES_DIR = ROOT / "templates" + +CATEGORIES = { + "app", + "db", + "network", + "os", + "hardware", + "cloud", + "container", + "web", + "virtualization", + "power", + "printer", + "san", + "custom", +} +METHODS = { + "agent", + "agent2", + "snmp", + "http", + "ipmi", + "jmx", + "ssh", + "telnet", + "odbc", + "external", + "script", + "calculated", + "dependent", + "other", +} +SEMVER_RE = re.compile(r"^\d+\.\d+\.\d+$") +ZABBIX_VERSION_RE = re.compile(r"^\d+\.\d+$") +ID_RE = re.compile(r"^[a-z0-9_]+(?:/[a-z0-9_]+)+$") +REQUIRED_FIELDS = ( + "id", + "name", + "description", + "version", + "category", + "zabbix", + "maintainer", +) + + +class Result: + def __init__(self) -> None: + self.errors: list[str] = [] + self.warnings: list[str] = [] + + def error(self, path: Path | str, message: str) -> None: + self.errors.append(f"{display(path)}: {message}") + + def warning(self, path: Path | str, message: str) -> None: + self.warnings.append(f"{display(path)}: {message}") + + +def display(path: Path | str) -> str: + path = Path(path) + try: + return path.relative_to(ROOT).as_posix() + except ValueError: + return str(path) + + +def load_yaml(path: Path, result: Result): + try: + with path.open(encoding="utf-8") as fh: + return yaml.safe_load(fh) + except yaml.YAMLError as exc: + result.error(path, f"Could not parse YAML: {exc}") + return None + + +def version_key(value: str) -> tuple[int, int]: + major, minor = value.split(".") + return int(major), int(minor) + + +def validate_exports( + package_dir: Path, + min_version: str, + primary_name: str, + result: Result, +) -> None: + version_dirs = sorted( + ( + path + for path in package_dir.iterdir() + if path.is_dir() and ZABBIX_VERSION_RE.match(path.name) + ), + key=lambda path: version_key(path.name), + ) + + if not version_dirs: + result.error(package_dir, "No version directory found (for example, 7.0/)") + return + + if not any(path.name == min_version for path in version_dirs): + result.error( + package_dir, + f"Missing `{min_version}/` directory required by `zabbix.min`", + ) + + for version_dir in version_dirs: + if version_key(version_dir.name) < version_key(min_version): + result.warning( + version_dir, + f"`{version_dir.name}/` is older than `zabbix.min`", + ) + + yaml_files = sorted(version_dir.glob("*.yaml")) + sorted( + version_dir.glob("*.yml") + ) + if not yaml_files: + result.warning( + version_dir, + "No exported YAML found", + ) + continue + + names: set[str] = set() + for yaml_path in yaml_files: + data = load_yaml(yaml_path, result) + if not isinstance(data, dict): + continue + + export = data.get("zabbix_export") + if not isinstance(export, dict): + result.error(yaml_path, "Missing `zabbix_export`") + continue + + export_version = export.get("version") + if str(export_version) != version_dir.name: + result.error( + yaml_path, + f"`zabbix_export.version` is `{export_version}` but the " + f"directory is `{version_dir.name}`", + ) + + if export.get("hosts"): + result.warning( + yaml_path, + "Hosts are included; export templates only", + ) + + templates = export.get("templates") + if not isinstance(templates, list) or not templates: + result.error(yaml_path, "Missing `zabbix_export.templates`") + continue + + for template in templates: + if not isinstance(template, dict): + continue + for key in ("template", "name"): + value = template.get(key) + if value: + names.add(str(value)) + + if primary_name and primary_name not in names: + result.warning( + version_dir, + f"Template name `{primary_name}` from manifest.yaml was not " + "found in the export", + ) + + +def validate_manifest( + path: Path, + templates_root: Path, + result: Result, +) -> tuple[str, str] | None: + data = load_yaml(path, result) + if not isinstance(data, dict): + result.error(path, "manifest.yaml must contain a mapping") + return None + + rel = path.parent.relative_to(templates_root).as_posix() + + for field in REQUIRED_FIELDS: + value = data.get(field) + if value is None or value == "": + result.error(path, f"Missing required field `{field}`") + + template_id = str(data.get("id") or "") + if template_id: + if not ID_RE.match(template_id): + result.error( + path, + "`id` must use lowercase letters, digits, and `_`, " + "separated by `/`", + ) + if template_id != rel: + result.error( + path, + f"`id` must match the directory path `{rel}`", + ) + + category = str(data.get("category") or "") + if category: + if category not in CATEGORIES: + result.error(path, f"Unknown category `{category}`") + if template_id and template_id.split("/")[0] != category: + result.error(path, "`category` must match the first segment of `id`") + + version = data.get("version") + if version is not None and not SEMVER_RE.match(str(version)): + result.error(path, "`version` must use SemVer (for example, 1.0.0)") + + method = data.get("method") + if method and str(method) not in METHODS: + result.error(path, f"Unknown `method`: {method}") + + for filename in ("README.md", "CHANGELOG.md"): + if not (path.parent / filename).is_file(): + result.error(path, f"{filename} is missing") + + zabbix = data.get("zabbix") + min_version = None + if not isinstance(zabbix, dict): + result.error(path, "`zabbix` must be a mapping") + else: + min_version = zabbix.get("min") + if not min_version or not ZABBIX_VERSION_RE.match(str(min_version)): + result.error(path, "`zabbix.min` must use the `7.0` format") + min_version = None + else: + min_version = str(min_version) + + max_version = zabbix.get("max") + if max_version is not None: + if not ZABBIX_VERSION_RE.match(str(max_version)): + result.error( + path, + "`zabbix.max` must use the `8.0` format or be null", + ) + elif min_version and version_key(str(max_version)) < version_key( + min_version + ): + result.error(path, "`zabbix.max` is lower than `zabbix.min`") + + tested = zabbix.get("tested") or [] + if not isinstance(tested, list): + result.error(path, "`zabbix.tested` must be a list") + else: + for item in tested: + if not ZABBIX_VERSION_RE.match(str(item)): + result.error( + path, + f"`zabbix.tested` entry `{item}` must use the `7.0` format", + ) + + depends_on = data.get("depends_on") or [] + if not isinstance(depends_on, list): + result.error(path, "`depends_on` must be a list") + + if min_version: + validate_exports( + path.parent, + min_version, + str(data.get("name") or ""), + result, + ) + + return template_id, str(data.get("name") or "") + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Validate template package structure and manifest.yaml." + ) + parser.add_argument( + "path", + nargs="?", + default=str(TEMPLATES_DIR), + help="Directory to validate (default: templates/)", + ) + args = parser.parse_args() + + root = Path(args.path).resolve() + if not root.exists(): + print(f"ERROR Target directory does not exist: {root}", file=sys.stderr) + return 1 + + manifests = sorted(root.rglob("manifest.yaml")) + result = Result() + seen_ids: dict[str, Path] = {} + seen_names: dict[str, Path] = {} + + for manifest in manifests: + info = validate_manifest(manifest, root, result) + if not info: + continue + template_id, name = info + if template_id: + if template_id in seen_ids: + result.error( + manifest, + f"Duplicate `id`: {template_id} " + f"({display(seen_ids[template_id])})", + ) + else: + seen_ids[template_id] = manifest + if name: + if name in seen_names: + result.error( + manifest, + f"Duplicate template name: {name} " + f"({display(seen_names[name])})", + ) + else: + seen_names[name] = manifest + + for warning in result.warnings: + print(f"WARN {warning}") + for error in result.errors: + print(f"ERROR {error}") + + if not manifests: + print("No template packages found.") + return 0 + + print() + if result.errors: + print( + f"Validation failed: {len(manifests)} package(s), " + f"{len(result.errors)} error(s), {len(result.warnings)} warning(s)" + ) + return 1 + + print( + f"Validation passed: {len(manifests)} package(s), " + f"{len(result.warnings)} warning(s)" + ) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/templates/README.md b/templates/README.md new file mode 100644 index 0000000..2144c77 --- /dev/null +++ b/templates/README.md @@ -0,0 +1,17 @@ +# templates + +One directory is one import unit. + +```text +// +├── README.md +├── CHANGELOG.md +├── manifest.yaml +├── 7.0/ +│ └── template_....yaml +└── assets/ # optional +``` + +- Categories are `app`, `db`, `network`, `os`, `hardware`, `cloud`, `container`, `web`, `virtualization`, `power`, `printer`, `san`, and `custom`. +- Use a third level such as `network/cisco/ios/` only when vendor grouping is necessary. +- Generate new packages with `make new`. See [../docs/conventions.md](../docs/conventions.md) for details. diff --git a/templates/san/dell_powervault_me/7.0/template_san_dell_powervault_me_snmp.yaml b/templates/san/dell_powervault_me/7.0/template_san_dell_powervault_me_snmp.yaml new file mode 100644 index 0000000..6fde0fd --- /dev/null +++ b/templates/san/dell_powervault_me/7.0/template_san_dell_powervault_me_snmp.yaml @@ -0,0 +1,1241 @@ +zabbix_export: + version: '7.0' + template_groups: + - uuid: 1922297aaf2746069dbec26847d7414a + name: Templates/SAN + templates: + - uuid: 7dd20b46a71a45a1949830081511d4f5 + template: 'Dell PowerVault ME by SNMP' + name: 'Dell PowerVault ME by SNMP' + description: | + Setup: + 1. Create a host for the PowerVault ME management interface and assign this template. + 2. Configure an SNMP interface with SNMPv2c or SNMPv3 credentials. + 3. Adjust macro values if needed. + + Overview: + This template monitors Dell PowerVault ME storage systems via SNMP. It covers system information, connectivity unit health and state, hardware sensors, Fibre Channel ports, and firmware revisions. + + The template uses numeric FCMGMT-MIB OIDs (1.3.6.1.3.94), so MIB files are not required on the Zabbix server. + + Tested by importing into Zabbix 7.0 and linking to a host. Not yet tested against a live PowerVault ME system. + groups: + - name: Templates/SAN + tags: + - tag: class + value: hardware + - tag: class + value: storage + - tag: subclass + value: server + - tag: target + value: dell + - tag: target + value: powervault-me + macros: + - macro: '{$DELL.POWERVAULT.ME.UPTIME.WARN}' + value: 10m + description: 'Warning threshold for system uptime. A lower value indicates a recent restart.' + - macro: '{$DELL.POWERVAULT.ME.DISCOVERY.SENSOR.NAME.MATCHES}' + value: '^.*$' + description: 'This macro is used in sensor discovery to filter sensor names.' + - macro: '{$DELL.POWERVAULT.ME.DISCOVERY.SENSOR.NAME.NOT_MATCHES}' + value: '^$' + description: 'This macro is used in sensor discovery to exclude sensor names.' + - macro: '{$DELL.POWERVAULT.ME.DISCOVERY.PORT.TYPE.MATCHES}' + value: '^.*$' + description: 'This macro is used in port discovery to filter port types.' + - macro: '{$DELL.POWERVAULT.ME.DISCOVERY.PORT.TYPE.NOT_MATCHES}' + value: '^3$' + description: 'This macro is used in port discovery to exclude port types. The default excludes not-present(3) ports.' + - macro: '{$SNMP.TIMEOUT}' + value: 5m + description: 'Time interval used by the SNMP availability trigger.' + items: + - uuid: 1f70be666c524d73b128f09f10ec9824 + name: 'System name' + type: SNMP_AGENT + snmp_oid: 'get[1.3.6.1.2.1.1.5.0]' + key: dell.powervault.me.system.name + delay: 1h + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: SNMPv2-MIB + An administratively assigned name for this managed node. + inventory_link: NAME + preprocessing: + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1d + tags: + - tag: component + value: system + - uuid: 7b42511809514f38afdc016965dab3f6 + name: 'System description' + type: SNMP_AGENT + snmp_oid: 'get[1.3.6.1.2.1.1.1.0]' + key: dell.powervault.me.system.description + delay: 1h + history: 7d + trends: '0' + value_type: TEXT + description: | + MIB: SNMPv2-MIB + A textual description of the entity. + preprocessing: + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1d + tags: + - tag: component + value: system + - uuid: d0e836b21516401d9534a661a3419d05 + name: 'System object ID' + type: SNMP_AGENT + snmp_oid: 'get[1.3.6.1.2.1.1.2.0]' + key: dell.powervault.me.system.objectid + delay: 1h + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: SNMPv2-MIB + The vendor's authoritative identification of the network management subsystem. + preprocessing: + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1d + tags: + - tag: component + value: system + - uuid: d2280e1d77e24fb1bfdaa4842e60a099 + name: 'Uptime (network)' + type: SNMP_AGENT + snmp_oid: 'get[1.3.6.1.2.1.1.3.0]' + key: 'dell.powervault.me.system.uptime[sysUpTime.0]' + delay: 1m + history: 7d + trends: '0' + value_type: FLOAT + units: uptime + description: | + MIB: SNMPv2-MIB + Time (in hundredths of a second) since the network management portion of the system was last re-initialized. + preprocessing: + - type: MULTIPLIER + parameters: + - '0.01' + tags: + - tag: component + value: system + - uuid: 1ad329520d60498daead382277b2746a + name: 'System contact details' + type: SNMP_AGENT + snmp_oid: 'get[1.3.6.1.2.1.1.4.0]' + key: dell.powervault.me.system.contact + delay: 1h + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: SNMPv2-MIB + Contact information for the person responsible for this managed node. + inventory_link: CONTACT + preprocessing: + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1d + tags: + - tag: component + value: system + - uuid: d174ebff350d488ebf68f10f610bb6a2 + name: 'System location' + type: SNMP_AGENT + snmp_oid: 'get[1.3.6.1.2.1.1.6.0]' + key: dell.powervault.me.system.location + delay: 1h + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: SNMPv2-MIB + Physical location of this managed node. + inventory_link: LOCATION + preprocessing: + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1d + tags: + - tag: component + value: system + - uuid: 6b7741f3d9a146fcbb9c4caecd569ceb + name: 'SNMP agent availability' + type: INTERNAL + key: 'zabbix[host,snmp,available]' + delay: 1m + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + Availability of SNMP checks on the host. + 0 - not available + 1 - available + 2 - unknown + valuemap: + name: zabbix.host.available + tags: + - tag: component + value: health + - tag: component + value: network + triggers: + - uuid: 63df1dc46e174451a90f92ff3b7cc1ce + expression: 'max(/Dell PowerVault ME by SNMP/zabbix[host,snmp,available],{$SNMP.TIMEOUT})=0' + name: 'Dell PowerVault ME: No SNMP data collection' + opdata: 'Current state: {ITEM.LASTVALUE1}' + priority: WARNING + description: 'SNMP is not available for polling. Check device connectivity and SNMP settings.' + tags: + - tag: scope + value: availability + - uuid: 8baa6b8e6541439fb136217919f2c9ee + name: 'Connectivity unit SNMP walk' + type: SNMP_AGENT + snmp_oid: 'walk[1.3.6.1.3.94.1.6.1.3,1.3.6.1.3.94.1.6.1.4,1.3.6.1.3.94.1.6.1.5,1.3.6.1.3.94.1.6.1.6,1.3.6.1.3.94.1.6.1.7,1.3.6.1.3.94.1.6.1.8,1.3.6.1.3.94.1.6.1.9,1.3.6.1.3.94.1.6.1.10,1.3.6.1.3.94.1.6.1.14,1.3.6.1.3.94.1.6.1.20,1.3.6.1.3.94.1.6.1.21,1.3.6.1.3.94.1.6.1.23,1.3.6.1.3.94.1.6.1.24]' + key: dell.powervault.me.unit.walk + delay: 5m + history: '0' + trends: '0' + value_type: TEXT + description: 'Discovery of connectivity units (FCMGMT-MIB::connUnitTable).' + tags: + - tag: component + value: raw + - uuid: 7b22a6b05f7e4492be031abdc2ed34ff + name: 'Sensor SNMP walk' + type: SNMP_AGENT + snmp_oid: 'walk[1.3.6.1.3.94.1.8.1.3,1.3.6.1.3.94.1.8.1.4,1.3.6.1.3.94.1.8.1.6,1.3.6.1.3.94.1.8.1.7,1.3.6.1.3.94.1.8.1.8]' + key: dell.powervault.me.sensor.walk + delay: 5m + history: '0' + trends: '0' + value_type: TEXT + description: 'Discovery of hardware sensors (FCMGMT-MIB::connUnitSensorTable).' + tags: + - tag: component + value: raw + - uuid: 2ece655b7bef4a519ead8fd8a386890d + name: 'Port SNMP walk' + type: SNMP_AGENT + snmp_oid: 'walk[1.3.6.1.3.94.1.10.1.3,1.3.6.1.3.94.1.10.1.6,1.3.6.1.3.94.1.10.1.7,1.3.6.1.3.94.1.10.1.10,1.3.6.1.3.94.1.10.1.15,1.3.6.1.3.94.1.10.1.17,1.3.6.1.3.94.1.10.1.18]' + key: dell.powervault.me.port.walk + delay: 5m + history: '0' + trends: '0' + value_type: TEXT + description: 'Discovery of Fibre Channel ports (FCMGMT-MIB::connUnitPortTable).' + tags: + - tag: component + value: raw + - uuid: 3823bfaaa1a54fa5a388a63b6b0a3a10 + name: 'Revision SNMP walk' + type: SNMP_AGENT + snmp_oid: 'walk[1.3.6.1.3.94.1.7.1.3,1.3.6.1.3.94.1.7.1.4]' + key: dell.powervault.me.revision.walk + delay: 1h + history: '0' + trends: '0' + value_type: TEXT + description: 'Discovery of firmware and hardware revisions (FCMGMT-MIB::connUnitRevsTable).' + tags: + - tag: component + value: raw + discovery_rules: + - uuid: a4265e70b4d64f169e59ec687ca8186c + name: 'Connectivity unit discovery' + type: DEPENDENT + key: dell.powervault.me.unit.discovery + delay: '0' + lifetime: 7d + description: 'Discovery of connectivity units (FCMGMT-MIB::connUnitTable).' + item_prototypes: + - uuid: f1cf749af675432e91fe4997c6394787 + name: 'Connectivity unit [{#UNIT_NAME}]: Name' + type: DEPENDENT + key: 'dell.powervault.me.unit.name[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + A display string containing a name for this connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.20.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 447017aa257b466dbfdf847438502ce4 + name: 'Connectivity unit [{#UNIT_NAME}]: Product' + type: DEPENDENT + key: 'dell.powervault.me.unit.product[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + The vendor's product model name for this connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.7.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 3550934f5be04462a7cbf69e42550197 + name: 'Connectivity unit [{#UNIT_NAME}]: Serial number' + type: DEPENDENT + key: 'dell.powervault.me.unit.serial[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + The serial number for this connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.8.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 31357f5bdd354f458d5954de59745c73 + name: 'Connectivity unit [{#UNIT_NAME}]: Type' + type: DEPENDENT + key: 'dell.powervault.me.unit.type[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + The type of this connectivity unit. + valuemap: + name: 'Dell PowerVault ME: Unit type' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.3.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: f3103d561d0e42469cb6c34e79cd692d + name: 'Connectivity unit [{#UNIT_NAME}]: Uptime' + type: DEPENDENT + key: 'dell.powervault.me.unit.uptime[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: FLOAT + units: uptime + description: | + MIB: FCMGMT-MIB + The number of centiseconds since the last unit initialization. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.9.{#SNMPINDEX}' + - '0' + - type: MULTIPLIER + parameters: + - '0.01' + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 83826ac4328d49bf980661b44c3db009 + name: 'Connectivity unit [{#UNIT_NAME}]: Operational state' + type: DEPENDENT + key: 'dell.powervault.me.unit.state[{#SNMPINDEX}]' + delay: '0' + history: 30d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + Overall operational state of the connectivity unit. + valuemap: + name: 'Dell PowerVault ME: Unit operational state' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.5.{#SNMPINDEX}' + - '0' + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: health + - tag: component + value: storage + trigger_prototypes: + - uuid: eee556e619934bfe894584579bcb00d9 + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.unit.state[{#SNMPINDEX}])<>2' + name: 'Dell PowerVault ME: Unit [{#UNIT_NAME}]: Operational state is not online' + opdata: 'Current state: {ITEM.LASTVALUE1}' + priority: AVERAGE + description: | + MIB: FCMGMT-MIB + The connectivity unit state is not online(2). + tags: + - tag: scope + value: availability + - uuid: f2e789cdcb5e4147952d3326085eda80 + name: 'Connectivity unit [{#UNIT_NAME}]: Health status' + type: DEPENDENT + key: 'dell.powervault.me.unit.status[{#SNMPINDEX}]' + delay: '0' + history: 30d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + Overall health status of the connectivity unit. + valuemap: + name: 'Dell PowerVault ME: Unit health status' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.6.{#SNMPINDEX}' + - '0' + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: health + - tag: component + value: storage + trigger_prototypes: + - uuid: 8acaf2dc41864df1995e9dbb5a268cb4 + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.unit.status[{#SNMPINDEX}])=5' + name: 'Dell PowerVault ME: Unit [{#UNIT_NAME}]: Health status is in failed state' + opdata: 'Current status: {ITEM.LASTVALUE1}' + priority: HIGH + description: | + MIB: FCMGMT-MIB + The connectivity unit status is failed(5). + tags: + - tag: scope + value: availability + - uuid: c04e2b27f6cf4dbcb87de69efa52811f + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.unit.status[{#SNMPINDEX}])=4' + name: 'Dell PowerVault ME: Unit [{#UNIT_NAME}]: Health status is in warning state' + opdata: 'Current status: {ITEM.LASTVALUE1}' + priority: AVERAGE + description: | + MIB: FCMGMT-MIB + The connectivity unit status is warning(4). + tags: + - tag: scope + value: availability + - uuid: a090b07cdcac41198b4eb1c053ff525e + name: 'Connectivity unit [{#UNIT_NAME}]: Ports count' + type: DEPENDENT + key: 'dell.powervault.me.unit.ports[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + Number of physical ports in the connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.4.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 7f6a38bcaa6249eb88f4e0947e3ad55d + name: 'Connectivity unit [{#UNIT_NAME}]: Sensors count' + type: DEPENDENT + key: 'dell.powervault.me.unit.sensors[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + Number of sensors in the sensor table. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.14.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: a63be7410e0c4973ba39c57c6890f969 + name: 'Connectivity unit [{#UNIT_NAME}]: Location' + type: DEPENDENT + key: 'dell.powervault.me.unit.location[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + Location information for this connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.24.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 59ab633ae7804aee97002c802c41989d + name: 'Connectivity unit [{#UNIT_NAME}]: Contact' + type: DEPENDENT + key: 'dell.powervault.me.unit.contact[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + Contact information for this connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.23.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: f860b2e854ae4e55b037e330839e469b + name: 'Connectivity unit [{#UNIT_NAME}]: URL' + type: DEPENDENT + key: 'dell.powervault.me.unit.url[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + URL to launch a management application, if applicable. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.10.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 8fd6228f8f3a49509bf8f5134005a43f + name: 'Connectivity unit [{#UNIT_NAME}]: Information' + type: DEPENDENT + key: 'dell.powervault.me.unit.info[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: TEXT + description: | + MIB: FCMGMT-MIB + General information about this connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.21.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + master_item: + key: dell.powervault.me.unit.walk + preprocessing: + - type: SNMP_WALK_TO_JSON + parameters: + - '{#UNIT_NAME}' + - 1.3.6.1.3.94.1.6.1.20 + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1h + - uuid: 21d27a8a09464f59b12eb392453eeefe + name: 'Sensor discovery' + type: DEPENDENT + key: dell.powervault.me.sensor.discovery + delay: '0' + lifetime: 7d + filter: + evaltype: AND + conditions: + - macro: '{#SENSOR_NAME}' + value: '{$DELL.POWERVAULT.ME.DISCOVERY.SENSOR.NAME.MATCHES}' + formulaid: A + - macro: '{#SENSOR_NAME}' + value: '{$DELL.POWERVAULT.ME.DISCOVERY.SENSOR.NAME.NOT_MATCHES}' + operator: NOT_MATCHES_REGEX + formulaid: B + description: 'Discovery of hardware sensors (FCMGMT-MIB::connUnitSensorTable).' + item_prototypes: + - uuid: d9ae871b134c4c648f28e3168ddab443 + name: 'Sensor [{#SENSOR_NAME}]: Health status' + type: DEPENDENT + key: 'dell.powervault.me.sensor.status[{#SNMPINDEX}]' + delay: '0' + history: 30d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + Status indicated by the sensor. + valuemap: + name: 'Dell PowerVault ME: Sensor health status' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.8.1.4.{#SNMPINDEX}' + - '0' + master_item: + key: dell.powervault.me.sensor.walk + tags: + - tag: component + value: sensor + - tag: component + value: health + - tag: sensor + value: '{#SENSOR_NAME}' + trigger_prototypes: + - uuid: 7c78a5ef4954449ebe3a1aa2ca0fabe6 + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.sensor.status[{#SNMPINDEX}])=5' + name: 'Dell PowerVault ME: Sensor [{#SENSOR_NAME}]: Health status is in failed state' + opdata: 'Current status: {ITEM.LASTVALUE1}' + priority: HIGH + description: | + MIB: FCMGMT-MIB + The sensor status is failed(5). + tags: + - tag: scope + value: availability + - uuid: 06de7ec0a3734ba5a104b091c505f4cf + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.sensor.status[{#SNMPINDEX}])=4' + name: 'Dell PowerVault ME: Sensor [{#SENSOR_NAME}]: Health status is in warning state' + opdata: 'Current status: {ITEM.LASTVALUE1}' + priority: WARNING + description: | + MIB: FCMGMT-MIB + The sensor status is warning(4). + tags: + - tag: scope + value: availability + - uuid: 48c30b1133eb4a6496d9e8dd14c2517c + name: 'Sensor [{#SENSOR_NAME}]: Message' + type: DEPENDENT + key: 'dell.powervault.me.sensor.message[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: TEXT + description: | + MIB: FCMGMT-MIB + Description of the sensor status. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.8.1.6.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.sensor.walk + tags: + - tag: component + value: sensor + - tag: sensor + value: '{#SENSOR_NAME}' + - uuid: b0848d6be728472d8a4d2c5f34964003 + name: 'Sensor [{#SENSOR_NAME}]: Type' + type: DEPENDENT + key: 'dell.powervault.me.sensor.type[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + The type of component being monitored by this sensor. + valuemap: + name: 'Dell PowerVault ME: Sensor type' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.8.1.7.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.sensor.walk + tags: + - tag: component + value: sensor + - tag: sensor + value: '{#SENSOR_NAME}' + - uuid: 96405eb6bb0c423faa5b97db1ff4f817 + name: 'Sensor [{#SENSOR_NAME}]: Characteristic' + type: DEPENDENT + key: 'dell.powervault.me.sensor.characteristic[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + The characteristic being monitored by this sensor. + valuemap: + name: 'Dell PowerVault ME: Sensor characteristic' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.8.1.8.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.sensor.walk + tags: + - tag: component + value: sensor + - tag: sensor + value: '{#SENSOR_NAME}' + master_item: + key: dell.powervault.me.sensor.walk + preprocessing: + - type: SNMP_WALK_TO_JSON + parameters: + - '{#SENSOR_NAME}' + - 1.3.6.1.3.94.1.8.1.3 + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1h + - uuid: 4fd6af5a52ba4bed967d2a84a19513a4 + name: 'Port discovery' + type: DEPENDENT + key: dell.powervault.me.port.discovery + delay: '0' + lifetime: 7d + filter: + evaltype: AND + conditions: + - macro: '{#PORT_TYPE}' + value: '{$DELL.POWERVAULT.ME.DISCOVERY.PORT.TYPE.MATCHES}' + formulaid: A + - macro: '{#PORT_TYPE}' + value: '{$DELL.POWERVAULT.ME.DISCOVERY.PORT.TYPE.NOT_MATCHES}' + operator: NOT_MATCHES_REGEX + formulaid: B + description: 'Discovery of Fibre Channel ports (FCMGMT-MIB::connUnitPortTable).' + item_prototypes: + - uuid: 8d6368d49dad4a26b5f1acbcd56bb2ee + name: 'Port {#PORT_NUMBER}: Health status' + type: DEPENDENT + key: 'dell.powervault.me.port.status[{#SNMPINDEX}]' + delay: '0' + history: 30d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + Overall protocol status for the port. + valuemap: + name: 'Dell PowerVault ME: Port health status' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.10.1.7.{#SNMPINDEX}' + - '0' + master_item: + key: dell.powervault.me.port.walk + tags: + - tag: component + value: port + - tag: component + value: health + - tag: port + value: '{#PORT_NUMBER}' + trigger_prototypes: + - uuid: 7bd95938fb194b2ca3631e6bd75a8349 + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.port.status[{#SNMPINDEX}])=5' + name: 'Dell PowerVault ME: Port {#PORT_NUMBER}: Health status is in failure state' + opdata: 'Current status: {ITEM.LASTVALUE1}' + priority: HIGH + description: | + MIB: FCMGMT-MIB + The port status is failure(5). + tags: + - tag: scope + value: availability + - uuid: c1983be544634c36a3a4b39d5b706ade + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.port.status[{#SNMPINDEX}])=4' + name: 'Dell PowerVault ME: Port {#PORT_NUMBER}: Health status is in warning state' + opdata: 'Current status: {ITEM.LASTVALUE1}' + priority: WARNING + description: | + MIB: FCMGMT-MIB + The port status is warning(4). + tags: + - tag: scope + value: availability + - uuid: 218dd64a05d641c2a9b2f4f762c01bd5 + name: 'Port {#PORT_NUMBER}: Name' + type: DEPENDENT + key: 'dell.powervault.me.port.name[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + A string describing the port. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.10.1.17.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.port.walk + tags: + - tag: component + value: port + - tag: port + value: '{#PORT_NUMBER}' + - uuid: 8fef8e0fd31549e28b568e7743325582 + name: 'Port {#PORT_NUMBER}: Operational state' + type: DEPENDENT + key: 'dell.powervault.me.port.state[{#SNMPINDEX}]' + delay: '0' + history: 30d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + State of the port hardware. + valuemap: + name: 'Dell PowerVault ME: Port operational state' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.10.1.6.{#SNMPINDEX}' + - '0' + master_item: + key: dell.powervault.me.port.walk + tags: + - tag: component + value: port + - tag: port + value: '{#PORT_NUMBER}' + - uuid: 8603870e651045f08e6b84967b0c2d04 + name: 'Port {#PORT_NUMBER}: Speed' + type: DEPENDENT + key: 'dell.powervault.me.port.speed[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + units: KBps + description: | + MIB: FCMGMT-MIB + Speed of the port in kilobytes per second. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.10.1.15.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.port.walk + tags: + - tag: component + value: port + - tag: port + value: '{#PORT_NUMBER}' + - uuid: 6a37efa76cd64fb38896696de900c3a3 + name: 'Port {#PORT_NUMBER}: Type' + type: DEPENDENT + key: 'dell.powervault.me.port.type[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + The port type. + valuemap: + name: 'Dell PowerVault ME: Port type' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.10.1.3.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.port.walk + tags: + - tag: component + value: port + - tag: port + value: '{#PORT_NUMBER}' + - uuid: 95ec697491a840e4a3f1ff85e78e2b63 + name: 'Port {#PORT_NUMBER}: WWN' + type: DEPENDENT + key: 'dell.powervault.me.port.wwn[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + World Wide Name of the port. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.10.1.10.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.port.walk + tags: + - tag: component + value: port + - tag: port + value: '{#PORT_NUMBER}' + master_item: + key: dell.powervault.me.port.walk + preprocessing: + - type: SNMP_WALK_TO_JSON + parameters: + - '{#PORT_NUMBER}' + - 1.3.6.1.3.94.1.10.1.18 + - '0' + - '{#PORT_TYPE}' + - 1.3.6.1.3.94.1.10.1.3 + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1h + - uuid: c5db2417e7054d8badc09316db6091be + name: 'Revision discovery' + type: DEPENDENT + key: dell.powervault.me.revision.discovery + delay: '0' + lifetime: 7d + description: 'Discovery of firmware and hardware revisions (FCMGMT-MIB::connUnitRevsTable).' + item_prototypes: + - uuid: e2f965cf35444e4e9bf7d5c16fb0cd3f + name: 'Revision [{#COMPONENT}]: Version' + type: DEPENDENT + key: 'dell.powervault.me.revision.value[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + Vendor-specific revision identifier of the component. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.7.1.3.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.revision.walk + tags: + - tag: component + value: revision + master_item: + key: dell.powervault.me.revision.walk + preprocessing: + - type: SNMP_WALK_TO_JSON + parameters: + - '{#COMPONENT}' + - 1.3.6.1.3.94.1.7.1.4 + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1h + valuemaps: + - uuid: f381a35f8ab5430eb3e8027981ca72fa + name: 'Dell PowerVault ME: Unit operational state' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Online + - value: '3' + newvalue: Offline + - uuid: 511e84b84cb04c3daa60e87617eaacb2 + name: 'Dell PowerVault ME: Unit health status' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Unused + - value: '3' + newvalue: OK + - value: '4' + newvalue: Warning + - value: '5' + newvalue: Failed + - uuid: a34874cb96b447b9973dc528387910f0 + name: 'Dell PowerVault ME: Unit type' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Other + - value: '3' + newvalue: Hub + - value: '4' + newvalue: Switch + - value: '5' + newvalue: Gateway + - value: '6' + newvalue: Converter + - value: '7' + newvalue: HBA + - value: '8' + newvalue: Proxy agent + - value: '9' + newvalue: Storage device + - value: '10' + newvalue: Host + - value: '11' + newvalue: Storage subsystem + - value: '12' + newvalue: Module + - value: '13' + newvalue: Software driver + - value: '14' + newvalue: Storage access device + - uuid: 59e3eb7f21284bd98f8d0d6f992d2387 + name: 'Dell PowerVault ME: Sensor health status' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Other + - value: '3' + newvalue: OK + - value: '4' + newvalue: Warning + - value: '5' + newvalue: Failed + - uuid: 1f4c0b2ce14e4fb6a8b5f911ac81e0d0 + name: 'Dell PowerVault ME: Sensor type' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Other + - value: '3' + newvalue: Battery + - value: '4' + newvalue: Fan + - value: '5' + newvalue: Power supply + - value: '6' + newvalue: Transmitter + - value: '7' + newvalue: Enclosure + - value: '8' + newvalue: Board + - value: '9' + newvalue: Receiver + - uuid: 36916cb2b6d04e61b36f8527b45918aa + name: 'Dell PowerVault ME: Sensor characteristic' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Other + - value: '3' + newvalue: Temperature + - value: '4' + newvalue: Pressure + - value: '5' + newvalue: EMF + - value: '6' + newvalue: Current + - value: '7' + newvalue: Airflow + - value: '8' + newvalue: Frequency + - value: '9' + newvalue: Power + - uuid: 9adca061c20d4fc7b2d69edab9902c07 + name: 'Dell PowerVault ME: Port health status' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Unused + - value: '3' + newvalue: OK + - value: '4' + newvalue: Warning + - value: '5' + newvalue: Failure + - value: '6' + newvalue: Not participating + - value: '7' + newvalue: Initializing + - value: '8' + newvalue: Bypass + - uuid: b75bcc1392434993a460d7b4d040da7c + name: 'Dell PowerVault ME: Port operational state' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Online + - value: '3' + newvalue: Offline + - value: '4' + newvalue: Bypassed + - uuid: e017ab56f2004ce9942c13af4b123295 + name: 'Dell PowerVault ME: Port type' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Other + - value: '3' + newvalue: Not present + - value: '4' + newvalue: Hub port + - value: '5' + newvalue: N-port + - value: '6' + newvalue: L-port + - value: '7' + newvalue: FL-port + - value: '8' + newvalue: F-port + - value: '9' + newvalue: E-port + - value: '10' + newvalue: G-port + - value: '11' + newvalue: Domain controller + - value: '12' + newvalue: Hub controller + - value: '13' + newvalue: SCSI + - value: '14' + newvalue: ESCON + - value: '15' + newvalue: LAN + - value: '16' + newvalue: WAN + - uuid: 17c6219674ac41488b4e1cb0d9d2b2e2 + name: zabbix.host.available + mappings: + - value: '0' + newvalue: Not available + - value: '1' + newvalue: Available + - value: '2' + newvalue: Unknown + triggers: + - uuid: 9e1fba95a5ec45c087469b58a95ce8ee + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.system.uptime[sysUpTime.0])<{$DELL.POWERVAULT.ME.UPTIME.WARN}' + name: 'Dell PowerVault ME: Host has been restarted' + event_name: 'Dell PowerVault ME: {HOST.NAME} has been restarted (uptime < {$DELL.POWERVAULT.ME.UPTIME.WARN})' + priority: WARNING + description: 'Uptime is less than {$DELL.POWERVAULT.ME.UPTIME.WARN}.' + manual_close: 'YES' + dependencies: + - name: 'Dell PowerVault ME: No SNMP data collection' + expression: 'max(/Dell PowerVault ME by SNMP/zabbix[host,snmp,available],{$SNMP.TIMEOUT})=0' + tags: + - tag: scope + value: notice diff --git a/templates/san/dell_powervault_me/8.0/template_san_dell_powervault_me_snmp.yaml b/templates/san/dell_powervault_me/8.0/template_san_dell_powervault_me_snmp.yaml new file mode 100644 index 0000000..15738e2 --- /dev/null +++ b/templates/san/dell_powervault_me/8.0/template_san_dell_powervault_me_snmp.yaml @@ -0,0 +1,1257 @@ +zabbix_export: + version: '8.0' + template_groups: + - uuid: 1922297aaf2746069dbec26847d7414a + name: Templates/SAN + templates: + - uuid: 7dd20b46a71a45a1949830081511d4f5 + template: 'Dell PowerVault ME by SNMP' + name: 'Dell PowerVault ME by SNMP' + description: | + Setup: + 1. Create a host for the PowerVault ME management interface and assign this template. + 2. Configure an SNMP interface with SNMPv2c or SNMPv3 credentials. + 3. Adjust macro values if needed. + + Overview: + This template monitors Dell PowerVault ME storage systems via SNMP. It covers system information, connectivity unit health and state, hardware sensors, Fibre Channel ports, and firmware revisions. + + The template uses numeric FCMGMT-MIB OIDs (1.3.6.1.3.94), so MIB files are not required on the Zabbix server. + + Tested by importing into a Zabbix 8.0.0 development build and linking to a host. Not yet tested against a live PowerVault ME system. + wizard_ready: 'YES' + readme: | + ## Setup + 1. Create a host for the PowerVault ME management interface. + 2. Assign this template to the host. + 3. Configure an SNMP interface with SNMPv2c or SNMPv3 credentials. + 4. Adjust macro values if needed. + + ## Overview + This template monitors Dell PowerVault ME storage systems via SNMP. It covers system information, connectivity unit health and state, hardware sensors, Fibre Channel ports, and firmware revisions. + + ## Known limitations + FA MIB 2.2 exposes aggregate disk health through `connUnitStatus` and the `Overall Status` sensor. Per-disk and per-disk-group status require the ME REST API/CLI or a dedicated MIB. + vendor: + name: 'Yoshihiro OKUMURA' + version: '1.0.0' + groups: + - name: Templates/SAN + tags: + - tag: class + value: hardware + - tag: class + value: storage + - tag: subclass + value: server + - tag: target + value: dell + - tag: target + value: powervault-me + macros: + - macro: '{$DELL.POWERVAULT.ME.UPTIME.WARN}' + value: 10m + description: 'Warning threshold for system uptime. A lower value indicates a recent restart.' + - macro: '{$DELL.POWERVAULT.ME.DISCOVERY.SENSOR.NAME.MATCHES}' + value: '^.*$' + description: 'This macro is used in sensor discovery to filter sensor names.' + - macro: '{$DELL.POWERVAULT.ME.DISCOVERY.SENSOR.NAME.NOT_MATCHES}' + value: '^$' + description: 'This macro is used in sensor discovery to exclude sensor names.' + - macro: '{$DELL.POWERVAULT.ME.DISCOVERY.PORT.TYPE.MATCHES}' + value: '^.*$' + description: 'This macro is used in port discovery to filter port types.' + - macro: '{$DELL.POWERVAULT.ME.DISCOVERY.PORT.TYPE.NOT_MATCHES}' + value: '^3$' + description: 'This macro is used in port discovery to exclude port types. The default excludes not-present(3) ports.' + - macro: '{$SNMP.TIMEOUT}' + value: 5m + description: 'Time interval used by the SNMP availability trigger.' + items: + - uuid: 1f70be666c524d73b128f09f10ec9824 + name: 'System name' + type: SNMP_AGENT + snmp_oid: 'get[1.3.6.1.2.1.1.5.0]' + key: dell.powervault.me.system.name + delay: 1h + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: SNMPv2-MIB + An administratively assigned name for this managed node. + inventory_link: NAME + preprocessing: + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1d + tags: + - tag: component + value: system + - uuid: 7b42511809514f38afdc016965dab3f6 + name: 'System description' + type: SNMP_AGENT + snmp_oid: 'get[1.3.6.1.2.1.1.1.0]' + key: dell.powervault.me.system.description + delay: 1h + history: 7d + trends: '0' + value_type: TEXT + description: | + MIB: SNMPv2-MIB + A textual description of the entity. + preprocessing: + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1d + tags: + - tag: component + value: system + - uuid: d0e836b21516401d9534a661a3419d05 + name: 'System object ID' + type: SNMP_AGENT + snmp_oid: 'get[1.3.6.1.2.1.1.2.0]' + key: dell.powervault.me.system.objectid + delay: 1h + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: SNMPv2-MIB + The vendor's authoritative identification of the network management subsystem. + preprocessing: + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1d + tags: + - tag: component + value: system + - uuid: d2280e1d77e24fb1bfdaa4842e60a099 + name: 'Uptime (network)' + type: SNMP_AGENT + snmp_oid: 'get[1.3.6.1.2.1.1.3.0]' + key: 'dell.powervault.me.system.uptime[sysUpTime.0]' + delay: 1m + history: 7d + trends: '0' + value_type: FLOAT + units: uptime + description: | + MIB: SNMPv2-MIB + Time (in hundredths of a second) since the network management portion of the system was last re-initialized. + preprocessing: + - type: MULTIPLIER + parameters: + - '0.01' + tags: + - tag: component + value: system + - uuid: 1ad329520d60498daead382277b2746a + name: 'System contact details' + type: SNMP_AGENT + snmp_oid: 'get[1.3.6.1.2.1.1.4.0]' + key: dell.powervault.me.system.contact + delay: 1h + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: SNMPv2-MIB + Contact information for the person responsible for this managed node. + inventory_link: CONTACT + preprocessing: + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1d + tags: + - tag: component + value: system + - uuid: d174ebff350d488ebf68f10f610bb6a2 + name: 'System location' + type: SNMP_AGENT + snmp_oid: 'get[1.3.6.1.2.1.1.6.0]' + key: dell.powervault.me.system.location + delay: 1h + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: SNMPv2-MIB + Physical location of this managed node. + inventory_link: LOCATION + preprocessing: + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1d + tags: + - tag: component + value: system + - uuid: 6b7741f3d9a146fcbb9c4caecd569ceb + name: 'SNMP agent availability' + type: INTERNAL + key: 'zabbix[host,snmp,available]' + delay: 1m + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + Availability of SNMP checks on the host. + 0 - not available + 1 - available + 2 - unknown + valuemap: + name: zabbix.host.available + tags: + - tag: component + value: health + - tag: component + value: network + triggers: + - uuid: 63df1dc46e174451a90f92ff3b7cc1ce + expression: 'max(/Dell PowerVault ME by SNMP/zabbix[host,snmp,available],{$SNMP.TIMEOUT})=0' + name: 'Dell PowerVault ME: No SNMP data collection' + opdata: 'Current state: {ITEM.LASTVALUE1}' + priority: WARNING + description: 'SNMP is not available for polling. Check device connectivity and SNMP settings.' + tags: + - tag: scope + value: availability + - uuid: 8baa6b8e6541439fb136217919f2c9ee + name: 'Connectivity unit SNMP walk' + type: SNMP_AGENT + snmp_oid: 'walk[1.3.6.1.3.94.1.6.1.3,1.3.6.1.3.94.1.6.1.4,1.3.6.1.3.94.1.6.1.5,1.3.6.1.3.94.1.6.1.6,1.3.6.1.3.94.1.6.1.7,1.3.6.1.3.94.1.6.1.8,1.3.6.1.3.94.1.6.1.9,1.3.6.1.3.94.1.6.1.10,1.3.6.1.3.94.1.6.1.14,1.3.6.1.3.94.1.6.1.20,1.3.6.1.3.94.1.6.1.21,1.3.6.1.3.94.1.6.1.23,1.3.6.1.3.94.1.6.1.24]' + key: dell.powervault.me.unit.walk + delay: 5m + history: '0' + trends: '0' + value_type: TEXT + description: 'Discovery of connectivity units (FCMGMT-MIB::connUnitTable).' + tags: + - tag: component + value: raw + - uuid: 7b22a6b05f7e4492be031abdc2ed34ff + name: 'Sensor SNMP walk' + type: SNMP_AGENT + snmp_oid: 'walk[1.3.6.1.3.94.1.8.1.3,1.3.6.1.3.94.1.8.1.4,1.3.6.1.3.94.1.8.1.6,1.3.6.1.3.94.1.8.1.7,1.3.6.1.3.94.1.8.1.8]' + key: dell.powervault.me.sensor.walk + delay: 5m + history: '0' + trends: '0' + value_type: TEXT + description: 'Discovery of hardware sensors (FCMGMT-MIB::connUnitSensorTable).' + tags: + - tag: component + value: raw + - uuid: 2ece655b7bef4a519ead8fd8a386890d + name: 'Port SNMP walk' + type: SNMP_AGENT + snmp_oid: 'walk[1.3.6.1.3.94.1.10.1.3,1.3.6.1.3.94.1.10.1.6,1.3.6.1.3.94.1.10.1.7,1.3.6.1.3.94.1.10.1.10,1.3.6.1.3.94.1.10.1.15,1.3.6.1.3.94.1.10.1.17,1.3.6.1.3.94.1.10.1.18]' + key: dell.powervault.me.port.walk + delay: 5m + history: '0' + trends: '0' + value_type: TEXT + description: 'Discovery of Fibre Channel ports (FCMGMT-MIB::connUnitPortTable).' + tags: + - tag: component + value: raw + - uuid: 3823bfaaa1a54fa5a388a63b6b0a3a10 + name: 'Revision SNMP walk' + type: SNMP_AGENT + snmp_oid: 'walk[1.3.6.1.3.94.1.7.1.3,1.3.6.1.3.94.1.7.1.4]' + key: dell.powervault.me.revision.walk + delay: 1h + history: '0' + trends: '0' + value_type: TEXT + description: 'Discovery of firmware and hardware revisions (FCMGMT-MIB::connUnitRevsTable).' + tags: + - tag: component + value: raw + discovery_rules: + - uuid: a4265e70b4d64f169e59ec687ca8186c + name: 'Connectivity unit discovery' + type: DEPENDENT + key: dell.powervault.me.unit.discovery + delay: '0' + lifetime: 7d + description: 'Discovery of connectivity units (FCMGMT-MIB::connUnitTable).' + item_prototypes: + - uuid: f1cf749af675432e91fe4997c6394787 + name: 'Connectivity unit [{#UNIT_NAME}]: Name' + type: DEPENDENT + key: 'dell.powervault.me.unit.name[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + A display string containing a name for this connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.20.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 447017aa257b466dbfdf847438502ce4 + name: 'Connectivity unit [{#UNIT_NAME}]: Product' + type: DEPENDENT + key: 'dell.powervault.me.unit.product[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + The vendor's product model name for this connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.7.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 3550934f5be04462a7cbf69e42550197 + name: 'Connectivity unit [{#UNIT_NAME}]: Serial number' + type: DEPENDENT + key: 'dell.powervault.me.unit.serial[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + The serial number for this connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.8.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 31357f5bdd354f458d5954de59745c73 + name: 'Connectivity unit [{#UNIT_NAME}]: Type' + type: DEPENDENT + key: 'dell.powervault.me.unit.type[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + The type of this connectivity unit. + valuemap: + name: 'Dell PowerVault ME: Unit type' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.3.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: f3103d561d0e42469cb6c34e79cd692d + name: 'Connectivity unit [{#UNIT_NAME}]: Uptime' + type: DEPENDENT + key: 'dell.powervault.me.unit.uptime[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: FLOAT + units: uptime + description: | + MIB: FCMGMT-MIB + The number of centiseconds since the last unit initialization. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.9.{#SNMPINDEX}' + - '0' + - type: MULTIPLIER + parameters: + - '0.01' + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 83826ac4328d49bf980661b44c3db009 + name: 'Connectivity unit [{#UNIT_NAME}]: Operational state' + type: DEPENDENT + key: 'dell.powervault.me.unit.state[{#SNMPINDEX}]' + delay: '0' + history: 30d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + Overall operational state of the connectivity unit. + valuemap: + name: 'Dell PowerVault ME: Unit operational state' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.5.{#SNMPINDEX}' + - '0' + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: health + - tag: component + value: storage + trigger_prototypes: + - uuid: eee556e619934bfe894584579bcb00d9 + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.unit.state[{#SNMPINDEX}])<>2' + name: 'Dell PowerVault ME: Unit [{#UNIT_NAME}]: Operational state is not online' + opdata: 'Current state: {ITEM.LASTVALUE1}' + priority: AVERAGE + description: | + MIB: FCMGMT-MIB + The connectivity unit state is not online(2). + tags: + - tag: scope + value: availability + - uuid: f2e789cdcb5e4147952d3326085eda80 + name: 'Connectivity unit [{#UNIT_NAME}]: Health status' + type: DEPENDENT + key: 'dell.powervault.me.unit.status[{#SNMPINDEX}]' + delay: '0' + history: 30d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + Overall health status of the connectivity unit. + valuemap: + name: 'Dell PowerVault ME: Unit health status' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.6.{#SNMPINDEX}' + - '0' + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: health + - tag: component + value: storage + trigger_prototypes: + - uuid: 8acaf2dc41864df1995e9dbb5a268cb4 + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.unit.status[{#SNMPINDEX}])=5' + name: 'Dell PowerVault ME: Unit [{#UNIT_NAME}]: Health status is in failed state' + opdata: 'Current status: {ITEM.LASTVALUE1}' + priority: HIGH + description: | + MIB: FCMGMT-MIB + The connectivity unit status is failed(5). + tags: + - tag: scope + value: availability + - uuid: c04e2b27f6cf4dbcb87de69efa52811f + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.unit.status[{#SNMPINDEX}])=4' + name: 'Dell PowerVault ME: Unit [{#UNIT_NAME}]: Health status is in warning state' + opdata: 'Current status: {ITEM.LASTVALUE1}' + priority: AVERAGE + description: | + MIB: FCMGMT-MIB + The connectivity unit status is warning(4). + tags: + - tag: scope + value: availability + - uuid: a090b07cdcac41198b4eb1c053ff525e + name: 'Connectivity unit [{#UNIT_NAME}]: Ports count' + type: DEPENDENT + key: 'dell.powervault.me.unit.ports[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + Number of physical ports in the connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.4.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 7f6a38bcaa6249eb88f4e0947e3ad55d + name: 'Connectivity unit [{#UNIT_NAME}]: Sensors count' + type: DEPENDENT + key: 'dell.powervault.me.unit.sensors[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + Number of sensors in the sensor table. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.14.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: a63be7410e0c4973ba39c57c6890f969 + name: 'Connectivity unit [{#UNIT_NAME}]: Location' + type: DEPENDENT + key: 'dell.powervault.me.unit.location[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + Location information for this connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.24.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 59ab633ae7804aee97002c802c41989d + name: 'Connectivity unit [{#UNIT_NAME}]: Contact' + type: DEPENDENT + key: 'dell.powervault.me.unit.contact[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + Contact information for this connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.23.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: f860b2e854ae4e55b037e330839e469b + name: 'Connectivity unit [{#UNIT_NAME}]: URL' + type: DEPENDENT + key: 'dell.powervault.me.unit.url[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + URL to launch a management application, if applicable. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.10.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + - uuid: 8fd6228f8f3a49509bf8f5134005a43f + name: 'Connectivity unit [{#UNIT_NAME}]: Information' + type: DEPENDENT + key: 'dell.powervault.me.unit.info[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: TEXT + description: | + MIB: FCMGMT-MIB + General information about this connectivity unit. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.6.1.21.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.unit.walk + tags: + - tag: component + value: storage + master_item: + key: dell.powervault.me.unit.walk + preprocessing: + - type: SNMP_WALK_TO_JSON + parameters: + - '{#UNIT_NAME}' + - 1.3.6.1.3.94.1.6.1.20 + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1h + - uuid: 21d27a8a09464f59b12eb392453eeefe + name: 'Sensor discovery' + type: DEPENDENT + key: dell.powervault.me.sensor.discovery + delay: '0' + lifetime: 7d + filter: + evaltype: AND + conditions: + - macro: '{#SENSOR_NAME}' + value: '{$DELL.POWERVAULT.ME.DISCOVERY.SENSOR.NAME.MATCHES}' + formulaid: A + - macro: '{#SENSOR_NAME}' + value: '{$DELL.POWERVAULT.ME.DISCOVERY.SENSOR.NAME.NOT_MATCHES}' + operator: NOT_MATCHES_REGEX + formulaid: B + description: 'Discovery of hardware sensors (FCMGMT-MIB::connUnitSensorTable).' + item_prototypes: + - uuid: d9ae871b134c4c648f28e3168ddab443 + name: 'Sensor [{#SENSOR_NAME}]: Health status' + type: DEPENDENT + key: 'dell.powervault.me.sensor.status[{#SNMPINDEX}]' + delay: '0' + history: 30d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + Status indicated by the sensor. + valuemap: + name: 'Dell PowerVault ME: Sensor health status' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.8.1.4.{#SNMPINDEX}' + - '0' + master_item: + key: dell.powervault.me.sensor.walk + tags: + - tag: component + value: sensor + - tag: component + value: health + - tag: sensor + value: '{#SENSOR_NAME}' + trigger_prototypes: + - uuid: 7c78a5ef4954449ebe3a1aa2ca0fabe6 + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.sensor.status[{#SNMPINDEX}])=5' + name: 'Dell PowerVault ME: Sensor [{#SENSOR_NAME}]: Health status is in failed state' + opdata: 'Current status: {ITEM.LASTVALUE1}' + priority: HIGH + description: | + MIB: FCMGMT-MIB + The sensor status is failed(5). + tags: + - tag: scope + value: availability + - uuid: 06de7ec0a3734ba5a104b091c505f4cf + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.sensor.status[{#SNMPINDEX}])=4' + name: 'Dell PowerVault ME: Sensor [{#SENSOR_NAME}]: Health status is in warning state' + opdata: 'Current status: {ITEM.LASTVALUE1}' + priority: WARNING + description: | + MIB: FCMGMT-MIB + The sensor status is warning(4). + tags: + - tag: scope + value: availability + - uuid: 48c30b1133eb4a6496d9e8dd14c2517c + name: 'Sensor [{#SENSOR_NAME}]: Message' + type: DEPENDENT + key: 'dell.powervault.me.sensor.message[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: TEXT + description: | + MIB: FCMGMT-MIB + Description of the sensor status. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.8.1.6.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.sensor.walk + tags: + - tag: component + value: sensor + - tag: sensor + value: '{#SENSOR_NAME}' + - uuid: b0848d6be728472d8a4d2c5f34964003 + name: 'Sensor [{#SENSOR_NAME}]: Type' + type: DEPENDENT + key: 'dell.powervault.me.sensor.type[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + The type of component being monitored by this sensor. + valuemap: + name: 'Dell PowerVault ME: Sensor type' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.8.1.7.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.sensor.walk + tags: + - tag: component + value: sensor + - tag: sensor + value: '{#SENSOR_NAME}' + - uuid: 96405eb6bb0c423faa5b97db1ff4f817 + name: 'Sensor [{#SENSOR_NAME}]: Characteristic' + type: DEPENDENT + key: 'dell.powervault.me.sensor.characteristic[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + The characteristic being monitored by this sensor. + valuemap: + name: 'Dell PowerVault ME: Sensor characteristic' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.8.1.8.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.sensor.walk + tags: + - tag: component + value: sensor + - tag: sensor + value: '{#SENSOR_NAME}' + master_item: + key: dell.powervault.me.sensor.walk + preprocessing: + - type: SNMP_WALK_TO_JSON + parameters: + - '{#SENSOR_NAME}' + - 1.3.6.1.3.94.1.8.1.3 + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1h + - uuid: 4fd6af5a52ba4bed967d2a84a19513a4 + name: 'Port discovery' + type: DEPENDENT + key: dell.powervault.me.port.discovery + delay: '0' + lifetime: 7d + filter: + evaltype: AND + conditions: + - macro: '{#PORT_TYPE}' + value: '{$DELL.POWERVAULT.ME.DISCOVERY.PORT.TYPE.MATCHES}' + formulaid: A + - macro: '{#PORT_TYPE}' + value: '{$DELL.POWERVAULT.ME.DISCOVERY.PORT.TYPE.NOT_MATCHES}' + operator: NOT_MATCHES_REGEX + formulaid: B + description: 'Discovery of Fibre Channel ports (FCMGMT-MIB::connUnitPortTable).' + item_prototypes: + - uuid: 8d6368d49dad4a26b5f1acbcd56bb2ee + name: 'Port {#PORT_NUMBER}: Health status' + type: DEPENDENT + key: 'dell.powervault.me.port.status[{#SNMPINDEX}]' + delay: '0' + history: 30d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + Overall protocol status for the port. + valuemap: + name: 'Dell PowerVault ME: Port health status' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.10.1.7.{#SNMPINDEX}' + - '0' + master_item: + key: dell.powervault.me.port.walk + tags: + - tag: component + value: port + - tag: component + value: health + - tag: port + value: '{#PORT_NUMBER}' + trigger_prototypes: + - uuid: 7bd95938fb194b2ca3631e6bd75a8349 + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.port.status[{#SNMPINDEX}])=5' + name: 'Dell PowerVault ME: Port {#PORT_NUMBER}: Health status is in failure state' + opdata: 'Current status: {ITEM.LASTVALUE1}' + priority: HIGH + description: | + MIB: FCMGMT-MIB + The port status is failure(5). + tags: + - tag: scope + value: availability + - uuid: c1983be544634c36a3a4b39d5b706ade + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.port.status[{#SNMPINDEX}])=4' + name: 'Dell PowerVault ME: Port {#PORT_NUMBER}: Health status is in warning state' + opdata: 'Current status: {ITEM.LASTVALUE1}' + priority: WARNING + description: | + MIB: FCMGMT-MIB + The port status is warning(4). + tags: + - tag: scope + value: availability + - uuid: 218dd64a05d641c2a9b2f4f762c01bd5 + name: 'Port {#PORT_NUMBER}: Name' + type: DEPENDENT + key: 'dell.powervault.me.port.name[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + A string describing the port. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.10.1.17.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.port.walk + tags: + - tag: component + value: port + - tag: port + value: '{#PORT_NUMBER}' + - uuid: 8fef8e0fd31549e28b568e7743325582 + name: 'Port {#PORT_NUMBER}: Operational state' + type: DEPENDENT + key: 'dell.powervault.me.port.state[{#SNMPINDEX}]' + delay: '0' + history: 30d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + State of the port hardware. + valuemap: + name: 'Dell PowerVault ME: Port operational state' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.10.1.6.{#SNMPINDEX}' + - '0' + master_item: + key: dell.powervault.me.port.walk + tags: + - tag: component + value: port + - tag: port + value: '{#PORT_NUMBER}' + - uuid: 8603870e651045f08e6b84967b0c2d04 + name: 'Port {#PORT_NUMBER}: Speed' + type: DEPENDENT + key: 'dell.powervault.me.port.speed[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + units: KBps + description: | + MIB: FCMGMT-MIB + Speed of the port in kilobytes per second. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.10.1.15.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.port.walk + tags: + - tag: component + value: port + - tag: port + value: '{#PORT_NUMBER}' + - uuid: 6a37efa76cd64fb38896696de900c3a3 + name: 'Port {#PORT_NUMBER}: Type' + type: DEPENDENT + key: 'dell.powervault.me.port.type[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: UNSIGNED + description: | + MIB: FCMGMT-MIB + The port type. + valuemap: + name: 'Dell PowerVault ME: Port type' + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.10.1.3.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.port.walk + tags: + - tag: component + value: port + - tag: port + value: '{#PORT_NUMBER}' + - uuid: 95ec697491a840e4a3f1ff85e78e2b63 + name: 'Port {#PORT_NUMBER}: WWN' + type: DEPENDENT + key: 'dell.powervault.me.port.wwn[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + World Wide Name of the port. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.10.1.10.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.port.walk + tags: + - tag: component + value: port + - tag: port + value: '{#PORT_NUMBER}' + master_item: + key: dell.powervault.me.port.walk + preprocessing: + - type: SNMP_WALK_TO_JSON + parameters: + - '{#PORT_NUMBER}' + - 1.3.6.1.3.94.1.10.1.18 + - '0' + - '{#PORT_TYPE}' + - 1.3.6.1.3.94.1.10.1.3 + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1h + - uuid: c5db2417e7054d8badc09316db6091be + name: 'Revision discovery' + type: DEPENDENT + key: dell.powervault.me.revision.discovery + delay: '0' + lifetime: 7d + description: 'Discovery of firmware and hardware revisions (FCMGMT-MIB::connUnitRevsTable).' + item_prototypes: + - uuid: e2f965cf35444e4e9bf7d5c16fb0cd3f + name: 'Revision [{#COMPONENT}]: Version' + type: DEPENDENT + key: 'dell.powervault.me.revision.value[{#SNMPINDEX}]' + delay: '0' + history: 7d + trends: '0' + value_type: CHAR + description: | + MIB: FCMGMT-MIB + Vendor-specific revision identifier of the component. + preprocessing: + - type: SNMP_WALK_VALUE + parameters: + - '1.3.6.1.3.94.1.7.1.3.{#SNMPINDEX}' + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 6h + master_item: + key: dell.powervault.me.revision.walk + tags: + - tag: component + value: revision + master_item: + key: dell.powervault.me.revision.walk + preprocessing: + - type: SNMP_WALK_TO_JSON + parameters: + - '{#COMPONENT}' + - 1.3.6.1.3.94.1.7.1.4 + - '0' + - type: DISCARD_UNCHANGED_HEARTBEAT + parameters: + - 1h + valuemaps: + - uuid: f381a35f8ab5430eb3e8027981ca72fa + name: 'Dell PowerVault ME: Unit operational state' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Online + - value: '3' + newvalue: Offline + - uuid: 511e84b84cb04c3daa60e87617eaacb2 + name: 'Dell PowerVault ME: Unit health status' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Unused + - value: '3' + newvalue: OK + - value: '4' + newvalue: Warning + - value: '5' + newvalue: Failed + - uuid: a34874cb96b447b9973dc528387910f0 + name: 'Dell PowerVault ME: Unit type' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Other + - value: '3' + newvalue: Hub + - value: '4' + newvalue: Switch + - value: '5' + newvalue: Gateway + - value: '6' + newvalue: Converter + - value: '7' + newvalue: HBA + - value: '8' + newvalue: Proxy agent + - value: '9' + newvalue: Storage device + - value: '10' + newvalue: Host + - value: '11' + newvalue: Storage subsystem + - value: '12' + newvalue: Module + - value: '13' + newvalue: Software driver + - value: '14' + newvalue: Storage access device + - uuid: 59e3eb7f21284bd98f8d0d6f992d2387 + name: 'Dell PowerVault ME: Sensor health status' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Other + - value: '3' + newvalue: OK + - value: '4' + newvalue: Warning + - value: '5' + newvalue: Failed + - uuid: 1f4c0b2ce14e4fb6a8b5f911ac81e0d0 + name: 'Dell PowerVault ME: Sensor type' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Other + - value: '3' + newvalue: Battery + - value: '4' + newvalue: Fan + - value: '5' + newvalue: Power supply + - value: '6' + newvalue: Transmitter + - value: '7' + newvalue: Enclosure + - value: '8' + newvalue: Board + - value: '9' + newvalue: Receiver + - uuid: 36916cb2b6d04e61b36f8527b45918aa + name: 'Dell PowerVault ME: Sensor characteristic' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Other + - value: '3' + newvalue: Temperature + - value: '4' + newvalue: Pressure + - value: '5' + newvalue: EMF + - value: '6' + newvalue: Current + - value: '7' + newvalue: Airflow + - value: '8' + newvalue: Frequency + - value: '9' + newvalue: Power + - uuid: 9adca061c20d4fc7b2d69edab9902c07 + name: 'Dell PowerVault ME: Port health status' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Unused + - value: '3' + newvalue: OK + - value: '4' + newvalue: Warning + - value: '5' + newvalue: Failure + - value: '6' + newvalue: Not participating + - value: '7' + newvalue: Initializing + - value: '8' + newvalue: Bypass + - uuid: b75bcc1392434993a460d7b4d040da7c + name: 'Dell PowerVault ME: Port operational state' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Online + - value: '3' + newvalue: Offline + - value: '4' + newvalue: Bypassed + - uuid: e017ab56f2004ce9942c13af4b123295 + name: 'Dell PowerVault ME: Port type' + mappings: + - value: '1' + newvalue: Unknown + - value: '2' + newvalue: Other + - value: '3' + newvalue: Not present + - value: '4' + newvalue: Hub port + - value: '5' + newvalue: N-port + - value: '6' + newvalue: L-port + - value: '7' + newvalue: FL-port + - value: '8' + newvalue: F-port + - value: '9' + newvalue: E-port + - value: '10' + newvalue: G-port + - value: '11' + newvalue: Domain controller + - value: '12' + newvalue: Hub controller + - value: '13' + newvalue: SCSI + - value: '14' + newvalue: ESCON + - value: '15' + newvalue: LAN + - value: '16' + newvalue: WAN + - uuid: 17c6219674ac41488b4e1cb0d9d2b2e2 + name: zabbix.host.available + mappings: + - value: '0' + newvalue: Not available + - value: '1' + newvalue: Available + - value: '2' + newvalue: Unknown + triggers: + - uuid: 9e1fba95a5ec45c087469b58a95ce8ee + expression: 'last(/Dell PowerVault ME by SNMP/dell.powervault.me.system.uptime[sysUpTime.0])<{$DELL.POWERVAULT.ME.UPTIME.WARN}' + name: 'Dell PowerVault ME: Host has been restarted' + event_name: 'Dell PowerVault ME: {HOST.NAME} has been restarted (uptime < {$DELL.POWERVAULT.ME.UPTIME.WARN})' + priority: WARNING + description: 'Uptime is less than {$DELL.POWERVAULT.ME.UPTIME.WARN}.' + manual_close: 'YES' + dependencies: + - name: 'Dell PowerVault ME: No SNMP data collection' + expression: 'max(/Dell PowerVault ME by SNMP/zabbix[host,snmp,available],{$SNMP.TIMEOUT})=0' + tags: + - tag: scope + value: notice diff --git a/templates/san/dell_powervault_me/CHANGELOG.md b/templates/san/dell_powervault_me/CHANGELOG.md new file mode 100644 index 0000000..0f8c545 --- /dev/null +++ b/templates/san/dell_powervault_me/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +All notable changes to this template will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.0.0] - 2026-11-03 + +### Added + +- Initial release. +- System information items based on SNMPv2-MIB. +- Connectivity unit discovery and health monitoring based on FCMGMT-MIB. +- Sensor discovery with warning and failure triggers. +- Fibre Channel port discovery and status monitoring. +- Firmware and hardware revision discovery. +- Added a Zabbix 8.0 export. diff --git a/templates/san/dell_powervault_me/README.md b/templates/san/dell_powervault_me/README.md new file mode 100644 index 0000000..0b01c25 --- /dev/null +++ b/templates/san/dell_powervault_me/README.md @@ -0,0 +1,107 @@ +# Dell PowerVault ME by SNMP + +## Setup + +1. Create a host for the PowerVault ME management interface. +2. Assign this template to the host. +3. Configure an SNMP interface with SNMPv2c or SNMPv3 credentials. +4. Adjust macro values if needed. + +## Overview + +This template monitors Dell PowerVault ME storage systems through SNMP. It covers system identification, overall unit health, hardware sensors, Fibre Channel ports, and firmware revisions. + +The template uses the standard `FCMGMT-MIB` (`1.3.6.1.3.94`) objects that are referenced by `DELLTRAPS-MIB`. Numeric OIDs are used, so the MIB files do not need to be installed on the Zabbix server. + +## Requirements + +- Zabbix 7.0 or later +- Import the YAML from `7.0/` for Zabbix 7.0, or from `8.0/` for Zabbix 8.0 +- SNMP enabled on the PowerVault ME management interface +- SNMPv2c community or SNMPv3 credentials configured on the host +- The device firmware must expose the `FCMGMT-MIB` tables used by this template + +## Import + +1. Open **Data collection > Templates** in Zabbix. +2. Choose **Import**. +3. Select the YAML file from the directory that matches your Zabbix version (`7.0/` or `8.0/`). +4. Link the template to a host and configure an SNMP interface. + +## Macros + +| Macro | Default | Description | +|---|---|---| +| `{$DELL.POWERVAULT.ME.UPTIME.WARN}` | `10m` | Warning threshold for system uptime. A lower value indicates a recent restart. | +| `{$DELL.POWERVAULT.ME.DISCOVERY.SENSOR.NAME.MATCHES}` | `^.*$` | Sensor names to include in discovery. | +| `{$DELL.POWERVAULT.ME.DISCOVERY.SENSOR.NAME.NOT_MATCHES}` | `^$` | Sensor names to exclude from discovery. | +| `{$DELL.POWERVAULT.ME.DISCOVERY.PORT.TYPE.MATCHES}` | `^.*$` | Port types to include in discovery. | +| `{$DELL.POWERVAULT.ME.DISCOVERY.PORT.TYPE.NOT_MATCHES}` | `^3$` | Port types to exclude from discovery. The default excludes not-present(3) ports. | +| `{$SNMP.TIMEOUT}` | `5m` | Time interval used by the SNMP availability trigger. | + +## Discovery rules + +| Rule | Source | Description | +|---|---|---| +| Connectivity unit discovery | `FCMGMT-MIB::connUnitTable` | Discovers storage controllers and collects model, serial number, state, status, and counts. | +| Sensor discovery | `FCMGMT-MIB::connUnitSensorTable` | Discovers batteries, fans, power supplies, temperature sensors, and other components. | +| Port discovery | `FCMGMT-MIB::connUnitPortTable` | Discovers Fibre Channel ports and monitors port status. | +| Revision discovery | `FCMGMT-MIB::connUnitRevsTable` | Collects firmware and hardware revision strings. | + +Key OID roots: + +| Object | OID | +|---|---| +| Connectivity unit table | `1.3.6.1.3.94.1.6.1` | +| Revision table | `1.3.6.1.3.94.1.7.1` | +| Sensor table | `1.3.6.1.3.94.1.8.1` | +| Port table | `1.3.6.1.3.94.1.10.1` | + +## Disk and Disk Group Health + +FA MIB 2.2 does not expose individual HDD or disk group objects. The PowerVault ME4/ME5 Administrator's Guides state that significant status, including the health of storage elements such as virtual disks, is combined into the overall status sensor and `connUnitStatus`. + +This template monitors both: + +- `connUnitStatus` at the unit level (warning or failed) +- The `Overall Status` sensor from `connUnitSensorTable` (index 23 in the ME4/ME5 guides; discovered dynamically by name) + +A disk or disk group failure that affects overall health therefore raises a trigger. The template can detect that a disk or disk group problem exists, but it cannot identify which disk or disk group is affected. Per-disk and per-disk-group status require the ME REST API/CLI or a dedicated MIB. + +## Triggers + +- No SNMP data collection +- Host has been restarted +- Connectivity unit status is warning or failed +- Connectivity unit state is not online +- Sensor status is warning or failed +- Port status is warning or failure + +Port state and unused or offline ports are collected as items but do not raise triggers, because unused ports are commonly offline. Adjust the triggers if your environment requires port-level availability alerts. + +## Known limitations + +- This template has been validated by importing it into Zabbix 7.0 and a Zabbix 8.0.0 development build and linking it to a test host, but it has not been tested against a live PowerVault ME system. +- Sensor and port tables vary by model and firmware. Verify the available OIDs with `snmpwalk` before relying on them. +- Individual HDD and disk group status are not exposed by FA MIB 2.2. Use the ME REST API/CLI or a dedicated MIB if per-disk monitoring is required. +- Trap-based event monitoring from `DELLTRAPS-MIB` is not included. Use a dedicated SNMP trap template if trap processing is required. +- The template uses the generic `FCMGMT-MIB` objects. If Dell provides a model-specific MIB with more detailed health information, add it as a separate template or extend this one. +- The MIB files are not bundled with this package. Obtain them from Dell support if you need to inspect or extend the OIDs. + +## Troubleshooting + +If the import fails because the `Templates/SAN` group is missing, enable **Template groups** in the import options or create the group manually before importing. + +Check basic SNMP connectivity: + +```bash +snmpwalk -v2c -c 1.3.6.1.3.94.1.6 +snmpwalk -v2c -c 1.3.6.1.3.94.1.8 +snmpwalk -v2c -c 1.3.6.1.3.94.1.10 +``` + +If the unit table is empty, the firmware may not expose `FCMGMT-MIB`. Check the Dell support documentation for the SNMP MIB support of your firmware version. + +## Changelog + +[CHANGELOG.md](CHANGELOG.md) diff --git a/templates/san/dell_powervault_me/manifest.yaml b/templates/san/dell_powervault_me/manifest.yaml new file mode 100644 index 0000000..bf390be --- /dev/null +++ b/templates/san/dell_powervault_me/manifest.yaml @@ -0,0 +1,16 @@ +id: san/dell_powervault_me +name: Dell PowerVault ME by SNMP +description: Monitors Dell PowerVault ME storage systems via SNMP, including system information, unit health, sensors, ports, and firmware revisions. +version: 1.0.0 +category: san +vendor: Dell +method: snmp + +zabbix: + min: "7.0" + max: null + tested: ["7.0", "8.0"] + +depends_on: [] +source: original +maintainer: Yoshihiro OKUMURA diff --git a/tests/.env.example b/tests/.env.example new file mode 100644 index 0000000..c9add6e --- /dev/null +++ b/tests/.env.example @@ -0,0 +1,13 @@ +# Test Zabbix settings +ZBX_WEB_PORT=8080 +ZBX_SERVER_PORT=10051 +POSTGRES_PASSWORD=zabbix_pwd +PHP_TZ=Asia/Tokyo + +# Zabbix image tags (for example, alpine-7.0-latest or alpine-8.0-latest) +ZBX_SERVER_IMAGE=alpine-7.0-latest +ZBX_WEB_IMAGE=alpine-7.0-latest + +# Zabbix user used by the import test +ZBX_USER=Admin +ZBX_PASSWORD=zabbix diff --git a/tests/compose.yaml b/tests/compose.yaml new file mode 100644 index 0000000..cea89b6 --- /dev/null +++ b/tests/compose.yaml @@ -0,0 +1,51 @@ +services: + postgres: + image: postgres:16-alpine + environment: + POSTGRES_USER: zabbix + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-zabbix_pwd} + POSTGRES_DB: zabbix + volumes: + - zabbix-db:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U zabbix -d zabbix"] + interval: 5s + timeout: 5s + retries: 20 + restart: unless-stopped + + zabbix-server: + image: zabbix/zabbix-server-pgsql:${ZBX_SERVER_IMAGE:-alpine-7.0-latest} + environment: + DB_SERVER_HOST: postgres + POSTGRES_USER: zabbix + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-zabbix_pwd} + POSTGRES_DB: zabbix + depends_on: + postgres: + condition: service_healthy + ports: + - "${ZBX_SERVER_PORT:-10051}:10051" + restart: unless-stopped + + zabbix-web: + image: zabbix/zabbix-web-nginx-pgsql:${ZBX_WEB_IMAGE:-alpine-7.0-latest} + environment: + ZBX_SERVER_HOST: zabbix-server + DB_SERVER_HOST: postgres + POSTGRES_USER: zabbix + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-zabbix_pwd} + POSTGRES_DB: zabbix + PHP_TZ: ${PHP_TZ:-Asia/Tokyo} + ZBX_SERVER_NAME: Zabbix Test + depends_on: + postgres: + condition: service_healthy + zabbix-server: + condition: service_started + ports: + - "${ZBX_WEB_PORT:-8080}:8080" + restart: unless-stopped + +volumes: + zabbix-db: