Skip to content

Commit 60137eb

Browse files
authored
Merge pull request #741 from maurerle/quiet-output
Output: use logging, remove verbose output by default
2 parents a7a993f + da520e2 commit 60137eb

File tree

1 file changed

+56
-54
lines changed

1 file changed

+56
-54
lines changed

podman_compose.py

Lines changed: 56 additions & 54 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("podman volume inspect %s || podman volume create %s", vol_name, 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,9 +555,11 @@ 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(
567-
f'WARNING: Service {cnt["_service"]} uses secret "{sec}" with uid, gid, or mode.'
568-
+ " These fields are not supported by this implementation of the Compose file"
558+
log.warning(
559+
"WARNING: Service %s uses secret %s with uid, gid, or mode."
560+
+ " These fields are not supported by this implementation of the Compose file",
561+
cnt["_service"],
562+
sec,
569563
)
570564
return volume_ref
571565
# v3.5 and up added external flag, earlier the spec
@@ -594,11 +588,12 @@ def get_secret_args(compose, cnt, secret):
594588
if target and target != secret_name:
595589
raise ValueError(err_str.format(target, secret_name))
596590
if target:
597-
log(
598-
'WARNING: Service "{}" uses target: "{}" for secret: "{}".'.format(
599-
cnt["_service"], target, secret_name
600-
)
601-
+ " That is un-supported and a no-op and is ignored."
591+
log.warning(
592+
'WARNING: Service "%s" uses target: "%s" for secret: "%s".'
593+
+ " That is un-supported and a no-op and is ignored.",
594+
cnt["_service"],
595+
target,
596+
secret_name,
602597
)
603598
return ["--secret", "{}{}".format(secret_name, secret_opts)]
604599

@@ -778,7 +773,7 @@ def get_net_args(compose, cnt):
778773
elif net.startswith("bridge"):
779774
is_bridge = True
780775
else:
781-
print(f"unknown network_mode [{net}]")
776+
log.fatal("unknown network_mode [%s]", net)
782777
sys.exit(1)
783778
else:
784779
is_bridge = True
@@ -921,10 +916,10 @@ async def container_to_args(compose, cnt, detached=True):
921916
await assert_cnt_nets(compose, cnt)
922917
podman_args.extend(get_net_args(compose, cnt))
923918

924-
logging = cnt.get("logging", None)
925-
if logging is not None:
926-
podman_args.append(f'--log-driver={logging.get("driver", "k8s-file")}')
927-
log_opts = logging.get("options") or {}
919+
log_config = cnt.get("logging", None)
920+
if log_config is not None:
921+
podman_args.append(f'--log-driver={log_config.get("driver", "k8s-file")}')
922+
log_opts = log_config.get("options") or {}
928923
podman_args += [f"--log-opt={name}={value}" for name, value in log_opts.items()]
929924
for secret in cnt.get("secrets", []):
930925
podman_args.extend(get_secret_args(compose, cnt, secret))
@@ -1154,7 +1149,7 @@ async def output(self, podman_args, cmd="", cmd_args=None):
11541149
cmd_args = cmd_args or []
11551150
xargs = self.compose.get_podman_args(cmd) if cmd else []
11561151
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
1157-
log(cmd_ls)
1152+
log.info(str(cmd_ls))
11581153
p = await asyncio.subprocess.create_subprocess_exec(
11591154
*cmd_ls, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
11601155
)
@@ -1174,7 +1169,7 @@ def exec(
11741169
cmd_args = list(map(str, cmd_args or []))
11751170
xargs = self.compose.get_podman_args(cmd) if cmd else []
11761171
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
1177-
log(" ".join([str(i) for i in cmd_ls]))
1172+
log.info(" ".join([str(i) for i in cmd_ls]))
11781173
os.execlp(self.podman_path, *cmd_ls)
11791174

11801175
async def run(
@@ -1191,7 +1186,7 @@ async def run(
11911186
cmd_args = list(map(str, cmd_args or []))
11921187
xargs = self.compose.get_podman_args(cmd) if cmd else []
11931188
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
1194-
log(" ".join([str(i) for i in cmd_ls]))
1189+
log.info(" ".join([str(i) for i in cmd_ls]))
11951190
if self.dry_run:
11961191
return None
11971192

@@ -1225,16 +1220,16 @@ async def format_out(stdout):
12251220
try:
12261221
exit_code = await p.wait()
12271222
except asyncio.CancelledError:
1228-
log("Sending termination signal")
1223+
log.info("Sending termination signal")
12291224
p.terminate()
12301225
try:
12311226
exit_code = await wait_with_timeout(p.wait(), 10)
12321227
except TimeoutError:
1233-
log("container did not shut down after 10 seconds, killing")
1228+
log.warning("container did not shut down after 10 seconds, killing")
12341229
p.kill()
12351230
exit_code = await p.wait()
12361231

1237-
log(f"exit code: {exit_code}")
1232+
log.info("exit code: %s", exit_code)
12381233
return exit_code
12391234

12401235
async def volume_ls(self, proj=None):
@@ -1482,7 +1477,7 @@ def assert_services(self, services):
14821477
missing = given - self.all_services
14831478
if missing:
14841479
missing_csv = ",".join(missing)
1485-
log(f"missing services [{missing_csv}]")
1480+
log.warning("missing services [%s]", missing_csv)
14861481
sys.exit(1)
14871482

14881483
def get_podman_args(self, cmd):
@@ -1496,7 +1491,7 @@ def get_podman_args(self, cmd):
14961491
return xargs
14971492

14981493
async def run(self):
1499-
log("podman-compose version: " + __version__)
1494+
log.info("podman-compose version: %s", __version__)
15001495
args = self._parse_args()
15011496
podman_path = args.podman_path
15021497
if podman_path != "podman":
@@ -1505,7 +1500,7 @@ async def run(self):
15051500
else:
15061501
# this also works if podman hasn't been installed now
15071502
if args.dry_run is False:
1508-
log(f"Binary {podman_path} has not been found.")
1503+
log.fatal("Binary %s has not been found.", podman_path)
15091504
sys.exit(1)
15101505
self.podman = Podman(self, podman_path, args.dry_run, asyncio.Semaphore(args.parallel))
15111506

@@ -1519,9 +1514,9 @@ async def run(self):
15191514
except subprocess.CalledProcessError:
15201515
self.podman_version = None
15211516
if not self.podman_version:
1522-
log("it seems that you do not have `podman` installed")
1517+
log.fatal("it seems that you do not have `podman` installed")
15231518
sys.exit(1)
1524-
log("using podman version: " + self.podman_version)
1519+
log.info("using podman version: %s", self.podman_version)
15251520
cmd_name = args.command
15261521
compose_required = cmd_name != "version" and (
15271522
cmd_name != "systemd" or args.action != "create-unit"
@@ -1549,15 +1544,15 @@ def _parse_compose_file(self):
15491544
args.file = list(filter(os.path.exists, default_ls))
15501545
files = args.file
15511546
if not files:
1552-
log(
1547+
log.fatal(
15531548
"no compose.yaml, docker-compose.yml or container-compose.yml file found, "
15541549
"pass files with -f"
15551550
)
15561551
sys.exit(-1)
15571552
ex = map(os.path.exists, files)
15581553
missing = [fn0 for ex0, fn0 in zip(ex, files) if not ex0]
15591554
if missing:
1560-
log("missing files: ", missing)
1555+
log.fatal("missing files: %s", missing)
15611556
sys.exit(1)
15621557
# make absolute
15631558
relative_files = files
@@ -1635,7 +1630,7 @@ def _parse_compose_file(self):
16351630
compose["_dirname"] = dirname
16361631
# debug mode
16371632
if len(files) > 1:
1638-
log(" ** merged:\n", json.dumps(compose, indent=2))
1633+
log.debug(" ** merged:\n%s", json.dumps(compose, indent=2))
16391634
# ver = compose.get('version', None)
16401635

16411636
if not project_name:
@@ -1656,7 +1651,7 @@ def _parse_compose_file(self):
16561651
services = compose.get("services", None)
16571652
if services is None:
16581653
services = {}
1659-
log("WARNING: No services defined")
1654+
log.warning("WARNING: No services defined")
16601655
# include services with no profile defined or the selected profiles
16611656
services = self._resolve_profiles(services, set(args.profile))
16621657

@@ -1689,7 +1684,7 @@ def _parse_compose_file(self):
16891684
unused_nets = given_nets - allnets - set(["default"])
16901685
if len(unused_nets):
16911686
unused_nets_str = ",".join(unused_nets)
1692-
log(f"WARNING: unused networks: {unused_nets_str}")
1687+
log.warning("WARNING: unused networks: %s", unused_nets_str)
16931688
if len(missing_nets):
16941689
missing_nets_str = ",".join(missing_nets)
16951690
raise RuntimeError(f"missing networks: {missing_nets_str}")
@@ -1800,6 +1795,8 @@ def _parse_args(self):
18001795
if not self.global_args.command or self.global_args.command == "help":
18011796
parser.print_help()
18021797
sys.exit(-1)
1798+
1799+
logging.basicConfig(level=("DEBUG" if self.global_args.verbose else "WARN"))
18031800
return self.global_args
18041801

18051802
@staticmethod
@@ -1887,6 +1884,11 @@ def _init_global_parser(parser):
18871884
parser.add_argument(
18881885
"--parallel", type=int, default=os.environ.get("COMPOSE_PARALLEL_LIMIT", sys.maxsize)
18891886
)
1887+
parser.add_argument(
1888+
"--verbose",
1889+
help="Print debugging output",
1890+
action="store_true",
1891+
)
18901892

18911893

18921894
podman_compose = PodmanCompose()
@@ -1982,15 +1984,15 @@ async def compose_systemd(compose, args):
19821984
proj_name = compose.project_name
19831985
fn = os.path.expanduser(f"~/{stacks_dir}/{proj_name}.env")
19841986
os.makedirs(os.path.dirname(fn), exist_ok=True)
1985-
print(f"writing [{fn}]: ...")
1987+
log.debug("writing [%s]: ...", fn)
19861988
with open(fn, "w", encoding="utf-8") as f:
19871989
for k, v in compose.environ.items():
19881990
if k.startswith("COMPOSE_") or k.startswith("PODMAN_"):
19891991
f.write(f"{k}={v}\n")
1990-
print(f"writing [{fn}]: done.")
1991-
print("\n\ncreating the pod without starting it: ...\n\n")
1992+
log.debug("writing [%s]: done.", fn)
1993+
log.info("\n\ncreating the pod without starting it: ...\n\n")
19921994
process = await asyncio.subprocess.create_subprocess_exec(script, ["up", "--no-start"])
1993-
print("\nfinal exit code is ", process)
1995+
log.info("\nfinal exit code is ", process)
19941996
username = getpass.getuser()
19951997
print(
19961998
f"""
@@ -2037,18 +2039,18 @@ async def compose_systemd(compose, args):
20372039
WantedBy=default.target
20382040
"""
20392041
if os.access(os.path.dirname(fn), os.W_OK):
2040-
print(f"writing [{fn}]: ...")
2042+
log.debug("writing [%s]: ...", fn)
20412043
with open(fn, "w", encoding="utf-8") as f:
20422044
f.write(out)
2043-
print(f"writing [{fn}]: done.")
2045+
log.debug("writing [%s]: done.", fn)
20442046
print(
20452047
"""
20462048
while in your project type `podman-compose systemd -a register`
20472049
"""
20482050
)
20492051
else:
20502052
print(out)
2051-
log(f"Could not write to [{fn}], use 'sudo'")
2053+
log.warning("Could not write to [%s], use 'sudo'", fn)
20522054

20532055

20542056
@cmd_run(podman_compose, "pull", "pull stack images")
@@ -2188,7 +2190,7 @@ def get_excluded(compose, args):
21882190
for service in args.services:
21892191
excluded -= compose.services[service]["_deps"]
21902192
excluded.discard(service)
2191-
log("** excluding: ", excluded)
2193+
log.debug("** excluding: %s", excluded)
21922194
return excluded
21932195

21942196

@@ -2221,18 +2223,18 @@ async def compose_up(compose: PodmanCompose, args):
22212223
)
22222224
diff_hashes = [i for i in hashes if i and i != compose.yaml_hash]
22232225
if args.force_recreate or len(diff_hashes):
2224-
log("recreating: ...")
2226+
log.info("recreating: ...")
22252227
down_args = argparse.Namespace(**dict(args.__dict__, volumes=False))
22262228
await compose.commands["down"](compose, down_args)
2227-
log("recreating: done\n\n")
2229+
log.info("recreating: done\n\n")
22282230
# args.no_recreate disables check for changes (which is not implemented)
22292231

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

22322234
await create_pods(compose, args)
22332235
for cnt in compose.containers:
22342236
if cnt["_service"] in excluded:
2235-
log("** skipping: ", cnt["name"])
2237+
log.debug("** skipping: %s", cnt["name"])
22362238
continue
22372239
podman_args = await container_to_args(compose, cnt, detached=args.detach)
22382240
subproc = await compose.podman.run([], podman_command, podman_args)
@@ -2264,7 +2266,7 @@ async def compose_up(compose: PodmanCompose, args):
22642266
space_suffix = " " * (max_service_length - len(cnt["_service"]) + 1)
22652267
log_formatter = "{}[{}]{}|\x1b[0m".format(color, cnt["_service"], space_suffix)
22662268
if cnt["_service"] in excluded:
2267-
log("** skipping: ", cnt["name"])
2269+
log.debug("** skipping: %s", cnt["name"])
22682270
continue
22692271

22702272
tasks.add(
@@ -2368,7 +2370,7 @@ async def compose_down(compose, args):
23682370
if cnt["_service"] not in excluded:
23692371
continue
23702372
vol_names_to_keep.update(get_volume_names(compose, cnt))
2371-
log("keep", vol_names_to_keep)
2373+
log.debug("keep %s", vol_names_to_keep)
23722374
for volume_name in await compose.podman.volume_ls():
23732375
if volume_name in vol_names_to_keep:
23742376
continue
@@ -2643,7 +2645,7 @@ async def compose_unpause(compose, args):
26432645
async def compose_kill(compose, args):
26442646
# to ensure that the user did not execute the command by mistake
26452647
if not args.services and not args.all:
2646-
print(
2648+
log.fatal(
26472649
"Error: you must provide at least one service name or use (--all) to kill all services"
26482650
)
26492651
sys.exit()

0 commit comments

Comments
 (0)