Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ae5df04
refactor: generalize Distro add_user and shutdown_command
blackboxsw Mar 21, 2026
ec6144e
chore: move groups normalization into cc_users_groups and out of PR 6801
blackboxsw Apr 11, 2026
b439d92
feat(azure): introduce experimental skip_ready_report for Azure (#6771)
cjp256 Mar 11, 2026
aa411f1
feat(util): fail early when hostname is not resolvable in is_resolvab…
aale24 Mar 11, 2026
482b4cd
WSL: Subprocess cmd.exe with /U to output UTF-16LE (#6717)
CarlosNihelton Mar 16, 2026
7877c03
fix(azure): catch import error as reportable (#6714)
cadejacobson Mar 16, 2026
f21c0bb
fix(bsd): correct the _ROOT_TMPDIR path for *BSD system (#6794)
hcartiaux Mar 16, 2026
5fa5d8f
ci: add cloud-init integration test logs upon failure (#6803)
blackboxsw Mar 24, 2026
8bce95b
chore(net): log when klibc is parsed (#6799)
holmanb Mar 25, 2026
dc001ea
chore: auto-format shell (#6780)
holmanb Mar 25, 2026
f5f7849
ci: fix integration test CLOUD_INIT_LOCAL_LOG_PATH. drop hashFiles (#…
blackboxsw Mar 25, 2026
2c83aed
chore: drop outdated code (#6798)
holmanb Mar 26, 2026
bbde151
test: fix missing mocker of rmtree for redhat unittests (#6808)
blackboxsw Mar 28, 2026
8fffad7
fix(openbsd): specify the correct usr_lib_exec path (#6793)
hcartiaux Mar 30, 2026
c375e21
ci: disable daily jobs on forks (#6821)
holmanb Mar 31, 2026
e10bcc0
chore: drop unnecessary pylint ignore settings, use pytest --strict-m…
holmanb Mar 31, 2026
23de7d3
tools: fix brpm script to use correct builddir in temp directory (#6809)
blackboxsw Mar 31, 2026
80efde1
test: fix test_schema when the schema validation takes longer (#6822)
ani-sinha Apr 1, 2026
5499bf0
test: fix integration test_combined for rhel (#6791)
xiachen-rh Apr 2, 2026
279e631
fix(ubuntu): Configure arm64 to use archive.ubuntu.com (#6826)
waveform80 Apr 3, 2026
f0b4f99
feat: owasp security event logging for user, password, and shutdown e…
blackboxsw Mar 21, 2026
70c7bed
refactor: typing for user_groups in distro
blackboxsw Apr 2, 2026
00d4133
tests: update security log unittests providing a test for invalid pay…
blackboxsw Apr 3, 2026
eae55c5
chore: drop noop logs for user/groups and avoid deepcopy during sec log
blackboxsw Apr 3, 2026
af195e0
chore: avoid datetime module in favor of logging.Formatter.formatTime
blackboxsw Apr 3, 2026
b61adfb
tests: fix ISO 8601 format and related tests
blackboxsw Apr 4, 2026
014cbd5
chore: add _post_set_password for netbsd, make user_add groups required
blackboxsw Apr 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/10-daily-unit-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
run: tox -e hypothesis-slow
devel_tests:
name: "Tip: Python"
if: github.repository == 'canonical/cloud-init'
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand All @@ -44,14 +45,15 @@ jobs:
- name: Run unittest
run: tox -e py3 -- --color=yes
format_tip:
name: "Tip: Lint"
if: github.repository == 'canonical/cloud-init'
runs-on: ubuntu-latest
env:
FORCE_COLOR: 1
strategy:
fail-fast: false
matrix:
env: [tip-ruff, tip-mypy, tip-pylint, tip-black, tip-isort, py3-fast]
name: "Tip: Lint"
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand All @@ -65,6 +67,7 @@ jobs:
run: tox
macos:
name: Python ${{matrix.python-version}} ${{ matrix.slug }}
if: github.repository == 'canonical/cloud-init'
runs-on: macos-latest
strategy:
matrix:
Expand Down
21 changes: 7 additions & 14 deletions .github/workflows/21-pr-check-format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ defaults:
shell: sh -ex {0}

jobs:
check_format:
check_linters:
strategy:
fail-fast: false
matrix:
env: [ruff, mypy, pylint, black, isort]
env: [check_format]
name: Check ${{ matrix.env }}
runs-on: ubuntu-latest
env:
Expand All @@ -30,6 +30,7 @@ jobs:
run: |
sudo DEBIAN_FRONTEND=noninteractive apt-get -qy update
sudo DEBIAN_FRONTEND=noninteractive apt-get -qy install tox
sudo snap install shfmt

- name: Print version
run: python3 --version
Expand All @@ -39,20 +40,12 @@ jobs:
# matrix env: not to be confused w/environment variables or testenv
TOXENV: ${{ matrix.env }}
run: tox
schema-format:
strategy:
fail-fast: false
name: Check json format
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Test format
- name: Formatting check failed
if: failure()
run: |
tools/check_json_format.sh cloudinit/config/schemas/schema-cloud-config-v1.json
tools/check_json_format.sh cloudinit/config/schemas/schema-network-config-v1.json
tools/check_json_format.sh cloudinit/config/schemas/versions.schema.cloud-config.json
echo "[31mResolve formatting errors with `tox -e do_format` (requires shfmt to format shell).\e[0m"
echo "[31mFor mypy and pylint failures see the warnings above.\e[0m"

doc:
strategy:
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/24-pr-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,12 @@ jobs:
echo "[lxd]" > /home/$USER/.config/pycloudlib.toml
- name: Run integration Tests
run: |
CLOUD_INIT_CLOUD_INIT_SOURCE="$(ls ${{ runner.temp }}/cloud-init-base*.deb)" CLOUD_INIT_OS_IMAGE=${{ env.RELEASE }} tox -e integration-tests-ci -- --color=yes tests/integration_tests/
CLOUD_INIT_CLOUD_INIT_SOURCE="$(ls ${{ runner.temp }}/cloud-init-base*.deb)" CLOUD_INIT_OS_IMAGE=${{ env.RELEASE }} CLOUD_INIT_LOCAL_LOG_PATH=./cloudinit_logs tox -e integration-tests-ci -- --color=yes tests/integration_tests/
- name: Upload cloudinit logs on failure
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: 'cloudinit-logs'
path: './cloudinit_logs'
retention-days: 3
if-no-files-found: ignore
29 changes: 0 additions & 29 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -32,32 +32,3 @@ output-format=parseable

# Just the errors please, no full report
reports=no


[TYPECHECK]

# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
http.client,
httplib,
pkg_resources,
# cloud_tests requirements.
boto3,
botocore,
paramiko,
pylxd,
simplestreams

# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
# argparse.Namespace from https://github.com/PyCQA/pylint/issues/2413
ignored-classes=argparse.Namespace,optparse.Values,thread._local,ImageManager,ContainerManager

# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=types,http.client,command_handlers,m_.*,enter_context
33 changes: 2 additions & 31 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,18 @@ distro ?= redhat

GENERATOR_F=./systemd/cloud-init-generator
DS_IDENTIFY=./tools/ds-identify
BENCHMARK=./tools/benchmark.sh


all: check

check: test

style-check: lint

lint:
@$(CWD)/tools/run-lint

unittest: clean_pyc
$(PYTHON) -m pytest -v tests/unittests cloudinit

render-template:
$(PYTHON) ./tools/render-template --variant=$(VARIANT) $(FILE) $(subst .tmpl,,$(FILE))

# from systemd-generator(7) regarding generators:
# "We do recommend C code however, since generators are executed
# synchronously and hence delay the entire boot if they are slow."
#
# Our generator is a shell script. Make it easy to measure the
# generator. This should be monitored for performance regressions
benchmark-generator: FILE=$(GENERATOR_F).tmpl
benchmark-generator: VARIANT="benchmark"
benchmark-generator: export ITER=$(NUM_ITER)
benchmark-generator: render-template
$(BENCHMARK) $(GENERATOR_F)

benchmark-ds-identify: export ITER=$(NUM_ITER)
benchmark-ds-identify:
$(BENCHMARK) $(DS_IDENTIFY)

ci-deps-ubuntu:
@$(PYTHON) $(CWD)/tools/read-dependencies --distro ubuntu --test-distro

Expand Down Expand Up @@ -103,13 +81,6 @@ deb-src:
doc:
tox -e doc

fmt:
tox -e do_format && tox -e check_format

fmt-tip:
tox -e do_format_tip && tox -e check_format_tip


.PHONY: all check test lint clean rpm srpm deb deb-src clean_pyc
.PHONY: unittest style-check render-template benchmark-generator
.PHONY: all check test clean rpm srpm deb deb-src clean_pyc
.PHONY: unittest render-template
.PHONY: clean_pytest clean_packaging clean_release doc
4 changes: 2 additions & 2 deletions cloudinit/config/cc_set_passwords.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import random
import re
import string
from typing import List
from typing import List, Tuple

from cloudinit import features, lifecycle, subp, util
from cloudinit.cloud import Cloud
Expand All @@ -32,7 +32,7 @@
LOG = logging.getLogger(__name__)


def get_users_by_type(users_list: list, pw_type: str) -> list:
def get_users_by_type(users_list: list, pw_type: str) -> List[Tuple[str, str]]:
"""either password or type: RANDOM is required, user is always required"""
return (
[]
Expand Down
36 changes: 35 additions & 1 deletion cloudinit/config/cc_users_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"""Users and Groups: Configure users and groups"""

import logging
from typing import List, Union

from cloudinit import lifecycle
from cloudinit.cloud import Cloud

# Ensure this is aliased to a name not 'distros'
Expand All @@ -32,6 +34,37 @@
NEED_HOME = ("ssh_authorized_keys", "ssh_import_id", "ssh_redirect_user")


def _normalize_user_groups(
user: str, groups: Union[str, List[str], dict]
) -> List[str]:
if not groups:
return []

if isinstance(groups, str):
return [group.strip() for group in groups.split(",") if group.strip()]

if isinstance(groups, dict):
lifecycle.deprecate(
deprecated=f"The user {user} has a 'groups' config value "
"of type dict",
deprecated_version="22.3",
extra_message="Use a comma-delimited string or "
"array instead: group1,group2.",
)
return list(groups)

if isinstance(groups, list):
if not all(isinstance(group, str) for group in groups):
raise TypeError(
f"Not creating user {user}. 'groups' must contain only "
"string values."
)
return groups
raise TypeError(
f"Not creating user {user}. 'groups' must be a string, list, or dict."
)


def handle(name: str, cfg: Config, cloud: Cloud, args: list) -> None:
(users, groups) = ug_util.normalize_users_groups(cfg, cloud.distro)
(default_user, _user_config) = ug_util.extract_default(users)
Expand All @@ -41,6 +74,7 @@ def handle(name: str, cfg: Config, cloud: Cloud, args: list) -> None:
cloud.distro.create_group(name, members)

for user, config in users.items():
user_groups = _normalize_user_groups(user, config.pop("groups", []))

no_home = [key for key in NO_HOME if config.get(key)]
need_home = [key for key in NEED_HOME if config.get(key)]
Expand Down Expand Up @@ -77,4 +111,4 @@ def handle(name: str, cfg: Config, cloud: Cloud, args: list) -> None:
config["ssh_redirect_user"] = default_user
config["cloud_public_ssh_keys"] = cloud_keys

cloud.distro.create_user(user, **config)
cloud.distro.create_user(user, groups=user_groups, **config)
Loading