Skip to content

NodeUtils: export upcall variables to the environment - #705

Open
thiell wants to merge 1 commit into
clustershell:masterfrom
thiell:fix/upcall-env
Open

NodeUtils: export upcall variables to the environment#705
thiell wants to merge 1 commit into
clustershell:masterfrom
thiell:fix/upcall-env

Conversation

@thiell

@thiell thiell commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Upcall commands already inherit the caller's full environment. This change simply sets the four substitution variables ($GROUP, $NODE, $SOURCE, $CFGDIR) in that environment, so shell parameter expansions that are not replaced by the library, like ${GROUP:-default}, expand to the same values instead of silently reading whatever the caller exported. $GROUP and $NODE are set empty when they do not apply to the upcall. Textual substitution is unchanged and still happens first, so existing configs behave identically.

This makes it easy for a map upcall to support a default when the group name is empty, e.g. for query-backed sources:

[prometheus]
map: promtool query -o json instant http://localhost:9090 "up{job=~\"${GROUP:-.*}\"}" | jq -r '.[].metric.instance' | cut -d: -f1

Here each Prometheus scrape job is a node group, resolving to the hostnames of its targets: @prometheus:node_exporter expands to the nodes scraped by the node_exporter job, and @prometheus: (empty group name) expands to the nodes of all jobs (useful for map-only sources, where @prometheus:* cannot work).

See #609 for a related earlier discussion (FYI).

Docs updated: groups.conf(5) + sphinx config.

Closes #704

@thiell thiell added this to the 1.11 milestone Aug 5, 2026
@thiell
thiell requested a review from degremont August 5, 2026 02:16
@thiell thiell self-assigned this Aug 5, 2026
@thiell

thiell commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

The docs now state it explicitly: exported variables take precedence over any same-named variables from the calling environment.

Flagging for the 1.11 release notes as a minor behavior change: upcall commands no longer inherit caller-exported GROUP, NODE, SOURCE or CFGDIR values.

@@ -217,8 +217,11 @@ def _upcall_read(self, cmdtpl, args=dict()):
"""
cmdline = Template(self.upcalls[cmdtpl]).safe_substitute(args)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we start supporting variable interpolation through real shell variables (through environment), it seems we do not need the template anymore? The shell variable supports below will handle everything, no?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. The shell doesn't expand variables inside single quotes, and single-quoted $GROUP is used in the field (just look at man groups.conf, single quotes are used in the example). So the environment export complements the template (for shell-side expansions like ${GROUP:-default}) rather than replacing it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, a bit weird, as now the expansion will happen sometimes under single quote, and sometimes not. User may be surprised.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template.safe_substitute() is pure text replacement and has always ignored shell quoting. $GROUP is always replaced if found like that in the command text. The only surprise might come from existing ${GROUP:-default} patterns not in single quote that were not resolved and that will then be resolved with this patch. It's actually the bug I am trying to fix here as I saw it in the field. :)

That said, I agree a single mechanism (shell-only) would probably be cleaner, but that breaks single-quoted $GROUP configs, including provided example configs and man pages. If we think it's a big deal (not sure), it's something we could consider to deprecate in a 2.0 maybe.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, so, what would be the less surprising to people over time would be for the variable to be 100% shell variables. So, let's keep the patch as-is, but, in the same time, we must change examples to use double quotes where appropriate. Let's write them as we were only supporting shell variables. We could deprecate that later.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me and actually that's a very good point: it would be possible to have an empty variable with this I think, so it is highly recommended to double-quote variables in upcalls. Best practice anyway (SC2086). Thus, this will start a clean migration to shell-only variables in the future. I'll update this PR (docs, examples) with this.

Group source upcalls only support textual substitution of $GROUP,
$NODE, $SOURCE and $CFGDIR. Also export them as environment variables
so shell parameter expansions like ${GROUP:-default} work as users
expect, instead of silently reading the caller's environment.

Write the example upcall commands in plain shell style, with
double-quoted variables, so they work with either mechanism.

Signed-off-by: Stephane Thiell <stephane@thiell.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

groups.conf upcalls: ${GROUP:-default} expands from the caller's environment, not the group name

2 participants