Repository navigation
Conversation
scibi
force-pushed
the
feature/zabbix-server-role
branch
from
August 28, 2026 14:54
68cf208 to
909baeb
Compare
scibi
force-pushed
the
feature/zabbix-server-role
branch
from
September 16, 2026 12:44
909baeb to
04109b0
Compare
scibi
force-pushed
the
feature/zabbix-server-role
branch
3 times, most recently
from
September 29, 2026 23:07
5dc7e20 to
4e4b146
Compare
Add a new role that installs and configures Zabbix Server from the official upstream APT repository, imports the PostgreSQL database schema idempotently (checked against the 'dbversion' table, not a marker file so it survives database restores), and configures the PHP-FPM/nginx web frontend without the interactive setup wizard. The role also bootstraps the Zabbix API: on a fresh install it changes the default Admin password to one generated into the DebOps 'secret/' directory and creates a long-lived API token, then uses that token to manage media types, the built-in "Report problems" action (disabled by default in the database schema, which silently drops all notifications), user groups, users and custom templates (a bundled "LXC container" template used together with the 'zabbix_agent__cgroup_metrics' feature) through idempotent create/update JSON-RPC calls. Host item overrides let a template disable host-wide items made misleading by a more specific one, for example disabling 'system.cpu.*' on hosts where the LXC template's own cgroup-based item is linked instead. Add the 'service/zabbix_server.yml' playbook (following the phpipam pattern: keyring, apt_preferences, python, php, ferm, nginx, postgresql, then the role itself) and wire it into 'layer/app.yml', plus role-index.rst and CHANGELOG.rst entries and the role documentation (getting-started, defaults-detailed, man pages). Generated-By: LLM (Claude)
Reformat the bundled 'LXC container' template JSON with pretty-format-json (matching the project's pre-commit hook config) and drop a mention of a private inventory group name from its description, replacing it with a reference to the zabbix_agent role feature that actually provides the UserParameters. Generated-By: LLM (Claude)
Stop the 'zabbix-server' systemd service before purging the
'zabbix-server-pgsql'/'zabbix-server-mysql' package on removal,
since the package provides the unit file the earlier unconditional
'stopped' task relied on -- running it afterwards failed with "Could
not find the requested service".
Use the actual configuration-test flag: 'zabbix_server' does not
support '--print', only '-T'/'--test-config', so the config-check
handler could never succeed before restarting the service.
Make 'zabbix_server__trapper_port' actually take effect: 'ListenPort'
was always rendered as a comment, and the ferm rule opened the
'zabbix-trapper' /etc/services entry instead of the configured port,
so a non-default value silently had no effect on the server or the
firewall while the frontend and local facts still advertised it.
Fix the Admin password bootstrap on a fresh install: Zabbix 7.0's
'user.update' expects 'passwd' for the new password, not 'password',
so the JSON-RPC call failed validation and aborted the bootstrap
before a token could ever be created.
Add 'no_log' to the four 'host_item_override.yml' API requests, which
sent the bearer token in the 'Authorization' header without it, and
switch the 'key_regex' filter from Ansible's 'match' test (anchored
to the start of the string) to 'search', matching the documented
Python 're.search()' semantics and avoiding missed, still-enabled
items for any pattern not anchored at position zero.
Wrap the initial PostgreSQL schema import in a single transaction
('psql --single-transaction'), so a failure partway through cannot
leave 'public.dbversion' committed with the rest of the schema
missing -- which would make the next run skip the import entirely
and start the server against a half-imported database.
Set the local facts file mode to 0644: at 0755 'ansible.builtin.setup'
treated the shebang-less rendered JSON as an executable script.
Keep the web frontend converging even when only the frontend itself
is disabled (not the whole role): both the 'php' and 'nginx' role
invocations in the playbook, and the 'zabbix_server' role's own
frontend task file, were skipped entirely whenever
'zabbix_server__frontend_enabled' was False, even though the
underlying 'dependent_pools'/'dependent_upstreams'/'dependent_servers'
variables already encode the desired absent/disabled state -- so
disabling the frontend after enabling it left a stale PHP-FPM pool,
nginx vhost and 'zabbix.conf.php' behind instead of removing them.
Also add fail-fast assertions for the two other ways an enabled
frontend can end up broken at runtime instead of during the run: a
non-PostgreSQL database (the bundled frontend template is PostgreSQL
only) and an invalid 'zabbix_server__frontend_image_format', which is
interpolated directly into a PHP constant name.
Finally, fix the 'zabbix_server__users' example in the getting
started guide, which used 'omit' for 'usrgrpid' and the display name
'Email' for 'mediatypeid' -- both are passed to the Zabbix API as-is
without any name-to-id lookup, so the example would fail as written.
Generated-By: LLM (Claude)
Add the author's copyright line to every file that only listed the DebOps project, since this is a brand new role and none of its files had a prior copyright holder to build on. Generated-By: LLM (Claude)
Reset 'zabbix_server__fact_override_itemids' unconditionally in 'host_item_override.yml': when an override's template does not exist, or is not linked to any host, the previous 'set_fact' was skipped by its own 'when', leaving the previous override's item IDs in place -- "Disable matching items" could then act on a completely unrelated override's items. Also add 'failed_when' to the template/host/item lookups so a real API error (e.g. an expired token) fails loudly instead of being treated as "nothing found". Keep the API token file in 'secret/' on the Ansible Controller: the 'stat' and 'copy' tasks that check for and write it in 'api_bootstrap.yml' were delegated to 'zabbix_server__api_delegate_to', while the 'lookup(\"file\", ...)' calls that read it always run on the Controller regardless. With a non-default delegate host this checked and wrote the token on the wrong host, while every read still looked on the Controller. Delegate those two file tasks to 'localhost' explicitly, matching where 'secret/' actually lives. Generated-By: LLM (Claude)
On a fresh install, user.update of the Admin password invalidates the session obtained with the stock credentials. Re-login with the new password before token.create / token.generate so bootstrap does not fail before the token is written to secret/. Look up the configured token name before creating a new one, and generate the secret string against the existing tokenid when a previous run created the object but then failed to persist it. That avoids leaving a second enabled, non-expiring token behind on retry. Derive the frontend $DB['TYPE'] from zabbix_server__database (already guarded by the PostgreSQL-only frontend assert) instead of hardcoding POSTGRESQL. Generated-By: LLM (Claude)
Zabbix 7.0 allows the same token name on different accounts. token.get filtered only by name, so a missing secret/ file could regenerate another user's token and persist it as the bootstrap credential. Resolve the Admin userid on every no-token path and pass it as userids. Generated-By: LLM (Grok)
The defaults-detailed note referred to zabbix_server__api_token_content, which is not a role variable. Point custom lookup tasks at the token file in secret/ (zabbix_server__api_token_path) and mention the same-play register fact used by the role tasks. Generated-By: LLM (Grok)
Hide the template-import API call with no_log so the bearer token and template source do not leak on failure or verbose output. Always purge the frontend package on deploy_state=absent, even if the frontend is currently disabled. Document that the PHP-FPM/nginx step is optional (enabled by default) and that user group / media type lists create-or-update by name, while the example IDs stay stable because they match built-in objects. Generated-By: LLM (Grok)
The configuration drop-in notifies a restart, and flushing handlers ran that restart before the schema import. On an empty database zabbix-server exits immediately and systemd fails the unit. Import the schema first, and stop the service while the initial import runs so a crash-loop cannot touch the database. Generated-By: LLM (Grok 4.7 via Cursor)
configuration.import requires source to be a string, and a templated YAML body turned the rule booleans into "True"/"False". Send one to_json document. The method returns true even when nothing changed, so store a SHA1 of the source that was sent and treat a later run as unchanged when that checksum is already on the host. Generated-By: LLM (Grok 4.7 via Cursor)
A token file left over from a destroyed database is rejected with "Not authorized." Probe the stored token and bootstrap a new one in that case. Connection failures and any other API error keep the file and fail the play, so a password changed in the UI is not reset while the token is still valid. Generated-By: LLM (Grok 4.7 via Cursor)
The man page translator emits defaults/main.rst for every role. List it in the toctree, before defaults-detailed, so sphinx-build -n -W accepts the page. Generated-By: LLM (Cursor Grok 4.7)
scibi
force-pushed
the
feature/zabbix-server-role
branch
from
October 6, 2026 15:24
4e4b146 to
4695b99
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This adds a new role that installs and configures Zabbix Server from the official upstream APT repository, imports the PostgreSQL database schema idempotently by checking the dbversion table rather than a marker file, and configures the PHP-FPM/nginx web frontend without the interactive setup wizard, following the existing phpipam/netbox pattern of PostgreSQL-backed PHP applications.
The role also bootstraps the Zabbix API on a fresh install: it changes the default Admin password to one generated into the DebOps secret directory, creates a long-lived API token, and then uses that token to manage media types, the built-in Report Problems action (disabled by default in the database schema, which silently drops all notifications), user groups, users and custom templates through idempotent JSON-RPC calls. A bundled LXC container template and host item overrides complement the cgroup metrics feature added to zabbix_agent in a companion pull request, letting a fresh installation reach a fully working, notification-capable state without any manual steps through the web interface.