1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
#!/usr/bin/env python3
# Copyright (C) 2017 Canonical Ltd.
#
# This file is part of cloud-init. See LICENSE file for license information.
"""Define 'clean' utility and handler as part of cloud-init commandline."""
import argparse
import glob
import os
import sys
from cloudinit import settings
from cloudinit.stages import Init
from cloudinit.subp import ProcessExecutionError, runparts, subp
from cloudinit.util import (
del_dir,
del_file,
error,
get_config_logfiles,
is_link,
)
ETC_MACHINE_ID = "/etc/machine-id"
def get_parser(parser=None):
"""Build or extend an arg parser for clean utility.
@param parser: Optional existing ArgumentParser instance representing the
clean subcommand which will be extended to support the args of
this utility.
@returns: ArgumentParser with proper argument configuration.
"""
if not parser:
parser = argparse.ArgumentParser(
prog="clean",
description=(
"Remove logs and artifacts so cloud-init re-runs on "
"a clean system"
),
)
parser.add_argument(
"-l",
"--logs",
action="store_true",
default=False,
dest="remove_logs",
help="Remove cloud-init logs.",
)
parser.add_argument(
"--machine-id",
action="store_true",
default=False,
help=(
"Remove /etc/machine-id for golden image creation."
" Next boot generates a new machine-id."
),
)
parser.add_argument(
"-r",
"--reboot",
action="store_true",
default=False,
help="Reboot system after logs are cleaned so cloud-init re-runs.",
)
parser.add_argument(
"-s",
"--seed",
action="store_true",
default=False,
dest="remove_seed",
help="Remove cloud-init seed directory /var/lib/cloud/seed.",
)
return parser
def remove_artifacts(remove_logs, remove_seed=False):
"""Helper which removes artifacts dir and optionally log files.
@param: remove_logs: Boolean. Set True to delete the cloud_dir path. False
preserves them.
@param: remove_seed: Boolean. Set True to also delete seed subdir in
paths.cloud_dir.
@returns: 0 on success, 1 otherwise.
"""
init = Init(ds_deps=[])
init.read_cfg()
if remove_logs:
for log_file in get_config_logfiles(init.cfg):
del_file(log_file)
if not os.path.isdir(init.paths.cloud_dir):
return 0 # Artifacts dir already cleaned
seed_path = os.path.join(init.paths.cloud_dir, "seed")
for path in glob.glob("%s/*" % init.paths.cloud_dir):
if path == seed_path and not remove_seed:
continue
try:
if os.path.isdir(path) and not is_link(path):
del_dir(path)
else:
del_file(path)
except OSError as e:
error("Could not remove {0}: {1}".format(path, str(e)))
return 1
try:
runparts(settings.CLEAN_RUNPARTS_DIR)
except Exception as e:
error(
f"Failure during run-parts of {settings.CLEAN_RUNPARTS_DIR}: {e}"
)
return 1
return 0
def handle_clean_args(name, args):
"""Handle calls to 'cloud-init clean' as a subcommand."""
exit_code = remove_artifacts(args.remove_logs, args.remove_seed)
if args.machine_id:
del_file(ETC_MACHINE_ID)
if exit_code == 0 and args.reboot:
cmd = ["shutdown", "-r", "now"]
try:
subp(cmd, capture=False)
except ProcessExecutionError as e:
error(
'Could not reboot this system using "{0}": {1}'.format(
cmd, str(e)
)
)
exit_code = 1
return exit_code
def main():
"""Tool to collect and tar all cloud-init related logs."""
parser = get_parser()
sys.exit(handle_clean_args("clean", parser.parse_args()))
if __name__ == "__main__":
main()
|