Skip to content

refactor: generalize Distro add_user and shutdown_command#6800

Open
blackboxsw wants to merge 4 commits intocanonical:mainfrom
blackboxsw:owasp-logs-part1
Open

refactor: generalize Distro add_user and shutdown_command#6800
blackboxsw wants to merge 4 commits intocanonical:mainfrom
blackboxsw:owasp-logs-part1

Conversation

@blackboxsw
Copy link
Copy Markdown
Collaborator

@blackboxsw blackboxsw commented Mar 21, 2026

Decomposed #6689 into part-1 and part-2 to aid reviewing.

Proposed Commit Message

Perform preliminary refactor to be used by security event logging.

Split add_user method into separate methods:
- _add_user: allow distro overrides for custom user creation handling
- _build_add_user_cmd: return tuple of cmd and log_command
- _post_add_user: distro-specific post-creation steps for Alpine
- _user_groups_to_list: normalize group input to a list

Move util.is_user check into create_user and make add_user
raise on failure instead of returning bool.  Distro subclasses now
override the separate methods instead of duplicating add_user.

Refactor shutdown_command introducing a new
_build_shutdown_command which is overridden in subclasses.

Additional Context

Test Steps

tox -e py3

Merge type

  • Squash merge using "Proposed Commit Message"
  • Rebase and merge unique commits. Requires commit messages per-commit each referencing the pull request number (#<PR_NUM>)

Comment thread cloudinit/distros/alpine.py Outdated
@blackboxsw blackboxsw requested a review from holmanb March 31, 2026 21:05
@blackboxsw
Copy link
Copy Markdown
Collaborator Author

@holmanb I think I have addressed your question. I'm uncertain if there is something else you would like me to address here.

@blackboxsw blackboxsw mentioned this pull request Apr 6, 2026
2 tasks
Comment thread cloudinit/distros/__init__.py Outdated
Comment thread cloudinit/distros/alpine.py Outdated
Comment thread cloudinit/distros/alpine.py
Comment thread cloudinit/distros/__init__.py Outdated
@blackboxsw
Copy link
Copy Markdown
Collaborator Author

Thanks @holmanb I have responded to your questions and pulled in our group param normalization from #6801.

@blackboxsw blackboxsw requested a review from holmanb April 13, 2026 15:39
Copy link
Copy Markdown
Member

@holmanb holmanb left a comment

Choose a reason for hiding this comment

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

I'd like to avoid using unnamed keyword args - being explicit is less verbose and easier to read.

Comment thread cloudinit/distros/__init__.py Outdated
Comment thread cloudinit/distros/alpine.py Outdated
Comment thread cloudinit/distros/__init__.py Outdated
Comment thread cloudinit/distros/__init__.py Outdated
Comment thread cloudinit/distros/__init__.py Outdated
Comment thread cloudinit/distros/alpine.py Outdated
@github-actions github-actions Bot added the stale-pr Pull request is stale; will be auto-closed soon label Apr 28, 2026
@canonical canonical deleted a comment from github-actions Bot Apr 28, 2026
@blackboxsw
Copy link
Copy Markdown
Collaborator Author

blackboxsw commented Apr 28, 2026

@holmanb I dropped _add_user_preprocess_kwargs in favor of encapsulating that in _add_user. Additionally, I've added typing for passwd for passwd in _post_add_user

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Preliminary refactor of distro user-creation and shutdown command construction to support upcoming security event logging work, along with corresponding test updates and some typing cleanups.

Changes:

  • Refactors Distro.add_user into a wrapper + internal hooks (_add_user, _build_add_user_cmd, _post_add_user) and adjusts create_user semantics around existing users.
  • Introduces _build_shutdown_command to centralize shutdown command construction with distro overrides (e.g., Alpine).
  • Normalizes user groups handling in cc_users_groups and updates unit tests to pass list-based groups explicitly.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
cloudinit/distros/__init__.py Refactors user creation flow, adds hook methods, updates shutdown command building, adjusts snap-user handling.
cloudinit/config/cc_users_groups.py Adds _normalize_user_groups and passes normalized groups into distro.create_user.
cloudinit/distros/alpine.py Switches Alpine user creation to override _add_user and adds Alpine _build_shutdown_command.
cloudinit/distros/raspberry_pi_os.py Moves Raspberry Pi OS post-user setup into _post_add_user.
cloudinit/distros/netbsd.py Refactors NetBSD user creation to _build_add_user_cmd + _post_add_user.
cloudinit/distros/freebsd.py Refactors FreeBSD user creation to _build_add_user_cmd + _post_add_user.
cloudinit/distros/bsd.py Tightens type annotations for chpasswd.
cloudinit/netinfo.py Corrects return type annotation for netdev_info.
cloudinit/config/cc_set_passwords.py Tightens return type annotation for get_users_by_type.
tests/unittests/config/test_cc_users_groups.py Adds coverage for group normalization/deprecation and updates expected calls.
tests/unittests/distros/test_create_users.py Updates calls to create_user(..., groups=...) and adjusts deprecation-log assertions.
tests/unittests/distros/test_alpine.py Updates Alpine user creation tests for new groups parameter and logstring expectations.
tests/unittests/distros/test_raspberry_pi_os.py Updates Raspberry Pi OS user creation tests for new hook-based behavior.
tests/unittests/distros/test_user_data_normalize.py Updates snap-user tests for new create_user call pattern and group list usage.
tests/unittests/distros/test_openbsd.py Updates add_user calls to include groups=[].
tests/unittests/distros/test_netbsd.py Updates add_user calls to include groups=[].
tests/unittests/distros/test_freebsd.py Updates add_user calls to include groups=[].
tests/unittests/distros/test_dragonflybsd.py Updates add_user calls to include groups=[].

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/unittests/distros/test_create_users.py Outdated
Comment thread cloudinit/distros/__init__.py Outdated
Comment thread cloudinit/distros/alpine.py Outdated
Comment thread cloudinit/distros/__init__.py Outdated
Comment thread cloudinit/distros/__init__.py Outdated
Comment thread cloudinit/config/cc_users_groups.py
Comment thread cloudinit/distros/raspberry_pi_os.py
@blackboxsw
Copy link
Copy Markdown
Collaborator Author

Addressed all outstanding review comments from copilot as well as @holmanb. This is ready for re-review.

Copy link
Copy Markdown
Member

@holmanb holmanb left a comment

Choose a reason for hiding this comment

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

Getting better, thanks!

Comment thread cloudinit/config/cc_users_groups.py Outdated
Comment thread cloudinit/distros/__init__.py Outdated
Comment thread cloudinit/distros/__init__.py
Comment thread cloudinit/distros/__init__.py
Comment thread cloudinit/distros/__init__.py Outdated
Comment thread cloudinit/distros/alpine.py Outdated
Comment thread cloudinit/distros/alpine.py Outdated
# or if the user is a system user
# Don't create the home directory if directed so or if the user is a
# system user
if kwargs.get("no_create_home") or kwargs.get("system"):
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.

Can we avoid kwargs use here?

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.

Done in alpine. Left freebsd, netbsd and init untyped because of the complexity of useradd_flags processing that would require a lot more work than I want to include in this PR.

Comment thread cloudinit/distros/freebsd.py
Comment thread cloudinit/distros/netbsd.py
Comment thread cloudinit/distros/raspberry_pi_os.py
Copy link
Copy Markdown
Collaborator Author

@blackboxsw blackboxsw left a comment

Choose a reason for hiding this comment

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

@holmanb thanks for the review again.
I believe I have addressed all comments.

Comment thread cloudinit/distros/alpine.py Outdated
Comment thread cloudinit/distros/alpine.py
Comment thread cloudinit/config/cc_users_groups.py Outdated
Comment thread cloudinit/distros/__init__.py Outdated
Comment thread cloudinit/distros/__init__.py Outdated
Comment thread cloudinit/distros/alpine.py Outdated
Comment thread cloudinit/distros/alpine.py Outdated
Comment thread cloudinit/distros/freebsd.py
Comment thread cloudinit/distros/netbsd.py
Comment thread cloudinit/distros/raspberry_pi_os.py
@blackboxsw blackboxsw requested a review from holmanb April 29, 2026 00:40
@github-actions github-actions Bot removed the stale-pr Pull request is stale; will be auto-closed soon label Apr 29, 2026
Comment thread cloudinit/config/cc_users_groups.py
@blackboxsw blackboxsw force-pushed the owasp-logs-part1 branch 3 times, most recently from a42add6 to 480eae5 Compare May 5, 2026 04:34
@blackboxsw
Copy link
Copy Markdown
Collaborator Author

Alternate distros action expected fail. Success run seen with PR #6864

@blackboxsw blackboxsw requested a review from holmanb May 5, 2026 04:47
@blackboxsw
Copy link
Copy Markdown
Collaborator Author

Now that CI actions are happy and snap stores are back online, We are now ready for re-review. Note I rebased against update/main and squash merged into 4 logically separate commits to add visibility to the separate intent in each changeset. This helped me review any stray whitespace changes I introduced during this refactor. Should be ready for review @holmanb. Also failing Alpine/edge job is expected dueto missing dependency. #6864 should resolve that issue.

blackboxsw added 4 commits May 6, 2026 13:01
Drop user group normalization from Distro.add_user
because it is now performed in cc_user_groups.
Move pre-existing user check outside of add_user and into create_user.
Avoid util.logexc in favor of LOG.warning for known
subp.ProcessExecutionErrors.
Distributions such as Alpine, *BSD and RPI can now specialize _add_user
behavior with the following additional hooks:
 - _build_add_user_command: to provide unique useadd command switches
 - _post_add_user: for delayed password processing or user renames

BREAKING_CHANGE: Distro.add_user no longer returns a bool indicating
whether a user was created. This is not a public API for cloud-init.
…anup

The hook _build_shutdown_command allows Alpine to override shutdown
behavior without having to subclass the public method shutdown_command.
@blackboxsw
Copy link
Copy Markdown
Collaborator Author

Rebased against main to get alpine workflow fix.

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.

3 participants