diff --git a/pyinfra/operations/docker.py b/pyinfra/operations/docker.py index 915791b68..d968ac563 100644 --- a/pyinfra/operations/docker.py +++ b/pyinfra/operations/docker.py @@ -4,17 +4,20 @@ as inventory directly. """ +from typing import Any, Dict + from pyinfra import host from pyinfra.api import operation from pyinfra.facts.docker import DockerContainer, DockerNetwork, DockerVolume -from .util.docker import handle_docker +from .util.docker import CONTAINER_CONFIG_HASH_LABEL, ContainerSpec, handle_docker @operation() def container( container, image="", + args=None, ports=None, networks=None, volumes=None, @@ -28,6 +31,7 @@ def container( Manage Docker containers + container: name to identify the container + + args: list of command-line args to supply to the image + image: container image and tag ex: nginx:alpine + networks: network list to attach on container + ports: port list to expose @@ -70,56 +74,69 @@ def container( ) """ - existent_container = host.get_fact(DockerContainer, object_id=container) + want_spec = ContainerSpec( + image, + args or list(), + set(ports) if ports else set(), + set(networks) if networks else set(), + volumes or list(), + set(env_vars) if env_vars else set(), + pull_always, + ) - if force: - if existent_container: - yield handle_docker( - resource="container", - command="remove", - container=container, - ) + existent_container: Dict[str, Any] = next( + iter(host.get_fact(DockerContainer, object_id=container)), {} + ) - if present: - if not existent_container or force: - yield handle_docker( - resource="container", - command="create", - container=container, - image=image, - ports=ports, - networks=networks, - volumes=volumes, - env_vars=env_vars, - pull_always=pull_always, - present=present, - force=force, - start=start, - ) - - if existent_container and start: - if existent_container[0]["State"]["Status"] != "running": - yield handle_docker( - resource="container", - command="start", - container=container, - ) - - if existent_container and not start: - if existent_container[0]["State"]["Status"] == "running": - yield handle_docker( - resource="container", - command="stop", - container=container, - ) - - if existent_container and not present: + old_hash = ( + existent_container.get("Config", {}) + .get("Labels", {}) + .get(CONTAINER_CONFIG_HASH_LABEL, None) + ) + + container_spec_changed = old_hash != want_spec.config_hash() + + is_running = existent_container.get("State", {}).get("Status", "") == "running" + recreating = existent_container and (force or container_spec_changed) + removing = existent_container and not present + + do_remove = recreating or removing + do_create = not removing and ((present and not existent_container) or recreating) + do_start = present and start and (recreating or not is_running) + do_stop = not start and not removing and is_running and not recreating + + if not (do_remove or do_create or do_start or do_stop): + host.noop("container configuration is already correct") + + if do_remove: yield handle_docker( resource="container", command="remove", container=container, ) + if do_create: + yield handle_docker( + resource="container", + command="create", + container=container, + spec=want_spec, + ) + + if do_start: + yield handle_docker( + resource="container", + command="start", + container=container, + ) + + if do_stop: + yield handle_docker( + resource="container", + command="stop", + container=container, + ) + @operation(is_idempotent=False) def image(image, present=True): diff --git a/pyinfra/operations/util/docker.py b/pyinfra/operations/util/docker.py index fc8015e22..eda003316 100644 --- a/pyinfra/operations/util/docker.py +++ b/pyinfra/operations/util/docker.py @@ -1,38 +1,83 @@ +import dataclasses +import hashlib +import json +from typing import Any, List, Set + from pyinfra.api import OperationError +CONTAINER_CONFIG_HASH_LABEL = "com.github.pyinfra.config-hash" -def _create_container(**kwargs): - command = [] - networks = kwargs["networks"] if kwargs["networks"] else [] - ports = kwargs["ports"] if kwargs["ports"] else [] - volumes = kwargs["volumes"] if kwargs["volumes"] else [] - env_vars = kwargs["env_vars"] if kwargs["env_vars"] else [] +def _json_repr(obj: Any): + try: + return dataclasses.asdict(obj) + except TypeError: + pass + + if isinstance(obj, set): + return sorted(obj) + + # If there are other alternative types to try (e.g. dates) then do so here + + raise TypeError(f"object {type(obj).__name__} not serializable") + - if kwargs["image"] == "": - raise OperationError("missing 1 required argument: 'image'") +@dataclasses.dataclass +class ContainerSpec: + image: str = "" + args: List[str] = dataclasses.field(default_factory=list) + ports: Set[str] = dataclasses.field(default_factory=set) + networks: Set[str] = dataclasses.field(default_factory=set) + volumes: List[str] = dataclasses.field(default_factory=list) + env_vars: Set[str] = dataclasses.field(default_factory=set) + pull_always: bool = False - command.append("docker container create --name {0}".format(kwargs["container"])) + def container_create_args(self): + args = [f"--label '{CONTAINER_CONFIG_HASH_LABEL}={self.config_hash()}'"] + for network in sorted(self.networks): + args.append("--network {0}".format(network)) - for network in networks: - command.append("--network {0}".format(network)) + for port in sorted(self.ports): + args.append("-p {0}".format(port)) - for port in ports: - command.append("-p {0}".format(port)) + for volume in self.volumes: + args.append("-v {0}".format(volume)) - for volume in volumes: - command.append("-v {0}".format(volume)) + for env_var in sorted(self.env_vars): + args.append("-e {0}".format(env_var)) - for env_var in env_vars: - command.append("-e {0}".format(env_var)) + if self.pull_always: + args.append("--pull always") + + args.append(self.image) + args.extend(self.args) + + return args + + def config_hash(self) -> str: + serialized = json.dumps( + self, + default=_json_repr, + ensure_ascii=False, + sort_keys=True, + indent=None, + separators=(",", ":"), + ).encode("utf-8") + return hashlib.sha256(serialized).hexdigest() + + +def _create_container(**kwargs): + if "spec" not in kwargs: + raise OperationError("missing 1 required argument: 'spec'") - if kwargs["pull_always"]: - command.append("--pull always") + spec = kwargs["spec"] - command.append(kwargs["image"]) + if not spec.image: + raise OperationError("Docker image not specified") - if kwargs["start"]: - command.append("; {0}".format(_start_container(container=kwargs["container"]))) + command = [ + "docker container create --name {0}".format(kwargs["container"]) + ] + spec.container_create_args() return " ".join(command) diff --git a/tests/operations/docker.container/add_and_start_no_existent_container.json b/tests/operations/docker.container/add_and_start_no_existent_container.json index e16b515e2..307ba16f9 100644 --- a/tests/operations/docker.container/add_and_start_no_existent_container.json +++ b/tests/operations/docker.container/add_and_start_no_existent_container.json @@ -2,18 +2,37 @@ "kwargs": { "container": "nginx", "image": "nginx:alpine", + "args": [ + "nginx-debug", + "-g", + "'daemon off;'" + ], + "networks": [ + "foo", + "bar" + ], + "volumes": [ + "/host/a:/container/a", + "/host/b:/container/b" + ], "ports": [ - "80:80" + "80:80", + "8081:8081" + ], + "env_vars": [ + "ENV_A=foo", + "ENV_B=bar" ], "present": true, "start": true }, "facts": { "docker.DockerContainer": { - "object_id=nginx": [] + "object_id=nginx": [] } }, "commands": [ - "docker container create --name nginx -p 80:80 nginx:alpine ; docker container start nginx" + "docker container create --name nginx --label 'com.github.pyinfra.config-hash=72d37ab8f5ea3db48272d045bc10e211bbd628f2b4bab5c54d948b073313c9a3' --network bar --network foo -p 8081:8081 -p 80:80 -v /host/a:/container/a -v /host/b:/container/b -e ENV_A=foo -e ENV_B=bar nginx:alpine nginx-debug -g 'daemon off;'", + "docker container start nginx" ] } \ No newline at end of file diff --git a/tests/operations/docker.container/add_existent_container.json b/tests/operations/docker.container/add_existent_container.json deleted file mode 100644 index 4473baebc..000000000 --- a/tests/operations/docker.container/add_existent_container.json +++ /dev/null @@ -1,250 +0,0 @@ -{ - "kwargs": { - "container": "nginx", - "image": "nginx:alpine", - "ports": [ - "80:80" - ], - "present": true, - "force": true - }, - "facts": { - "docker.DockerContainer": - { - "object_id=nginx": [ - - { - "Id": "9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4", - "Created": "2024-05-26T22: 01: 24.10525839Z", - "Path": "/docker-entrypoint.sh", - "Args": [ - "nginx", - "-g", - "daemon off;" - ], - "State": { - "Status": "running", - "Running": "True", - "Paused": "False", - "Restarting": "False", - "OOMKilled": "False", - "Dead": "False", - "Pid": 8407, - "ExitCode": 0, - "Error": "", - "StartedAt": "2024-05-26T22: 01: 24.502384646Z", - "FinishedAt": "0001-01-01T00: 00: 00Z" - }, - "Image": "sha256:e784f4560448b14a66f55c26e1b4dad2c2877cc73d001b7cd0b18e24a700a070", - "ResolvConfPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/resolv.conf", - "HostnamePath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hostname", - "HostsPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hosts", - "LogPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4-json.log", - "Name": "/nginx", - "RestartCount": 0, - "Driver": "overlay2", - "Platform": "linux", - "MountLabel": "", - "ProcessLabel": "", - "AppArmorProfile": "", - "ExecIDs": "None", - "HostConfig": { - "Binds": "None", - "ContainerIDFile": "", - "LogConfig": { - "Type": "json-file", - "Config": {} - }, - "NetworkMode": "bridge", - "PortBindings": { - "80/tcp": [ - { - "HostIp": "", - "HostPort": "80" - } - ] - }, - "RestartPolicy": { - "Name": "no", - "MaximumRetryCount": 0 - }, - "AutoRemove": "False", - "VolumeDriver": "", - "VolumesFrom": "None", - "ConsoleSize": [ - 0, - 0 - ], - "CapAdd": "None", - "CapDrop": "None", - "CgroupnsMode": "private", - "Dns": [], - "DnsOptions": [], - "DnsSearch": [], - "ExtraHosts": "None", - "GroupAdd": "None", - "IpcMode": "private", - "Cgroup": "", - "Links": "None", - "OomScoreAdj": 0, - "PidMode": "", - "Privileged": "False", - "PublishAllPorts": "False", - "ReadonlyRootfs": "False", - "SecurityOpt": "None", - "UTSMode": "", - "UsernsMode": "", - "ShmSize": 67108864, - "Runtime": "runc", - "Isolation": "", - "CpuShares": 0, - "Memory": 0, - "NanoCpus": 0, - "CgroupParent": "", - "BlkioWeight": 0, - "BlkioWeightDevice": [], - "BlkioDeviceReadBps": [], - "BlkioDeviceWriteBps": [], - "BlkioDeviceReadIOps": [], - "BlkioDeviceWriteIOps": [], - "CpuPeriod": 0, - "CpuQuota": 0, - "CpuRealtimePeriod": 0, - "CpuRealtimeRuntime": 0, - "CpusetCpus": "", - "CpusetMems": "", - "Devices": [], - "DeviceCgroupRules": "None", - "DeviceRequests": "None", - "MemoryReservation": 0, - "MemorySwap": 0, - "MemorySwappiness": "None", - "OomKillDisable": "None", - "PidsLimit": "None", - "Ulimits": [], - "CpuCount": 0, - "CpuPercent": 0, - "IOMaximumIOps": 0, - "IOMaximumBandwidth": 0, - "MaskedPaths": [ - "/proc/asound", - "/proc/acpi", - "/proc/kcore", - "/proc/keys", - "/proc/latency_stats", - "/proc/timer_list", - "/proc/timer_stats", - "/proc/sched_debug", - "/proc/scsi", - "/sys/firmware", - "/sys/devices/virtual/powercap" - ], - "ReadonlyPaths": [ - "/proc/bus", - "/proc/fs", - "/proc/irq", - "/proc/sys", - "/proc/sysrq-trigger" - ] - }, - "GraphDriver": { - "Data": { - "LowerDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca-init/diff:/var/lib/docker/overlay2/21b7dde68322832abacbc35a1fdfe6a75bacb0ef4b55d5341b29c0be312d457e/diff:/var/lib/docker/overlay2/7b978a86e25dd74d51c81795b8af92c4ae3c0cd8d5d34602e70dfe3be604aebe/diff:/var/lib/docker/overlay2/483058275ebfbe7dbc3e5bb15f2d7c45ec3f61a935b2a098d82f16cf8ba5231b/diff:/var/lib/docker/overlay2/87438f28df76ef0175c7ccd134f23f70e83fd85870f693735d6757bf6cb88f98/diff:/var/lib/docker/overlay2/ac61c96de3b3fd3644979b81c98d1071e6a063bfd2dcfb9c73cae30e064efdb8/diff:/var/lib/docker/overlay2/d744f3a16ab1a2cfd7889959279e6cc693199e5c1099d48f3c0794f62b045cc7/diff:/var/lib/docker/overlay2/572ed1139aed78c5873bc6ca8f8172b10b9876062f9a385c653e17244d88e421/diff", - "MergedDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/merged", - "UpperDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/diff", - "WorkDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/work" - }, - "Name": "overlay2" - }, - "Mounts": [], - "Config": { - "Hostname": "9bb5a79e7c4d", - "Domainname": "", - "User": "", - "AttachStdin": "False", - "AttachStdout": "True", - "AttachStderr": "True", - "ExposedPorts": { - "80/tcp": {} - }, - "Tty": "False", - "OpenStdin": "False", - "StdinOnce": "False", - "Env": [ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "NGINX_VERSION=1.25.5", - "NJS_VERSION=0.8.4", - "NJS_RELEASE=3~bookworm", - "PKG_RELEASE=1~bookworm" - ], - "Cmd": [ - "nginx", - "-g", - "daemon off;" - ], - "Image": "nginx", - "Volumes": "None", - "WorkingDir": "", - "Entrypoint": [ - "/docker-entrypoint.sh" - ], - "OnBuild": "None", - "Labels": { - "maintainer": "NGINX Docker Maintainers " - }, - "StopSignal": "SIGQUIT" - }, - "NetworkSettings": { - "Bridge": "", - "SandboxID": "30102172778c8c2268fa443d0c29ac898beaa07c6ca3d73a93751a21e0812f14", - "SandboxKey": "/var/run/docker/netns/30102172778c", - "Ports": { - "80/tcp": [ - { - "HostIp": "0.0.0.0", - "HostPort": "80" - } - ] - }, - "HairpinMode": "False", - "LinkLocalIPv6Address": "", - "LinkLocalIPv6PrefixLen": 0, - "SecondaryIPAddresses": "None", - "SecondaryIPv6Addresses": "None", - "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", - "Gateway": "172.17.0.1", - "GlobalIPv6Address": "", - "GlobalIPv6PrefixLen": 0, - "IPAddress": "172.17.0.2", - "IPPrefixLen": 16, - "IPv6Gateway": "", - "MacAddress": "02: 42:ac: 11: 00: 02", - "Networks": { - "bridge": { - "IPAMConfig": "None", - "Links": "None", - "Aliases": "None", - "MacAddress": "02: 42:ac: 11: 00: 02", - "NetworkID": "9602c89bf5d2a3b55665598ec99ec803cd54e0df0c2a25a511d59ecc2dc047b5", - "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", - "Gateway": "172.17.0.1", - "IPAddress": "172.17.0.2", - "IPPrefixLen": 16, - "IPv6Gateway": "", - "GlobalIPv6Address": "", - "GlobalIPv6PrefixLen": 0, - "DriverOpts": "None", - "DNSNames": "None" - } - } - } - - } - ] - } - }, - "commands": [ - "docker container rm -f nginx", - "docker container create --name nginx -p 80:80 nginx:alpine ; docker container start nginx" - ] -} \ No newline at end of file diff --git a/tests/operations/docker.container/add_existent_container_changed_ports.json b/tests/operations/docker.container/add_existent_container_changed_ports.json new file mode 100644 index 000000000..4c90673a9 --- /dev/null +++ b/tests/operations/docker.container/add_existent_container_changed_ports.json @@ -0,0 +1,249 @@ +{ + "kwargs": { + "container": "nginx", + "image": "nginx:alpine", + "ports": [ + "80:8080" + ], + "present": true, + "force": false + }, + "facts": { + "docker.DockerContainer": { + "object_id=nginx": [ + { + "Id": "9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4", + "Created": "2024-05-26T22: 01: 24.10525839Z", + "Path": "/docker-entrypoint.sh", + "Args": [ + "nginx", + "-g", + "daemon off;" + ], + "State": { + "Status": "running", + "Running": "True", + "Paused": "False", + "Restarting": "False", + "OOMKilled": "False", + "Dead": "False", + "Pid": 8407, + "ExitCode": 0, + "Error": "", + "StartedAt": "2024-05-26T22: 01: 24.502384646Z", + "FinishedAt": "0001-01-01T00: 00: 00Z" + }, + "Image": "sha256:e784f4560448b14a66f55c26e1b4dad2c2877cc73d001b7cd0b18e24a700a070", + "ResolvConfPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/resolv.conf", + "HostnamePath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hostname", + "HostsPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hosts", + "LogPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4-json.log", + "Name": "/nginx", + "RestartCount": 0, + "Driver": "overlay2", + "Platform": "linux", + "MountLabel": "", + "ProcessLabel": "", + "AppArmorProfile": "", + "ExecIDs": "None", + "HostConfig": { + "Binds": "None", + "ContainerIDFile": "", + "LogConfig": { + "Type": "json-file", + "Config": {} + }, + "NetworkMode": "bridge", + "PortBindings": { + "80/tcp": [ + { + "HostIp": "", + "HostPort": "80" + } + ] + }, + "RestartPolicy": { + "Name": "no", + "MaximumRetryCount": 0 + }, + "AutoRemove": "False", + "VolumeDriver": "", + "VolumesFrom": "None", + "ConsoleSize": [ + 0, + 0 + ], + "CapAdd": "None", + "CapDrop": "None", + "CgroupnsMode": "private", + "Dns": [], + "DnsOptions": [], + "DnsSearch": [], + "ExtraHosts": "None", + "GroupAdd": "None", + "IpcMode": "private", + "Cgroup": "", + "Links": "None", + "OomScoreAdj": 0, + "PidMode": "", + "Privileged": "False", + "PublishAllPorts": "False", + "ReadonlyRootfs": "False", + "SecurityOpt": "None", + "UTSMode": "", + "UsernsMode": "", + "ShmSize": 67108864, + "Runtime": "runc", + "Isolation": "", + "CpuShares": 0, + "Memory": 0, + "NanoCpus": 0, + "CgroupParent": "", + "BlkioWeight": 0, + "BlkioWeightDevice": [], + "BlkioDeviceReadBps": [], + "BlkioDeviceWriteBps": [], + "BlkioDeviceReadIOps": [], + "BlkioDeviceWriteIOps": [], + "CpuPeriod": 0, + "CpuQuota": 0, + "CpuRealtimePeriod": 0, + "CpuRealtimeRuntime": 0, + "CpusetCpus": "", + "CpusetMems": "", + "Devices": [], + "DeviceCgroupRules": "None", + "DeviceRequests": "None", + "MemoryReservation": 0, + "MemorySwap": 0, + "MemorySwappiness": "None", + "OomKillDisable": "None", + "PidsLimit": "None", + "Ulimits": [], + "CpuCount": 0, + "CpuPercent": 0, + "IOMaximumIOps": 0, + "IOMaximumBandwidth": 0, + "MaskedPaths": [ + "/proc/asound", + "/proc/acpi", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware", + "/sys/devices/virtual/powercap" + ], + "ReadonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ] + }, + "GraphDriver": { + "Data": { + "LowerDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca-init/diff:/var/lib/docker/overlay2/21b7dde68322832abacbc35a1fdfe6a75bacb0ef4b55d5341b29c0be312d457e/diff:/var/lib/docker/overlay2/7b978a86e25dd74d51c81795b8af92c4ae3c0cd8d5d34602e70dfe3be604aebe/diff:/var/lib/docker/overlay2/483058275ebfbe7dbc3e5bb15f2d7c45ec3f61a935b2a098d82f16cf8ba5231b/diff:/var/lib/docker/overlay2/87438f28df76ef0175c7ccd134f23f70e83fd85870f693735d6757bf6cb88f98/diff:/var/lib/docker/overlay2/ac61c96de3b3fd3644979b81c98d1071e6a063bfd2dcfb9c73cae30e064efdb8/diff:/var/lib/docker/overlay2/d744f3a16ab1a2cfd7889959279e6cc693199e5c1099d48f3c0794f62b045cc7/diff:/var/lib/docker/overlay2/572ed1139aed78c5873bc6ca8f8172b10b9876062f9a385c653e17244d88e421/diff", + "MergedDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/merged", + "UpperDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/diff", + "WorkDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/work" + }, + "Name": "overlay2" + }, + "Mounts": [], + "Config": { + "Hostname": "9bb5a79e7c4d", + "Domainname": "", + "User": "", + "AttachStdin": "False", + "AttachStdout": "True", + "AttachStderr": "True", + "ExposedPorts": { + "80/tcp": {} + }, + "Tty": "False", + "OpenStdin": "False", + "StdinOnce": "False", + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "NGINX_VERSION=1.25.5", + "NJS_VERSION=0.8.4", + "NJS_RELEASE=3~bookworm", + "PKG_RELEASE=1~bookworm" + ], + "Cmd": [ + "nginx", + "-g", + "daemon off;" + ], + "Image": "nginx", + "Volumes": "None", + "WorkingDir": "", + "Entrypoint": [ + "/docker-entrypoint.sh" + ], + "OnBuild": "None", + "Labels": { + "maintainer": "NGINX Docker Maintainers ", + "com.github.pyinfra.config-hash": "9be1c70576c6c4762c54bfce5fbd903638f9a68807453ce0549ad2e48b9a31f9" + }, + "StopSignal": "SIGQUIT" + }, + "NetworkSettings": { + "Bridge": "", + "SandboxID": "30102172778c8c2268fa443d0c29ac898beaa07c6ca3d73a93751a21e0812f14", + "SandboxKey": "/var/run/docker/netns/30102172778c", + "Ports": { + "80/tcp": [ + { + "HostIp": "0.0.0.0", + "HostPort": "80" + } + ] + }, + "HairpinMode": "False", + "LinkLocalIPv6Address": "", + "LinkLocalIPv6PrefixLen": 0, + "SecondaryIPAddresses": "None", + "SecondaryIPv6Addresses": "None", + "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", + "Gateway": "172.17.0.1", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "MacAddress": "02: 42:ac: 11: 00: 02", + "Networks": { + "bridge": { + "IPAMConfig": "None", + "Links": "None", + "Aliases": "None", + "MacAddress": "02: 42:ac: 11: 00: 02", + "NetworkID": "9602c89bf5d2a3b55665598ec99ec803cd54e0df0c2a25a511d59ecc2dc047b5", + "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", + "Gateway": "172.17.0.1", + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "DriverOpts": "None", + "DNSNames": "None" + } + } + } + } + ] + } + }, + "commands": [ + "docker container rm -f nginx", + "docker container create --name nginx --label 'com.github.pyinfra.config-hash=5351e6b8b50baa96591b7df3e87758fbbea39c56e29722ab17c4988a23e2803d' -p 80:8080 nginx:alpine", + "docker container start nginx" + ] +} \ No newline at end of file diff --git a/tests/operations/docker.container/add_existent_container_force.json b/tests/operations/docker.container/add_existent_container_force.json new file mode 100644 index 000000000..17684545e --- /dev/null +++ b/tests/operations/docker.container/add_existent_container_force.json @@ -0,0 +1,249 @@ +{ + "kwargs": { + "container": "nginx", + "image": "nginx:alpine", + "ports": [ + "80:80" + ], + "present": true, + "force": true + }, + "facts": { + "docker.DockerContainer": { + "object_id=nginx": [ + { + "Id": "9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4", + "Created": "2024-05-26T22: 01: 24.10525839Z", + "Path": "/docker-entrypoint.sh", + "Args": [ + "nginx", + "-g", + "daemon off;" + ], + "State": { + "Status": "running", + "Running": "True", + "Paused": "False", + "Restarting": "False", + "OOMKilled": "False", + "Dead": "False", + "Pid": 8407, + "ExitCode": 0, + "Error": "", + "StartedAt": "2024-05-26T22: 01: 24.502384646Z", + "FinishedAt": "0001-01-01T00: 00: 00Z" + }, + "Image": "sha256:e784f4560448b14a66f55c26e1b4dad2c2877cc73d001b7cd0b18e24a700a070", + "ResolvConfPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/resolv.conf", + "HostnamePath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hostname", + "HostsPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hosts", + "LogPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4-json.log", + "Name": "/nginx", + "RestartCount": 0, + "Driver": "overlay2", + "Platform": "linux", + "MountLabel": "", + "ProcessLabel": "", + "AppArmorProfile": "", + "ExecIDs": "None", + "HostConfig": { + "Binds": "None", + "ContainerIDFile": "", + "LogConfig": { + "Type": "json-file", + "Config": {} + }, + "NetworkMode": "bridge", + "PortBindings": { + "80/tcp": [ + { + "HostIp": "", + "HostPort": "80" + } + ] + }, + "RestartPolicy": { + "Name": "no", + "MaximumRetryCount": 0 + }, + "AutoRemove": "False", + "VolumeDriver": "", + "VolumesFrom": "None", + "ConsoleSize": [ + 0, + 0 + ], + "CapAdd": "None", + "CapDrop": "None", + "CgroupnsMode": "private", + "Dns": [], + "DnsOptions": [], + "DnsSearch": [], + "ExtraHosts": "None", + "GroupAdd": "None", + "IpcMode": "private", + "Cgroup": "", + "Links": "None", + "OomScoreAdj": 0, + "PidMode": "", + "Privileged": "False", + "PublishAllPorts": "False", + "ReadonlyRootfs": "False", + "SecurityOpt": "None", + "UTSMode": "", + "UsernsMode": "", + "ShmSize": 67108864, + "Runtime": "runc", + "Isolation": "", + "CpuShares": 0, + "Memory": 0, + "NanoCpus": 0, + "CgroupParent": "", + "BlkioWeight": 0, + "BlkioWeightDevice": [], + "BlkioDeviceReadBps": [], + "BlkioDeviceWriteBps": [], + "BlkioDeviceReadIOps": [], + "BlkioDeviceWriteIOps": [], + "CpuPeriod": 0, + "CpuQuota": 0, + "CpuRealtimePeriod": 0, + "CpuRealtimeRuntime": 0, + "CpusetCpus": "", + "CpusetMems": "", + "Devices": [], + "DeviceCgroupRules": "None", + "DeviceRequests": "None", + "MemoryReservation": 0, + "MemorySwap": 0, + "MemorySwappiness": "None", + "OomKillDisable": "None", + "PidsLimit": "None", + "Ulimits": [], + "CpuCount": 0, + "CpuPercent": 0, + "IOMaximumIOps": 0, + "IOMaximumBandwidth": 0, + "MaskedPaths": [ + "/proc/asound", + "/proc/acpi", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware", + "/sys/devices/virtual/powercap" + ], + "ReadonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ] + }, + "GraphDriver": { + "Data": { + "LowerDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca-init/diff:/var/lib/docker/overlay2/21b7dde68322832abacbc35a1fdfe6a75bacb0ef4b55d5341b29c0be312d457e/diff:/var/lib/docker/overlay2/7b978a86e25dd74d51c81795b8af92c4ae3c0cd8d5d34602e70dfe3be604aebe/diff:/var/lib/docker/overlay2/483058275ebfbe7dbc3e5bb15f2d7c45ec3f61a935b2a098d82f16cf8ba5231b/diff:/var/lib/docker/overlay2/87438f28df76ef0175c7ccd134f23f70e83fd85870f693735d6757bf6cb88f98/diff:/var/lib/docker/overlay2/ac61c96de3b3fd3644979b81c98d1071e6a063bfd2dcfb9c73cae30e064efdb8/diff:/var/lib/docker/overlay2/d744f3a16ab1a2cfd7889959279e6cc693199e5c1099d48f3c0794f62b045cc7/diff:/var/lib/docker/overlay2/572ed1139aed78c5873bc6ca8f8172b10b9876062f9a385c653e17244d88e421/diff", + "MergedDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/merged", + "UpperDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/diff", + "WorkDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/work" + }, + "Name": "overlay2" + }, + "Mounts": [], + "Config": { + "Hostname": "9bb5a79e7c4d", + "Domainname": "", + "User": "", + "AttachStdin": "False", + "AttachStdout": "True", + "AttachStderr": "True", + "ExposedPorts": { + "80/tcp": {} + }, + "Tty": "False", + "OpenStdin": "False", + "StdinOnce": "False", + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "NGINX_VERSION=1.25.5", + "NJS_VERSION=0.8.4", + "NJS_RELEASE=3~bookworm", + "PKG_RELEASE=1~bookworm" + ], + "Cmd": [ + "nginx", + "-g", + "daemon off;" + ], + "Image": "nginx", + "Volumes": "None", + "WorkingDir": "", + "Entrypoint": [ + "/docker-entrypoint.sh" + ], + "OnBuild": "None", + "Labels": { + "maintainer": "NGINX Docker Maintainers ", + "com.github.pyinfra.config-hash": "927b8c9ed243674a1bc23d0d88d867973cb71f0363e3029187ccaab7c7e79f19" + }, + "StopSignal": "SIGQUIT" + }, + "NetworkSettings": { + "Bridge": "", + "SandboxID": "30102172778c8c2268fa443d0c29ac898beaa07c6ca3d73a93751a21e0812f14", + "SandboxKey": "/var/run/docker/netns/30102172778c", + "Ports": { + "80/tcp": [ + { + "HostIp": "0.0.0.0", + "HostPort": "80" + } + ] + }, + "HairpinMode": "False", + "LinkLocalIPv6Address": "", + "LinkLocalIPv6PrefixLen": 0, + "SecondaryIPAddresses": "None", + "SecondaryIPv6Addresses": "None", + "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", + "Gateway": "172.17.0.1", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "MacAddress": "02: 42:ac: 11: 00: 02", + "Networks": { + "bridge": { + "IPAMConfig": "None", + "Links": "None", + "Aliases": "None", + "MacAddress": "02: 42:ac: 11: 00: 02", + "NetworkID": "9602c89bf5d2a3b55665598ec99ec803cd54e0df0c2a25a511d59ecc2dc047b5", + "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", + "Gateway": "172.17.0.1", + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "DriverOpts": "None", + "DNSNames": "None" + } + } + } + } + ] + } + }, + "commands": [ + "docker container rm -f nginx", + "docker container create --name nginx --label 'com.github.pyinfra.config-hash=927b8c9ed243674a1bc23d0d88d867973cb71f0363e3029187ccaab7c7e79f19' -p 80:80 nginx:alpine", + "docker container start nginx" + ] +} \ No newline at end of file diff --git a/tests/operations/docker.container/add_existent_container_no_changes.json b/tests/operations/docker.container/add_existent_container_no_changes.json new file mode 100644 index 000000000..32664a46b --- /dev/null +++ b/tests/operations/docker.container/add_existent_container_no_changes.json @@ -0,0 +1,246 @@ +{ + "kwargs": { + "container": "nginx", + "image": "nginx:alpine", + "ports": [ + "80:80" + ], + "present": true, + "force": false + }, + "facts": { + "docker.DockerContainer": { + "object_id=nginx": [ + { + "Id": "9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4", + "Created": "2024-05-26T22: 01: 24.10525839Z", + "Path": "/docker-entrypoint.sh", + "Args": [ + "nginx", + "-g", + "daemon off;" + ], + "State": { + "Status": "running", + "Running": "True", + "Paused": "False", + "Restarting": "False", + "OOMKilled": "False", + "Dead": "False", + "Pid": 8407, + "ExitCode": 0, + "Error": "", + "StartedAt": "2024-05-26T22: 01: 24.502384646Z", + "FinishedAt": "0001-01-01T00: 00: 00Z" + }, + "Image": "sha256:e784f4560448b14a66f55c26e1b4dad2c2877cc73d001b7cd0b18e24a700a070", + "ResolvConfPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/resolv.conf", + "HostnamePath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hostname", + "HostsPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hosts", + "LogPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4-json.log", + "Name": "/nginx", + "RestartCount": 0, + "Driver": "overlay2", + "Platform": "linux", + "MountLabel": "", + "ProcessLabel": "", + "AppArmorProfile": "", + "ExecIDs": "None", + "HostConfig": { + "Binds": "None", + "ContainerIDFile": "", + "LogConfig": { + "Type": "json-file", + "Config": {} + }, + "NetworkMode": "bridge", + "PortBindings": { + "80/tcp": [ + { + "HostIp": "", + "HostPort": "80" + } + ] + }, + "RestartPolicy": { + "Name": "no", + "MaximumRetryCount": 0 + }, + "AutoRemove": "False", + "VolumeDriver": "", + "VolumesFrom": "None", + "ConsoleSize": [ + 0, + 0 + ], + "CapAdd": "None", + "CapDrop": "None", + "CgroupnsMode": "private", + "Dns": [], + "DnsOptions": [], + "DnsSearch": [], + "ExtraHosts": "None", + "GroupAdd": "None", + "IpcMode": "private", + "Cgroup": "", + "Links": "None", + "OomScoreAdj": 0, + "PidMode": "", + "Privileged": "False", + "PublishAllPorts": "False", + "ReadonlyRootfs": "False", + "SecurityOpt": "None", + "UTSMode": "", + "UsernsMode": "", + "ShmSize": 67108864, + "Runtime": "runc", + "Isolation": "", + "CpuShares": 0, + "Memory": 0, + "NanoCpus": 0, + "CgroupParent": "", + "BlkioWeight": 0, + "BlkioWeightDevice": [], + "BlkioDeviceReadBps": [], + "BlkioDeviceWriteBps": [], + "BlkioDeviceReadIOps": [], + "BlkioDeviceWriteIOps": [], + "CpuPeriod": 0, + "CpuQuota": 0, + "CpuRealtimePeriod": 0, + "CpuRealtimeRuntime": 0, + "CpusetCpus": "", + "CpusetMems": "", + "Devices": [], + "DeviceCgroupRules": "None", + "DeviceRequests": "None", + "MemoryReservation": 0, + "MemorySwap": 0, + "MemorySwappiness": "None", + "OomKillDisable": "None", + "PidsLimit": "None", + "Ulimits": [], + "CpuCount": 0, + "CpuPercent": 0, + "IOMaximumIOps": 0, + "IOMaximumBandwidth": 0, + "MaskedPaths": [ + "/proc/asound", + "/proc/acpi", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware", + "/sys/devices/virtual/powercap" + ], + "ReadonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ] + }, + "GraphDriver": { + "Data": { + "LowerDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca-init/diff:/var/lib/docker/overlay2/21b7dde68322832abacbc35a1fdfe6a75bacb0ef4b55d5341b29c0be312d457e/diff:/var/lib/docker/overlay2/7b978a86e25dd74d51c81795b8af92c4ae3c0cd8d5d34602e70dfe3be604aebe/diff:/var/lib/docker/overlay2/483058275ebfbe7dbc3e5bb15f2d7c45ec3f61a935b2a098d82f16cf8ba5231b/diff:/var/lib/docker/overlay2/87438f28df76ef0175c7ccd134f23f70e83fd85870f693735d6757bf6cb88f98/diff:/var/lib/docker/overlay2/ac61c96de3b3fd3644979b81c98d1071e6a063bfd2dcfb9c73cae30e064efdb8/diff:/var/lib/docker/overlay2/d744f3a16ab1a2cfd7889959279e6cc693199e5c1099d48f3c0794f62b045cc7/diff:/var/lib/docker/overlay2/572ed1139aed78c5873bc6ca8f8172b10b9876062f9a385c653e17244d88e421/diff", + "MergedDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/merged", + "UpperDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/diff", + "WorkDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/work" + }, + "Name": "overlay2" + }, + "Mounts": [], + "Config": { + "Hostname": "9bb5a79e7c4d", + "Domainname": "", + "User": "", + "AttachStdin": "False", + "AttachStdout": "True", + "AttachStderr": "True", + "ExposedPorts": { + "80/tcp": {} + }, + "Tty": "False", + "OpenStdin": "False", + "StdinOnce": "False", + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "NGINX_VERSION=1.25.5", + "NJS_VERSION=0.8.4", + "NJS_RELEASE=3~bookworm", + "PKG_RELEASE=1~bookworm" + ], + "Cmd": [ + "nginx", + "-g", + "daemon off;" + ], + "Image": "nginx", + "Volumes": "None", + "WorkingDir": "", + "Entrypoint": [ + "/docker-entrypoint.sh" + ], + "OnBuild": "None", + "Labels": { + "maintainer": "NGINX Docker Maintainers ", + "com.github.pyinfra.config-hash": "927b8c9ed243674a1bc23d0d88d867973cb71f0363e3029187ccaab7c7e79f19" + }, + "StopSignal": "SIGQUIT" + }, + "NetworkSettings": { + "Bridge": "", + "SandboxID": "30102172778c8c2268fa443d0c29ac898beaa07c6ca3d73a93751a21e0812f14", + "SandboxKey": "/var/run/docker/netns/30102172778c", + "Ports": { + "80/tcp": [ + { + "HostIp": "0.0.0.0", + "HostPort": "80" + } + ] + }, + "HairpinMode": "False", + "LinkLocalIPv6Address": "", + "LinkLocalIPv6PrefixLen": 0, + "SecondaryIPAddresses": "None", + "SecondaryIPv6Addresses": "None", + "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", + "Gateway": "172.17.0.1", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "MacAddress": "02: 42:ac: 11: 00: 02", + "Networks": { + "bridge": { + "IPAMConfig": "None", + "Links": "None", + "Aliases": "None", + "MacAddress": "02: 42:ac: 11: 00: 02", + "NetworkID": "9602c89bf5d2a3b55665598ec99ec803cd54e0df0c2a25a511d59ecc2dc047b5", + "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", + "Gateway": "172.17.0.1", + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "DriverOpts": "None", + "DNSNames": "None" + } + } + } + } + ] + } + }, + "commands": [], + "noop_description": "container configuration is already correct" +} \ No newline at end of file diff --git a/tests/operations/docker.container/add_no_existent_container.json b/tests/operations/docker.container/add_no_existent_container.json index fdaa8ffba..8f87bb4d1 100644 --- a/tests/operations/docker.container/add_no_existent_container.json +++ b/tests/operations/docker.container/add_no_existent_container.json @@ -10,10 +10,10 @@ }, "facts": { "docker.DockerContainer": { - "object_id=nginx": [] + "object_id=nginx": [] } }, "commands": [ - "docker container create --name nginx -p 80:80 nginx:alpine" + "docker container create --name nginx --label 'com.github.pyinfra.config-hash=927b8c9ed243674a1bc23d0d88d867973cb71f0363e3029187ccaab7c7e79f19' -p 80:80 nginx:alpine" ] } \ No newline at end of file diff --git a/tests/operations/docker.container/remove_container.json b/tests/operations/docker.container/remove_container.json index 6f753fe83..0a8894ce2 100644 --- a/tests/operations/docker.container/remove_container.json +++ b/tests/operations/docker.container/remove_container.json @@ -8,239 +8,237 @@ "present": false }, "facts": { - "docker.DockerContainer": - { - "object_id=nginx": [ - - { - "Id": "9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4", - "Created": "2024-05-26T22: 01: 24.10525839Z", - "Path": "/docker-entrypoint.sh", - "Args": [ - "nginx", - "-g", - "daemon off;" - ], - "State": { - "Status": "running", - "Running": "True", - "Paused": "False", - "Restarting": "False", - "OOMKilled": "False", - "Dead": "False", - "Pid": 8407, - "ExitCode": 0, - "Error": "", - "StartedAt": "2024-05-26T22: 01: 24.502384646Z", - "FinishedAt": "0001-01-01T00: 00: 00Z" - }, - "Image": "sha256:e784f4560448b14a66f55c26e1b4dad2c2877cc73d001b7cd0b18e24a700a070", - "ResolvConfPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/resolv.conf", - "HostnamePath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hostname", - "HostsPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hosts", - "LogPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4-json.log", - "Name": "/nginx", - "RestartCount": 0, - "Driver": "overlay2", - "Platform": "linux", - "MountLabel": "", - "ProcessLabel": "", - "AppArmorProfile": "", - "ExecIDs": "None", - "HostConfig": { - "Binds": "None", - "ContainerIDFile": "", - "LogConfig": { - "Type": "json-file", - "Config": {} - }, - "NetworkMode": "bridge", - "PortBindings": { - "80/tcp": [ - { - "HostIp": "", - "HostPort": "80" - } - ] - }, - "RestartPolicy": { - "Name": "no", - "MaximumRetryCount": 0 - }, - "AutoRemove": "False", - "VolumeDriver": "", - "VolumesFrom": "None", - "ConsoleSize": [ - 0, - 0 - ], - "CapAdd": "None", - "CapDrop": "None", - "CgroupnsMode": "private", - "Dns": [], - "DnsOptions": [], - "DnsSearch": [], - "ExtraHosts": "None", - "GroupAdd": "None", - "IpcMode": "private", - "Cgroup": "", - "Links": "None", - "OomScoreAdj": 0, - "PidMode": "", - "Privileged": "False", - "PublishAllPorts": "False", - "ReadonlyRootfs": "False", - "SecurityOpt": "None", - "UTSMode": "", - "UsernsMode": "", - "ShmSize": 67108864, - "Runtime": "runc", - "Isolation": "", - "CpuShares": 0, - "Memory": 0, - "NanoCpus": 0, - "CgroupParent": "", - "BlkioWeight": 0, - "BlkioWeightDevice": [], - "BlkioDeviceReadBps": [], - "BlkioDeviceWriteBps": [], - "BlkioDeviceReadIOps": [], - "BlkioDeviceWriteIOps": [], - "CpuPeriod": 0, - "CpuQuota": 0, - "CpuRealtimePeriod": 0, - "CpuRealtimeRuntime": 0, - "CpusetCpus": "", - "CpusetMems": "", - "Devices": [], - "DeviceCgroupRules": "None", - "DeviceRequests": "None", - "MemoryReservation": 0, - "MemorySwap": 0, - "MemorySwappiness": "None", - "OomKillDisable": "None", - "PidsLimit": "None", - "Ulimits": [], - "CpuCount": 0, - "CpuPercent": 0, - "IOMaximumIOps": 0, - "IOMaximumBandwidth": 0, - "MaskedPaths": [ - "/proc/asound", - "/proc/acpi", - "/proc/kcore", - "/proc/keys", - "/proc/latency_stats", - "/proc/timer_list", - "/proc/timer_stats", - "/proc/sched_debug", - "/proc/scsi", - "/sys/firmware", - "/sys/devices/virtual/powercap" - ], - "ReadonlyPaths": [ - "/proc/bus", - "/proc/fs", - "/proc/irq", - "/proc/sys", - "/proc/sysrq-trigger" - ] - }, - "GraphDriver": { - "Data": { - "LowerDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca-init/diff:/var/lib/docker/overlay2/21b7dde68322832abacbc35a1fdfe6a75bacb0ef4b55d5341b29c0be312d457e/diff:/var/lib/docker/overlay2/7b978a86e25dd74d51c81795b8af92c4ae3c0cd8d5d34602e70dfe3be604aebe/diff:/var/lib/docker/overlay2/483058275ebfbe7dbc3e5bb15f2d7c45ec3f61a935b2a098d82f16cf8ba5231b/diff:/var/lib/docker/overlay2/87438f28df76ef0175c7ccd134f23f70e83fd85870f693735d6757bf6cb88f98/diff:/var/lib/docker/overlay2/ac61c96de3b3fd3644979b81c98d1071e6a063bfd2dcfb9c73cae30e064efdb8/diff:/var/lib/docker/overlay2/d744f3a16ab1a2cfd7889959279e6cc693199e5c1099d48f3c0794f62b045cc7/diff:/var/lib/docker/overlay2/572ed1139aed78c5873bc6ca8f8172b10b9876062f9a385c653e17244d88e421/diff", - "MergedDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/merged", - "UpperDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/diff", - "WorkDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/work" - }, - "Name": "overlay2" - }, - "Mounts": [], - "Config": { - "Hostname": "9bb5a79e7c4d", - "Domainname": "", - "User": "", - "AttachStdin": "False", - "AttachStdout": "True", - "AttachStderr": "True", - "ExposedPorts": { - "80/tcp": {} - }, - "Tty": "False", - "OpenStdin": "False", - "StdinOnce": "False", - "Env": [ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "NGINX_VERSION=1.25.5", - "NJS_VERSION=0.8.4", - "NJS_RELEASE=3~bookworm", - "PKG_RELEASE=1~bookworm" - ], - "Cmd": [ - "nginx", - "-g", - "daemon off;" - ], - "Image": "nginx", - "Volumes": "None", - "WorkingDir": "", - "Entrypoint": [ - "/docker-entrypoint.sh" - ], - "OnBuild": "None", - "Labels": { - "maintainer": "NGINX Docker Maintainers " - }, - "StopSignal": "SIGQUIT" - }, - "NetworkSettings": { - "Bridge": "", - "SandboxID": "30102172778c8c2268fa443d0c29ac898beaa07c6ca3d73a93751a21e0812f14", - "SandboxKey": "/var/run/docker/netns/30102172778c", - "Ports": { - "80/tcp": [ - { - "HostIp": "0.0.0.0", - "HostPort": "80" - } - ] - }, - "HairpinMode": "False", - "LinkLocalIPv6Address": "", - "LinkLocalIPv6PrefixLen": 0, - "SecondaryIPAddresses": "None", - "SecondaryIPv6Addresses": "None", - "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", - "Gateway": "172.17.0.1", - "GlobalIPv6Address": "", - "GlobalIPv6PrefixLen": 0, - "IPAddress": "172.17.0.2", - "IPPrefixLen": 16, - "IPv6Gateway": "", - "MacAddress": "02: 42:ac: 11: 00: 02", - "Networks": { - "bridge": { - "IPAMConfig": "None", - "Links": "None", - "Aliases": "None", - "MacAddress": "02: 42:ac: 11: 00: 02", - "NetworkID": "9602c89bf5d2a3b55665598ec99ec803cd54e0df0c2a25a511d59ecc2dc047b5", - "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", - "Gateway": "172.17.0.1", - "IPAddress": "172.17.0.2", - "IPPrefixLen": 16, - "IPv6Gateway": "", - "GlobalIPv6Address": "", - "GlobalIPv6PrefixLen": 0, - "DriverOpts": "None", - "DNSNames": "None" - } - } + "docker.DockerContainer": { + "object_id=nginx": [ + { + "Id": "9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4", + "Created": "2024-05-26T22: 01: 24.10525839Z", + "Path": "/docker-entrypoint.sh", + "Args": [ + "nginx", + "-g", + "daemon off;" + ], + "State": { + "Status": "running", + "Running": "True", + "Paused": "False", + "Restarting": "False", + "OOMKilled": "False", + "Dead": "False", + "Pid": 8407, + "ExitCode": 0, + "Error": "", + "StartedAt": "2024-05-26T22: 01: 24.502384646Z", + "FinishedAt": "0001-01-01T00: 00: 00Z" + }, + "Image": "sha256:e784f4560448b14a66f55c26e1b4dad2c2877cc73d001b7cd0b18e24a700a070", + "ResolvConfPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/resolv.conf", + "HostnamePath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hostname", + "HostsPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hosts", + "LogPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4-json.log", + "Name": "/nginx", + "RestartCount": 0, + "Driver": "overlay2", + "Platform": "linux", + "MountLabel": "", + "ProcessLabel": "", + "AppArmorProfile": "", + "ExecIDs": "None", + "HostConfig": { + "Binds": "None", + "ContainerIDFile": "", + "LogConfig": { + "Type": "json-file", + "Config": {} + }, + "NetworkMode": "bridge", + "PortBindings": { + "80/tcp": [ + { + "HostIp": "", + "HostPort": "80" } - + ] + }, + "RestartPolicy": { + "Name": "no", + "MaximumRetryCount": 0 + }, + "AutoRemove": "False", + "VolumeDriver": "", + "VolumesFrom": "None", + "ConsoleSize": [ + 0, + 0 + ], + "CapAdd": "None", + "CapDrop": "None", + "CgroupnsMode": "private", + "Dns": [], + "DnsOptions": [], + "DnsSearch": [], + "ExtraHosts": "None", + "GroupAdd": "None", + "IpcMode": "private", + "Cgroup": "", + "Links": "None", + "OomScoreAdj": 0, + "PidMode": "", + "Privileged": "False", + "PublishAllPorts": "False", + "ReadonlyRootfs": "False", + "SecurityOpt": "None", + "UTSMode": "", + "UsernsMode": "", + "ShmSize": 67108864, + "Runtime": "runc", + "Isolation": "", + "CpuShares": 0, + "Memory": 0, + "NanoCpus": 0, + "CgroupParent": "", + "BlkioWeight": 0, + "BlkioWeightDevice": [], + "BlkioDeviceReadBps": [], + "BlkioDeviceWriteBps": [], + "BlkioDeviceReadIOps": [], + "BlkioDeviceWriteIOps": [], + "CpuPeriod": 0, + "CpuQuota": 0, + "CpuRealtimePeriod": 0, + "CpuRealtimeRuntime": 0, + "CpusetCpus": "", + "CpusetMems": "", + "Devices": [], + "DeviceCgroupRules": "None", + "DeviceRequests": "None", + "MemoryReservation": 0, + "MemorySwap": 0, + "MemorySwappiness": "None", + "OomKillDisable": "None", + "PidsLimit": "None", + "Ulimits": [], + "CpuCount": 0, + "CpuPercent": 0, + "IOMaximumIOps": 0, + "IOMaximumBandwidth": 0, + "MaskedPaths": [ + "/proc/asound", + "/proc/acpi", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware", + "/sys/devices/virtual/powercap" + ], + "ReadonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ] + }, + "GraphDriver": { + "Data": { + "LowerDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca-init/diff:/var/lib/docker/overlay2/21b7dde68322832abacbc35a1fdfe6a75bacb0ef4b55d5341b29c0be312d457e/diff:/var/lib/docker/overlay2/7b978a86e25dd74d51c81795b8af92c4ae3c0cd8d5d34602e70dfe3be604aebe/diff:/var/lib/docker/overlay2/483058275ebfbe7dbc3e5bb15f2d7c45ec3f61a935b2a098d82f16cf8ba5231b/diff:/var/lib/docker/overlay2/87438f28df76ef0175c7ccd134f23f70e83fd85870f693735d6757bf6cb88f98/diff:/var/lib/docker/overlay2/ac61c96de3b3fd3644979b81c98d1071e6a063bfd2dcfb9c73cae30e064efdb8/diff:/var/lib/docker/overlay2/d744f3a16ab1a2cfd7889959279e6cc693199e5c1099d48f3c0794f62b045cc7/diff:/var/lib/docker/overlay2/572ed1139aed78c5873bc6ca8f8172b10b9876062f9a385c653e17244d88e421/diff", + "MergedDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/merged", + "UpperDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/diff", + "WorkDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/work" + }, + "Name": "overlay2" + }, + "Mounts": [], + "Config": { + "Hostname": "9bb5a79e7c4d", + "Domainname": "", + "User": "", + "AttachStdin": "False", + "AttachStdout": "True", + "AttachStderr": "True", + "ExposedPorts": { + "80/tcp": {} + }, + "Tty": "False", + "OpenStdin": "False", + "StdinOnce": "False", + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "NGINX_VERSION=1.25.5", + "NJS_VERSION=0.8.4", + "NJS_RELEASE=3~bookworm", + "PKG_RELEASE=1~bookworm" + ], + "Cmd": [ + "nginx", + "-g", + "daemon off;" + ], + "Image": "nginx", + "Volumes": "None", + "WorkingDir": "", + "Entrypoint": [ + "/docker-entrypoint.sh" + ], + "OnBuild": "None", + "Labels": { + "maintainer": "NGINX Docker Maintainers ", + "com.github.pyinfra.config-hash": "9be1c70576c6c4762c54bfce5fbd903638f9a68807453ce0549ad2e48b9a31f9" + }, + "StopSignal": "SIGQUIT" + }, + "NetworkSettings": { + "Bridge": "", + "SandboxID": "30102172778c8c2268fa443d0c29ac898beaa07c6ca3d73a93751a21e0812f14", + "SandboxKey": "/var/run/docker/netns/30102172778c", + "Ports": { + "80/tcp": [ + { + "HostIp": "0.0.0.0", + "HostPort": "80" + } + ] + }, + "HairpinMode": "False", + "LinkLocalIPv6Address": "", + "LinkLocalIPv6PrefixLen": 0, + "SecondaryIPAddresses": "None", + "SecondaryIPv6Addresses": "None", + "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", + "Gateway": "172.17.0.1", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "MacAddress": "02: 42:ac: 11: 00: 02", + "Networks": { + "bridge": { + "IPAMConfig": "None", + "Links": "None", + "Aliases": "None", + "MacAddress": "02: 42:ac: 11: 00: 02", + "NetworkID": "9602c89bf5d2a3b55665598ec99ec803cd54e0df0c2a25a511d59ecc2dc047b5", + "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", + "Gateway": "172.17.0.1", + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "DriverOpts": "None", + "DNSNames": "None" + } } - ] - } + } + } + ] + } }, "commands": [ "docker container rm -f nginx" diff --git a/tests/operations/docker.container/start_container.json b/tests/operations/docker.container/start_container.json index f16a01634..4b28087cc 100644 --- a/tests/operations/docker.container/start_container.json +++ b/tests/operations/docker.container/start_container.json @@ -9,8 +9,7 @@ }, "facts": { "docker.DockerContainer": { - - "object_id=nginx" :[ + "object_id=nginx": [ { "Id": "9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4", "Created": "2024-05-26T22: 01: 24.10525839Z", @@ -188,7 +187,8 @@ ], "OnBuild": "None", "Labels": { - "maintainer": "NGINX Docker Maintainers " + "maintainer": "NGINX Docker Maintainers ", + "com.github.pyinfra.config-hash": "927b8c9ed243674a1bc23d0d88d867973cb71f0363e3029187ccaab7c7e79f19" }, "StopSignal": "SIGQUIT" }, diff --git a/tests/operations/docker.container/stop_container.json b/tests/operations/docker.container/stop_container_no_changes.json similarity index 98% rename from tests/operations/docker.container/stop_container.json rename to tests/operations/docker.container/stop_container_no_changes.json index af9c57b87..273679f5f 100644 --- a/tests/operations/docker.container/stop_container.json +++ b/tests/operations/docker.container/stop_container_no_changes.json @@ -9,8 +9,7 @@ "start": false }, "facts": { - "docker.DockerContainer": - { + "docker.DockerContainer": { "object_id=nginx": [ { "Id": "9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4", @@ -189,7 +188,8 @@ ], "OnBuild": "None", "Labels": { - "maintainer": "NGINX Docker Maintainers " + "maintainer": "NGINX Docker Maintainers ", + "com.github.pyinfra.config-hash": "927b8c9ed243674a1bc23d0d88d867973cb71f0363e3029187ccaab7c7e79f19" }, "StopSignal": "SIGQUIT" }, @@ -240,7 +240,6 @@ } ] } - }, "commands": [ "docker container stop nginx" diff --git a/tests/operations/docker.container/stop_container_with_changes.json b/tests/operations/docker.container/stop_container_with_changes.json new file mode 100644 index 000000000..9c674b409 --- /dev/null +++ b/tests/operations/docker.container/stop_container_with_changes.json @@ -0,0 +1,266 @@ +{ + "kwargs": { + "container": "nginx", + "image": "nginx:alpine", + "args": [ + "nginx-debug", + "-g", + "'daemon off;'" + ], + "networks": [ + "foo", + "bar" + ], + "volumes": [ + "/host/a:/container/a", + "/host/b:/container/b" + ], + "ports": [ + "80:80", + "8081:8081" + ], + "env_vars": [ + "ENV_A=foo", + "ENV_B=bar" + ], + "present": true, + "start": false + }, + "facts": { + "docker.DockerContainer": { + "object_id=nginx": [ + { + "Id": "9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4", + "Created": "2024-05-26T22: 01: 24.10525839Z", + "Path": "/docker-entrypoint.sh", + "Args": [ + "nginx", + "-g", + "daemon off;" + ], + "State": { + "Status": "running", + "Running": "True", + "Paused": "False", + "Restarting": "False", + "OOMKilled": "False", + "Dead": "False", + "Pid": 8407, + "ExitCode": 0, + "Error": "", + "StartedAt": "2024-05-26T22: 01: 24.502384646Z", + "FinishedAt": "0001-01-01T00: 00: 00Z" + }, + "Image": "sha256:e784f4560448b14a66f55c26e1b4dad2c2877cc73d001b7cd0b18e24a700a070", + "ResolvConfPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/resolv.conf", + "HostnamePath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hostname", + "HostsPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/hosts", + "LogPath": "/var/lib/docker/containers/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4/9bb5a79e7c4da9ad38e7183aa7c943ee41dcbbab70e4832fe29b2788ab88d4b4-json.log", + "Name": "/nginx", + "RestartCount": 0, + "Driver": "overlay2", + "Platform": "linux", + "MountLabel": "", + "ProcessLabel": "", + "AppArmorProfile": "", + "ExecIDs": "None", + "HostConfig": { + "Binds": "None", + "ContainerIDFile": "", + "LogConfig": { + "Type": "json-file", + "Config": {} + }, + "NetworkMode": "bridge", + "PortBindings": { + "80/tcp": [ + { + "HostIp": "", + "HostPort": "80" + } + ] + }, + "RestartPolicy": { + "Name": "no", + "MaximumRetryCount": 0 + }, + "AutoRemove": "False", + "VolumeDriver": "", + "VolumesFrom": "None", + "ConsoleSize": [ + 0, + 0 + ], + "CapAdd": "None", + "CapDrop": "None", + "CgroupnsMode": "private", + "Dns": [], + "DnsOptions": [], + "DnsSearch": [], + "ExtraHosts": "None", + "GroupAdd": "None", + "IpcMode": "private", + "Cgroup": "", + "Links": "None", + "OomScoreAdj": 0, + "PidMode": "", + "Privileged": "False", + "PublishAllPorts": "False", + "ReadonlyRootfs": "False", + "SecurityOpt": "None", + "UTSMode": "", + "UsernsMode": "", + "ShmSize": 67108864, + "Runtime": "runc", + "Isolation": "", + "CpuShares": 0, + "Memory": 0, + "NanoCpus": 0, + "CgroupParent": "", + "BlkioWeight": 0, + "BlkioWeightDevice": [], + "BlkioDeviceReadBps": [], + "BlkioDeviceWriteBps": [], + "BlkioDeviceReadIOps": [], + "BlkioDeviceWriteIOps": [], + "CpuPeriod": 0, + "CpuQuota": 0, + "CpuRealtimePeriod": 0, + "CpuRealtimeRuntime": 0, + "CpusetCpus": "", + "CpusetMems": "", + "Devices": [], + "DeviceCgroupRules": "None", + "DeviceRequests": "None", + "MemoryReservation": 0, + "MemorySwap": 0, + "MemorySwappiness": "None", + "OomKillDisable": "None", + "PidsLimit": "None", + "Ulimits": [], + "CpuCount": 0, + "CpuPercent": 0, + "IOMaximumIOps": 0, + "IOMaximumBandwidth": 0, + "MaskedPaths": [ + "/proc/asound", + "/proc/acpi", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware", + "/sys/devices/virtual/powercap" + ], + "ReadonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ] + }, + "GraphDriver": { + "Data": { + "LowerDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca-init/diff:/var/lib/docker/overlay2/21b7dde68322832abacbc35a1fdfe6a75bacb0ef4b55d5341b29c0be312d457e/diff:/var/lib/docker/overlay2/7b978a86e25dd74d51c81795b8af92c4ae3c0cd8d5d34602e70dfe3be604aebe/diff:/var/lib/docker/overlay2/483058275ebfbe7dbc3e5bb15f2d7c45ec3f61a935b2a098d82f16cf8ba5231b/diff:/var/lib/docker/overlay2/87438f28df76ef0175c7ccd134f23f70e83fd85870f693735d6757bf6cb88f98/diff:/var/lib/docker/overlay2/ac61c96de3b3fd3644979b81c98d1071e6a063bfd2dcfb9c73cae30e064efdb8/diff:/var/lib/docker/overlay2/d744f3a16ab1a2cfd7889959279e6cc693199e5c1099d48f3c0794f62b045cc7/diff:/var/lib/docker/overlay2/572ed1139aed78c5873bc6ca8f8172b10b9876062f9a385c653e17244d88e421/diff", + "MergedDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/merged", + "UpperDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/diff", + "WorkDir": "/var/lib/docker/overlay2/ee7c8aaf7d9d84d989ea529b2cb1b4aea63c378ef0527ce8562f6d4d7530e1ca/work" + }, + "Name": "overlay2" + }, + "Mounts": [], + "Config": { + "Hostname": "9bb5a79e7c4d", + "Domainname": "", + "User": "", + "AttachStdin": "False", + "AttachStdout": "True", + "AttachStderr": "True", + "ExposedPorts": { + "80/tcp": {} + }, + "Tty": "False", + "OpenStdin": "False", + "StdinOnce": "False", + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "NGINX_VERSION=1.25.5", + "NJS_VERSION=0.8.4", + "NJS_RELEASE=3~bookworm", + "PKG_RELEASE=1~bookworm" + ], + "Cmd": [ + "nginx", + "-g", + "daemon off;" + ], + "Image": "nginx", + "Volumes": "None", + "WorkingDir": "", + "Entrypoint": [ + "/docker-entrypoint.sh" + ], + "OnBuild": "None", + "Labels": { + "maintainer": "NGINX Docker Maintainers ", + "com.github.pyinfra.config-hash": "927b8c9ed243674a1bc23d0d88d867973cb71f0363e3029187ccaab7c7e79f19" + }, + "StopSignal": "SIGQUIT" + }, + "NetworkSettings": { + "Bridge": "", + "SandboxID": "30102172778c8c2268fa443d0c29ac898beaa07c6ca3d73a93751a21e0812f14", + "SandboxKey": "/var/run/docker/netns/30102172778c", + "Ports": { + "80/tcp": [ + { + "HostIp": "0.0.0.0", + "HostPort": "80" + } + ] + }, + "HairpinMode": "False", + "LinkLocalIPv6Address": "", + "LinkLocalIPv6PrefixLen": 0, + "SecondaryIPAddresses": "None", + "SecondaryIPv6Addresses": "None", + "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", + "Gateway": "172.17.0.1", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "MacAddress": "02: 42:ac: 11: 00: 02", + "Networks": { + "bridge": { + "IPAMConfig": "None", + "Links": "None", + "Aliases": "None", + "MacAddress": "02: 42:ac: 11: 00: 02", + "NetworkID": "9602c89bf5d2a3b55665598ec99ec803cd54e0df0c2a25a511d59ecc2dc047b5", + "EndpointID": "2e0e98fd4346d9ad61d78294bd97e7c27f512a88c402115163a0df73bf83cad4", + "Gateway": "172.17.0.1", + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "DriverOpts": "None", + "DNSNames": "None" + } + } + } + } + ] + } + }, + "commands": [ + "docker container rm -f nginx", + "docker container create --name nginx --label 'com.github.pyinfra.config-hash=72d37ab8f5ea3db48272d045bc10e211bbd628f2b4bab5c54d948b073313c9a3' --network bar --network foo -p 8081:8081 -p 80:80 -v /host/a:/container/a -v /host/b:/container/b -e ENV_A=foo -e ENV_B=bar nginx:alpine nginx-debug -g 'daemon off;'" + ] +} \ No newline at end of file