mirror of
https://github.com/containers/podman-compose.git
synced 2024-12-26 00:29:00 +01:00
Support podman-specific per-network mac_address specifiation
Signed-off-by: Bas Zoetekouw <bas.zoetekouw@surf.nl>
This commit is contained in:
parent
91fbea3d89
commit
45ca1f994f
47
docs/Extensions.md
Normal file
47
docs/Extensions.md
Normal file
@ -0,0 +1,47 @@
|
||||
# Podman specific extensions to the docker-compose format
|
||||
|
||||
Podman-compose supports the following extension to the docker-compose format.
|
||||
|
||||
## Per-network MAC-addresses
|
||||
|
||||
Generic docker-compose files support specification of the MAC address on the container level. If the
|
||||
container has multiple network interfaces, the specified MAC address is applied to the first
|
||||
specified network.
|
||||
|
||||
Podman-compose in addition supports the specification of MAC addresses on a per-network basis. This
|
||||
is done by adding a `podman.mac_address` key to the network configuration in the container. The
|
||||
value of the `podman.mac_address` key is the MAC address to be used for the network interface.
|
||||
|
||||
Specifying a MAC address for the container and for individual networks at the same time is not
|
||||
supported.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
---
|
||||
version: "3"
|
||||
|
||||
networks:
|
||||
net0:
|
||||
driver: "bridge"
|
||||
ipam:
|
||||
config:
|
||||
- subnet: "192.168.0.0/24"
|
||||
net1:
|
||||
driver: "bridge"
|
||||
ipam:
|
||||
config:
|
||||
- subnet: "192.168.1.0/24"
|
||||
|
||||
services:
|
||||
webserver
|
||||
image: "busybox"
|
||||
command: ["/bin/busybox", "httpd", "-f", "-h", "/etc", "-p", "8001"]
|
||||
networks:
|
||||
net0:
|
||||
ipv4_address: "192.168.0.10"
|
||||
podman.mac_address: "02:aa:aa:aa:aa:aa"
|
||||
net1:
|
||||
ipv4_address: "192.168.1.10"
|
||||
podman.mac_address: "02:bb:bb:bb:bb:bb"
|
||||
```
|
@ -779,10 +779,8 @@ async def assert_cnt_nets(compose, cnt):
|
||||
def get_net_args(compose, cnt):
|
||||
service_name = cnt["service_name"]
|
||||
net_args = []
|
||||
mac_address = cnt.get("mac_address", None)
|
||||
if mac_address:
|
||||
net_args.extend(["--mac-address", mac_address])
|
||||
is_bridge = False
|
||||
mac_address = cnt.get("mac_address", None)
|
||||
net = cnt.get("network_mode", None)
|
||||
if net:
|
||||
if net == "none":
|
||||
@ -866,6 +864,18 @@ def get_net_args(compose, cnt):
|
||||
else:
|
||||
multiple_nets = {net: net_config or {} for net, net_config in multiple_nets.items()}
|
||||
|
||||
# if a mac_address was specified on the container level, we need to check that it is not
|
||||
# specified on the network level as well
|
||||
if mac_address is not None:
|
||||
for net_config_ in multiple_nets.values():
|
||||
network_mac = net_config_.get("podman.mac_address", None)
|
||||
if network_mac is not None:
|
||||
raise RuntimeError(
|
||||
f"conflicting mac addresses {mac_address} and {network_mac}:"
|
||||
"specifying mac_address on both container and network level "
|
||||
"is not supported"
|
||||
)
|
||||
|
||||
for net_, net_config_ in multiple_nets.items():
|
||||
net_desc = nets[net_] or {}
|
||||
is_ext = net_desc.get("external", None)
|
||||
@ -875,6 +885,16 @@ def get_net_args(compose, cnt):
|
||||
|
||||
ipv4 = net_config_.get("ipv4_address", None)
|
||||
ipv6 = net_config_.get("ipv6_address", None)
|
||||
# custom extension; not supported by docker-compose v3
|
||||
mac = net_config_.get("podman.mac_address", None)
|
||||
|
||||
# if a mac_address was specified on the container level, apply it to the first network
|
||||
# This works for Python > 3.6, because dict insert ordering is preserved, so we are
|
||||
# sure that the first network we encounter here is also the first one specified by
|
||||
# the user
|
||||
if mac is None and mac_address is not None:
|
||||
mac = mac_address
|
||||
mac_address = None
|
||||
|
||||
net_options = []
|
||||
if ipv4:
|
||||
@ -893,6 +913,8 @@ def get_net_args(compose, cnt):
|
||||
net_args.append(f"--ip={ip}")
|
||||
if ip6:
|
||||
net_args.append(f"--ip6={ip6}")
|
||||
if mac_address:
|
||||
net_args.append(f"--mac-address={mac_address}")
|
||||
|
||||
if is_bridge:
|
||||
net_args.extend(["--network-alias", ",".join(aliases)])
|
||||
|
@ -104,10 +104,27 @@ class TestGetNetArgs(unittest.TestCase):
|
||||
container["mac_address"] = mac
|
||||
|
||||
expected_args = [
|
||||
"--mac-address",
|
||||
mac,
|
||||
"--network",
|
||||
f"{PROJECT_NAME}_net0",
|
||||
"--mac-address=" + mac,
|
||||
"--network-alias",
|
||||
SERVICE_NAME,
|
||||
]
|
||||
args = get_net_args(compose, container)
|
||||
self.assertListEqual(expected_args, args)
|
||||
|
||||
def test_one_mac_two_nets(self):
|
||||
mac = "00:11:22:33:44:55"
|
||||
compose = get_networked_compose(num_networks=6)
|
||||
container = get_minimal_container()
|
||||
container["networks"] = {"net0": {}, "net1": {}}
|
||||
container["mac_address"] = mac
|
||||
|
||||
expected_args = [
|
||||
"--network",
|
||||
f"{PROJECT_NAME}_net0:mac={mac}",
|
||||
"--network",
|
||||
f"{PROJECT_NAME}_net1",
|
||||
"--network-alias",
|
||||
SERVICE_NAME,
|
||||
]
|
||||
@ -182,6 +199,49 @@ class TestGetNetArgs(unittest.TestCase):
|
||||
args = get_net_args(compose, container)
|
||||
self.assertListEqual(expected_args, args)
|
||||
|
||||
# custom extension; not supported by docker-compose
|
||||
def test_two_mac(self):
|
||||
mac0 = "00:00:00:00:00:01"
|
||||
mac1 = "00:00:00:00:00:02"
|
||||
compose = get_networked_compose(num_networks=2)
|
||||
container = get_minimal_container()
|
||||
container["networks"] = {
|
||||
"net0": {"podman.mac_address": mac0},
|
||||
"net1": {"podman.mac_address": mac1},
|
||||
}
|
||||
|
||||
expected_args = [
|
||||
"--network",
|
||||
f"{PROJECT_NAME}_net0:mac={mac0}",
|
||||
"--network",
|
||||
f"{PROJECT_NAME}_net1:mac={mac1}",
|
||||
"--network-alias",
|
||||
SERVICE_NAME,
|
||||
]
|
||||
args = get_net_args(compose, container)
|
||||
self.assertListEqual(expected_args, args)
|
||||
|
||||
def test_mixed_mac(self):
|
||||
ip4_0 = "192.168.0.42"
|
||||
ip4_1 = "192.168.1.42"
|
||||
ip4_2 = "192.168.2.42"
|
||||
mac_0 = "00:00:00:00:00:01"
|
||||
mac_1 = "00:00:00:00:00:02"
|
||||
|
||||
compose = get_networked_compose(num_networks=3)
|
||||
container = get_minimal_container()
|
||||
container["networks"] = {
|
||||
"net0": {"ipv4_address": ip4_0},
|
||||
"net1": {"ipv4_address": ip4_1, "podman.mac_address": mac_0},
|
||||
"net2": {"ipv4_address": ip4_2},
|
||||
}
|
||||
container["mac_address"] = mac_1
|
||||
|
||||
expected_exception = (
|
||||
r"specifying mac_address on both container and network level " r"is not supported"
|
||||
)
|
||||
self.assertRaisesRegex(RuntimeError, expected_exception, get_net_args, compose, container)
|
||||
|
||||
def test_mixed_config(self):
|
||||
ip4_0 = "192.168.0.42"
|
||||
ip4_1 = "192.168.1.42"
|
||||
@ -199,10 +259,8 @@ class TestGetNetArgs(unittest.TestCase):
|
||||
container["mac_address"] = mac
|
||||
|
||||
expected_args = [
|
||||
"--mac-address",
|
||||
mac,
|
||||
"--network",
|
||||
f"{PROJECT_NAME}_net0:ip={ip4_0},ip={ip6_0}",
|
||||
f"{PROJECT_NAME}_net0:ip={ip4_0},ip={ip6_0},mac={mac}",
|
||||
"--network",
|
||||
f"{PROJECT_NAME}_net1:ip={ip4_1}",
|
||||
"--network",
|
||||
|
@ -20,8 +20,10 @@ services:
|
||||
networks:
|
||||
shared-network:
|
||||
ipv4_address: "172.19.1.10"
|
||||
podman.mac_address: "02:01:01:00:01:01"
|
||||
internal-network:
|
||||
ipv4_address: "172.19.2.10"
|
||||
podman.mac_address: "02:01:01:00:02:01"
|
||||
volumes:
|
||||
- ./test1.txt:/var/www/html/index.txt:ro,z
|
||||
web2:
|
||||
|
@ -91,8 +91,11 @@ class TestPodmanComposeNetwork(RunSubprocessMixin, unittest.TestCase):
|
||||
self.assertEqual(f"{expect}\r\n", out.decode('utf-8'))
|
||||
|
||||
expected_macip = {
|
||||
"web1": {"eth0": ["172.19.1.10"], "eth1": ["172.19.2.10"]},
|
||||
"web2": {"eth0": ["172.19.2.11"]},
|
||||
"web1": {
|
||||
"eth0": ["172.19.1.10", "02:01:01:00:01:01"],
|
||||
"eth1": ["172.19.2.10", "02:01:01:00:02:01"],
|
||||
},
|
||||
"web2": {"eth0": ["172.19.2.11", "02:01:01:00:02:02"]},
|
||||
}
|
||||
|
||||
for service, interfaces in expected_macip.items():
|
||||
@ -108,5 +111,6 @@ class TestPodmanComposeNetwork(RunSubprocessMixin, unittest.TestCase):
|
||||
]
|
||||
out, _ = self.run_subprocess_assert_returncode(ip_cmd)
|
||||
for interface, values in interfaces.items():
|
||||
ip = values[0]
|
||||
ip, mac = values
|
||||
self.assertIn(f"ether {mac}", out.decode('utf-8'))
|
||||
self.assertIn(f"inet {ip}/", out.decode('utf-8'))
|
||||
|
Loading…
Reference in New Issue
Block a user