From c05d68f28c0322dc8c7e24e108857496e44fd545 Mon Sep 17 00:00:00 2001 From: Navid Sassan Date: Wed, 21 Oct 2026 11:30:48 +0200 Subject: [PATCH 1/3] chore(roles/graylog_datanode, roles/graylog_server): record the packaged release each template is based on Each 7.x template and the unversioned jvm.options and environment file templates name the package release they were derived from, as a Jinja comment that is not rendered into the deployed file. tools/follow-upstream uses it as the base of the three-way merge. Determined by diffing each template against the files extracted from the graylog-server and graylog-datanode RPMs; where several releases ship an identical file, the newest is recorded. The 6.x templates are left without the line. --- .../templates/etc/graylog/datanode/7.0-datanode.conf.j2 | 1 + .../templates/etc/graylog/datanode/7.1-datanode.conf.j2 | 1 + .../templates/etc/graylog/datanode/7.2-datanode.conf.j2 | 1 + .../templates/etc/graylog/datanode/jvm.options.j2 | 1 + roles/graylog_server/templates/etc/default/graylog-server.j2 | 1 + .../templates/etc/graylog/server/7.0-server.conf.j2 | 1 + .../templates/etc/graylog/server/7.1-server.conf.j2 | 1 + .../templates/etc/graylog/server/7.2-server.conf.j2 | 1 + roles/graylog_server/templates/etc/sysconfig/graylog-server.j2 | 1 + 9 files changed, 9 insertions(+) diff --git a/roles/graylog_datanode/templates/etc/graylog/datanode/7.0-datanode.conf.j2 b/roles/graylog_datanode/templates/etc/graylog/datanode/7.0-datanode.conf.j2 index 34b42741f..7b4647a4c 100644 --- a/roles/graylog_datanode/templates/etc/graylog/datanode/7.0-datanode.conf.j2 +++ b/roles/graylog_datanode/templates/etc/graylog/datanode/7.0-datanode.conf.j2 @@ -1,6 +1,7 @@ # {{ ansible_managed }} # 2026061001 # 7.0 +{# Based on graylog-datanode 7.0.15 #} # see https://go2docs.graylog.org/7-0/setting_up_graylog/data_node_configuration_file.htm ##################################### # GRAYLOG DATANODE CONFIGURATION FILE diff --git a/roles/graylog_datanode/templates/etc/graylog/datanode/7.1-datanode.conf.j2 b/roles/graylog_datanode/templates/etc/graylog/datanode/7.1-datanode.conf.j2 index 05e8e6ef4..d09e38498 100644 --- a/roles/graylog_datanode/templates/etc/graylog/datanode/7.1-datanode.conf.j2 +++ b/roles/graylog_datanode/templates/etc/graylog/datanode/7.1-datanode.conf.j2 @@ -1,6 +1,7 @@ # {{ ansible_managed }} # 2026061001 # 7.1 +{# Based on graylog-datanode 7.1.11 #} # see https://go2docs.graylog.org/7-1/setting_up_graylog/data_node_configuration_file.htm ##################################### # GRAYLOG DATANODE CONFIGURATION FILE diff --git a/roles/graylog_datanode/templates/etc/graylog/datanode/7.2-datanode.conf.j2 b/roles/graylog_datanode/templates/etc/graylog/datanode/7.2-datanode.conf.j2 index cb6a273c7..dca78ce49 100644 --- a/roles/graylog_datanode/templates/etc/graylog/datanode/7.2-datanode.conf.j2 +++ b/roles/graylog_datanode/templates/etc/graylog/datanode/7.2-datanode.conf.j2 @@ -1,6 +1,7 @@ # {{ ansible_managed }} # 2026101401 # 7.2 +{# Based on graylog-datanode 7.2.1 #} # see https://go2docs.graylog.org/7-2/setting_up_graylog/data_node_configuration_file.htm ##################################### # GRAYLOG DATANODE CONFIGURATION FILE diff --git a/roles/graylog_datanode/templates/etc/graylog/datanode/jvm.options.j2 b/roles/graylog_datanode/templates/etc/graylog/datanode/jvm.options.j2 index 10f464af5..4e426235b 100644 --- a/roles/graylog_datanode/templates/etc/graylog/datanode/jvm.options.j2 +++ b/roles/graylog_datanode/templates/etc/graylog/datanode/jvm.options.j2 @@ -1,5 +1,6 @@ # {{ ansible_managed }} # 2024110601 +{# Based on graylog-datanode 7.2.1 #} # JVM Heap Settings # diff --git a/roles/graylog_server/templates/etc/default/graylog-server.j2 b/roles/graylog_server/templates/etc/default/graylog-server.j2 index c7a7e63fb..d2b225906 100644 --- a/roles/graylog_server/templates/etc/default/graylog-server.j2 +++ b/roles/graylog_server/templates/etc/default/graylog-server.j2 @@ -1,5 +1,6 @@ # {{ ansible_managed }} # 2024022201 +{# Based on graylog-server 7.2.1 #} # Path to a custom java executable. By default the java executable of the # bundled JVM is used. diff --git a/roles/graylog_server/templates/etc/graylog/server/7.0-server.conf.j2 b/roles/graylog_server/templates/etc/graylog/server/7.0-server.conf.j2 index ba4a7c6f9..2330b7420 100644 --- a/roles/graylog_server/templates/etc/graylog/server/7.0-server.conf.j2 +++ b/roles/graylog_server/templates/etc/graylog/server/7.0-server.conf.j2 @@ -1,6 +1,7 @@ # {{ ansible_managed }} # 2026100901 # 7.0 +{# Based on graylog-server 7.0.15 #} ############################ # GRAYLOG CONFIGURATION FILE ############################ diff --git a/roles/graylog_server/templates/etc/graylog/server/7.1-server.conf.j2 b/roles/graylog_server/templates/etc/graylog/server/7.1-server.conf.j2 index 21f9f1bc1..bc69e6cea 100644 --- a/roles/graylog_server/templates/etc/graylog/server/7.1-server.conf.j2 +++ b/roles/graylog_server/templates/etc/graylog/server/7.1-server.conf.j2 @@ -1,6 +1,7 @@ # {{ ansible_managed }} # 2026100701 # 7.1 +{# Based on graylog-server 7.1.10 #} ############################ # GRAYLOG CONFIGURATION FILE ############################ diff --git a/roles/graylog_server/templates/etc/graylog/server/7.2-server.conf.j2 b/roles/graylog_server/templates/etc/graylog/server/7.2-server.conf.j2 index 1790cced5..a4a591748 100644 --- a/roles/graylog_server/templates/etc/graylog/server/7.2-server.conf.j2 +++ b/roles/graylog_server/templates/etc/graylog/server/7.2-server.conf.j2 @@ -1,6 +1,7 @@ # {{ ansible_managed }} # 2026101401 # 7.2 +{# Based on graylog-server 7.2.1 #} ############################ # GRAYLOG CONFIGURATION FILE ############################ diff --git a/roles/graylog_server/templates/etc/sysconfig/graylog-server.j2 b/roles/graylog_server/templates/etc/sysconfig/graylog-server.j2 index c7a7e63fb..d2b225906 100644 --- a/roles/graylog_server/templates/etc/sysconfig/graylog-server.j2 +++ b/roles/graylog_server/templates/etc/sysconfig/graylog-server.j2 @@ -1,5 +1,6 @@ # {{ ansible_managed }} # 2024022201 +{# Based on graylog-server 7.2.1 #} # Path to a custom java executable. By default the java executable of the # bundled JVM is used. From 4dd1eb4db4d7ba166bd65dabff1c39d598672e18 Mon Sep 17 00:00:00 2001 From: Navid Sassan Date: Wed, 21 Oct 2026 10:43:48 +0200 Subject: [PATCH 2/3] chore(roles/graylog_server): sync the 7.1 server.conf template with Graylog 7.1.11 Compared against the server.conf shipped in graylog-server 7.1.11: adds the commented events_index_refresh_interval setting. --- .../templates/etc/graylog/server/7.1-server.conf.j2 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/roles/graylog_server/templates/etc/graylog/server/7.1-server.conf.j2 b/roles/graylog_server/templates/etc/graylog/server/7.1-server.conf.j2 index bc69e6cea..128f7f881 100644 --- a/roles/graylog_server/templates/etc/graylog/server/7.1-server.conf.j2 +++ b/roles/graylog_server/templates/etc/graylog/server/7.1-server.conf.j2 @@ -1,7 +1,7 @@ # {{ ansible_managed }} -# 2026100701 +# 2026102001 # 7.1 -{# Based on graylog-server 7.1.10 #} +{# Based on graylog-server 7.1.11 #} ############################ # GRAYLOG CONFIGURATION FILE ############################ @@ -312,6 +312,14 @@ elasticsearch_max_total_connections_per_route = {{ graylog_server__elasticsearch # #default_system_events_index_prefix = gl-system-events +# The refresh interval for the Graylog events indices. This applies to both the events and the +# system events index sets, and only takes effect on newly created or updated index templates. +# Lower values make new events searchable sooner at the cost of indexing throughput. Some managed +# OpenSearch offerings enforce a cluster-wide minimum refresh interval and will reject the index +# template if this value is below it. Must be 1 second or longer. +# Default: 1s +#events_index_refresh_interval = 1s + # Analyzer (tokenizer) to use for message and full_message field. The "standard" filter usually is a good idea. # All supported analyzers are: standard, simple, whitespace, stop, keyword, pattern, language, snowball, custom # Elasticsearch documentation: https://www.elastic.co/guide/en/elasticsearch/reference/2.3/analysis.html From 489bc141663d545b263c3bc0f729250cd5f75c15 Mon Sep 17 00:00:00 2001 From: Navid Sassan Date: Wed, 21 Oct 2026 10:44:01 +0200 Subject: [PATCH 3/3] feat(tools): add follow-upstream to merge upstream configuration changes into templates tools/follow-upstream extracts /etc from the RPM and DEB of an upstream release in a podman container and three-way merges the packaged file changes since each template's base release into the template, creating the template for a new release series from the previous one. On every run it reports packaged files that are neither templated nor ignored, templated files that disappeared, and files that differ between RPM and DEB. tools/follow-upstream.yml lists the applications, starting with Graylog. The lfops-follow-upstream skill drives the tool from a release notice and covers what it cannot decide: conflicts, new or removed options, packaging changes, tests and the CHANGELOG. .claude is excluded from the collection build. --- .claude/skills/lfops-follow-upstream/SKILL.md | 91 ++++ CONTRIBUTING.md | 1 + galaxy.yml | 1 + tools/follow-upstream | 443 ++++++++++++++++++ tools/follow-upstream.yml | 57 +++ 5 files changed, 593 insertions(+) create mode 100644 .claude/skills/lfops-follow-upstream/SKILL.md create mode 100755 tools/follow-upstream create mode 100644 tools/follow-upstream.yml diff --git a/.claude/skills/lfops-follow-upstream/SKILL.md b/.claude/skills/lfops-follow-upstream/SKILL.md new file mode 100644 index 000000000..77ea933da --- /dev/null +++ b/.claude/skills/lfops-follow-upstream/SKILL.md @@ -0,0 +1,91 @@ +--- +name: lfops-follow-upstream +description: Update LFOps after an upstream application release, e.g. a newreleases.io notice ("New Graylog2/graylog2-server releases"), a pasted release mail, or "Graylog 7.3.0 is out". Merges the packaged configuration changes into the versioned templates, adds templates for a new release series, and prepares the CHANGELOG entry and commit message. Use when a release notice or a new upstream version is mentioned. +--- + +# LFOps follow upstream + +Brings the LFOps templates in line with a new upstream release. The deterministic part (fetching the packaged files, the three-way merge, header and supported-versions bookkeeping) is done by `tools/follow-upstream`; this skill covers what the tool cannot judge. Work from the repository root. Never commit: end with a report and a proposed commit message. The only exception is a headless run of the follow-upstream timer, whose prompt says what it may commit and push. + + +## 1. Collect the releases + +Take the releases from whatever the user provides: + +* A pasted mail or text: extract upstream project and versions. A newreleases.io mail lists them as `Graylog2/graylog2-server on GitHub ...` followed by `- 7.2.1` lines. Matomo instances send "New Matomo 5.14.0 is available". +* ` ` as arguments. +* Nothing: if `NOTMUCH_PROFILE=newreleases notmuch count tag:lfops-todo` works, read the mails with `NOTMUCH_PROFILE=newreleases notmuch show --format=json tag:lfops-todo`. Otherwise ask what was released. + +Ignore pre-releases (`alpha`, `beta`, `rc`, `-dev`). + + +## 2. Triage every release + +The repository is the state, not the mail: a release already covered needs no work, however often it is reported. + +* Find the application in `tools/follow-upstream.yml` by its `upstream` names. +* Not listed: check whether a role deploys the application at all (`grep -ril roles/*/README.md`). No role: report "not used by LFOps" and move on. A role exists: report it as a candidate for `tools/follow-upstream.yml` and ask before adding it (see "Adding an application"). +* Listed: run `tools/follow-upstream `, oldest release first. It fetches the RPM and the DEB of the release on every run, so expect a few GB of downloads for large packages. Exit code 0: nothing to review, 1: findings or conflicts, 2: the run aborted. +* `packaging:` lines come first. Each one means upstream changed how it packages the application: a file below /etc that is neither templated nor ignored, a templated file the release no longer ships, or a file that differs between RPM and DEB. Do not resolve these yourself, and do not accept the merge of that release: stop and report them, with the `diff` the tool prints. Whether the role needs a new template, a per-format template or an `ignore` entry is the user's decision. +* A failed fetch (`not found in`) aborts the run. Upstream may have published one format before the other; report it and retry later rather than merging without the check. +* Then one line per template: + * `already covers`, `is identical in`: nothing to do. + * `merged cleanly` / `N conflict(s)`: continue with step 3. + * `no "Based on " line`: see "Bootstrapping a template". + * A new release series (template created from the latest older one): also step 4. + + +## 3. Review the merge + +For every changed template, read the upstream diff the tool prints (`diff `) and the release notes / upgrade notes of the release. + +* Resolve conflict markers (`<<<<<<<`). Keep the LFOps change (role variables, Jinja logic, security defaults) and take the upstream text around it. +* New upstream option: leave it as shipped (usually commented out). Only propose a role variable if an administrator plausibly needs it, and ask first. +* Removed or renamed upstream option that a role variable feeds: stop and ask. Renaming or dropping a role variable is a breaking change of the public interface. +* Changed upstream default that a role default overrides: report it. +* Do not reformat, re-wrap or "fix" upstream text. Templates stay as close to the packaged file as possible. +* `copies` in `tools/follow-upstream.yml` receive the same merge result; check that they still match their target platform. + + +## 4. New release series + +The tool created `-.j2` from the latest older template and added the series to `supported_versions`. + +* Fix every line the tool lists as still mentioning the old series (e.g. a `go2docs.graylog.org/7-1/` link). +* Check the role for other places that enumerate versions: README (`grep -n roles//README.md`), `meta/argument_specs.yml` choices, related `repo_*` roles. +* Read the upgrade notes for breaking changes, required migration steps and dropped platforms. Report them; they may need tasks, preflight checks or a `Breaking Changes` entry. +* Check whether a series has gone EOL upstream. Dropping a series is a separate decision for the user (CONTRIBUTING: "Do not support EOL software versions"). + + +## 5. Test + +* Run the Molecule scenario that covers the role if one exists (`grep -rl extensions/molecule/*/converge.yml`), per CONTRIBUTING.md "Testing". Report it if there is none. +* Check for leftover conflict markers: `grep -rn '^<<<<<<<\|^>>>>>>>' roles//templates`. + + +## 6. Changelog and commit message + +Follow CONTRIBUTING.md "Changelog" and "Changelog Sections", and the existing entries: + +* Patch release inside an existing series: no CHANGELOG entry (the deployed file only gains upstream comments). Commit: `chore(roles/): sync the template with `, the body names what upstream changed. +* New series: entry under `### Added` of `## [Unreleased]`, at the top: `* **role:, role:**: Add template for .` Commit: `feat(roles/, roles/): add template for `. +* A change an administrator has to act on: `### Breaking Changes` or `### Changed`, as CONTRIBUTING.md describes. + + +## 7. Report + +Per release: what was done or why nothing was, conflicts and how they were resolved, open questions, test result, proposed commit message(s). With the notmuch source, once the user has accepted the result, offer to retag the mails: `NOTMUCH_PROFILE=newreleases notmuch tag -lfops-todo +lfops-done -- id:` (`+lfops-skip` for releases LFOps does not use). + + +## Bootstrapping a template + +`tools/follow-upstream` needs `{# Based on #}` below the version line of the template header. The Jinja comment does not end up in the deployed file, so adding it changes nothing on the hosts and needs no timestamp bump. To find the version: + +1. Fetch the packaged file of the candidate releases of the series (the tool caches them under `~/.cache/lfops-follow-upstream/-/root/`). The upstream git tree under `~/git/other` is a good first filter, but packages may rewrite the file (Graylog sets absolute paths), so confirm against the package. +2. Diff each against the template (skipping the header). The release with the fewest differing lines is the base. Where several releases ship an identical file, take the newest. +3. Add the line and rerun the tool. + + +## Adding an application + +Add an entry to `tools/follow-upstream.yml` (format in its header comment). Only for templates that are copies of a packaged file; a drop-in written from scratch has no base. `tools/follow-upstream` needs both a Yum and an APT repository serving every release of a series; an application packaged only for one family, or only by the distributions, needs the tool extended first. Run the tool once for the current release and put every reported file LFOps does not template into `ignore`, after checking that no role deploys it. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2bfc84ddd..f7146352f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -514,6 +514,7 @@ roles: * Mirror the target path below `templates/` (`templates/etc/httpd/sites-available/default.conf.j2`) and always use `.j2`. * Deploy self-written scripts to `/usr/local/sbin` (SELinux). Helpers run only by a systemd unit (not by an admin, not exec'd by a confined domain) MAY live in `/usr/local/libexec`: as `usr_t`, a root `oneshot` service in `init_t` runs them via `execute_no_trans` without AVC denial on RHEL 8, 9 and 10. Admin-invokable commands stay in `/usr/local/sbin`, and a script a confined domain must exec never goes to `/usr/local/libexec`. * Keep templates as close to the original file as possible, which eases rpmnew/rpmsave handling. +* A template that is a copy of a packaged file names the package release it was taken from in a Jinja comment right below the version line, `{# Based on graylog-server 7.2.1 #}`, which does not end up on the host. List it in `tools/follow-upstream.yml`; `tools/follow-upstream` uses the line to merge the configuration changes of later releases into the template, see the `lfops-follow-upstream` skill. * If the role picks a file by the installed version (`-.conf.j2`, `vars/.yml`), list the shipped versions in `vars/main.yml` and assert against them right after reading the version, as `roles/example` does (`__example__supported_versions`), so the admin gets the supported versions instead of a missing-file path. Document the abort under `## Troubleshooting` (pin a supported version, or add the file). * After deploying a file that may get rpmnew / rpmsave files (or Debian equivalents), include `shared` with `tasks_from: 'remove-rpmnew-rpmsave.yml'` and `shared__remove_rpmnew_rpmsave_config_file`, as in `roles/example`. diff --git a/galaxy.yml b/galaxy.yml index de3388153..a9fcaa80f 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -89,6 +89,7 @@ issues: 'https://github.com/linuxfabrik/lfops/issues' # and '.git' are always filtered build_ignore: - '.git*' + - '.claude' - 'build' - 'context' - 'tools' diff --git a/tools/follow-upstream b/tools/follow-upstream new file mode 100755 index 000000000..dd5e56007 --- /dev/null +++ b/tools/follow-upstream @@ -0,0 +1,443 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8; py-indent-offset: 4 -*- +# +# Author: Linuxfabrik GmbH, Zurich, Switzerland +# Contact: info (at) linuxfabrik (dot) ch +# https://www.linuxfabrik.ch/ +# License: The Unlicense, see LICENSE file. + +"""Merges the configuration changes of an upstream release into the LFOps templates. + +Every template listed in tools/follow-upstream.yml is a copy of a packaged configuration +file with LFOps changes on top, and names the package release it is based on in a Jinja +comment in its header (`{# Based on graylog-server 7.2.1 #}`), which does not end up in +the deployed file. For a new release, this tool extracts /etc from the RPM and the DEB +of the release (streamed, in a podman container) and: + +1. Checks the packaging, on every run: files below /etc that are neither templated + nor ignored in tools/follow-upstream.yml, templated files the release no longer ships, + and files whose content differs between RPM and DEB. +2. Merges the upstream changes into every template not based on this release yet: + + git merge-file