Skip to content

[policy] - Add rootless container support and log-line limiting - #4446

Draft
snagoor wants to merge 2 commits into
sosreport:mainfrom
snagoor:feature/container-helpers
Draft

[policy] - Add rootless container support and log-line limiting#4446
snagoor wants to merge 2 commits into
sosreport:mainfrom
snagoor:feature/container-helpers

Conversation

@snagoor

@snagoor snagoor commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

This PR extends the container runtime helpers so sos plugins can collect data from rootless containers (containers started by a non-root user) and optionally limit the number of log lines collected per container.

Changes at a glance

sos/policies/runtimes/__init__.py

  • get_containers() gains a runas parameter. When set, the ps command is run as that user via sos_get_command_output(runas=...), making the user's rootless containers visible.
  • get_logs_command() gains a log_lines parameter. When set, --tail N is appended to the logs command so output is capped.

sos/policies/runtimes/podman.py

  • Adds four new helper methods to PodmanContainerRuntime:
    • info_command(run_debug=False) — returns podman info [--debug]
    • list_command(get_all, list_fmt) — returns a podman ps command with a format string (defaults to JSON)
    • inspect_command(container) — returns podman inspect <container>
    • exec_command(container, cmd) — returns podman exec <container> <cmd>
  • These let plugins build the correct Podman commands without hardcoding the binary name.

sos/report/plugins/__init__.py

  • New get_containers_by_user(user, get_all=False) method on Plugin. Queries the loaded runtime as user so plugins can discover rootless containers owned by a specific user.

  • add_container_logs() gains two new parameters:

    • runas — when set, containers are looked up in the named user's rootless runtime using an exact name match instead of a regex.
    • log_lines — passed through to get_logs_command() to cap log output.

    Assisted-by: Claude Code

@packit-as-a-service

Copy link
Copy Markdown

Congratulations! One of the builds has completed. 🍾

You can install the built RPMs by following these steps:

  • sudo dnf install -y 'dnf*-command(copr)'
  • dnf copr enable packit/sosreport-sos-4446
  • And now you can install the packages.

Please note that the RPMs should be used only in a testing environment.

…container helpers

Signed-off-by: Nagoor Shaik <nshaik@redhat.com>

Assisted-by: Claude Code
@snagoor
snagoor force-pushed the feature/container-helpers branch from 629730f to acbd9a7 Compare August 12, 2026 10:41
@snagoor
snagoor force-pushed the feature/container-helpers branch from fc7b883 to 913e643 Compare August 12, 2026 16:21
@snagoor
snagoor force-pushed the feature/container-helpers branch from 913e643 to 860c97b Compare August 12, 2026 16:29
@snagoor snagoor changed the title [runtime] - Add rootless container support and log-line limiting [policy] - Add rootless container support and log-line limiting Aug 12, 2026
Comment thread sos/report/plugins/__init__.py Outdated
Comment on lines +3013 to +3021
elif _runtime is not None:
_cons = self.get_all_containers_by_regex(container, get_all)
for _con in _cons:
cmd = _runtime.get_logs_command(_con[1])
self.add_cmd_output(cmd, **kwargs)
else:
self._log_debug(f"No container runtime available to collect "
f"logs for '{container}'")
continue
if _runtime is None:
self._log_debug(f"No container runtime available to collect "
f"logs for '{container}'")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We shouldn't be doing this check with every container in the list.

The runtime check should remain outside the loop, as it is currently.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the review @TurboTurtle , agreed. I've moved the runtime check and resolution back out of the loop with an early return if no runtime is available.

While restructuring, I also noticed get_containers_by_user() was being called once per container in the runas branch. Since the exact-match filtering doesn't depend on per-container runtime state, the user's rootless runtime is now queried just once before the loop and matched inside it.

return vols

def get_logs_command(self, container):
def get_logs_command(self, container, log_lines=None):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If we're going to add this parameter, we should hook it up to the actual collection for the runtime. If the runtime doesn't support it, then we shouldn't make it available as a parameter.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

LXD collects logs via lxc info --show-log, which doesn't support limiting line output, so the parameter can't be meaningfully hooked up there.

Changes made:

  • Reverted LxdContainerRuntime.get_logs_command() to its original signature without log_lines.

  • Added a log_line_limit capability attribute to ContainerRuntime (default True, False on LXD). add_container_logs() now checks this capability and falls back to full logs with a debug message if line limits aren't supported.

  • Applied the same logic to runas: removed it from the CRI-O and LXD get_containers() overrides (since they are daemon-based and don't support rootless mode) and added a rootless capability check.

  • Overrode CrioContainerRuntime.get_logs_command() so it uses crictl logs --tail N correctly (crictl uses -t for --tail, unlike Docker/Podman where -t means timestamps).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't see where we're using any of these new methods?

Also, I don't see why these would be methods at all. If they aren't class attrs being set like we do with PackageManager() classes, then they'd probably need to be properties.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

These four helpers form the runtime API surface is consumed by dependent PR #4450 (which refactors aap_containerized plugin to remove hardcoded su - <user> -c 'podman ...' strings). Because #4450 stacks on this PR, they appear unused in isolation.

On methods vs. properties: They are methods because they accept parameters (like container, cmd, get_all, or list_fmt), which properties can't do. This matches the established parameterized pattern on ContainerRuntime (e.g., get_logs_command() and get_copy_command()).

Fixed a docstring copy-paste error in info_command() and refactored exec_command() to reuse the self.run_cmd prefix as well.

@TurboTurtle TurboTurtle added Kind/Enhancement Status/Needs Review This issue still needs a review from project members Reviewed/Needs Iteration Review has been performed, change needs to be iterated on based on feedback before merge. labels Aug 12, 2026
@snagoor
snagoor force-pushed the feature/container-helpers branch from 860c97b to a8c97c6 Compare August 13, 2026 12:00
@snagoor

snagoor commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Summary of current changes:

  • Moved the runtime check outside the loop in add_container_logs() and limited rootless user runtime queries to a single call.

  • Removed log_lines from LXD and gated it behind a new log_line_limit capability.

  • Gated runas behind a rootless capability and cleaned up CRI-O / LXD overrides.

  • Fixed CRI-O log tail syntax (crictl logs --tail).

@snagoor
snagoor force-pushed the feature/container-helpers branch 2 times, most recently from b6239c4 to a7dba9e Compare August 13, 2026 13:29
Comment thread sos/policies/runtimes/__init__.py
Comment thread sos/policies/runtimes/crio.py Outdated
:returns: Formatted runtime command to get logs from `container`
:rtype: ``str``
"""
if log_lines is not None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ditto wrt log_line_limit

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Same change applied to the CRI-O override, crictl logs --tail N is only emitted when log_line_limit is set.

Comment thread sos/report/plugins/__init__.py Outdated
_log_lines = None
else:
_log_lines = log_lines
if _log_lines is not None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This condition is redundant; if _log_lines is None, we can still call get_logs_command with log_lines=_log_lines due to the if log_lines is not None: test there.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed, the if _log_lines is not None: branch was redundant, since get_logs_command(..., log_lines=None) and get_logs_command(...) are equivalent (the parameter defaults to None).

I've dropped the intermediate _log_lines variable and pass log_lines straight through; the runtime itself now decides whether to append --tail (see the log_line_limit guard), and the plugin keeps only the debug message when the capability is off.

Comment thread sos/report/plugins/__init__.py Outdated
Comment thread sos/policies/runtimes/podman.py Outdated
return f"{self.binary} info --debug"
return f"{self.binary} info"

def list_command(self, get_all=False, list_fmt=None):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The list_fmt is not used even in the #4450, is it worth having it?

Further, calling this method makes sense "only" for non-root users (with runas set), right? Since runtime does automatically collect this info already (just for root). Since the #4450 uses this method for runas set, we cant reuse the runtime's collected info and the method is really necessary. (this took me a while to understand rationale for the method).

Comment thread sos/report/plugins/__init__.py Outdated
Comment on lines +2987 to +2988
system-level runtime. Container names are then
treated as *exact* matches, not regexes, against

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Couldnt this inconsistency (regexp for root containers, exact match for rootless) be confusing for users using this method?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch, you're right that the inconsistency is confusing. A plugin author passing a regex like my-app.* would get regex semantics on the system-level runtime but silent no-matches on the rootless path.

Fixed: the rootless path now also uses re.match() when filtering the pre-fetched user container list, so both code paths behave identically.

Comment thread sos/policies/runtimes/crio.py
@snagoor
snagoor force-pushed the feature/container-helpers branch 3 times, most recently from 981f09c to a6618a3 Compare August 14, 2026 12:42
…ontainer helpers

Signed-off-by: Nagoor Shaik <nshaik@redhat.com>

Assisted-by: Claude Code
@snagoor
snagoor force-pushed the feature/container-helpers branch from a6618a3 to 1e148c5 Compare August 14, 2026 13:29

@pmoravec pmoravec left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

@pmoravec pmoravec added the Reviewed/Needs 2nd Ack Require a 2nd ack from a maintainer label Aug 14, 2026
@snagoor
snagoor marked this pull request as draft August 16, 2026 16:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Kind/Enhancement Reviewed/Needs Iteration Review has been performed, change needs to be iterated on based on feedback before merge. Reviewed/Needs 2nd Ack Require a 2nd ack from a maintainer Status/Needs Review This issue still needs a review from project members

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants