1
0
Fork 0

Compare commits

...

9 commits

Author SHA1 Message Date
d5ea5e64ee
generate: generate: Bump version to 0.0.13
Signed-off-by: Enno Tensing <tenno@suij.in>
2025-08-11 17:52:42 +02:00
9805419555
containerctl: Silence tee error messages
Signed-off-by: Enno Tensing <tenno@suij.in>
2025-08-11 17:52:13 +02:00
b3fe3b8a10
containerctl: Add usage message
Signed-off-by: Enno Tensing <tenno@suij.in>
2025-08-11 17:51:50 +02:00
94fcd6828f
containerctl: Expand python version check
Signed-off-by: Enno Tensing <tenno@suij.in>
2025-08-11 17:47:52 +02:00
d67137363f
containerctl: Fix python version check
Signed-off-by: Enno Tensing <tenno@suij.in>
2025-08-11 17:39:09 +02:00
2e793fd31f
generate: generate: Set the logging prefix after loading the json file
Signed-off-by: Enno Tensing <tenno@suij.in>
2025-08-11 17:38:30 +02:00
11d6b574f3
generate: log: Add a log prefix
Add a log prefix. This enables logging the config file that contained
the error or warning, which is helpful when regenerating all containers.

Signed-off-by: Enno Tensing <tenno@suij.in>
2025-08-11 17:37:32 +02:00
e3125ea4fe
generate: generate: Bump to 0.0.12
Signed-off-by: Enno Tensing <tenno@suij.in>
2025-08-09 20:19:35 +02:00
8f156e9f70
generate: container: Combine Network, Dns and Ports to ContainerNetwork
Signed-off-by: Enno Tensing <tenno@suij.in>
2025-08-09 20:19:30 +02:00
4 changed files with 92 additions and 25 deletions

View file

@ -11,9 +11,42 @@ LOGDIR="/var/log/containerctl"
TODAY="$(date '+%F')"
LOG="${LOGDIR}/${TODAY}"
get_python_path()
{
py="python3"
pyver="$(/usr/bin/env "${py}" -c 'import sys; print(sys.version_info.minor)')"
if [ "${pyver}" -lt "11" ]
then
py="python3.13"
else
printf '%b' "${py}"
return
fi
if /usr/bin/env "${py}" 2> /dev/null
then
return
fi
py="python3.12"
if /usr/bin/env "${py}" 2> /dev/null
then
return
fi
py="python3.11"
if /usr/bin/env "${py}" 2> /dev/null
then
return
fi
log_error 'containerctl needs at least Python 3.11 to run!'
exit 1
}
log_error()
{
printf '[%b] (EE) %b\n' "${TODAY}" "${@}" | tee -a "${LOG}"
printf '[%b] (EE) %b\n' "${TODAY}" "${@}" | tee -a "${LOG}" 2> /dev/null
}
list_containers()
@ -106,12 +139,7 @@ generate_container()
exit 1
fi
mypython="python3"
pyver="$(/usr/bin/env "${mypython}" -c 'import sys; print(sys.version_info.minor)')"
if [ "${pyver}" -gt "11" ]
then
mypython="python3.11"
fi
mypython="$(get_python_path)"
/usr/bin/env "${mypython}" "${BASEDIR}/generate/generate.py" \
"${CONFIGDIR}/${config}" "${LOG}" "${CONTAINERDIR}"
@ -130,10 +158,17 @@ generate_all()
done
}
usage()
{
printf '%b list-containers|list-configs|generate CONFIG-FILE|generate-all|CONTAINER-NAME ACTION\n' "${0}"
}
case "${1}" in
"list-containers") list_containers ;;
"list-configs") list_configs ;;
"generate-all") generate_all ;;
"generate") shift; generate_container "${@}" ;;
"help") usage "${0}" ;;
"usage") usage "${0}" ;;
*) exec_script "${@}" ;;
esac

View file

@ -415,7 +415,7 @@ class Environment:
if cmd == "":
return ""
return header + cmd
return header + f"printf '\\n' > {self.file}\n" + cmd
def remove(self) -> str:
"""Remove env file."""
@ -665,15 +665,44 @@ class ContainerOptions:
return ""
@dataclass
class ContainerNetwork:
"""Wrapper for Network, Dns and Ports."""
network: Network
dns: Dns
ports: Ports
@classmethod
def from_json(cls, json: ConfigValue, logger: Log) -> Self:
"""Create from JSON."""
network_config = maybe(json, "network")
dns_config = maybe(json, "dns")
ports_config = maybe(json, "ports")
network = Network.from_json(network_config, logger)
dns = Dns.from_json(dns_config, logger)
ports = Ports.from_json(ports_config, logger)
return cls(network, dns, ports)
def command(self) -> str:
"""Option for podman container create."""
cmd = ""
cmd += self.network.command()
cmd += self.dns.command()
cmd += self.ports.command()
return cmd
class Container:
"""Container."""
name: str
image: Image
ct_opts: ContainerOptions
network: Network
dns: Dns
ports: Ports
ct_network: ContainerNetwork
env: Environment
secrets: list
volumes: list
@ -695,9 +724,6 @@ class Container:
ct_opts = ContainerOptions.from_json(json, logger)
if not ct_opts.is_valid:
return
network = maybe(json, "network")
dns = maybe(json, "dns")
ports = maybe(json, "ports")
env = maybe(json, "env")
secrets = maybe(json, "secrets")
volumes = maybe(json, "volumes")
@ -706,9 +732,7 @@ class Container:
self.name = str(name)
self.image = Image.from_json(image, logger)
self.ct_opts = ct_opts
self.network = Network.from_json(network, logger)
self.dns = Dns.from_json(dns, logger)
self.ports = Ports.from_json(ports, logger)
self.ct_network = ContainerNetwork.from_json(json, logger)
self.env = Environment.from_json(env, logger)
self.env.file = "/var/lib/containerctl/environment-files/"
self.env.file += f"{self.name}"
@ -747,9 +771,7 @@ class Container:
cmd += "podman container create \\\n"
cmd += f"\t--name={self.name} \\\n"
cmd += f"{self.ct_opts.command()}"
cmd += f"{self.network.command()}"
cmd += f"{self.dns.command()}"
cmd += f"{self.ports.command()}"
cmd += f"{self.ct_network.command()}"
cmd += f"{self.env.command()}"
for secret in self.secrets:
cmd += f"{secret.command()}"

View file

@ -14,7 +14,7 @@ from pathlib import Path
from container import ConfigError, Container
from log import Log
GENERATE_VERSION = "0.0.11"
GENERATE_VERSION = "0.0.13"
HEADER = f"""#!/bin/sh
# This script was generated by containerctl v{GENERATE_VERSION}
# Report bugs with _this script_ to <tenno+containerctl@suij.in>
@ -80,6 +80,7 @@ def main() -> None:
if data is None:
logger.log_error(f"{config_file} is invalid, aborting!")
sys.exit(1)
logger.set_prefix(Path(config_file).name)
ct = create_container_from_config(data, logger)
if ct is None:
sys.exit(1)

View file

@ -15,6 +15,7 @@ class Log:
messages: list = []
logfile: Path
prefix: str = ""
def __init__(self, path: str) -> None:
"""Init for Log."""
@ -25,15 +26,19 @@ class Log:
def log_error(self, msg: str) -> None:
"""Log an error."""
now = self.timestamp()
prefix = "EE"
log_message = f"[{now}] ({prefix}) {msg}"
prefix = "(EE)"
if self.prefix != "":
prefix += f" {self.prefix}:"
log_message = f"[{now}] {prefix} {msg}"
self.write_message(log_message)
def log_warning(self, msg: str) -> None:
"""Log a warning."""
now = self.timestamp()
prefix = "WW"
log_message = f"[{now}] ({prefix}) {msg}"
prefix = "(WW)"
if self.prefix != "":
prefix += f" {self.prefix}:"
log_message = f"[{now}] {prefix} {msg}"
self.write_message(log_message)
def write_message(self, msg: str) -> None:
@ -49,3 +54,7 @@ class Log:
return datetime.datetime.now(tz=datetime.UTC).strftime(
"%Y-%m-%d %H:%M:%S",
)
def set_prefix(self, prefix: str) -> None:
"""Set a prefix."""
self.prefix = prefix