Add namespace management files
This commit is contained in:
parent
74c0bf76a1
commit
f588078b75
4 changed files with 196 additions and 0 deletions
134
global/overlay/etc/puppet/modules/cdn/files/l4lb/sunet-l4lb-namespace
Executable file
134
global/overlay/etc/puppet/modules/cdn/files/l4lb/sunet-l4lb-namespace
Executable file
|
@ -0,0 +1,134 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# pylint:disable=invalid-name
|
||||||
|
# pylint:enable=invalid-name
|
||||||
|
# pylint:disable=invalid-name
|
||||||
|
# pylint:enable=invalid-name
|
||||||
|
"""
|
||||||
|
netplan does not have network namespace support so configure by hand
|
||||||
|
|
||||||
|
Tools used before committing code:
|
||||||
|
black sunet-l4lb-namespace
|
||||||
|
isort sunet-l4lb-namespace
|
||||||
|
pylint sunet-l4lb-namespace
|
||||||
|
mypy --strict sunet-l4lb-namespace
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(cmd: str) -> subprocess.CompletedProcess[str]:
|
||||||
|
"""Execute subprocess command"""
|
||||||
|
args = shlex.split(cmd)
|
||||||
|
try:
|
||||||
|
proc = subprocess.run(args, capture_output=True, check=True, encoding="utf-8")
|
||||||
|
except subprocess.CalledProcessError as exc:
|
||||||
|
stderr_str = exc.stderr.rstrip()
|
||||||
|
print(
|
||||||
|
f"command failed: cmd='{cmd}', rc={exc.returncode}, stderr='{stderr_str}'",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
return proc
|
||||||
|
|
||||||
|
|
||||||
|
def configure_interfaces(
|
||||||
|
namespace: str, if_data: dict[str, dict[str, list[str]]]
|
||||||
|
) -> None:
|
||||||
|
"""Configure interfaces"""
|
||||||
|
proc = run_command("ip netns exec l4lb ip -j addr show")
|
||||||
|
namespace_ifs = json.loads(proc.stdout)
|
||||||
|
for if_name, data in if_data.items():
|
||||||
|
if_exists = next(
|
||||||
|
(True for interface in namespace_ifs if interface["ifname"] == if_name),
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
if not if_exists:
|
||||||
|
run_command(f"ip link set {if_name} netns {namespace}")
|
||||||
|
|
||||||
|
proc = run_command(f"ip netns exec {namespace} ip -j addr show dev {if_name}")
|
||||||
|
if_conf = json.loads(proc.stdout)
|
||||||
|
for ipv4_cidr in data["ipv4"]:
|
||||||
|
ip4, prefix = ipv4_cidr.split("/")
|
||||||
|
v4_addr_exists = next(
|
||||||
|
(
|
||||||
|
True
|
||||||
|
for addr in if_conf[0]["addr_info"]
|
||||||
|
if addr["local"] == ip4 and addr["prefixlen"] == int(prefix)
|
||||||
|
),
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
if not v4_addr_exists:
|
||||||
|
run_command(
|
||||||
|
f"ip netns exec {namespace} ip addr add {ipv4_cidr} dev {if_name}"
|
||||||
|
)
|
||||||
|
for ipv6_cidr in data["ipv6"]:
|
||||||
|
ip6, prefix = ipv6_cidr.split("/")
|
||||||
|
v6_addr_exists = next(
|
||||||
|
(
|
||||||
|
True
|
||||||
|
for addr in if_conf[0]["addr_info"]
|
||||||
|
if addr["local"] == ip6 and addr["prefixlen"] == int(prefix)
|
||||||
|
),
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
if not v6_addr_exists:
|
||||||
|
run_command(
|
||||||
|
f"ip netns exec {namespace} ip addr add {ipv6_cidr} dev {if_name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
run_command(f"ip netns exec {namespace} ip link set {if_name} up")
|
||||||
|
|
||||||
|
|
||||||
|
def setup_namespaces(netns_data: dict[str, dict[str, dict[str, list[str]]]]) -> None:
|
||||||
|
"""Setup network namespaces"""
|
||||||
|
proc = run_command("ip -j netns list")
|
||||||
|
existing_netns = json.loads(proc.stdout)
|
||||||
|
for namespace, if_data in netns_data.items():
|
||||||
|
netns_exists = next(
|
||||||
|
(True for netns in existing_netns if netns["name"] == namespace), False
|
||||||
|
)
|
||||||
|
if not netns_exists:
|
||||||
|
run_command(f"ip netns add {namespace}")
|
||||||
|
|
||||||
|
# Make localhost available
|
||||||
|
run_command(f"ip netns exec {namespace} ip link set lo up")
|
||||||
|
|
||||||
|
configure_interfaces(namespace, if_data)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
"""Starting point of the program"""
|
||||||
|
|
||||||
|
# JSON file format:
|
||||||
|
# {
|
||||||
|
# "namespace1": {
|
||||||
|
# "interface1": {
|
||||||
|
# "ipv4": [
|
||||||
|
# "192.168.10.1/31"
|
||||||
|
# ],
|
||||||
|
# "ipv6": [
|
||||||
|
# "2001:db8:1337:74::1/127"
|
||||||
|
# ]
|
||||||
|
# },
|
||||||
|
# "interface2": {
|
||||||
|
# "ipv4": [
|
||||||
|
# "192.168.10.3/31"
|
||||||
|
# ],
|
||||||
|
# "ipv6": [
|
||||||
|
# "2001:db8:1338:75::1/127"
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
with open("/etc/sunet-cdn-l4lb/netns.json", encoding="utf-8") as f:
|
||||||
|
netns_data = json.load(f)
|
||||||
|
|
||||||
|
setup_namespaces(netns_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -14,4 +14,35 @@ class cdn::l4lb(
|
||||||
description => 'SUNET CDN l4lb',
|
description => 'SUNET CDN l4lb',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file { '/etc/sunet-l4lb':
|
||||||
|
ensure => directory,
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
mode => '0640',
|
||||||
|
}
|
||||||
|
|
||||||
|
file { '/etc/sunet-l4lb/netns.json':
|
||||||
|
ensure => file,
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
mode => '0644',
|
||||||
|
content => template('cdn/l4lb/netns.json.erb'),
|
||||||
|
}
|
||||||
|
|
||||||
|
file { '/usr/local/bin/sunet-l4lb-namespace':
|
||||||
|
ensure => file,
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
mode => '0755',
|
||||||
|
content => file('cdn/l4lb/sunet-l4lb-namespace'),
|
||||||
|
}
|
||||||
|
|
||||||
|
file { '/etc/systemd/system/sunet-l4lb-namespace.service':
|
||||||
|
ensure => file,
|
||||||
|
owner => 'root',
|
||||||
|
group => 'root',
|
||||||
|
mode => '0644',
|
||||||
|
content => template('cdn/l4lb/sunet-l4lb-namespace.service.erb'),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"l4lb": {
|
||||||
|
"enp129s0f1np1": {
|
||||||
|
"ipv4": [
|
||||||
|
"130.242.64.233/31"
|
||||||
|
],
|
||||||
|
"ipv6": [
|
||||||
|
"2001:6b0:2006:74::1/127"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"enp129s0f0np0": {
|
||||||
|
"ipv4": [
|
||||||
|
"130.242.64.235/31"
|
||||||
|
],
|
||||||
|
"ipv6": [
|
||||||
|
"2001:6b0:2006:75::1/127"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Setup l4lb namespace used for all service traffic
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/sunet-l4lb-namespace
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
Loading…
Add table
Reference in a new issue