mirror of
https://github.com/containers/podman-compose.git
synced 2025-04-01 19:57:29 +02:00
FIXES #380: output to stderr
This commit is contained in:
parent
30051c2f5b
commit
7ad377557d
@ -7,8 +7,6 @@
|
|||||||
# https://docs.docker.com/compose/django/
|
# https://docs.docker.com/compose/django/
|
||||||
# https://docs.docker.com/compose/wordpress/
|
# https://docs.docker.com/compose/wordpress/
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import argparse
|
import argparse
|
||||||
@ -37,13 +35,8 @@ from dotenv import dotenv_values
|
|||||||
|
|
||||||
__version__ = '1.0.3'
|
__version__ = '1.0.3'
|
||||||
|
|
||||||
PY3 = sys.version_info[0] == 3
|
|
||||||
if PY3:
|
|
||||||
basestring = str
|
|
||||||
|
|
||||||
# helper functions
|
# helper functions
|
||||||
|
is_str = lambda s: isinstance(s, str)
|
||||||
is_str = lambda s: isinstance(s, basestring)
|
|
||||||
is_dict = lambda d: isinstance(d, dict)
|
is_dict = lambda d: isinstance(d, dict)
|
||||||
is_list = lambda l: not is_str(l) and not is_dict(l) and hasattr(l, "__iter__")
|
is_list = lambda l: not is_str(l) and not is_dict(l) and hasattr(l, "__iter__")
|
||||||
# identity filter
|
# identity filter
|
||||||
@ -67,6 +60,11 @@ def try_float(i, fallback=None):
|
|||||||
pass
|
pass
|
||||||
return fallback
|
return fallback
|
||||||
|
|
||||||
|
def log(*msgs, sep=" ", end="\n"):
|
||||||
|
line = (sep.join(["{}".format(msg) for msg in msgs]))+end
|
||||||
|
sys.stderr.write(line)
|
||||||
|
sys.stderr.flush()
|
||||||
|
|
||||||
dir_re = re.compile("^[~/\.]")
|
dir_re = re.compile("^[~/\.]")
|
||||||
propagation_re = re.compile("^(?:z|Z|O|U|r?shared|r?slave|r?private|r?unbindable|r?bind|(?:no)?(?:exec|dev|suid))$")
|
propagation_re = re.compile("^(?:z|Z|O|U|r?shared|r?slave|r?private|r?unbindable|r?bind|(?:no)?(?:exec|dev|suid))$")
|
||||||
norm_re = re.compile('[^-_a-z0-9]')
|
norm_re = re.compile('[^-_a-z0-9]')
|
||||||
@ -290,7 +288,7 @@ def assert_volume(compose, mount_dict):
|
|||||||
if mount_dict["type"] != "volume" or not vol or vol.get("external", None) or not vol.get("name", None): return
|
if mount_dict["type"] != "volume" or not vol or vol.get("external", None) or not vol.get("name", None): return
|
||||||
proj_name = compose.project_name
|
proj_name = compose.project_name
|
||||||
vol_name = vol["name"]
|
vol_name = vol["name"]
|
||||||
print("podman volume inspect {vol_name} || podman volume create {vol_name}".format(vol_name=vol_name))
|
log("podman volume inspect {vol_name} || podman volume create {vol_name}".format(vol_name=vol_name))
|
||||||
# TODO: might move to using "volume list"
|
# TODO: might move to using "volume list"
|
||||||
# podman volume list --format '{{.Name}}\t{{.MountPoint}}' -f 'label=io.podman.compose.project=HERE'
|
# podman volume list --format '{{.Name}}\t{{.MountPoint}}' -f 'label=io.podman.compose.project=HERE'
|
||||||
try: out = compose.podman.output([], "volume", ["inspect", vol_name]).decode('utf-8')
|
try: out = compose.podman.output([], "volume", ["inspect", vol_name]).decode('utf-8')
|
||||||
@ -449,7 +447,7 @@ def get_secret_args(compose, cnt, secret):
|
|||||||
'--volume', '{}:{}:ro,rprivate,rbind'.format(source_file, dest_file)
|
'--volume', '{}:{}:ro,rprivate,rbind'.format(source_file, dest_file)
|
||||||
]
|
]
|
||||||
if uid or gid or mode:
|
if uid or gid or mode:
|
||||||
print(
|
log(
|
||||||
'WARNING: Service "{}" uses secret "{}" with uid, gid, or mode.'
|
'WARNING: Service "{}" uses secret "{}" with uid, gid, or mode.'
|
||||||
.format(cnt['_service'], target if target else secret_name)
|
.format(cnt['_service'], target if target else secret_name)
|
||||||
+ ' These fields are not supported by this implementation of the Compose file'
|
+ ' These fields are not supported by this implementation of the Compose file'
|
||||||
@ -478,7 +476,7 @@ def get_secret_args(compose, cnt, secret):
|
|||||||
elif target and target != secret_name:
|
elif target and target != secret_name:
|
||||||
raise ValueError(err_str.format(target, secret_name))
|
raise ValueError(err_str.format(target, secret_name))
|
||||||
elif target:
|
elif target:
|
||||||
print('WARNING: Service "{}" uses target: "{}" for secret: "{}".'
|
log('WARNING: Service "{}" uses target: "{}" for secret: "{}".'
|
||||||
.format(cnt['_service'], target, secret_name)
|
.format(cnt['_service'], target, secret_name)
|
||||||
+ ' That is un-supported and a no-op and is ignored.')
|
+ ' That is un-supported and a no-op and is ignored.')
|
||||||
return [ '--secret', '{}{}'.format(secret_name, secret_opts) ]
|
return [ '--secret', '{}{}'.format(secret_name, secret_opts) ]
|
||||||
@ -816,7 +814,7 @@ class Podman:
|
|||||||
cmd_args = cmd_args or []
|
cmd_args = cmd_args or []
|
||||||
xargs = self.compose.get_podman_args(cmd) if cmd else []
|
xargs = self.compose.get_podman_args(cmd) if cmd else []
|
||||||
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
|
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
|
||||||
print(cmd_ls)
|
log(cmd_ls)
|
||||||
return subprocess.check_output(cmd_ls)
|
return subprocess.check_output(cmd_ls)
|
||||||
|
|
||||||
def run(self, podman_args, cmd='', cmd_args=None, wait=True, sleep=1, obj=None):
|
def run(self, podman_args, cmd='', cmd_args=None, wait=True, sleep=1, obj=None):
|
||||||
@ -825,14 +823,14 @@ class Podman:
|
|||||||
cmd_args = list(map(str, cmd_args or []))
|
cmd_args = list(map(str, cmd_args or []))
|
||||||
xargs = self.compose.get_podman_args(cmd) if cmd else []
|
xargs = self.compose.get_podman_args(cmd) if cmd else []
|
||||||
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
|
cmd_ls = [self.podman_path, *podman_args, cmd] + xargs + cmd_args
|
||||||
print(" ".join([str(i) for i in cmd_ls]))
|
log(" ".join([str(i) for i in cmd_ls]))
|
||||||
if self.dry_run:
|
if self.dry_run:
|
||||||
return None
|
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)
|
# 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)
|
||||||
p = subprocess.Popen(cmd_ls)
|
p = subprocess.Popen(cmd_ls)
|
||||||
if wait:
|
if wait:
|
||||||
exit_code = p.wait()
|
exit_code = p.wait()
|
||||||
print("exit code:", exit_code)
|
log("exit code:", exit_code)
|
||||||
if obj is not None:
|
if obj is not None:
|
||||||
obj.exit_code = exit_code
|
obj.exit_code = exit_code
|
||||||
|
|
||||||
@ -1016,7 +1014,7 @@ class PodmanCompose:
|
|||||||
if not self.podman_version:
|
if not self.podman_version:
|
||||||
sys.stderr.write("it seems that you do not have `podman` installed\n")
|
sys.stderr.write("it seems that you do not have `podman` installed\n")
|
||||||
exit(1)
|
exit(1)
|
||||||
print("using podman version: "+self.podman_version)
|
log("using podman version: "+self.podman_version)
|
||||||
cmd_name = args.command
|
cmd_name = args.command
|
||||||
if (cmd_name != "version"):
|
if (cmd_name != "version"):
|
||||||
self._parse_compose_file()
|
self._parse_compose_file()
|
||||||
@ -1036,12 +1034,12 @@ class PodmanCompose:
|
|||||||
args.file = list(filter(os.path.exists, default_ls))
|
args.file = list(filter(os.path.exists, default_ls))
|
||||||
files = args.file
|
files = args.file
|
||||||
if not files:
|
if not files:
|
||||||
print("no compose.yaml, docker-compose.yml or container-compose.yml file found, pass files with -f")
|
log("no compose.yaml, docker-compose.yml or container-compose.yml file found, pass files with -f")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
ex = map(os.path.exists, files)
|
ex = map(os.path.exists, files)
|
||||||
missing = [ fn0 for ex0, fn0 in zip(ex, files) if not ex0 ]
|
missing = [ fn0 for ex0, fn0 in zip(ex, files) if not ex0 ]
|
||||||
if missing:
|
if missing:
|
||||||
print("missing files: ", missing)
|
log("missing files: ", missing)
|
||||||
exit(1)
|
exit(1)
|
||||||
# make absolute
|
# make absolute
|
||||||
relative_files = files
|
relative_files = files
|
||||||
@ -1081,22 +1079,22 @@ class PodmanCompose:
|
|||||||
for filename in files:
|
for filename in files:
|
||||||
with open(filename, 'r') as f:
|
with open(filename, 'r') as f:
|
||||||
content = yaml.safe_load(f)
|
content = yaml.safe_load(f)
|
||||||
#print(filename, json.dumps(content, indent = 2))
|
#log(filename, json.dumps(content, indent = 2))
|
||||||
if not isinstance(content, dict):
|
if not isinstance(content, dict):
|
||||||
sys.stderr.write("Compose file does not contain a top level object: %s\n"%filename)
|
sys.stderr.write("Compose file does not contain a top level object: %s\n"%filename)
|
||||||
exit(1)
|
exit(1)
|
||||||
content = normalize(content)
|
content = normalize(content)
|
||||||
#print(filename, json.dumps(content, indent = 2))
|
#log(filename, json.dumps(content, indent = 2))
|
||||||
content = rec_subs(content, self.environ)
|
content = rec_subs(content, self.environ)
|
||||||
rec_merge(compose, content)
|
rec_merge(compose, content)
|
||||||
# debug mode
|
# debug mode
|
||||||
if len(files)>1:
|
if len(files)>1:
|
||||||
print(" ** merged:\n", json.dumps(compose, indent = 2))
|
log(" ** merged:\n", json.dumps(compose, indent = 2))
|
||||||
ver = compose.get('version', None)
|
ver = compose.get('version', None)
|
||||||
services = compose.get('services', None)
|
services = compose.get('services', None)
|
||||||
if services is None:
|
if services is None:
|
||||||
services = {}
|
services = {}
|
||||||
print("WARNING: No services defined")
|
log("WARNING: No services defined")
|
||||||
|
|
||||||
# NOTE: maybe add "extends.service" to _deps at this stage
|
# NOTE: maybe add "extends.service" to _deps at this stage
|
||||||
flat_deps(services, with_extends=True)
|
flat_deps(services, with_extends=True)
|
||||||
@ -1157,7 +1155,7 @@ class PodmanCompose:
|
|||||||
else:
|
else:
|
||||||
name = name0
|
name = name0
|
||||||
container_names_by_service[service_name].append(name)
|
container_names_by_service[service_name].append(name)
|
||||||
# print(service_name,service_desc)
|
# log(service_name,service_desc)
|
||||||
cnt = dict(name=name, num=num,
|
cnt = dict(name=name, num=num,
|
||||||
service_name=service_name, **service_desc)
|
service_name=service_name, **service_desc)
|
||||||
if 'image' not in cnt:
|
if 'image' not in cnt:
|
||||||
@ -1178,10 +1176,10 @@ class PodmanCompose:
|
|||||||
given_containers.append(cnt)
|
given_containers.append(cnt)
|
||||||
self.container_names_by_service = container_names_by_service
|
self.container_names_by_service = container_names_by_service
|
||||||
container_by_name = dict([(c["name"], c) for c in given_containers])
|
container_by_name = dict([(c["name"], c) for c in given_containers])
|
||||||
#print("deps:", [(c["name"], c["_deps"]) for c in given_containers])
|
#log("deps:", [(c["name"], c["_deps"]) for c in given_containers])
|
||||||
given_containers = list(container_by_name.values())
|
given_containers = list(container_by_name.values())
|
||||||
given_containers.sort(key=lambda c: len(c.get('_deps', None) or []))
|
given_containers.sort(key=lambda c: len(c.get('_deps', None) or []))
|
||||||
#print("sorted:", [c["name"] for c in given_containers])
|
#log("sorted:", [c["name"] for c in given_containers])
|
||||||
pods, containers = tr_identity(project_name, given_containers)
|
pods, containers = tr_identity(project_name, given_containers)
|
||||||
self.pods = pods
|
self.pods = pods
|
||||||
self.containers = containers
|
self.containers = containers
|
||||||
@ -1271,7 +1269,7 @@ class cmd_parse:
|
|||||||
|
|
||||||
@cmd_run(podman_compose, 'version', 'show version')
|
@cmd_run(podman_compose, 'version', 'show version')
|
||||||
def compose_version(compose, args):
|
def compose_version(compose, args):
|
||||||
print("podman-composer version ", __version__)
|
log("podman-composer version ", __version__)
|
||||||
compose.podman.run(["--version"], "", [], sleep=0)
|
compose.podman.run(["--version"], "", [], sleep=0)
|
||||||
|
|
||||||
def is_local(container: dict) -> bool:
|
def is_local(container: dict) -> bool:
|
||||||
@ -1376,7 +1374,7 @@ def up_specific(compose, args):
|
|||||||
for service in args.services:
|
for service in args.services:
|
||||||
deps.extend([])
|
deps.extend([])
|
||||||
# args.always_recreate_deps
|
# args.always_recreate_deps
|
||||||
print("services", args.services)
|
log("services", args.services)
|
||||||
raise NotImplementedError("starting specific services is not yet implemented")
|
raise NotImplementedError("starting specific services is not yet implemented")
|
||||||
|
|
||||||
def get_excluded(compose, args):
|
def get_excluded(compose, args):
|
||||||
@ -1386,7 +1384,7 @@ def get_excluded(compose, args):
|
|||||||
for service in args.services:
|
for service in args.services:
|
||||||
excluded-= compose.services[service]['_deps']
|
excluded-= compose.services[service]['_deps']
|
||||||
excluded.discard(service)
|
excluded.discard(service)
|
||||||
print("** excluding: ", excluded)
|
log("** excluding: ", excluded)
|
||||||
return excluded
|
return excluded
|
||||||
|
|
||||||
@cmd_run(podman_compose, 'up', 'Create and start the entire stack or some of its services')
|
@cmd_run(podman_compose, 'up', 'Create and start the entire stack or some of its services')
|
||||||
@ -1410,7 +1408,7 @@ def compose_up(compose, args):
|
|||||||
create_pods(compose, args)
|
create_pods(compose, args)
|
||||||
for cnt in compose.containers:
|
for cnt in compose.containers:
|
||||||
if cnt["_service"] in excluded:
|
if cnt["_service"] in excluded:
|
||||||
print("** skipping: ", cnt['name'])
|
log("** skipping: ", cnt['name'])
|
||||||
continue
|
continue
|
||||||
podman_args = container_to_args(compose, cnt, detached=args.detach)
|
podman_args = container_to_args(compose, cnt, detached=args.detach)
|
||||||
subproc = compose.podman.run([], podman_command, podman_args)
|
subproc = compose.podman.run([], podman_command, podman_args)
|
||||||
@ -1428,7 +1426,7 @@ def compose_up(compose, args):
|
|||||||
threads = []
|
threads = []
|
||||||
for cnt in compose.containers:
|
for cnt in compose.containers:
|
||||||
if cnt["_service"] in excluded:
|
if cnt["_service"] in excluded:
|
||||||
print("** skipping: ", cnt['name'])
|
log("** skipping: ", cnt['name'])
|
||||||
continue
|
continue
|
||||||
# TODO: remove sleep from podman.run
|
# TODO: remove sleep from podman.run
|
||||||
obj = compose if exit_code_from == cnt['_service'] else None
|
obj = compose if exit_code_from == cnt['_service'] else None
|
||||||
@ -1483,7 +1481,7 @@ def compose_down(compose, args):
|
|||||||
for cnt in containers:
|
for cnt in containers:
|
||||||
if cnt["_service"] not in excluded: continue
|
if cnt["_service"] not in excluded: continue
|
||||||
vol_names_to_keep.update(get_volume_names(compose, cnt))
|
vol_names_to_keep.update(get_volume_names(compose, cnt))
|
||||||
print("keep", vol_names_to_keep)
|
log("keep", vol_names_to_keep)
|
||||||
volume_names = [vol["Name"] for vol in compose.podman.volume_inspect_proj()]
|
volume_names = [vol["Name"] for vol in compose.podman.volume_inspect_proj()]
|
||||||
for volume_name in volume_names:
|
for volume_name in volume_names:
|
||||||
if volume_name in vol_names_to_keep: continue
|
if volume_name in vol_names_to_keep: continue
|
||||||
|
Loading…
Reference in New Issue
Block a user