Commit 97295fc2 authored by Dom Sekotill's avatar Dom Sekotill
Browse files

Merge branch 'release/0.3.x' into release/0.4.x

parents 3f65eeb1 aba62f81
Loading
Loading
Loading
Loading
Loading
+37 −16
Original line number Diff line number Diff line
#  Copyright 2021-2022  Dominik Sekotill <dom.sekotill@kodo.org.uk>
#  Copyright 2021-2023  Dominik Sekotill <dom.sekotill@kodo.org.uk>
#
#  This Source Code Form is subject to the terms of the Mozilla Public
#  License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -36,7 +36,6 @@ from typing import Iterator
from typing import MutableMapping
from typing import NewType
from typing import Protocol
from typing import Tuple
from typing import TypeVar
from typing import Union
from typing import cast
@@ -266,7 +265,7 @@ class Container:
		self.entrypoint = entrypoint
		self.privileged = privileged
		self.publish = publish
		self.networks = dict[Network, Tuple[str, ...]]()
		self.networks = dict[Network, tuple[IPAddress, tuple[str, ...]]]()
		self.cid: ShaID|None = None

		if network:
@@ -276,9 +275,12 @@ class Container:
		return self

	def __exit__(self, etype: type[BaseException], exc: BaseException, tb: TracebackType) -> None:
		try:
			if self.cid and exc:
				self.show_logs()
			self.stop(rm=True)
		except Exception:
			logging.getLogger(__name__).exception("ignoring exception while stopping")

	@contextmanager
	def started(self: T) -> Iterator[T]:
@@ -350,7 +352,11 @@ class Container:
			opts.append(b"--network=none")

		self.cid = ShaID(
			docker_output(b"container", b"create", *opts, self.image.iid, *self.cmd),
			docker_output(
				b"container", b"create",
				"--label", "uk.org.kodo.behave-utils",
				*opts, self.image.iid, *self.cmd,
			),
		)
		assert self.cid

@@ -358,6 +364,10 @@ class Container:
		if not self.publish:
			docker_quiet(b"network", b"disconnect", b"none", self.cid)

		# Connect any pre-configured networks
		for network, (address, aliases) in self.networks.items():
			self._connect_network(self.cid, network, address, aliases)

		return self.cid

	def start(self) -> None:
@@ -396,22 +406,32 @@ class Container:
		Any aliases supplied will be resolvable to the container by other containers on the
		network.
		"""
		cid = self.get_id()
		opts = [f'--alias={a}' for a in aliases]
		if network in self.networks:
			if self.networks[network][1] == aliases:
				return
			if self.cid is not None:
				docker(b"network", b"disconnect", str(network), self.cid)

		if address is None:
			address = network.reserve_address()
		self.networks[network] = address, aliases

		if self.cid is not None:
			self._connect_network(self.cid, network, address, aliases)

	@staticmethod
	def _connect_network(
		contrid: str,
		network: Network,
		address: IPAddress,
		aliases: Iterable[str],
	) -> None:
		opts = [f'--alias={a}' for a in aliases]
		opts.append(
			f"--ip={address}" if isinstance(address, ipaddress.IPv4Address) else
			f"--ip6={address}",
		)

		if network in self.networks:
			if self.networks[network] == aliases:
				return
			docker(b"network", b"disconnect", str(network), cid)
		docker(b"network", b"connect", *opts, str(network), cid)
		self.networks[network] = aliases
		docker(b"network", b"connect", *opts, str(network), contrid)

	def show_logs(self) -> None:
		"""
@@ -441,6 +461,7 @@ class Container:
		"""
		Run "cmd" to completion inside the container and return the result
		"""
		self.is_running(raise_on_exit=True)
		return run(
			self.get_exec_args(cmd),
			stdin=stdin, stdout=stdout, stderr=stderr,