Simplified statements to retrieve keys from dictionaries

Signed-off-by: Felix Rubio <felix@kngnt.org>
This commit is contained in:
Felix Rubio 2024-12-01 20:24:40 +01:00 committed by Povilas Kanapickas
parent a67fa0beb5
commit 145ae47c48

View File

@ -205,9 +205,9 @@ def fix_mount_dict(compose, mount_dict, srv_name):
return mount_dict return mount_dict
if mount_dict["type"] == "volume": if mount_dict["type"] == "volume":
vols = compose.vols vols = compose.vols
source = mount_dict.get("source", None) source = mount_dict.get("source")
vol = (vols.get(source, None) or {}) if source else {} vol = (vols.get(source, {}) or {}) if source else {}
name = vol.get("name", None) name = vol.get("name")
mount_dict["_vol"] = vol mount_dict["_vol"] = vol
# handle anonymous or implied volume # handle anonymous or implied volume
if not source: if not source:
@ -218,7 +218,7 @@ def fix_mount_dict(compose, mount_dict, srv_name):
hashlib.sha256(mount_dict["target"].encode("utf-8")).hexdigest(), hashlib.sha256(mount_dict["target"].encode("utf-8")).hexdigest(),
]) ])
elif not name: elif not name:
external = vol.get("external", None) external = vol.get("external")
if isinstance(external, dict): if isinstance(external, dict):
vol["name"] = external.get("name", f"{source}") vol["name"] = external.get("name", f"{source}")
elif external: elif external:
@ -337,8 +337,8 @@ def norm_ulimit(inner_value):
if isinstance(inner_value, dict): if isinstance(inner_value, dict):
if not inner_value.keys() & {"soft", "hard"}: if not inner_value.keys() & {"soft", "hard"}:
raise ValueError("expected at least one soft or hard limit") raise ValueError("expected at least one soft or hard limit")
soft = inner_value.get("soft", inner_value.get("hard", None)) soft = inner_value.get("soft", inner_value.get("hard"))
hard = inner_value.get("hard", inner_value.get("soft", None)) hard = inner_value.get("hard", inner_value.get("soft"))
return f"{soft}:{hard}" return f"{soft}:{hard}"
if is_list(inner_value): if is_list(inner_value):
return norm_ulimit(norm_as_dict(inner_value)) return norm_ulimit(norm_as_dict(inner_value))
@ -384,7 +384,7 @@ async def assert_volume(compose, mount_dict):
inspect volume to get directory inspect volume to get directory
create volume if needed create volume if needed
""" """
vol = mount_dict.get("_vol", None) vol = mount_dict.get("_vol")
if mount_dict["type"] == "bind": if mount_dict["type"] == "bind":
basedir = os.path.realpath(compose.dirname) basedir = os.path.realpath(compose.dirname)
mount_src = mount_dict["source"] mount_src = mount_dict["source"]
@ -395,10 +395,10 @@ async def assert_volume(compose, mount_dict):
except OSError: except OSError:
pass pass
return return
if mount_dict["type"] != "volume" or not vol or not vol.get("name", None): if mount_dict["type"] != "volume" or not vol or not vol.get("name"):
return return
vol_name = vol["name"] vol_name = vol["name"]
is_ext = vol.get("external", None) is_ext = vol.get("external")
log.debug("podman volume inspect %s || podman volume create %s", vol_name, vol_name) log.debug("podman volume inspect %s || podman volume create %s", 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}}' \ # podman volume list --format '{{.Name}}\t{{.MountPoint}}' \
@ -408,7 +408,7 @@ async def assert_volume(compose, mount_dict):
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
if is_ext: if is_ext:
raise RuntimeError(f"External volume [{vol_name}] does not exists") from e raise RuntimeError(f"External volume [{vol_name}] does not exists") from e
labels = vol.get("labels", None) or [] labels = vol.get("labels", [])
args = [ args = [
"create", "create",
"--label", "--label",
@ -418,10 +418,10 @@ async def assert_volume(compose, mount_dict):
] ]
for item in norm_as_list(labels): for item in norm_as_list(labels):
args.extend(["--label", item]) args.extend(["--label", item])
driver = vol.get("driver", None) driver = vol.get("driver")
if driver: if driver:
args.extend(["--driver", driver]) args.extend(["--driver", driver])
driver_opts = vol.get("driver_opts", None) or {} driver_opts = vol.get("driver_opts", {})
for opt, value in driver_opts.items(): for opt, value in driver_opts.items():
args.extend(["--opt", f"{opt}={value}"]) args.extend(["--opt", f"{opt}={value}"])
args.append(vol_name) args.append(vol_name)
@ -430,29 +430,29 @@ async def assert_volume(compose, mount_dict):
def mount_desc_to_mount_args(compose, mount_desc, srv_name, cnt_name): # pylint: disable=unused-argument def mount_desc_to_mount_args(compose, mount_desc, srv_name, cnt_name): # pylint: disable=unused-argument
mount_type = mount_desc.get("type", None) mount_type = mount_desc.get("type")
vol = mount_desc.get("_vol", None) if mount_type == "volume" else None vol = mount_desc.get("_vol") if mount_type == "volume" else None
source = vol["name"] if vol else mount_desc.get("source", None) source = vol["name"] if vol else mount_desc.get("source")
target = mount_desc["target"] target = mount_desc["target"]
opts = [] opts = []
if mount_desc.get(mount_type, None): if mount_desc.get(mount_type, None):
# TODO: we might need to add mount_dict[mount_type]["propagation"] = "z" # TODO: we might need to add mount_dict[mount_type]["propagation"] = "z"
mount_prop = mount_desc.get(mount_type, {}).get("propagation", None) mount_prop = mount_desc.get(mount_type, {}).get("propagation")
if mount_prop: if mount_prop:
opts.append(f"{mount_type}-propagation={mount_prop}") opts.append(f"{mount_type}-propagation={mount_prop}")
if mount_desc.get("read_only", False): if mount_desc.get("read_only", False):
opts.append("ro") opts.append("ro")
if mount_type == "tmpfs": if mount_type == "tmpfs":
tmpfs_opts = mount_desc.get("tmpfs", {}) tmpfs_opts = mount_desc.get("tmpfs", {})
tmpfs_size = tmpfs_opts.get("size", None) tmpfs_size = tmpfs_opts.get("size")
if tmpfs_size: if tmpfs_size:
opts.append(f"tmpfs-size={tmpfs_size}") opts.append(f"tmpfs-size={tmpfs_size}")
tmpfs_mode = tmpfs_opts.get("mode", None) tmpfs_mode = tmpfs_opts.get("mode")
if tmpfs_mode: if tmpfs_mode:
opts.append(f"tmpfs-mode={tmpfs_mode}") opts.append(f"tmpfs-mode={tmpfs_mode}")
if mount_type == "bind": if mount_type == "bind":
bind_opts = mount_desc.get("bind", {}) bind_opts = mount_desc.get("bind", {})
selinux = bind_opts.get("selinux", None) selinux = bind_opts.get("selinux")
if selinux is not None: if selinux is not None:
opts.append(selinux) opts.append(selinux)
opts = ",".join(opts) opts = ",".join(opts)
@ -486,7 +486,7 @@ def container_to_ulimit_args(cnt, podman_args):
def container_to_ulimit_build_args(cnt, podman_args): def container_to_ulimit_build_args(cnt, podman_args):
build = cnt.get("build", None) build = cnt.get("build")
if build is not None: if build is not None:
ulimit_to_ulimit_args(build.get("ulimits", []), podman_args) ulimit_to_ulimit_args(build.get("ulimits", []), podman_args)
@ -496,8 +496,8 @@ def mount_desc_to_volume_args(compose, mount_desc, srv_name, cnt_name): # pylin
mount_type = mount_desc["type"] mount_type = mount_desc["type"]
if mount_type not in ("bind", "volume"): if mount_type not in ("bind", "volume"):
raise ValueError("unknown mount type:" + mount_type) raise ValueError("unknown mount type:" + mount_type)
vol = mount_desc.get("_vol", None) if mount_type == "volume" else None vol = mount_desc.get("_vol") if mount_type == "volume" else None
source = vol["name"] if vol else mount_desc.get("source", None) source = vol["name"] if vol else mount_desc.get("source")
if not source: if not source:
raise ValueError(f"missing mount source for {mount_type} on {srv_name}") raise ValueError(f"missing mount source for {mount_type} on {srv_name}")
target = mount_desc["target"] target = mount_desc["target"]
@ -517,12 +517,12 @@ def mount_desc_to_volume_args(compose, mount_desc, srv_name, cnt_name): # pylin
# [nosuid|suid] # [nosuid|suid]
# [O] # [O]
# [U] # [U]
read_only = mount_desc.get("read_only", None) read_only = mount_desc.get("read_only")
if read_only is not None: if read_only is not None:
opts.append("ro" if read_only else "rw") opts.append("ro" if read_only else "rw")
if mount_type == "bind": if mount_type == "bind":
bind_opts = mount_desc.get("bind", {}) bind_opts = mount_desc.get("bind", {})
selinux = bind_opts.get("selinux", None) selinux = bind_opts.get("selinux")
if selinux is not None: if selinux is not None:
opts.append(selinux) opts.append(selinux)
@ -551,10 +551,10 @@ async def get_mount_args(compose, cnt, volume):
args = volume["target"] args = volume["target"]
tmpfs_opts = volume.get("tmpfs", {}) tmpfs_opts = volume.get("tmpfs", {})
opts = [] opts = []
size = tmpfs_opts.get("size", None) size = tmpfs_opts.get("size")
if size: if size:
opts.append(f"size={size}") opts.append(f"size={size}")
mode = tmpfs_opts.get("mode", None) mode = tmpfs_opts.get("mode")
if mode: if mode:
opts.append(f"mode={mode}") opts.append(f"mode={mode}")
if opts: if opts:
@ -571,12 +571,12 @@ def get_secret_args(compose, cnt, secret, podman_is_building=False):
podman_is_building: True if we are preparing arguments for an invocation of "podman build" podman_is_building: True if we are preparing arguments for an invocation of "podman build"
False if we are preparing for something else like "podman run" False if we are preparing for something else like "podman run"
""" """
secret_name = secret if isinstance(secret, str) else secret.get("source", None) secret_name = secret if isinstance(secret, str) else secret.get("source")
if not secret_name or secret_name not in compose.declared_secrets.keys(): if not secret_name or secret_name not in compose.declared_secrets.keys():
raise ValueError(f'ERROR: undeclared secret: "{secret}", service: {cnt["_service"]}') raise ValueError(f'ERROR: undeclared secret: "{secret}", service: {cnt["_service"]}')
declared_secret = compose.declared_secrets[secret_name] declared_secret = compose.declared_secrets[secret_name]
source_file = declared_secret.get("file", None) source_file = declared_secret.get("file")
dest_file = "" dest_file = ""
secret_opts = "" secret_opts = ""
@ -586,11 +586,11 @@ def get_secret_args(compose, cnt, secret, podman_is_building=False):
secret_mode = None secret_mode = None
secret_type = None secret_type = None
if isinstance(secret, dict): if isinstance(secret, dict):
secret_target = secret.get("target", None) secret_target = secret.get("target")
secret_uid = secret.get("uid", None) secret_uid = secret.get("uid")
secret_gid = secret.get("gid", None) secret_gid = secret.get("gid")
secret_mode = secret.get("mode", None) secret_mode = secret.get("mode")
secret_type = secret.get("type", None) secret_type = secret.get("type")
if source_file: if source_file:
# assemble path for source file first, because we need it for all cases # assemble path for source file first, because we need it for all cases
@ -636,7 +636,7 @@ def get_secret_args(compose, cnt, secret, podman_is_building=False):
# since these commands are directly translated to # since these commands are directly translated to
# podman-create commands, albeit we can only support a 1:1 mapping # podman-create commands, albeit we can only support a 1:1 mapping
# at the moment # at the moment
if declared_secret.get("external", False) or declared_secret.get("name", None): if declared_secret.get("external", False) or declared_secret.get("name"):
secret_opts += f",uid={secret_uid}" if secret_uid else "" secret_opts += f",uid={secret_uid}" if secret_uid else ""
secret_opts += f",gid={secret_gid}" if secret_gid else "" secret_opts += f",gid={secret_gid}" if secret_gid else ""
secret_opts += f",mode={secret_mode}" if secret_mode else "" secret_opts += f",mode={secret_mode}" if secret_mode else ""
@ -647,7 +647,7 @@ def get_secret_args(compose, cnt, secret, podman_is_building=False):
# for type=mount as well. # for type=mount as well.
# having a custom name for the external secret # having a custom name for the external secret
# has the same problem as well # has the same problem as well
ext_name = declared_secret.get("name", None) ext_name = declared_secret.get("name")
err_str = ( err_str = (
'ERROR: Custom name/target reference "{}" ' 'ERROR: Custom name/target reference "{}" '
'for mounted external secret "{}" is not supported' 'for mounted external secret "{}" is not supported'
@ -680,17 +680,17 @@ def container_to_gpu_res_args(cnt, podman_args):
# https://docs.docker.com/compose/gpu-support/ # https://docs.docker.com/compose/gpu-support/
# https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/cdi-support.html # https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/cdi-support.html
deploy = cnt.get("deploy", None) or {} deploy = cnt.get("deploy", {})
res = deploy.get("resources", None) or {} res = deploy.get("resources", {})
reservations = res.get("reservations", None) or {} reservations = res.get("reservations", {})
devices = reservations.get("devices", []) devices = reservations.get("devices", [])
gpu_on = False gpu_on = False
for device in devices: for device in devices:
driver = device.get("driver", None) driver = device.get("driver")
if driver is None: if driver is None:
continue continue
capabilities = device.get("capabilities", None) capabilities = device.get("capabilities")
if capabilities is None: if capabilities is None:
continue continue
@ -730,21 +730,21 @@ def container_to_gpu_res_args(cnt, podman_args):
def container_to_cpu_res_args(cnt, podman_args): def container_to_cpu_res_args(cnt, podman_args):
# v2: https://docs.docker.com/compose/compose-file/compose-file-v2/#cpu-and-other-resources # v2: https://docs.docker.com/compose/compose-file/compose-file-v2/#cpu-and-other-resources
# cpus, cpu_shares, mem_limit, mem_reservation # cpus, cpu_shares, mem_limit, mem_reservation
cpus_limit_v2 = try_float(cnt.get("cpus", None), None) cpus_limit_v2 = try_float(cnt.get("cpus"), None)
cpu_shares_v2 = try_int(cnt.get("cpu_shares", None), None) cpu_shares_v2 = try_int(cnt.get("cpu_shares"), None)
mem_limit_v2 = cnt.get("mem_limit", None) mem_limit_v2 = cnt.get("mem_limit")
mem_res_v2 = cnt.get("mem_reservation", None) mem_res_v2 = cnt.get("mem_reservation")
# v3: https://docs.docker.com/compose/compose-file/compose-file-v3/#resources # v3: https://docs.docker.com/compose/compose-file/compose-file-v3/#resources
# spec: https://github.com/compose-spec/compose-spec/blob/master/deploy.md#resources # spec: https://github.com/compose-spec/compose-spec/blob/master/deploy.md#resources
# deploy.resources.{limits,reservations}.{cpus, memory} # deploy.resources.{limits,reservations}.{cpus, memory}
deploy = cnt.get("deploy", None) or {} deploy = cnt.get("deploy", {})
res = deploy.get("resources", None) or {} res = deploy.get("resources", {})
limits = res.get("limits", None) or {} limits = res.get("limits", {})
cpus_limit_v3 = try_float(limits.get("cpus", None), None) cpus_limit_v3 = try_float(limits.get("cpus"), None)
mem_limit_v3 = limits.get("memory", None) mem_limit_v3 = limits.get("memory")
reservations = res.get("reservations", None) or {} reservations = res.get("reservations", {})
# cpus_res_v3 = try_float(reservations.get('cpus', None), None) # cpus_res_v3 = try_float(reservations.get('cpus', None), None)
mem_res_v3 = reservations.get("memory", None) mem_res_v3 = reservations.get("memory")
# add args # add args
cpus = cpus_limit_v3 or cpus_limit_v2 cpus = cpus_limit_v3 or cpus_limit_v2
if cpus: if cpus:
@ -773,10 +773,10 @@ def container_to_cpu_res_args(cnt, podman_args):
def port_dict_to_str(port_desc): def port_dict_to_str(port_desc):
# NOTE: `mode: host|ingress` is ignored # NOTE: `mode: host|ingress` is ignored
cnt_port = port_desc.get("target", None) cnt_port = port_desc.get("target")
published = port_desc.get("published", None) or "" published = port_desc.get("published", "")
host_ip = port_desc.get("host_ip", None) host_ip = port_desc.get("host_ip")
protocol = port_desc.get("protocol", None) or "tcp" protocol = port_desc.get("protocol", "tcp")
if not cnt_port: if not cnt_port:
raise ValueError("target container port must be specified") raise ValueError("target container port must be specified")
if host_ip: if host_ip:
@ -814,31 +814,31 @@ def get_network_create_args(net_desc, proj_name, net_name):
f"com.docker.compose.project={proj_name}", f"com.docker.compose.project={proj_name}",
] ]
# TODO: add more options here, like dns, ipv6, etc. # TODO: add more options here, like dns, ipv6, etc.
labels = net_desc.get("labels", None) or [] labels = net_desc.get("labels", [])
for item in norm_as_list(labels): for item in norm_as_list(labels):
args.extend(["--label", item]) args.extend(["--label", item])
if net_desc.get("internal", None): if net_desc.get("internal"):
args.append("--internal") args.append("--internal")
driver = net_desc.get("driver", None) driver = net_desc.get("driver")
if driver: if driver:
args.extend(("--driver", driver)) args.extend(("--driver", driver))
driver_opts = net_desc.get("driver_opts", None) or {} driver_opts = net_desc.get("driver_opts", {})
for key, value in driver_opts.items(): for key, value in driver_opts.items():
args.extend(("--opt", f"{key}={value}")) args.extend(("--opt", f"{key}={value}"))
ipam = net_desc.get("ipam", None) or {} ipam = net_desc.get("ipam", {})
ipam_driver = ipam.get("driver", None) ipam_driver = ipam.get("driver")
if ipam_driver and ipam_driver != "default": if ipam_driver and ipam_driver != "default":
args.extend(("--ipam-driver", ipam_driver)) args.extend(("--ipam-driver", ipam_driver))
ipam_config_ls = ipam.get("config", None) or [] ipam_config_ls = ipam.get("config", [])
if net_desc.get("enable_ipv6", None): if net_desc.get("enable_ipv6"):
args.append("--ipv6") args.append("--ipv6")
if isinstance(ipam_config_ls, dict): if isinstance(ipam_config_ls, dict):
ipam_config_ls = [ipam_config_ls] ipam_config_ls = [ipam_config_ls]
for ipam_config in ipam_config_ls: for ipam_config in ipam_config_ls:
subnet = ipam_config.get("subnet", None) subnet = ipam_config.get("subnet")
ip_range = ipam_config.get("ip_range", None) ip_range = ipam_config.get("ip_range")
gateway = ipam_config.get("gateway", None) gateway = ipam_config.get("gateway")
if subnet: if subnet:
args.extend(("--subnet", subnet)) args.extend(("--subnet", subnet))
if ip_range: if ip_range:
@ -854,19 +854,19 @@ async def assert_cnt_nets(compose, cnt):
""" """
create missing networks create missing networks
""" """
net = cnt.get("network_mode", None) net = cnt.get("network_mode")
if net and not net.startswith("bridge"): if net and not net.startswith("bridge"):
return return
cnt_nets = cnt.get("networks", None) cnt_nets = cnt.get("networks")
if cnt_nets and isinstance(cnt_nets, dict): if cnt_nets and isinstance(cnt_nets, dict):
cnt_nets = list(cnt_nets.keys()) cnt_nets = list(cnt_nets.keys())
cnt_nets = norm_as_list(cnt_nets or compose.default_net) cnt_nets = norm_as_list(cnt_nets or compose.default_net)
for net in cnt_nets: for net in cnt_nets:
net_desc = compose.networks[net] or {} net_desc = compose.networks[net] or {}
is_ext = net_desc.get("external", None) is_ext = net_desc.get("external")
ext_desc = is_ext if isinstance(is_ext, dict) else {} ext_desc = is_ext if isinstance(is_ext, dict) else {}
default_net_name = default_network_name_for_project(compose, net, is_ext) default_net_name = default_network_name_for_project(compose, net, is_ext)
net_name = ext_desc.get("name", None) or net_desc.get("name", None) or default_net_name net_name = ext_desc.get("name") or net_desc.get("name") or default_net_name
try: try:
await compose.podman.output([], "network", ["exists", net_name]) await compose.podman.output([], "network", ["exists", net_name])
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
@ -881,8 +881,8 @@ def get_net_args(compose, cnt):
service_name = cnt["service_name"] service_name = cnt["service_name"]
net_args = [] net_args = []
is_bridge = False is_bridge = False
mac_address = cnt.get("mac_address", None) mac_address = cnt.get("mac_address")
net = cnt.get("network_mode", None) net = cnt.get("network_mode")
if net: if net:
if net == "none": if net == "none":
is_bridge = False is_bridge = False
@ -911,7 +911,7 @@ def get_net_args(compose, cnt):
sys.exit(1) sys.exit(1)
else: else:
is_bridge = True is_bridge = True
cnt_nets = cnt.get("networks", None) cnt_nets = cnt.get("networks")
aliases = [service_name] aliases = [service_name]
# NOTE: from podman manpage: # NOTE: from podman manpage:
@ -921,23 +921,23 @@ def get_net_args(compose, cnt):
ip = None ip = None
ip6 = None ip6 = None
ip_assignments = 0 ip_assignments = 0
if cnt.get("_aliases", None): if cnt.get("_aliases"):
aliases.extend(cnt.get("_aliases", None)) aliases.extend(cnt.get("_aliases"))
if cnt_nets and isinstance(cnt_nets, dict): if cnt_nets and isinstance(cnt_nets, dict):
prioritized_cnt_nets = [] prioritized_cnt_nets = []
# cnt_nets is {net_key: net_value, ...} # cnt_nets is {net_key: net_value, ...}
for net_key, net_value in cnt_nets.items(): for net_key, net_value in cnt_nets.items():
net_value = net_value or {} net_value = net_value or {}
aliases.extend(norm_as_list(net_value.get("aliases", None))) aliases.extend(norm_as_list(net_value.get("aliases")))
if net_value.get("ipv4_address", None) is not None: if net_value.get("ipv4_address") is not None:
ip_assignments = ip_assignments + 1 ip_assignments = ip_assignments + 1
if net_value.get("ipv6_address", None) is not None: if net_value.get("ipv6_address") is not None:
ip_assignments = ip_assignments + 1 ip_assignments = ip_assignments + 1
if not ip: if not ip:
ip = net_value.get("ipv4_address", None) ip = net_value.get("ipv4_address")
if not ip6: if not ip6:
ip6 = net_value.get("ipv6_address", None) ip6 = net_value.get("ipv6_address")
net_priority = net_value.get("priority", 0) net_priority = net_value.get("priority", 0)
prioritized_cnt_nets.append(( prioritized_cnt_nets.append((
net_priority, net_priority,
@ -950,10 +950,10 @@ def get_net_args(compose, cnt):
net_names = [] net_names = []
for net in cnt_nets: for net in cnt_nets:
net_desc = compose.networks[net] or {} net_desc = compose.networks[net] or {}
is_ext = net_desc.get("external", None) is_ext = net_desc.get("external")
ext_desc = is_ext if isinstance(is_ext, str) else {} ext_desc = is_ext if isinstance(is_ext, str) else {}
default_net_name = default_network_name_for_project(compose, net, is_ext) default_net_name = default_network_name_for_project(compose, net, is_ext)
net_name = ext_desc.get("name", None) or net_desc.get("name", None) or default_net_name net_name = ext_desc.get("name") or net_desc.get("name") or default_net_name
net_names.append(net_name) net_names.append(net_name)
net_names_str = ",".join(net_names) net_names_str = ",".join(net_names)
@ -963,7 +963,7 @@ def get_net_args(compose, cnt):
# podman currently ignores this if a per-container network-alias is set; as pdoman-compose # podman currently ignores this if a per-container network-alias is set; as pdoman-compose
# always sets a network-alias to the container name, is currently doesn't make sense to # always sets a network-alias to the container name, is currently doesn't make sense to
# implement this. # implement this.
multiple_nets = cnt.get("networks", None) multiple_nets = cnt.get("networks")
if multiple_nets and len(multiple_nets) > 1: if multiple_nets and len(multiple_nets) > 1:
# networks can be specified as a dict with config per network or as a plain list without # networks can be specified as a dict with config per network or as a plain list without
# config. Support both cases by converting the plain list to a dict with empty config. # config. Support both cases by converting the plain list to a dict with empty config.
@ -976,7 +976,7 @@ def get_net_args(compose, cnt):
# specified on the network level as well # specified on the network level as well
if mac_address is not None: if mac_address is not None:
for net_config_ in multiple_nets.values(): for net_config_ in multiple_nets.values():
network_mac = net_config_.get("x-podman.mac_address", None) network_mac = net_config_.get("x-podman.mac_address")
if network_mac is not None: if network_mac is not None:
raise RuntimeError( raise RuntimeError(
f"conflicting mac addresses {mac_address} and {network_mac}:" f"conflicting mac addresses {mac_address} and {network_mac}:"
@ -986,15 +986,15 @@ def get_net_args(compose, cnt):
for net_, net_config_ in multiple_nets.items(): for net_, net_config_ in multiple_nets.items():
net_desc = compose.networks[net_] or {} net_desc = compose.networks[net_] or {}
is_ext = net_desc.get("external", None) is_ext = net_desc.get("external")
ext_desc = is_ext if isinstance(is_ext, str) else {} ext_desc = is_ext if isinstance(is_ext, str) else {}
default_net_name = default_network_name_for_project(compose, net_, is_ext) default_net_name = default_network_name_for_project(compose, net_, is_ext)
net_name = ext_desc.get("name", None) or net_desc.get("name", None) or default_net_name net_name = ext_desc.get("name") or net_desc.get("name") or default_net_name
ipv4 = net_config_.get("ipv4_address", None) ipv4 = net_config_.get("ipv4_address")
ipv6 = net_config_.get("ipv6_address", None) ipv6 = net_config_.get("ipv6_address")
# custom extension; not supported by docker-compose v3 # custom extension; not supported by docker-compose v3
mac = net_config_.get("x-podman.mac_address", None) mac = net_config_.get("x-podman.mac_address")
# if a mac_address was specified on the container level, apply it to the first network # if a mac_address was specified on the container level, apply it to the first network
# This works for Python > 3.6, because dict insert ordering is preserved, so we are # This works for Python > 3.6, because dict insert ordering is preserved, so we are
@ -1039,7 +1039,7 @@ def get_net_args(compose, cnt):
async def container_to_args(compose, cnt, detached=True): async def container_to_args(compose, cnt, detached=True):
# TODO: double check -e , --add-host, -v, --read-only # TODO: double check -e , --add-host, -v, --read-only
dirname = compose.dirname dirname = compose.dirname
pod = cnt.get("pod", None) or "" pod = cnt.get("pod", "")
name = cnt["name"] name = cnt["name"]
podman_args = [f"--name={name}"] podman_args = [f"--name={name}"]
@ -1049,20 +1049,20 @@ async def container_to_args(compose, cnt, detached=True):
if pod: if pod:
podman_args.append(f"--pod={pod}") podman_args.append(f"--pod={pod}")
deps = [] deps = []
for dep_srv in cnt.get("_deps", None) or []: for dep_srv in cnt.get("_deps", []):
deps.extend(compose.container_names_by_service.get(dep_srv.name, None) or []) deps.extend(compose.container_names_by_service.get(dep_srv.name, []))
if deps: if deps:
deps_csv = ",".join(deps) deps_csv = ",".join(deps)
podman_args.append(f"--requires={deps_csv}") podman_args.append(f"--requires={deps_csv}")
sec = norm_as_list(cnt.get("security_opt", None)) sec = norm_as_list(cnt.get("security_opt"))
for sec_item in sec: for sec_item in sec:
podman_args.extend(["--security-opt", sec_item]) podman_args.extend(["--security-opt", sec_item])
ann = norm_as_list(cnt.get("annotations", None)) ann = norm_as_list(cnt.get("annotations"))
for a in ann: for a in ann:
podman_args.extend(["--annotation", a]) podman_args.extend(["--annotation", a])
if cnt.get("read_only", None): if cnt.get("read_only"):
podman_args.append("--read-only") podman_args.append("--read-only")
if cnt.get("http_proxy", None) is False: if cnt.get("http_proxy") is False:
podman_args.append("--http-proxy=false") podman_args.append("--http-proxy=false")
for i in cnt.get("labels", []): for i in cnt.get("labels", []):
podman_args.extend(["--label", i]) podman_args.extend(["--label", i])
@ -1074,11 +1074,11 @@ async def container_to_args(compose, cnt, detached=True):
podman_args.extend(["--group-add", item]) podman_args.extend(["--group-add", item])
for item in cnt.get("devices", []): for item in cnt.get("devices", []):
podman_args.extend(["--device", item]) podman_args.extend(["--device", item])
for item in norm_as_list(cnt.get("dns", None)): for item in norm_as_list(cnt.get("dns")):
podman_args.extend(["--dns", item]) podman_args.extend(["--dns", item])
for item in norm_as_list(cnt.get("dns_opt", None)): for item in norm_as_list(cnt.get("dns_opt")):
podman_args.extend(["--dns-opt", item]) podman_args.extend(["--dns-opt", item])
for item in norm_as_list(cnt.get("dns_search", None)): for item in norm_as_list(cnt.get("dns_search")):
podman_args.extend(["--dns-search", item]) podman_args.extend(["--dns-search", item])
env_file = cnt.get("env_file", []) env_file = cnt.get("env_file", [])
if isinstance(env_file, (dict, str)): if isinstance(env_file, (dict, str)):
@ -1112,10 +1112,10 @@ async def container_to_args(compose, cnt, detached=True):
await assert_cnt_nets(compose, cnt) await assert_cnt_nets(compose, cnt)
podman_args.extend(get_net_args(compose, cnt)) podman_args.extend(get_net_args(compose, cnt))
log_config = cnt.get("logging", None) log_config = cnt.get("logging")
if log_config is not None: if log_config is not None:
podman_args.append(f'--log-driver={log_config.get("driver", "k8s-file")}') podman_args.append(f'--log-driver={log_config.get("driver", "k8s-file")}')
log_opts = log_config.get("options") or {} log_opts = log_config.get("options", {})
podman_args += [f"--log-opt={name}={value}" for name, value in log_opts.items()] podman_args += [f"--log-opt={name}={value}" for name, value in log_opts.items()]
for secret in cnt.get("secrets", []): for secret in cnt.get("secrets", []):
podman_args.extend(get_secret_args(compose, cnt, secret)) podman_args.extend(get_secret_args(compose, cnt, secret))
@ -1123,9 +1123,9 @@ async def container_to_args(compose, cnt, detached=True):
podman_args.extend(["--add-host", i]) podman_args.extend(["--add-host", i])
for i in cnt.get("expose", []): for i in cnt.get("expose", []):
podman_args.extend(["--expose", i]) podman_args.extend(["--expose", i])
if cnt.get("publishall", None): if cnt.get("publishall"):
podman_args.append("-P") podman_args.append("-P")
ports = cnt.get("ports", None) or [] ports = cnt.get("ports", [])
if isinstance(ports, str): if isinstance(ports, str):
ports = [ports] ports = [ports]
for port in ports: for port in ports:
@ -1135,22 +1135,22 @@ async def container_to_args(compose, cnt, detached=True):
raise TypeError("port should be either string or dict") raise TypeError("port should be either string or dict")
podman_args.extend(["-p", port]) podman_args.extend(["-p", port])
userns_mode = cnt.get("userns_mode", None) userns_mode = cnt.get("userns_mode")
if userns_mode is not None: if userns_mode is not None:
podman_args.extend(["--userns", userns_mode]) podman_args.extend(["--userns", userns_mode])
user = cnt.get("user", None) user = cnt.get("user")
if user is not None: if user is not None:
podman_args.extend(["-u", user]) podman_args.extend(["-u", user])
if cnt.get("working_dir", None) is not None: if cnt.get("working_dir") is not None:
podman_args.extend(["-w", cnt["working_dir"]]) podman_args.extend(["-w", cnt["working_dir"]])
if cnt.get("hostname", None): if cnt.get("hostname"):
podman_args.extend(["--hostname", cnt["hostname"]]) podman_args.extend(["--hostname", cnt["hostname"]])
if cnt.get("shm_size", None): if cnt.get("shm_size"):
podman_args.extend(["--shm-size", str(cnt["shm_size"])]) podman_args.extend(["--shm-size", str(cnt["shm_size"])])
if cnt.get("stdin_open", None): if cnt.get("stdin_open"):
podman_args.append("-i") podman_args.append("-i")
if cnt.get("stop_signal", None): if cnt.get("stop_signal"):
podman_args.extend(["--stop-signal", cnt["stop_signal"]]) podman_args.extend(["--stop-signal", cnt["stop_signal"]])
sysctls = cnt.get("sysctls") sysctls = cnt.get("sysctls")
@ -1164,41 +1164,41 @@ async def container_to_args(compose, cnt, detached=True):
else: else:
raise TypeError("sysctls should be either dict or list") raise TypeError("sysctls should be either dict or list")
if cnt.get("tty", None): if cnt.get("tty"):
podman_args.append("--tty") podman_args.append("--tty")
if cnt.get("privileged", None): if cnt.get("privileged"):
podman_args.append("--privileged") podman_args.append("--privileged")
if cnt.get("pid", None): if cnt.get("pid"):
podman_args.extend(["--pid", cnt["pid"]]) podman_args.extend(["--pid", cnt["pid"]])
pull_policy = cnt.get("pull_policy", None) pull_policy = cnt.get("pull_policy")
if pull_policy is not None and pull_policy != "build": if pull_policy is not None and pull_policy != "build":
podman_args.extend(["--pull", pull_policy]) podman_args.extend(["--pull", pull_policy])
if cnt.get("restart", None) is not None: if cnt.get("restart") is not None:
podman_args.extend(["--restart", cnt["restart"]]) podman_args.extend(["--restart", cnt["restart"]])
container_to_ulimit_args(cnt, podman_args) container_to_ulimit_args(cnt, podman_args)
container_to_res_args(cnt, podman_args) container_to_res_args(cnt, podman_args)
# currently podman shipped by fedora does not package this # currently podman shipped by fedora does not package this
if cnt.get("init", None): if cnt.get("init"):
podman_args.append("--init") podman_args.append("--init")
if cnt.get("init-path", None): if cnt.get("init-path"):
podman_args.extend(["--init-path", cnt["init-path"]]) podman_args.extend(["--init-path", cnt["init-path"]])
entrypoint = cnt.get("entrypoint", None) entrypoint = cnt.get("entrypoint")
if entrypoint is not None: if entrypoint is not None:
if isinstance(entrypoint, str): if isinstance(entrypoint, str):
entrypoint = shlex.split(entrypoint) entrypoint = shlex.split(entrypoint)
podman_args.extend(["--entrypoint", json.dumps(entrypoint)]) podman_args.extend(["--entrypoint", json.dumps(entrypoint)])
platform = cnt.get("platform", None) platform = cnt.get("platform")
if platform is not None: if platform is not None:
podman_args.extend(["--platform", platform]) podman_args.extend(["--platform", platform])
if cnt.get("runtime", None): if cnt.get("runtime"):
podman_args.extend(["--runtime", cnt["runtime"]]) podman_args.extend(["--runtime", cnt["runtime"]])
# WIP: healthchecks are still work in progress # WIP: healthchecks are still work in progress
healthcheck = cnt.get("healthcheck", None) or {} healthcheck = cnt.get("healthcheck", {})
if not isinstance(healthcheck, dict): if not isinstance(healthcheck, dict):
raise ValueError("'healthcheck' must be a key-value mapping") raise ValueError("'healthcheck' must be a key-value mapping")
healthcheck_disable = healthcheck.get("disable", False) healthcheck_disable = healthcheck.get("disable", False)
healthcheck_test = healthcheck.get("test", None) healthcheck_test = healthcheck.get("test")
if healthcheck_disable: if healthcheck_disable:
healthcheck_test = ["NONE"] healthcheck_test = ["NONE"]
if healthcheck_test: if healthcheck_test:
@ -1257,7 +1257,7 @@ async def container_to_args(compose, cnt, detached=True):
podman_args.extend(["--gidmap", gidmap]) podman_args.extend(["--gidmap", gidmap])
if cnt.get("x-podman.no_hosts", False): if cnt.get("x-podman.no_hosts", False):
podman_args.extend(["--no-hosts"]) podman_args.extend(["--no-hosts"])
rootfs = cnt.get('x-podman.rootfs', None) rootfs = cnt.get('x-podman.rootfs')
if rootfs is not None: if rootfs is not None:
rootfs_mode = True rootfs_mode = True
podman_args.extend(["--rootfs", rootfs]) podman_args.extend(["--rootfs", rootfs])
@ -1265,7 +1265,7 @@ async def container_to_args(compose, cnt, detached=True):
if not rootfs_mode: if not rootfs_mode:
podman_args.append(cnt["image"]) # command, ..etc. podman_args.append(cnt["image"]) # command, ..etc.
command = cnt.get("command", None) command = cnt.get("command")
if command is not None: if command is not None:
if isinstance(command, str): if isinstance(command, str):
podman_args.extend(shlex.split(command)) podman_args.extend(shlex.split(command))
@ -1341,7 +1341,7 @@ def rec_deps(services, service_name, start_point=None):
# avoid A depens on A # avoid A depens on A
if dep_name.name == service_name: if dep_name.name == service_name:
continue continue
dep_srv = services.get(dep_name.name, None) dep_srv = services.get(dep_name.name)
if not dep_srv: if not dep_srv:
continue continue
# NOTE: avoid creating loops, A->B->A # NOTE: avoid creating loops, A->B->A
@ -1362,7 +1362,7 @@ def flat_deps(services, with_extends=False):
srv["_deps"] = deps srv["_deps"] = deps
# TODO: manage properly the dependencies coming from base services when extended # TODO: manage properly the dependencies coming from base services when extended
if with_extends: if with_extends:
ext = srv.get("extends", {}).get("service", None) ext = srv.get("extends", {}).get("service")
if ext: if ext:
if ext != name: if ext != name:
deps.add(ServiceDependency(ext, "service_started")) deps.add(ServiceDependency(ext, "service_started"))
@ -1374,7 +1374,7 @@ def flat_deps(services, with_extends=False):
deps_ls = [ServiceDependency(k, v["condition"]) for k, v in deps_ls.items()] deps_ls = [ServiceDependency(k, v["condition"]) for k, v in deps_ls.items()]
deps.update(deps_ls) deps.update(deps_ls)
# parse link to get service name and remove alias # parse link to get service name and remove alias
links_ls = srv.get("links", None) or [] links_ls = srv.get("links", [])
if not is_list(links_ls): if not is_list(links_ls):
links_ls = [links_ls] links_ls = [links_ls]
deps.update([ServiceDependency(c.split(":")[0], "service_started") for c in links_ls]) deps.update([ServiceDependency(c.split(":")[0], "service_started") for c in links_ls])
@ -1557,7 +1557,7 @@ def normalize_service(service, sub_dir=""):
service["build"] = {"context": build} service["build"] = {"context": build}
if sub_dir and "build" in service: if sub_dir and "build" in service:
build = service["build"] build = service["build"]
context = build.get("context", None) or "" context = build.get("context", "")
if context or sub_dir: if context or sub_dir:
if context.startswith("./"): if context.startswith("./"):
context = context[2:] context = context[2:]
@ -1616,7 +1616,7 @@ def normalize(compose):
""" """
convert compose dict of some keys from string or dicts into arrays convert compose dict of some keys from string or dicts into arrays
""" """
services = compose.get("services", None) or {} services = compose.get("services", {})
for service in services.values(): for service in services.values():
normalize_service(service) normalize_service(service)
return compose return compose
@ -1634,7 +1634,7 @@ def normalize_service_final(service: dict, project_dir: str) -> dict:
def normalize_final(compose: dict, project_dir: str) -> dict: def normalize_final(compose: dict, project_dir: str) -> dict:
services = compose.get("services", None) or {} services = compose.get("services", {})
for service in services.values(): for service in services.values():
normalize_service_final(service, project_dir) normalize_service_final(service, project_dir)
return compose return compose
@ -1701,10 +1701,10 @@ def resolve_extends(services, service_names, environ):
ext = service.get("extends", {}) ext = service.get("extends", {})
if isinstance(ext, str): if isinstance(ext, str):
ext = {"service": ext} ext = {"service": ext}
from_service_name = ext.get("service", None) from_service_name = ext.get("service")
if not from_service_name: if not from_service_name:
continue continue
filename = ext.get("file", None) filename = ext.get("file")
if filename: if filename:
if filename.startswith("./"): if filename.startswith("./"):
filename = filename[2:] filename = filename[2:]
@ -1798,7 +1798,7 @@ class PodmanCompose:
for args in self.global_args.podman_args: for args in self.global_args.podman_args:
xargs.extend(shlex.split(args)) xargs.extend(shlex.split(args))
cmd_norm = cmd if cmd != "create" else "run" cmd_norm = cmd if cmd != "create" else "run"
cmd_args = self.global_args.__dict__.get(f"podman_{cmd_norm}_args", None) or [] cmd_args = self.global_args.__dict__.get(f"podman_{cmd_norm}_args", [])
for args in cmd_args: for args in cmd_args:
xargs.extend(shlex.split(args)) xargs.extend(shlex.split(args))
return xargs return xargs
@ -1850,12 +1850,12 @@ class PodmanCompose:
def _parse_compose_file(self): def _parse_compose_file(self):
args = self.global_args args = self.global_args
# cmd = args.command # cmd = args.command
dirname = os.environ.get("COMPOSE_PROJECT_DIR", None) dirname = os.environ.get("COMPOSE_PROJECT_DIR")
if dirname and os.path.isdir(dirname): if dirname and os.path.isdir(dirname):
os.chdir(dirname) os.chdir(dirname)
pathsep = os.environ.get("COMPOSE_PATH_SEPARATOR", None) or os.pathsep pathsep = os.environ.get("COMPOSE_PATH_SEPARATOR", os.pathsep)
if not args.file: if not args.file:
default_str = os.environ.get("COMPOSE_FILE", None) default_str = os.environ.get("COMPOSE_FILE")
if default_str: if default_str:
default_ls = default_str.split(pathsep) default_ls = default_str.split(pathsep)
else: else:
@ -1943,7 +1943,7 @@ class PodmanCompose:
content = rec_subs(content, self.environ) content = rec_subs(content, self.environ)
rec_merge(compose, content) rec_merge(compose, content)
# If `include` is used, append included files to files # If `include` is used, append included files to files
include = compose.get("include", None) include = compose.get("include")
if include: if include:
files.extend(include) files.extend(include)
# As compose obj is updated and tested with every loop, not deleting `include` # As compose obj is updated and tested with every loop, not deleting `include`
@ -1963,16 +1963,14 @@ class PodmanCompose:
# debug mode # debug mode
if len(files) > 1: if len(files) > 1:
log.debug(" ** merged:\n%s", json.dumps(compose, indent=2)) log.debug(" ** merged:\n%s", json.dumps(compose, indent=2))
# ver = compose.get('version', None) # ver = compose.get('version')
if not project_name: if not project_name:
project_name = compose.get("name", None) project_name = compose.get("name")
if project_name is None: if project_name is None:
# More strict then actually needed for simplicity: # More strict then actually needed for simplicity:
# podman requires [a-zA-Z0-9][a-zA-Z0-9_.-]* # podman requires [a-zA-Z0-9][a-zA-Z0-9_.-]*
project_name = ( project_name = self.environ.get("COMPOSE_PROJECT_NAME", dir_basename.lower())
self.environ.get("COMPOSE_PROJECT_NAME", None) or dir_basename.lower()
)
project_name = norm_re.sub("", project_name) project_name = norm_re.sub("", project_name)
if not project_name: if not project_name:
raise RuntimeError(f"Project name [{dir_basename}] normalized to empty") raise RuntimeError(f"Project name [{dir_basename}] normalized to empty")
@ -1980,7 +1978,7 @@ class PodmanCompose:
self.project_name = project_name self.project_name = project_name
self.environ.update({"COMPOSE_PROJECT_NAME": self.project_name}) self.environ.update({"COMPOSE_PROJECT_NAME": self.project_name})
services = compose.get("services", None) services = compose.get("services")
if services is None: if services is None:
services = {} services = {}
log.warning("WARNING: No services defined") log.warning("WARNING: No services defined")
@ -1995,7 +1993,7 @@ class PodmanCompose:
flat_deps(services) flat_deps(services)
service_names = sorted([(len(srv["_deps"]), name) for name, srv in services.items()]) service_names = sorted([(len(srv["_deps"]), name) for name, srv in services.items()])
service_names = [name for _, name in service_names] service_names = [name for _, name in service_names]
nets = compose.get("networks", None) or {} nets = compose.get("networks", {})
if not nets: if not nets:
nets["default"] = None nets["default"] = None
self.networks = nets self.networks = nets
@ -2007,7 +2005,7 @@ class PodmanCompose:
self.default_net = None self.default_net = None
allnets = set() allnets = set()
for name, srv in services.items(): for name, srv in services.items():
srv_nets = srv.get("networks", None) or self.default_net srv_nets = srv.get("networks", self.default_net)
srv_nets = ( srv_nets = (
list(srv_nets.keys()) if isinstance(srv_nets, dict) else norm_as_list(srv_nets) list(srv_nets.keys()) if isinstance(srv_nets, dict) else norm_as_list(srv_nets)
) )
@ -2057,12 +2055,12 @@ class PodmanCompose:
"service_name": service_name, "service_name": service_name,
**service_desc, **service_desc,
} }
x_podman = service_desc.get("x-podman", None) x_podman = service_desc.get("x-podman")
rootfs_mode = x_podman is not None and x_podman.get("rootfs", None) is not None rootfs_mode = x_podman is not None and x_podman.get("rootfs") is not None
if "image" not in cnt and not rootfs_mode: if "image" not in cnt and not rootfs_mode:
cnt["image"] = f"{project_name}_{service_name}" cnt["image"] = f"{project_name}_{service_name}"
labels = norm_as_list(cnt.get("labels", None)) labels = norm_as_list(cnt.get("labels"))
cnt["ports"] = norm_ports(cnt.get("ports", None)) cnt["ports"] = norm_ports(cnt.get("ports"))
labels.extend(podman_compose_labels) labels.extend(podman_compose_labels)
labels.extend([ labels.extend([
f"com.docker.compose.container-number={num}", f"com.docker.compose.container-number={num}",
@ -2072,11 +2070,11 @@ class PodmanCompose:
cnt["_service"] = service_name cnt["_service"] = service_name
cnt["_project"] = project_name cnt["_project"] = project_name
given_containers.append(cnt) given_containers.append(cnt)
volumes = cnt.get("volumes", None) or [] volumes = cnt.get("volumes", [])
for volume in volumes: for volume in volumes:
mnt_dict = get_mnt_dict(self, cnt, volume) mnt_dict = get_mnt_dict(self, cnt, volume)
if ( if (
mnt_dict.get("type", None) == "volume" mnt_dict.get("type") == "volume"
and mnt_dict["source"] and mnt_dict["source"]
and mnt_dict["source"] not in self.vols and mnt_dict["source"] not in self.vols
): ):
@ -2087,7 +2085,7 @@ class PodmanCompose:
container_by_name = {c["name"]: c for c in given_containers} container_by_name = {c["name"]: c for c in given_containers}
# log("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", [])))
# log("sorted:", [c["name"] for c in given_containers]) # log("sorted:", [c["name"] for c in given_containers])
self.x_podman = compose.get("x-podman", {}) self.x_podman = compose.get("x-podman", {})
@ -2452,7 +2450,7 @@ async def build_one(compose, args, cnt):
if not hasattr(build_desc, "items"): if not hasattr(build_desc, "items"):
build_desc = {"context": build_desc} build_desc = {"context": build_desc}
ctx = build_desc.get("context", ".") ctx = build_desc.get("context", ".")
dockerfile = build_desc.get("dockerfile", None) dockerfile = build_desc.get("dockerfile")
if dockerfile: if dockerfile:
dockerfile = os.path.join(ctx, dockerfile) dockerfile = os.path.join(ctx, dockerfile)
else: else:
@ -2548,7 +2546,7 @@ async def create_pods(compose, args): # pylint: disable=unused-argument
podman_args.extend(shlex.split(args.pod_args)) podman_args.extend(shlex.split(args.pod_args))
# if compose.podman_version and not strverscmp_lt(compose.podman_version, "3.4.0"): # if compose.podman_version and not strverscmp_lt(compose.podman_version, "3.4.0"):
# podman_args.append("--infra-name={}_infra".format(pod["name"])) # podman_args.append("--infra-name={}_infra".format(pod["name"]))
ports = pod.get("ports", None) or [] ports = pod.get("ports", [])
if isinstance(ports, str): if isinstance(ports, str):
ports = [ports] ports = [ports]
for i in ports: for i in ports:
@ -2669,7 +2667,7 @@ async def compose_up(compose: PodmanCompose, args):
# TODO: handle already existing # TODO: handle already existing
# TODO: if error creating do not enter loop # TODO: if error creating do not enter loop
# TODO: colors if sys.stdout.isatty() # TODO: colors if sys.stdout.isatty()
exit_code_from = args.__dict__.get("exit_code_from", None) exit_code_from = args.__dict__.get("exit_code_from")
if exit_code_from: if exit_code_from:
args.abort_on_container_exit = True args.abort_on_container_exit = True
@ -2747,7 +2745,7 @@ def get_volume_names(compose, cnt):
mount_type = volume["type"] mount_type = volume["type"]
if mount_type != "volume": if mount_type != "volume":
continue continue
volume_name = (volume.get("_vol", None) or {}).get("name", None) volume_name = volume.get("_vol", {}).get("name")
ls.append(volume_name) ls.append(volume_name)
return ls return ls
@ -2767,7 +2765,7 @@ async def compose_down(compose: PodmanCompose, args):
podman_stop_args = [*podman_args] podman_stop_args = [*podman_args]
timeout = timeout_global timeout = timeout_global
if timeout is None: if timeout is None:
timeout_str = cnt.get("stop_grace_period", None) or STOP_GRACE_PERIOD timeout_str = cnt.get("stop_grace_period", STOP_GRACE_PERIOD)
timeout = str_to_seconds(timeout_str) timeout = str_to_seconds(timeout_str)
if timeout is not None: if timeout is not None:
podman_stop_args.extend(["-t", str(timeout)]) podman_stop_args.extend(["-t", str(timeout)])
@ -2912,7 +2910,7 @@ def compose_run_update_container_from_args(compose, cnt, args):
cnt["ports"] = ports cnt["ports"] = ports
if args.volume: if args.volume:
# TODO: handle volumes # TODO: handle volumes
volumes = clone(cnt.get("volumes", None) or []) volumes = clone(cnt.get("volumes", []))
volumes.extend(args.volume) volumes.extend(args.volume)
cnt["volumes"] = volumes cnt["volumes"] = volumes
cnt["tty"] = not args.T cnt["tty"] = not args.T
@ -2978,9 +2976,8 @@ async def transfer_service_status(compose, args, action):
if action != "start": if action != "start":
timeout = timeout_global timeout = timeout_global
if timeout is None: if timeout is None:
timeout_str = ( timeout_str = compose.container_by_name[target].get(
compose.container_by_name[target].get("stop_grace_period", None) "stop_grace_period", STOP_GRACE_PERIOD
or STOP_GRACE_PERIOD
) )
timeout = str_to_seconds(timeout_str) timeout = str_to_seconds(timeout_str)
if timeout is not None: if timeout is not None: