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

Output: use logging, remove garbage output by default #557

Closed
Closed
Changes from all commits
Commits
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
77 changes: 41 additions & 36 deletions podman_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import random
import json
import glob
import logging

from threading import Thread

Expand Down Expand Up @@ -70,10 +71,7 @@ def try_float(i, fallback=None):
return fallback


def log(*msgs, sep=" ", end="\n"):
line = (sep.join([str(msg) for msg in msgs])) + end
sys.stderr.write(line)
sys.stderr.flush()
log = logging.getLogger(__name__)


dir_re = re.compile(r"^[~/\.]")
Expand Down Expand Up @@ -354,7 +352,7 @@ def assert_volume(compose, mount_dict):
proj_name = compose.project_name
vol_name = vol["name"]
is_ext = vol.get("external", None)
log(f"podman volume inspect {vol_name} || podman volume create {vol_name}")
log.debug(f"podman volume inspect {vol_name} || podman volume create {vol_name}")
# TODO: might move to using "volume list"
# podman volume list --format '{{.Name}}\t{{.MountPoint}}' -f 'label=io.podman.compose.project=HERE'
try:
Expand Down Expand Up @@ -541,7 +539,7 @@ def get_secret_args(compose, cnt, secret):
volume_ref = ["--volume", f"{source_file}:{dest_file}:ro,rprivate,rbind"]
if uid or gid or mode:
sec = target if target else secret_name
log(
log.warn(
f'WARNING: Service {cnt["_service"]} uses secret "{sec}" with uid, gid, or mode.'
+ " These fields are not supported by this implementation of the Compose file"
)
Expand Down Expand Up @@ -569,7 +567,7 @@ def get_secret_args(compose, cnt, secret):
if target and target != secret_name:
raise ValueError(err_str.format(target, secret_name))
if target:
log(
log.warn(
'WARNING: Service "{}" uses target: "{}" for secret: "{}".'.format(
cnt["_service"], target, secret_name
)
Expand Down Expand Up @@ -761,7 +759,7 @@ def get_net_args(compose, cnt):
elif net.startswith("bridge"):
is_bridge = True
else:
print(f"unknown network_mode [{net}]")
log.fatal(f"unknown network_mode [{net}]")
sys.exit(1)
else:
is_bridge = True
Expand Down Expand Up @@ -1056,7 +1054,7 @@ def output(self, podman_args, cmd="", cmd_args=None):
cmd_args = cmd_args or []
xargs = self.compose.get_podman_args(cmd) if cmd else []
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
log(cmd_ls)
log.info(str(cmd_ls))
return subprocess.check_output(cmd_ls)

def exec(
Expand All @@ -1068,7 +1066,7 @@ def exec(
cmd_args = list(map(str, cmd_args or []))
xargs = self.compose.get_podman_args(cmd) if cmd else []
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
log(" ".join([str(i) for i in cmd_ls]))
log.info(" ".join([str(i) for i in cmd_ls]))
os.execlp(self.podman_path, *cmd_ls)

def run(
Expand All @@ -1086,7 +1084,7 @@ def run(
cmd_args = list(map(str, cmd_args or []))
xargs = self.compose.get_podman_args(cmd) if cmd else []
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
log(" ".join([str(i) for i in cmd_ls]))
log.info(" ".join([str(i) for i in cmd_ls]))
if self.dry_run:
return None
# subprocess.Popen(args, bufsize = 0, executable = None, stdin = None, stdout = None, stderr = None, preexec_fn = None, close_fds = False, shell = False, cwd = None, env = None, universal_newlines = False, startupinfo = None, creationflags = 0)
Expand All @@ -1104,7 +1102,7 @@ def run(

if wait:
exit_code = p.wait()
log("exit code:", exit_code)
log.info("exit code:%s", exit_code)
if obj is not None:
obj.exit_code = exit_code

Expand Down Expand Up @@ -1335,7 +1333,7 @@ def assert_services(self, services):
missing = given - self.all_services
if missing:
missing_csv = ",".join(missing)
log(f"missing services [{missing_csv}]")
log.warn(f"missing services [{missing_csv}]")
sys.exit(1)

def get_podman_args(self, cmd):
Expand All @@ -1349,7 +1347,7 @@ def get_podman_args(self, cmd):
return xargs

def run(self):
log("podman-compose version: " + __version__)
log.info("podman-compose version: " + __version__)
args = self._parse_args()
podman_path = args.podman_path
if podman_path != "podman":
Expand All @@ -1358,7 +1356,7 @@ def run(self):
else:
# this also works if podman hasn't been installed now
if args.dry_run is False:
log(f"Binary {podman_path} has not been found.")
log.fatal(f"Binary {podman_path} has not been found.")
sys.exit(1)
self.podman = Podman(self, podman_path, args.dry_run)
if not args.dry_run:
Expand All @@ -1372,9 +1370,9 @@ def run(self):
except subprocess.CalledProcessError:
self.podman_version = None
if not self.podman_version:
log("it seems that you do not have `podman` installed")
log.fatal("it seems that you do not have `podman` installed")
sys.exit(1)
log("using podman version: " + self.podman_version)
log.info("using podman version: " + self.podman_version)
cmd_name = args.command
compose_required = cmd_name != "version" and (
cmd_name != "systemd" or args.action != "create-unit"
Expand All @@ -1400,14 +1398,14 @@ def _parse_compose_file(self):
args.file = list(filter(os.path.exists, default_ls))
files = args.file
if not files:
log(
log.fatal(
"no compose.yaml, docker-compose.yml or container-compose.yml file found, pass files with -f"
)
sys.exit(-1)
ex = map(os.path.exists, files)
missing = [fn0 for ex0, fn0 in zip(ex, files) if not ex0]
if missing:
log("missing files: ", missing)
log.fatal("missing files: %s", missing)
sys.exit(1)
# make absolute
relative_files = files
Expand Down Expand Up @@ -1465,7 +1463,7 @@ def _parse_compose_file(self):
compose["_dirname"] = dirname
# debug mode
if len(files) > 1:
log(" ** merged:\n", json.dumps(compose, indent=2))
log.debug(" ** merged:\n%s", json.dumps(compose, indent=2))
# ver = compose.get('version', None)

if not project_name:
Expand All @@ -1487,7 +1485,7 @@ def _parse_compose_file(self):
services = compose.get("services", None)
if services is None:
services = {}
log("WARNING: No services defined")
log.warn("WARNING: No services defined")

# NOTE: maybe add "extends.service" to _deps at this stage
flat_deps(services, with_extends=True)
Expand Down Expand Up @@ -1524,7 +1522,7 @@ def _parse_compose_file(self):
unused_nets = given_nets - allnets - set(["default"])
if len(unused_nets):
unused_nets_str = ",".join(unused_nets)
log(f"WARNING: unused networks: {unused_nets_str}")
log.warn(f"WARNING: unused networks: {unused_nets_str}")
if len(missing_nets):
missing_nets_str = ",".join(missing_nets)
raise RuntimeError(f"missing networks: {missing_nets_str}")
Expand Down Expand Up @@ -1616,6 +1614,8 @@ def _parse_args(self):
if not self.global_args.command or self.global_args.command == "help":
parser.print_help()
sys.exit(-1)

logging.basicConfig(level=('DEBUG' if self.global_args.verbose else 'WARN'))
return self.global_args

@staticmethod
Expand Down Expand Up @@ -1692,6 +1692,11 @@ def _init_global_parser(parser):
help="No action; perform a simulation of commands",
action="store_true",
)
parser.add_argument(
"--verbose",
help="Print debugging output",
action="store_true",
)


podman_compose = PodmanCompose()
Expand Down Expand Up @@ -1785,15 +1790,15 @@ def compose_systemd(compose, args):
proj_name = compose.project_name
fn = os.path.expanduser(f"~/{stacks_dir}/{proj_name}.env")
os.makedirs(os.path.dirname(fn), exist_ok=True)
print(f"writing [{fn}]: ...")
log.debug(f"writing [{fn}]: ...")
with open(fn, "w", encoding="utf-8") as f:
for k, v in compose.environ.items():
if k.startswith("COMPOSE_") or k.startswith("PODMAN_"):
f.write(f"{k}={v}\n")
print(f"writing [{fn}]: done.")
print("\n\ncreating the pod without starting it: ...\n\n")
log.debug(f"writing [{fn}]: done.")
log.info("\n\ncreating the pod without starting it: ...\n\n")
process = subprocess.run([script, "up", "--no-start"], check=False)
print("\nfinal exit code is ", process.returncode)
log.info("\nfinal exit code is ", process.returncode)
username = getpass.getuser()
print(
f"""
Expand Down Expand Up @@ -1840,18 +1845,18 @@ def compose_systemd(compose, args):
WantedBy=default.target
"""
if os.access(os.path.dirname(fn), os.W_OK):
print(f"writing [{fn}]: ...")
log.debug(f"writing [{fn}]: ...")
with open(fn, "w", encoding="utf-8") as f:
f.write(out)
print(f"writing [{fn}]: done.")
log.debug(f"writing [{fn}]: done.")
print(
"""
while in your project type `podman-compose systemd -a register`
"""
)
else:
print(out)
log(f"Could not write to [{fn}], use 'sudo'")
log.warn(f"Could not write to [{fn}], use 'sudo'")


@cmd_run(podman_compose, "pull", "pull stack images")
Expand Down Expand Up @@ -1975,7 +1980,7 @@ def get_excluded(compose, args):
for service in args.services:
excluded -= compose.services[service]["_deps"]
excluded.discard(service)
log("** excluding: ", excluded)
log.debug("** excluding: %s", excluded)
return excluded


Expand Down Expand Up @@ -2007,18 +2012,18 @@ def compose_up(compose, args):
)
diff_hashes = [i for i in hashes if i and i != compose.yaml_hash]
if args.force_recreate or len(diff_hashes):
log("recreating: ...")
log.info("recreating: ...")
down_args = argparse.Namespace(**dict(args.__dict__, volumes=False))
compose.commands["down"](compose, down_args)
log("recreating: done\n\n")
log.info("recreating: done\n\n")
# args.no_recreate disables check for changes (which is not implemented)

podman_command = "run" if args.detach and not args.no_start else "create"

create_pods(compose, args)
for cnt in compose.containers:
if cnt["_service"] in excluded:
log("** skipping: ", cnt["name"])
log.debug("** skipping: %s", cnt["name"])
continue
podman_args = container_to_args(compose, cnt, detached=args.detach)
subproc = compose.podman.run([], podman_command, podman_args)
Expand Down Expand Up @@ -2052,7 +2057,7 @@ def compose_up(compose, args):
)
log_formatter = ["sed", "-e", log_formatter]
if cnt["_service"] in excluded:
log("** skipping: ", cnt["name"])
log.debug("** skipping: %s", cnt["name"])
continue
# TODO: remove sleep from podman.run
obj = compose if exit_code_from == cnt["_service"] else None
Expand Down Expand Up @@ -2124,7 +2129,7 @@ def compose_down(compose, args):
if cnt["_service"] not in excluded:
continue
vol_names_to_keep.update(get_volume_names(compose, cnt))
log("keep", vol_names_to_keep)
log.debug("keep", vol_names_to_keep)
for volume_name in compose.podman.volume_ls():
if volume_name in vol_names_to_keep:
continue
Expand Down Expand Up @@ -2388,7 +2393,7 @@ def compose_unpause(compose, args):
def compose_kill(compose, args):
# to ensure that the user did not execute the command by mistake
if not args.services and not args.all:
print(
log.fatal(
"Error: you must provide at least one service name or use (--all) to kill all services"
)
sys.exit()
Expand Down