Skip to content

Commit 1e9e2ee

Browse files
jamesobmaurerle
authored andcommitted
Output: use logging, remove garbage output by default
Fixes #489. Introduces a --verbose flag if you want to see all the noise that was previously printed by default. Signed-off-by: James O'Beirne <james.obeirne@pm.me> Signed-off-by: Florian Maurer <f.maurer@outlook.de>
1 parent dcb6cdb commit 1e9e2ee

File tree

1 file changed

+43
-44
lines changed

1 file changed

+43
-44
lines changed

podman_compose.py

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import hashlib
1515
import itertools
1616
import json
17+
import logging
1718
import os
1819
import random
1920
import re
@@ -78,16 +79,7 @@ def try_float(i, fallback=None):
7879
return fallback
7980

8081

81-
def log(*msgs, sep=" ", end="\n"):
82-
try:
83-
current_task = asyncio.current_task()
84-
except RuntimeError:
85-
current_task = None
86-
line = (sep.join([str(msg) for msg in msgs])) + end
87-
if current_task and not current_task.get_name().startswith("Task"):
88-
line = f"[{current_task.get_name()}] " + line
89-
sys.stderr.write(line)
90-
sys.stderr.flush()
82+
log = logging.getLogger(__name__)
9183

9284

9385
dir_re = re.compile(r"^[~/\.]")
@@ -387,7 +379,7 @@ async def assert_volume(compose, mount_dict):
387379
proj_name = compose.project_name
388380
vol_name = vol["name"]
389381
is_ext = vol.get("external", None)
390-
log(f"podman volume inspect {vol_name} || podman volume create {vol_name}")
382+
log.debug(f"podman volume inspect {vol_name} || podman volume create {vol_name}")
391383
# TODO: might move to using "volume list"
392384
# podman volume list --format '{{.Name}}\t{{.MountPoint}}' \
393385
# -f 'label=io.podman.compose.project=HERE'
@@ -563,7 +555,7 @@ def get_secret_args(compose, cnt, secret):
563555
volume_ref = ["--volume", f"{source_file}:{dest_file}:ro,rprivate,rbind"]
564556
if uid or gid or mode:
565557
sec = target if target else secret_name
566-
log(
558+
log.warn(
567559
f'WARNING: Service {cnt["_service"]} uses secret "{sec}" with uid, gid, or mode.'
568560
+ " These fields are not supported by this implementation of the Compose file"
569561
)
@@ -594,7 +586,7 @@ def get_secret_args(compose, cnt, secret):
594586
if target and target != secret_name:
595587
raise ValueError(err_str.format(target, secret_name))
596588
if target:
597-
log(
589+
log.warn(
598590
'WARNING: Service "{}" uses target: "{}" for secret: "{}".'.format(
599591
cnt["_service"], target, secret_name
600592
)
@@ -778,7 +770,7 @@ def get_net_args(compose, cnt):
778770
elif net.startswith("bridge"):
779771
is_bridge = True
780772
else:
781-
print(f"unknown network_mode [{net}]")
773+
log.fatal(f"unknown network_mode [{net}]")
782774
sys.exit(1)
783775
else:
784776
is_bridge = True
@@ -1154,7 +1146,7 @@ async def output(self, podman_args, cmd="", cmd_args=None):
11541146
cmd_args = cmd_args or []
11551147
xargs = self.compose.get_podman_args(cmd) if cmd else []
11561148
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
1157-
log(cmd_ls)
1149+
log.info(str(cmd_ls))
11581150
p = await asyncio.subprocess.create_subprocess_exec(
11591151
*cmd_ls, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
11601152
)
@@ -1174,7 +1166,7 @@ def exec(
11741166
cmd_args = list(map(str, cmd_args or []))
11751167
xargs = self.compose.get_podman_args(cmd) if cmd else []
11761168
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
1177-
log(" ".join([str(i) for i in cmd_ls]))
1169+
log.info(" ".join([str(i) for i in cmd_ls]))
11781170
os.execlp(self.podman_path, *cmd_ls)
11791171

11801172
async def run(
@@ -1191,7 +1183,7 @@ async def run(
11911183
cmd_args = list(map(str, cmd_args or []))
11921184
xargs = self.compose.get_podman_args(cmd) if cmd else []
11931185
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
1194-
log(" ".join([str(i) for i in cmd_ls]))
1186+
log.info(" ".join([str(i) for i in cmd_ls]))
11951187
if self.dry_run:
11961188
return None
11971189

@@ -1225,16 +1217,16 @@ async def format_out(stdout):
12251217
try:
12261218
exit_code = await p.wait()
12271219
except asyncio.CancelledError:
1228-
log("Sending termination signal")
1220+
log.info("Sending termination signal")
12291221
p.terminate()
12301222
try:
12311223
exit_code = await wait_with_timeout(p.wait(), 10)
12321224
except TimeoutError:
1233-
log("container did not shut down after 10 seconds, killing")
1225+
log.warning("container did not shut down after 10 seconds, killing")
12341226
p.kill()
12351227
exit_code = await p.wait()
12361228

1237-
log(f"exit code: {exit_code}")
1229+
log.info(f"exit code: {exit_code}")
12381230
return exit_code
12391231

12401232
async def volume_ls(self, proj=None):
@@ -1482,7 +1474,7 @@ def assert_services(self, services):
14821474
missing = given - self.all_services
14831475
if missing:
14841476
missing_csv = ",".join(missing)
1485-
log(f"missing services [{missing_csv}]")
1477+
log.warn(f"missing services [{missing_csv}]")
14861478
sys.exit(1)
14871479

14881480
def get_podman_args(self, cmd):
@@ -1496,7 +1488,7 @@ def get_podman_args(self, cmd):
14961488
return xargs
14971489

14981490
async def run(self):
1499-
log("podman-compose version: " + __version__)
1491+
log.info("podman-compose version: " + __version__)
15001492
args = self._parse_args()
15011493
podman_path = args.podman_path
15021494
if podman_path != "podman":
@@ -1505,7 +1497,7 @@ async def run(self):
15051497
else:
15061498
# this also works if podman hasn't been installed now
15071499
if args.dry_run is False:
1508-
log(f"Binary {podman_path} has not been found.")
1500+
log.fatal(f"Binary {podman_path} has not been found.")
15091501
sys.exit(1)
15101502
self.podman = Podman(self, podman_path, args.dry_run, asyncio.Semaphore(args.parallel))
15111503

@@ -1519,9 +1511,9 @@ async def run(self):
15191511
except subprocess.CalledProcessError:
15201512
self.podman_version = None
15211513
if not self.podman_version:
1522-
log("it seems that you do not have `podman` installed")
1514+
log.fatal("it seems that you do not have `podman` installed")
15231515
sys.exit(1)
1524-
log("using podman version: " + self.podman_version)
1516+
log.info("using podman version: " + self.podman_version)
15251517
cmd_name = args.command
15261518
compose_required = cmd_name != "version" and (
15271519
cmd_name != "systemd" or args.action != "create-unit"
@@ -1549,15 +1541,15 @@ def _parse_compose_file(self):
15491541
args.file = list(filter(os.path.exists, default_ls))
15501542
files = args.file
15511543
if not files:
1552-
log(
1544+
log.fatal(
15531545
"no compose.yaml, docker-compose.yml or container-compose.yml file found, "
15541546
"pass files with -f"
15551547
)
15561548
sys.exit(-1)
15571549
ex = map(os.path.exists, files)
15581550
missing = [fn0 for ex0, fn0 in zip(ex, files) if not ex0]
15591551
if missing:
1560-
log("missing files: ", missing)
1552+
log.fatal("missing files: %s", missing)
15611553
sys.exit(1)
15621554
# make absolute
15631555
relative_files = files
@@ -1635,7 +1627,7 @@ def _parse_compose_file(self):
16351627
compose["_dirname"] = dirname
16361628
# debug mode
16371629
if len(files) > 1:
1638-
log(" ** merged:\n", json.dumps(compose, indent=2))
1630+
log.debug(" ** merged:\n%s", json.dumps(compose, indent=2))
16391631
# ver = compose.get('version', None)
16401632

16411633
if not project_name:
@@ -1656,7 +1648,7 @@ def _parse_compose_file(self):
16561648
services = compose.get("services", None)
16571649
if services is None:
16581650
services = {}
1659-
log("WARNING: No services defined")
1651+
log.warn("WARNING: No services defined")
16601652
# include services with no profile defined or the selected profiles
16611653
services = self._resolve_profiles(services, set(args.profile))
16621654

@@ -1689,7 +1681,7 @@ def _parse_compose_file(self):
16891681
unused_nets = given_nets - allnets - set(["default"])
16901682
if len(unused_nets):
16911683
unused_nets_str = ",".join(unused_nets)
1692-
log(f"WARNING: unused networks: {unused_nets_str}")
1684+
log.warn(f"WARNING: unused networks: {unused_nets_str}")
16931685
if len(missing_nets):
16941686
missing_nets_str = ",".join(missing_nets)
16951687
raise RuntimeError(f"missing networks: {missing_nets_str}")
@@ -1800,6 +1792,8 @@ def _parse_args(self):
18001792
if not self.global_args.command or self.global_args.command == "help":
18011793
parser.print_help()
18021794
sys.exit(-1)
1795+
1796+
logging.basicConfig(level=('DEBUG' if self.global_args.verbose else 'WARN'))
18031797
return self.global_args
18041798

18051799
@staticmethod
@@ -1887,6 +1881,11 @@ def _init_global_parser(parser):
18871881
parser.add_argument(
18881882
"--parallel", type=int, default=os.environ.get("COMPOSE_PARALLEL_LIMIT", sys.maxsize)
18891883
)
1884+
parser.add_argument(
1885+
"--verbose",
1886+
help="Print debugging output",
1887+
action="store_true",
1888+
)
18901889

18911890

18921891
podman_compose = PodmanCompose()
@@ -1982,15 +1981,15 @@ async def compose_systemd(compose, args):
19821981
proj_name = compose.project_name
19831982
fn = os.path.expanduser(f"~/{stacks_dir}/{proj_name}.env")
19841983
os.makedirs(os.path.dirname(fn), exist_ok=True)
1985-
print(f"writing [{fn}]: ...")
1984+
log.debug(f"writing [{fn}]: ...")
19861985
with open(fn, "w", encoding="utf-8") as f:
19871986
for k, v in compose.environ.items():
19881987
if k.startswith("COMPOSE_") or k.startswith("PODMAN_"):
19891988
f.write(f"{k}={v}\n")
1990-
print(f"writing [{fn}]: done.")
1991-
print("\n\ncreating the pod without starting it: ...\n\n")
1989+
log.debug(f"writing [{fn}]: done.")
1990+
log.info("\n\ncreating the pod without starting it: ...\n\n")
19921991
process = await asyncio.subprocess.create_subprocess_exec(script, ["up", "--no-start"])
1993-
print("\nfinal exit code is ", process)
1992+
log.info("\nfinal exit code is ", process)
19941993
username = getpass.getuser()
19951994
print(
19961995
f"""
@@ -2037,18 +2036,18 @@ async def compose_systemd(compose, args):
20372036
WantedBy=default.target
20382037
"""
20392038
if os.access(os.path.dirname(fn), os.W_OK):
2040-
print(f"writing [{fn}]: ...")
2039+
log.debug(f"writing [{fn}]: ...")
20412040
with open(fn, "w", encoding="utf-8") as f:
20422041
f.write(out)
2043-
print(f"writing [{fn}]: done.")
2042+
log.debug(f"writing [{fn}]: done.")
20442043
print(
20452044
"""
20462045
while in your project type `podman-compose systemd -a register`
20472046
"""
20482047
)
20492048
else:
20502049
print(out)
2051-
log(f"Could not write to [{fn}], use 'sudo'")
2050+
log.warn(f"Could not write to [{fn}], use 'sudo'")
20522051

20532052

20542053
@cmd_run(podman_compose, "pull", "pull stack images")
@@ -2188,7 +2187,7 @@ def get_excluded(compose, args):
21882187
for service in args.services:
21892188
excluded -= compose.services[service]["_deps"]
21902189
excluded.discard(service)
2191-
log("** excluding: ", excluded)
2190+
log.debug("** excluding: %s", excluded)
21922191
return excluded
21932192

21942193

@@ -2221,18 +2220,18 @@ async def compose_up(compose: PodmanCompose, args):
22212220
)
22222221
diff_hashes = [i for i in hashes if i and i != compose.yaml_hash]
22232222
if args.force_recreate or len(diff_hashes):
2224-
log("recreating: ...")
2223+
log.info("recreating: ...")
22252224
down_args = argparse.Namespace(**dict(args.__dict__, volumes=False))
22262225
await compose.commands["down"](compose, down_args)
2227-
log("recreating: done\n\n")
2226+
log.info("recreating: done\n\n")
22282227
# args.no_recreate disables check for changes (which is not implemented)
22292228

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

22322231
await create_pods(compose, args)
22332232
for cnt in compose.containers:
22342233
if cnt["_service"] in excluded:
2235-
log("** skipping: ", cnt["name"])
2234+
log.debug("** skipping: %s", cnt["name"])
22362235
continue
22372236
podman_args = await container_to_args(compose, cnt, detached=args.detach)
22382237
subproc = await compose.podman.run([], podman_command, podman_args)
@@ -2264,7 +2263,7 @@ async def compose_up(compose: PodmanCompose, args):
22642263
space_suffix = " " * (max_service_length - len(cnt["_service"]) + 1)
22652264
log_formatter = "{}[{}]{}|\x1b[0m".format(color, cnt["_service"], space_suffix)
22662265
if cnt["_service"] in excluded:
2267-
log("** skipping: ", cnt["name"])
2266+
log.debug("** skipping: %s", cnt["name"])
22682267
continue
22692268

22702269
tasks.add(
@@ -2368,7 +2367,7 @@ async def compose_down(compose, args):
23682367
if cnt["_service"] not in excluded:
23692368
continue
23702369
vol_names_to_keep.update(get_volume_names(compose, cnt))
2371-
log("keep", vol_names_to_keep)
2370+
log.debug("keep", vol_names_to_keep)
23722371
for volume_name in await compose.podman.volume_ls():
23732372
if volume_name in vol_names_to_keep:
23742373
continue
@@ -2643,7 +2642,7 @@ async def compose_unpause(compose, args):
26432642
async def compose_kill(compose, args):
26442643
# to ensure that the user did not execute the command by mistake
26452644
if not args.services and not args.all:
2646-
print(
2645+
log.fatal(
26472646
"Error: you must provide at least one service name or use (--all) to kill all services"
26482647
)
26492648
sys.exit()

0 commit comments

Comments
 (0)