mirror of
https://github.com/Red5d/docker-autocompose
synced 2026-09-06 03:31:47 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4479f0674f | ||
|
|
d213724bde | ||
|
|
105ab39c00 | ||
|
|
f9f210a274 | ||
|
|
64c19bbaeb | ||
|
|
64c7868bba |
@@ -43,7 +43,7 @@ jobs:
|
|||||||
uses: docker/setup-buildx-action@v1.3.0
|
uses: docker/setup-buildx-action@v1.3.0
|
||||||
|
|
||||||
- name: Cache Docker layers
|
- name: Cache Docker layers
|
||||||
uses: actions/cache@v2.1.6
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: /tmp/.buildx-cache
|
path: /tmp/.buildx-cache
|
||||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||||
|
|||||||
Generated
+18
-8
@@ -1,4 +1,4 @@
|
|||||||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "certifi"
|
name = "certifi"
|
||||||
@@ -6,6 +6,7 @@ version = "2024.8.30"
|
|||||||
description = "Python package for providing Mozilla's CA Bundle."
|
description = "Python package for providing Mozilla's CA Bundle."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.6"
|
||||||
|
groups = ["main"]
|
||||||
files = [
|
files = [
|
||||||
{file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"},
|
{file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"},
|
||||||
{file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"},
|
{file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"},
|
||||||
@@ -17,6 +18,7 @@ version = "3.4.0"
|
|||||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7.0"
|
python-versions = ">=3.7.0"
|
||||||
|
groups = ["main"]
|
||||||
files = [
|
files = [
|
||||||
{file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"},
|
{file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"},
|
||||||
{file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"},
|
{file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"},
|
||||||
@@ -131,6 +133,7 @@ version = "7.1.0"
|
|||||||
description = "A Python library for the Docker Engine API."
|
description = "A Python library for the Docker Engine API."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
files = [
|
files = [
|
||||||
{file = "docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0"},
|
{file = "docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0"},
|
||||||
{file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"},
|
{file = "docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c"},
|
||||||
@@ -149,17 +152,18 @@ websockets = ["websocket-client (>=1.3.0)"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "3.10"
|
version = "3.15"
|
||||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.6"
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
files = [
|
files = [
|
||||||
{file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
|
{file = "idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8"},
|
||||||
{file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
|
{file = "idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
|
all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyaml"
|
name = "pyaml"
|
||||||
@@ -167,6 +171,7 @@ version = "24.9.0"
|
|||||||
description = "PyYAML-based module to produce a bit more pretty and readable YAML-serialized data"
|
description = "PyYAML-based module to produce a bit more pretty and readable YAML-serialized data"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
files = [
|
files = [
|
||||||
{file = "pyaml-24.9.0-py3-none-any.whl", hash = "sha256:31080551502f1014852b3c966a96c796adc79b4cf86e165f28ed83455bf19c62"},
|
{file = "pyaml-24.9.0-py3-none-any.whl", hash = "sha256:31080551502f1014852b3c966a96c796adc79b4cf86e165f28ed83455bf19c62"},
|
||||||
{file = "pyaml-24.9.0.tar.gz", hash = "sha256:e78dee8b0d4fed56bb9fa11a8a7858e6fade1ec70a9a122cee6736efac3e69b5"},
|
{file = "pyaml-24.9.0.tar.gz", hash = "sha256:e78dee8b0d4fed56bb9fa11a8a7858e6fade1ec70a9a122cee6736efac3e69b5"},
|
||||||
@@ -184,6 +189,8 @@ version = "308"
|
|||||||
description = "Python for Window Extensions"
|
description = "Python for Window Extensions"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
|
groups = ["main"]
|
||||||
|
markers = "sys_platform == \"win32\""
|
||||||
files = [
|
files = [
|
||||||
{file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"},
|
{file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"},
|
||||||
{file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"},
|
{file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"},
|
||||||
@@ -211,6 +218,7 @@ version = "6.0.2"
|
|||||||
description = "YAML parser and emitter for Python"
|
description = "YAML parser and emitter for Python"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
files = [
|
files = [
|
||||||
{file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
|
{file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
|
||||||
{file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
|
{file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
|
||||||
@@ -273,6 +281,7 @@ version = "2.32.3"
|
|||||||
description = "Python HTTP for Humans."
|
description = "Python HTTP for Humans."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
files = [
|
files = [
|
||||||
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
|
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
|
||||||
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
|
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
|
||||||
@@ -294,18 +303,19 @@ version = "2.2.3"
|
|||||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
|
groups = ["main"]
|
||||||
files = [
|
files = [
|
||||||
{file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"},
|
{file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"},
|
||||||
{file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"},
|
{file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
|
brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""]
|
||||||
h2 = ["h2 (>=4,<5)"]
|
h2 = ["h2 (>=4,<5)"]
|
||||||
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||||
zstd = ["zstandard (>=0.18.0)"]
|
zstd = ["zstandard (>=0.18.0)"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.1"
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.8"
|
||||||
content-hash = "9fcebd0faade00ce36ae6f306ab2b23521a080299c97e62cc409a5472de8d8f7"
|
content-hash = "9fcebd0faade00ce36ae6f306ab2b23521a080299c97e62cc409a5472de8d8f7"
|
||||||
|
|||||||
+69
-8
@@ -13,6 +13,57 @@ pyaml.add_representer(bool,lambda s,o: s.represent_scalar('tag:yaml.org,2002:boo
|
|||||||
IGNORE_VALUES = [None, "", [], "null", {}, "default", 0, ",", "no"]
|
IGNORE_VALUES = [None, "", [], "null", {}, "default", 0, ",", "no"]
|
||||||
|
|
||||||
|
|
||||||
|
def format_compose_duration(value):
|
||||||
|
if isinstance(value, int):
|
||||||
|
return f"{value}ns"
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def build_service_networks(network_settings, default_networks):
|
||||||
|
custom_networks = {}
|
||||||
|
|
||||||
|
for network_name, network_attributes in network_settings.items():
|
||||||
|
if network_name in default_networks:
|
||||||
|
continue
|
||||||
|
|
||||||
|
network_values = {}
|
||||||
|
aliases = network_attributes.get("Aliases")
|
||||||
|
if aliases:
|
||||||
|
network_values["aliases"] = aliases
|
||||||
|
|
||||||
|
custom_networks[network_name] = network_values
|
||||||
|
|
||||||
|
if not custom_networks:
|
||||||
|
return None, set()
|
||||||
|
|
||||||
|
has_network_config = any(network_values for network_values in custom_networks.values())
|
||||||
|
if has_network_config:
|
||||||
|
return custom_networks, set(custom_networks.keys())
|
||||||
|
|
||||||
|
return sorted(custom_networks.keys()), set(custom_networks.keys())
|
||||||
|
|
||||||
|
|
||||||
|
def build_healthcheck(config):
|
||||||
|
healthcheck = config.get("Healthcheck")
|
||||||
|
if not isinstance(healthcheck, dict):
|
||||||
|
return None
|
||||||
|
|
||||||
|
values = {}
|
||||||
|
|
||||||
|
if healthcheck.get("Test") not in IGNORE_VALUES:
|
||||||
|
values["test"] = healthcheck.get("Test")
|
||||||
|
if healthcheck.get("Interval") not in IGNORE_VALUES:
|
||||||
|
values["interval"] = format_compose_duration(healthcheck.get("Interval"))
|
||||||
|
if healthcheck.get("Timeout") not in IGNORE_VALUES:
|
||||||
|
values["timeout"] = format_compose_duration(healthcheck.get("Timeout"))
|
||||||
|
if healthcheck.get("Retries") not in IGNORE_VALUES:
|
||||||
|
values["retries"] = healthcheck.get("Retries")
|
||||||
|
if healthcheck.get("StartPeriod") not in IGNORE_VALUES:
|
||||||
|
values["start_period"] = format_compose_duration(healthcheck.get("StartPeriod"))
|
||||||
|
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
def shell_escape_string(input_string):
|
def shell_escape_string(input_string):
|
||||||
# Currently known issues:
|
# Currently known issues:
|
||||||
# - Basic Auth strings (e.g. set via Træfik labels) contain $ characters, which must be doubled. See https://stackoverflow.com/a/40621373/5885325
|
# - Basic Auth strings (e.g. set via Træfik labels) contain $ characters, which must be doubled. See https://stackoverflow.com/a/40621373/5885325
|
||||||
@@ -169,6 +220,8 @@ def generate(cname, createvolumes=False):
|
|||||||
ct = cfile[cattrs.get("Name")[1:]]
|
ct = cfile[cattrs.get("Name")[1:]]
|
||||||
|
|
||||||
default_networks = ["bridge", "host", "none"]
|
default_networks = ["bridge", "host", "none"]
|
||||||
|
network_settings = cattrs.get("NetworkSettings", {}).get("Networks", {})
|
||||||
|
service_networks, attached_network_names = build_service_networks(network_settings, default_networks)
|
||||||
|
|
||||||
values = {
|
values = {
|
||||||
"cap_drop": cattrs.get("HostConfig", {}).get("CapDrop", None),
|
"cap_drop": cattrs.get("HostConfig", {}).get("CapDrop", None),
|
||||||
@@ -188,9 +241,8 @@ def generate(cname, createvolumes=False):
|
|||||||
"driver": cattrs.get("HostConfig", {}).get("LogConfig", {}).get("Type", None),
|
"driver": cattrs.get("HostConfig", {}).get("LogConfig", {}).get("Type", None),
|
||||||
"options": cattrs.get("HostConfig", {}).get("LogConfig", {}).get("Config", None),
|
"options": cattrs.get("HostConfig", {}).get("LogConfig", {}).get("Config", None),
|
||||||
},
|
},
|
||||||
"networks": {
|
"networks": service_networks,
|
||||||
x for x in cattrs.get("NetworkSettings", {}).get("Networks", {}).keys() if x not in default_networks
|
"healthcheck": build_healthcheck(cattrs.get("Config", {})),
|
||||||
},
|
|
||||||
"security_opt": cattrs.get("HostConfig", {}).get("SecurityOpt"),
|
"security_opt": cattrs.get("HostConfig", {}).get("SecurityOpt"),
|
||||||
"ulimits": cattrs.get("HostConfig", {}).get("Ulimits"),
|
"ulimits": cattrs.get("HostConfig", {}).get("Ulimits"),
|
||||||
# the line below would not handle type bind
|
# the line below would not handle type bind
|
||||||
@@ -204,7 +256,16 @@ def generate(cname, createvolumes=False):
|
|||||||
"domainname": cattrs.get("Config", {}).get("Domainname", None),
|
"domainname": cattrs.get("Config", {}).get("Domainname", None),
|
||||||
"hostname": cattrs.get("Config", {}).get("Hostname", None),
|
"hostname": cattrs.get("Config", {}).get("Hostname", None),
|
||||||
"ipc": cattrs.get("HostConfig", {}).get("IpcMode", None),
|
"ipc": cattrs.get("HostConfig", {}).get("IpcMode", None),
|
||||||
"mac_address": cattrs.get("NetworkSettings", {}).get("MacAddress", None),
|
"mac_address": cattrs.get("NetworkSettings", {}).get(
|
||||||
|
"MacAddress"
|
||||||
|
) or next(
|
||||||
|
(
|
||||||
|
net.get("MacAddress")
|
||||||
|
for net in cattrs.get("NetworkSettings", {}).get("Networks", {}).values()
|
||||||
|
if net.get("MacAddress")
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
),
|
||||||
"privileged": cattrs.get("HostConfig", {}).get("Privileged", None),
|
"privileged": cattrs.get("HostConfig", {}).get("Privileged", None),
|
||||||
"restart": cattrs.get("HostConfig", {}).get("RestartPolicy", {}).get("Name", None),
|
"restart": cattrs.get("HostConfig", {}).get("RestartPolicy", {}).get("Name", None),
|
||||||
"read_only": cattrs.get("HostConfig", {}).get("ReadonlyRootfs", None),
|
"read_only": cattrs.get("HostConfig", {}).get("ReadonlyRootfs", None),
|
||||||
@@ -219,17 +280,17 @@ def generate(cname, createvolumes=False):
|
|||||||
]
|
]
|
||||||
|
|
||||||
networks = {}
|
networks = {}
|
||||||
if values["networks"] == set():
|
if not attached_network_names:
|
||||||
del values["networks"]
|
del values["networks"]
|
||||||
|
|
||||||
if len(cattrs.get("NetworkSettings", {}).get("Networks", {}).keys()) > 0:
|
if len(network_settings.keys()) > 0:
|
||||||
assumed_default_network = list(cattrs.get("NetworkSettings", {}).get("Networks", {}).keys())[0]
|
assumed_default_network = list(network_settings.keys())[0]
|
||||||
values["network_mode"] = assumed_default_network
|
values["network_mode"] = assumed_default_network
|
||||||
networks = None
|
networks = None
|
||||||
else:
|
else:
|
||||||
networklist = c.networks.list()
|
networklist = c.networks.list()
|
||||||
for network in networklist:
|
for network in networklist:
|
||||||
if network.attrs["Name"] in values["networks"]:
|
if network.attrs["Name"] in attached_network_names:
|
||||||
networks[network.attrs["Name"]] = {
|
networks[network.attrs["Name"]] = {
|
||||||
"external": (not network.attrs["Internal"]),
|
"external": (not network.attrs["Internal"]),
|
||||||
"name": network.attrs["Name"],
|
"name": network.attrs["Name"],
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
import unittest
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from src import autocompose
|
||||||
|
|
||||||
|
|
||||||
|
class FakeContainerSummary:
|
||||||
|
name = "svc"
|
||||||
|
short_id = "abc123"
|
||||||
|
|
||||||
|
|
||||||
|
class FakeContainerWithAttrs:
|
||||||
|
def __init__(self, attrs):
|
||||||
|
self.attrs = attrs
|
||||||
|
|
||||||
|
|
||||||
|
class FakeContainers:
|
||||||
|
def __init__(self, attrs):
|
||||||
|
self._attrs = attrs
|
||||||
|
self._summary = FakeContainerSummary()
|
||||||
|
|
||||||
|
def list(self, **_kwargs):
|
||||||
|
return [self._summary]
|
||||||
|
|
||||||
|
def get(self, _cid):
|
||||||
|
return FakeContainerWithAttrs(self._attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeNetwork:
|
||||||
|
def __init__(self, name, internal=False):
|
||||||
|
self.attrs = {"Name": name, "Internal": internal}
|
||||||
|
|
||||||
|
|
||||||
|
class FakeNetworks:
|
||||||
|
def __init__(self, networks):
|
||||||
|
self._networks = [FakeNetwork(name, internal) for name, internal in networks]
|
||||||
|
|
||||||
|
def list(self):
|
||||||
|
return self._networks
|
||||||
|
|
||||||
|
|
||||||
|
class FakeDockerClient:
|
||||||
|
def __init__(self, attrs, networks):
|
||||||
|
self.containers = FakeContainers(attrs)
|
||||||
|
self.networks = FakeNetworks(networks)
|
||||||
|
|
||||||
|
|
||||||
|
def make_attrs(networks, healthcheck=None):
|
||||||
|
return {
|
||||||
|
"Name": "/svc",
|
||||||
|
"HostConfig": {
|
||||||
|
"CapDrop": None,
|
||||||
|
"CgroupParent": None,
|
||||||
|
"Dns": None,
|
||||||
|
"DnsSearch": None,
|
||||||
|
"ExtraHosts": None,
|
||||||
|
"Links": None,
|
||||||
|
"LogConfig": {"Type": None, "Config": None},
|
||||||
|
"SecurityOpt": None,
|
||||||
|
"Ulimits": None,
|
||||||
|
"VolumeDriver": None,
|
||||||
|
"VolumesFrom": None,
|
||||||
|
"IpcMode": None,
|
||||||
|
"Privileged": None,
|
||||||
|
"RestartPolicy": {"Name": None},
|
||||||
|
"ReadonlyRootfs": None,
|
||||||
|
"Devices": None,
|
||||||
|
"PortBindings": {},
|
||||||
|
},
|
||||||
|
"Config": {
|
||||||
|
"Env": None,
|
||||||
|
"Image": "test:latest",
|
||||||
|
"Labels": {},
|
||||||
|
"Entrypoint": None,
|
||||||
|
"User": None,
|
||||||
|
"WorkingDir": None,
|
||||||
|
"Domainname": None,
|
||||||
|
"Hostname": None,
|
||||||
|
"OpenStdin": None,
|
||||||
|
"Tty": None,
|
||||||
|
"Cmd": None,
|
||||||
|
"ExposedPorts": {},
|
||||||
|
"Healthcheck": healthcheck,
|
||||||
|
},
|
||||||
|
"NetworkSettings": {"Networks": networks, "MacAddress": None},
|
||||||
|
"Mounts": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class GenerateTests(unittest.TestCase):
|
||||||
|
def test_preserves_network_aliases(self):
|
||||||
|
attrs = make_attrs(
|
||||||
|
{
|
||||||
|
"custom_net": {
|
||||||
|
"Aliases": ["svc", "db"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
fake_client = FakeDockerClient(attrs, networks=[("custom_net", False)])
|
||||||
|
|
||||||
|
with patch("src.autocompose.docker.from_env", return_value=fake_client):
|
||||||
|
cfile, c_networks, _ = autocompose.generate("svc")
|
||||||
|
|
||||||
|
self.assertEqual(cfile["svc"]["networks"], {"custom_net": {"aliases": ["svc", "db"]}})
|
||||||
|
self.assertEqual(
|
||||||
|
c_networks,
|
||||||
|
{"custom_net": {"external": True, "name": "custom_net"}},
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_serializes_healthcheck_config(self):
|
||||||
|
attrs = make_attrs(
|
||||||
|
{"custom_net": {}},
|
||||||
|
healthcheck={
|
||||||
|
"Test": ["CMD-SHELL", "echo ok"],
|
||||||
|
"Interval": 1000000000,
|
||||||
|
"Timeout": 2000000000,
|
||||||
|
"Retries": 3,
|
||||||
|
"StartPeriod": 3000000000,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
fake_client = FakeDockerClient(attrs, networks=[("custom_net", False)])
|
||||||
|
|
||||||
|
with patch("src.autocompose.docker.from_env", return_value=fake_client):
|
||||||
|
cfile, _, _ = autocompose.generate("svc")
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
cfile["svc"]["healthcheck"],
|
||||||
|
{
|
||||||
|
"test": ["CMD-SHELL", "echo ok"],
|
||||||
|
"interval": "1000000000ns",
|
||||||
|
"timeout": "2000000000ns",
|
||||||
|
"retries": 3,
|
||||||
|
"start_period": "3000000000ns",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_simple_custom_network_uses_list_form(self):
|
||||||
|
attrs = make_attrs({"custom_net": {}})
|
||||||
|
fake_client = FakeDockerClient(attrs, networks=[("custom_net", True)])
|
||||||
|
|
||||||
|
with patch("src.autocompose.docker.from_env", return_value=fake_client):
|
||||||
|
cfile, c_networks, _ = autocompose.generate("svc")
|
||||||
|
|
||||||
|
self.assertEqual(cfile["svc"]["networks"], ["custom_net"])
|
||||||
|
self.assertEqual(
|
||||||
|
c_networks,
|
||||||
|
{"custom_net": {"external": False, "name": "custom_net"}},
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_default_network_still_uses_network_mode(self):
|
||||||
|
attrs = make_attrs({"bridge": {}})
|
||||||
|
fake_client = FakeDockerClient(attrs, networks=[("bridge", False)])
|
||||||
|
|
||||||
|
with patch("src.autocompose.docker.from_env", return_value=fake_client):
|
||||||
|
cfile, c_networks, _ = autocompose.generate("svc")
|
||||||
|
|
||||||
|
self.assertEqual(cfile["svc"]["network_mode"], "bridge")
|
||||||
|
self.assertNotIn("networks", cfile["svc"])
|
||||||
|
self.assertIsNone(c_networks)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user