Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dailies for Ubuntu/focal #5587

Merged
merged 69 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
9357c38
feat(aosc): Add 'AOSC OS' support (#5310)
leavelet Jul 3, 2024
053331e
fix(openbsd): fix mtu on newline in hostname files (#5412)
tobias-urdin Jul 3, 2024
2b6fe64
fix(vmware): Set IPv6 to dhcp when there is no IPv6 addr (#5471)
PengpengSun Jul 3, 2024
0af459e
test: pytestify and cleanup test_cc_mounts.py (#5459)
TheRealFalcon Jul 8, 2024
8a58270
test: Ensure mkcert executable in ftp tests (#5493)
TheRealFalcon Jul 9, 2024
7130bbb
test: Add missing assert to test_status.py (#5494)
TheRealFalcon Jul 9, 2024
db828d0
typing: fix check_untyped_defs in cloudinit.util (#5490)
aciba90 Jul 5, 2024
188656b
refactor: util.get_proc_env to work with strs (#5490)
aciba90 Jul 9, 2024
0128716
refactor: util.mounts to handle errors (#5490)
aciba90 Jul 9, 2024
4c0468c
Set MTU for bond parent interface (#5495)
jcmoore3 Jul 10, 2024
7d35664
fix: add schema rules for 'baseurl' and 'metalink' in yum repo config…
ani-sinha Jul 10, 2024
4abdd5a
feat(systemd): Warn user of unexpected run mode (#5209)
holmanb Apr 24, 2024
604d80e
test: Don't fail tests which call cloud-init as a command (#5209)
holmanb Jun 4, 2024
8aa1c30
test: allow verify_clean_boot to ignore all or specific tracebacks (#…
blackboxsw Jun 19, 2024
75add5c
feat(systemd): convert warning level message to deprecation (#5209)
blackboxsw Jun 19, 2024
a911d07
fix(test): Fix ip printer for non-lxd (#5488)
holmanb Jul 10, 2024
18d76ac
tests: revert expectation of exit 2 from cloud-init init --local (#5504)
blackboxsw Jul 10, 2024
8dbc5c2
test: Unconditionally skip test_multi_nic_hotplug_vpc (#5503)
TheRealFalcon Jul 10, 2024
e0e6a42
Fix configuration of DNS servers via OpenStack (#5384)
jcmoore3 Jul 11, 2024
311f723
fix: Update DNS behavior for NetworkManager interfaces (#5496)
jcmoore3 Jul 18, 2024
658d184
doc(OFV): Document how to configure cloud-init (#5519)
holmanb Jul 18, 2024
0b40843
Support setting mirrorlist in yum repository config (#5522)
ani-sinha Jul 18, 2024
550c685
fix: Clean cache if no datasource fallback (#5499)
TheRealFalcon Jul 18, 2024
57d130e
chore(formatting): fix squashed commit test formatting (#5524)
blackboxsw Jul 18, 2024
b0a673a
feat: Add trace-level logger (#5414)
TheRealFalcon Jun 19, 2024
8ec2f64
refactor: replace verbosity with log levels in logs.py (#5414)
TheRealFalcon Jun 19, 2024
19c86ff
refactor: logs.py pathlib changes (#5414)
TheRealFalcon Jun 19, 2024
6e4153b
refactor: logs.py add typing and small misc refactors (#5414)
TheRealFalcon Jun 19, 2024
23be88d
fix(ds-identify): Detect nocloud when seedfrom url exists (#5515)
holmanb Jul 16, 2024
7703634
chore: Improve detection logging for user clarity (#5515)
holmanb Jul 16, 2024
16a3198
chore: Deprecate partially supported system config (#5515)
holmanb Jul 17, 2024
5532b4a
feat(wsl): Special handling Landscape client config tags (#5460)
CarlosNihelton Jul 19, 2024
e1147bd
add openeuler to distros in cc_spacewalk.py (#5530)
xiaoge1001 Jul 22, 2024
7c2d4fd
feat: Support URI sources in `write_files` module (#5505)
LRitzdorf Jul 22, 2024
2534432
fix(azurelinux): Change default usr_lib_exec path (#5526)
rmhsawyer Jul 22, 2024
2d23852
test: fix no ds cache tests (#5529)
aciba90 Jul 22, 2024
f90f0b8
test: fix test_kernel_command_line_match (#5529)
aciba90 Jul 22, 2024
99ac819
fix(wsl): Put back the "path" argument to wsl_path in ds-identify (#5…
CarlosNihelton Jul 23, 2024
bb4b7c0
fix: auto label doc PRs (#5542)
aciba90 Jul 24, 2024
02beb9a
docs: improve qemu command line (#5540)
cpaelzer Jul 24, 2024
8ceae8b
doc: add diagram with boot stages (#5539)
aciba90 Jul 24, 2024
5f93726
feat(schema): add chef_license schema enum (#5543)
blackboxsw Jul 24, 2024
c176075
fix: doc auto label to consider schema json changes as doc PRs (#5543)
blackboxsw Jul 24, 2024
e5e78c2
doc: Update docs on boothooks (#5546)
aciba90 Jul 25, 2024
883d8e2
doc(modules): add section to wrap modules' doc (#5550)
aciba90 Jul 25, 2024
2ffd652
fix(doc-spelling): config spelling_word_list_filename (#5547)
aciba90 Jul 25, 2024
25058e1
chore: remove unneeded doc-lint tox env config (#5547)
aciba90 Jul 25, 2024
779dd6b
doc(autoinstall): Remove incorrect statements, be more direct (#5545)
holmanb Jul 25, 2024
81ef45e
doc(NoCloud): Categorize the different configuration types (#5521)
holmanb Jul 26, 2024
914a3a8
doc: improve drop-in custom modules (#5548)
aciba90 Jul 26, 2024
15200a0
chore: Deprecate ENI as an input configuration format (#5561)
holmanb Jul 26, 2024
f9ab856
docs: Overhaul user data formats documentation (#5551)
TheRealFalcon Jul 29, 2024
f8c1b51
fix(actions): doc labeler needs all clause instead of default any (#5…
blackboxsw Jul 29, 2024
00317d1
chore(debian): Remove vestigial postinst and preinst code (#5569)
holmanb Jul 29, 2024
f8d8a0c
fix: add host template for AOSC (#5557)
leavelet Jul 29, 2024
b5d4f3f
fix(actions): correct typo in cloudinit/config/schemas/ match (#5570)
blackboxsw Jul 31, 2024
e6b2e0f
feat: Eliminate redundant configuration reads (#5536)
holmanb Jul 31, 2024
5322dca
fix(NoCloudNet): Add network-config support (#5566)
holmanb Jul 31, 2024
ea831d6
fix: Integration tests (#5576)
holmanb Aug 2, 2024
d15a770
refactor: update handle function of cc_mounts (#5498)
TheRealFalcon Aug 2, 2024
ca3e6bc
chore: Add helper, refactor utilities into separate module (#5573)
holmanb Aug 2, 2024
143bc9e
feat: Single process optimization (#5489)
holmanb Aug 2, 2024
b7b11bc
fix: nocloud no fail when network-config absent (#5580)
blackboxsw Aug 3, 2024
0aea65c
chore: Fix log message in url_helper.py (#5583)
TheRealFalcon Aug 5, 2024
c0ffdd4
fix: Update default LXD meta-data with user meta-data (#5584)
holmanb Aug 5, 2024
dbe287a
merge from upstream/main at 24.2-65-gc0ffdd4d
TheRealFalcon Aug 6, 2024
5252fa3
update changelog (new upstream snapshot)
TheRealFalcon Aug 6, 2024
171926a
refresh patches
TheRealFalcon Aug 6, 2024
3ebfb85
update changelog
TheRealFalcon Aug 6, 2024
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: 6 additions & 1 deletion .github/labeler.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
documentation:
- doc/*
- all:
- changed-files:
- any-glob-to-any-file:
- 'doc/*'
- 'cloudinit/config/schemas/*'
- base-branch: ['main']
12 changes: 0 additions & 12 deletions .github/workflows/doc-autolabel.yml

This file was deleted.

9 changes: 9 additions & 0 deletions .github/workflows/labeler.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: "Pull Request Labeler"
on:
- pull_request_target

jobs:
labeler:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5
171 changes: 87 additions & 84 deletions cloudinit/cmd/devel/logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
"""Define 'collect-logs' utility and handler to include in cloud-init cmd."""

import argparse
import logging
import os
import pathlib
import shutil
import subprocess
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import NamedTuple, Optional
from typing import List, NamedTuple, Optional, cast

from cloudinit import log
from cloudinit.cmd.devel import read_cfg_paths
from cloudinit.stages import Init
from cloudinit.subp import ProcessExecutionError, subp
Expand All @@ -27,6 +29,8 @@
write_file,
)

LOG = cast(log.CustomLoggerType, logging.getLogger(__name__))


class LogPaths(NamedTuple):
userdata_raw: str
Expand Down Expand Up @@ -96,7 +100,9 @@ class ApportFile(NamedTuple):
]


def get_parser(parser=None):
def get_parser(
parser: Optional[argparse.ArgumentParser] = None,
) -> argparse.ArgumentParser:
"""Build or extend and arg parser for collect-logs utility.

@param parser: Optional existing ArgumentParser instance representing the
Expand Down Expand Up @@ -141,7 +147,7 @@ def get_parser(parser=None):
return parser


def _get_copytree_ignore_files(paths: LogPaths):
def _get_copytree_ignore_files(paths: LogPaths) -> List[str]:
"""Return a list of files to ignore for /run/cloud-init directory"""
ignored_files = [
"hook-hotplug-cmd", # named pipe for hotplug
Expand All @@ -152,111 +158,109 @@ def _get_copytree_ignore_files(paths: LogPaths):
return ignored_files


def _write_command_output_to_file(cmd, filename, msg, verbosity):
def _write_command_output_to_file(
cmd: List[str],
file_path: pathlib.Path,
msg: str,
) -> Optional[str]:
"""Helper which runs a command and writes output or error to filename."""
ensure_dir(os.path.dirname(filename))
file_path.parent.mkdir(parents=True, exist_ok=True)
try:
output = subp(cmd).stdout
except ProcessExecutionError as e:
write_file(filename, str(e))
_debug("collecting %s failed.\n" % msg, 1, verbosity)
write_file(file_path, str(e))
LOG.debug("collecting %s failed.", msg)
output = None
else:
write_file(filename, output)
_debug("collected %s\n" % msg, 1, verbosity)
return output
write_file(file_path, output)
LOG.debug("collected %s to file '%s'", msg, file_path.stem)
return output


def _stream_command_output_to_file(cmd, filename, msg, verbosity):
"""Helper which runs a command and writes output or error to filename."""
ensure_dir(os.path.dirname(filename))
def _stream_command_output_to_file(
cmd: List[str], file_path: pathlib.Path, msg: str
) -> None:
"""Helper which runs a command and writes output or error to filename.

`subprocess.call` is invoked directly here to stream output to the file.
Otherwise memory usage can be high for large outputs.
"""
file_path.parent.mkdir(parents=True, exist_ok=True)
try:
with open(filename, "w") as f:
with file_path.open("w") as f:
subprocess.call(cmd, stdout=f, stderr=f) # nosec B603
except OSError as e:
write_file(filename, str(e))
_debug("collecting %s failed.\n" % msg, 1, verbosity)
write_file(file_path, str(e))
LOG.debug("collecting %s failed.", msg)
else:
_debug("collected %s\n" % msg, 1, verbosity)
LOG.debug("collected %s to file '%s'", msg, file_path.stem)


def _debug(msg, level, verbosity):
if level <= verbosity:
sys.stderr.write(msg)


def _collect_file(path, out_dir, verbosity):
def _collect_file(path: str, out_dir: str) -> None:
if os.path.isfile(path):
copy(path, out_dir)
_debug("collected file: %s\n" % path, 1, verbosity)
LOG.debug("collected file: %s", path)
else:
_debug("file %s did not exist\n" % path, 2, verbosity)
LOG.trace("file %s did not exist", path)


def _collect_installer_logs(
log_dir: str, include_userdata: bool, verbosity: int
):
def _collect_installer_logs(log_dir: str, include_userdata: bool) -> None:
"""Obtain subiquity logs and config files."""
for src_file in INSTALLER_APPORT_FILES:
destination_dir = Path(log_dir + src_file.path).parent
destination_dir = pathlib.Path(log_dir + src_file.path).parent
if not destination_dir.exists():
ensure_dir(str(destination_dir))
_collect_file(src_file.path, str(destination_dir), verbosity)
_collect_file(src_file.path, str(destination_dir))
if include_userdata:
for src_file in INSTALLER_APPORT_SENSITIVE_FILES:
destination_dir = Path(log_dir + src_file.path).parent
destination_dir = pathlib.Path(log_dir + src_file.path).parent
if not destination_dir.exists():
ensure_dir(str(destination_dir))
_collect_file(src_file.path, str(destination_dir), verbosity)
_collect_file(src_file.path, str(destination_dir))


def _collect_version_info(log_dir: str, verbosity: int):
def _collect_version_info(log_dir: str) -> None:
version = _write_command_output_to_file(
cmd=["cloud-init", "--version"],
filename=os.path.join(log_dir, "version"),
file_path=pathlib.Path(log_dir, "version"),
msg="cloud-init --version",
verbosity=verbosity,
)
dpkg_ver = _write_command_output_to_file(
cmd=["dpkg-query", "--show", "-f=${Version}\n", "cloud-init"],
filename=os.path.join(log_dir, "dpkg-version"),
file_path=pathlib.Path(log_dir, "dpkg-version"),
msg="dpkg version",
verbosity=verbosity,
)
if not version:
version = dpkg_ver if dpkg_ver else "not-available"
_debug("collected cloud-init version: %s\n" % version, 1, verbosity)
version = dpkg_ver or "not-available"


def _collect_system_logs(log_dir: str, verbosity: int):
def _collect_system_logs(log_dir: str) -> None:
_stream_command_output_to_file(
cmd=["dmesg"],
filename=os.path.join(log_dir, "dmesg.txt"),
file_path=pathlib.Path(log_dir, "dmesg.txt"),
msg="dmesg output",
verbosity=verbosity,
)
_stream_command_output_to_file(
cmd=["journalctl", "--boot=0", "-o", "short-precise"],
filename=os.path.join(log_dir, "journal.txt"),
file_path=pathlib.Path(log_dir, "journal.txt"),
msg="systemd journal of current boot",
verbosity=verbosity,
)


def _collect_cloudinit_logs(
log_dir: str,
verbosity: int,
init: Init,
paths: LogPaths,
include_userdata: bool,
):
for log in get_config_logfiles(init.cfg):
_collect_file(log, log_dir, verbosity)
) -> None:
for logfile in get_config_logfiles(init.cfg):
_collect_file(logfile, log_dir)
if include_userdata:
user_data_file = paths.userdata_raw
_collect_file(user_data_file, log_dir, verbosity)
_collect_file(user_data_file, log_dir)


def _collect_run_dir(log_dir: str, verbosity: int, paths: LogPaths):
def _collect_run_dir(log_dir: str, paths: LogPaths) -> None:
run_dir = os.path.join(log_dir, "run")
ensure_dir(run_dir)
if os.path.exists(paths.run_dir):
Expand All @@ -267,38 +271,31 @@ def _collect_run_dir(log_dir: str, verbosity: int, paths: LogPaths):
ignore=lambda _, __: _get_copytree_ignore_files(paths),
)
except shutil.Error as e:
sys.stderr.write("Failed collecting file(s) due to error:\n")
sys.stderr.write(str(e) + "\n")
_debug("collected dir %s\n" % paths.run_dir, 1, verbosity)
LOG.warning("Failed collecting file(s) due to error: %s", e)
LOG.debug("collected directory: %s", paths.run_dir)
else:
_debug(
"directory '%s' did not exist\n" % paths.run_dir,
1,
verbosity,
)
LOG.debug("directory '%s' did not exist", paths.run_dir)
if os.path.exists(os.path.join(paths.run_dir, "disabled")):
# Fallback to grab previous cloud/data
cloud_data_dir = Path(paths.cloud_data)
cloud_data_dir = pathlib.Path(paths.cloud_data)
if cloud_data_dir.exists():
shutil.copytree(
str(cloud_data_dir),
Path(log_dir + str(cloud_data_dir)),
pathlib.Path(log_dir + str(cloud_data_dir)),
)


def collect_logs(
tarfile: str, include_userdata: bool, verbosity: int = 0
) -> int:
def collect_logs(tarfile: str, include_userdata: bool) -> int:
"""Collect all cloud-init logs and tar them up into the provided tarfile.

@param tarfile: The path of the tar-gzipped file to create.
@param include_userdata: Boolean, true means include user-data.
@return: 0 on success, 1 on failure.
"""
if include_userdata and os.getuid() != 0:
sys.stderr.write(
"To include userdata, root user is required."
" Try sudo cloud-init collect-logs\n"
LOG.error(
"To include userdata, root user is required. "
"Try sudo cloud-init collect-logs"
)
return 1

Expand All @@ -312,33 +309,39 @@ def collect_logs(
init.read_cfg()
paths = get_log_paths(init)

_collect_version_info(log_dir, verbosity)
_collect_system_logs(log_dir, verbosity)
_collect_cloudinit_logs(
log_dir, verbosity, init, paths, include_userdata
)
_collect_installer_logs(log_dir, include_userdata, verbosity)
_collect_run_dir(log_dir, verbosity, paths)
_collect_version_info(log_dir)
_collect_system_logs(log_dir)
_collect_cloudinit_logs(log_dir, init, paths, include_userdata)
_collect_installer_logs(log_dir, include_userdata)
_collect_run_dir(log_dir, paths)
with chdir(tmp_dir):
subp(["tar", "czvf", tarfile, log_dir.replace(f"{tmp_dir}/", "")])
sys.stderr.write("Wrote %s\n" % tarfile)
LOG.info("Wrote %s", tarfile)
return 0


def handle_collect_logs_args(name, args):
def _setup_logger(verbosity: int) -> None:
log.reset_logging()
if verbosity == 0:
level = logging.INFO
elif verbosity == 1:
level = logging.DEBUG
else:
level = log.TRACE
LOG.setLevel(level)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter("%(message)s"))
LOG.addHandler(handler)


def handle_collect_logs_args(_name: str, args: argparse.Namespace) -> int:
"""Handle calls to 'cloud-init collect-logs' as a subcommand."""
_setup_logger(args.verbosity)
return collect_logs(
tarfile=args.tarfile,
include_userdata=args.userdata,
verbosity=args.verbosity,
)


def main():
"""Tool to collect and tar all cloud-init related logs."""
parser = get_parser()
return handle_collect_logs_args("collect-logs", parser.parse_args())


if __name__ == "__main__":
sys.exit(main())
sys.exit(handle_collect_logs_args("", get_parser().parse_args()))
Loading