openec2/src/openec2/ipam.py

62 lines
2.1 KiB
Python

from sqlmodel import select
import libvirt
from openec2.libvirt import LibvirtSingleton
from openec2.db import DatabaseDep
from openec2.db.ipam import IPAMEntry
from openec2.utils.ip import ipv4_to_int, int_to_ipv4
def _libvirt_host_update(instance_id: str, mac: str, ipv4: str) -> str:
return f"<host name='{instance_id}' mac='{mac}' ip='{ipv4}' />"
def add_instance_dhcp_mapping(instance_id: str, mac: str, ipv4: str, db: DatabaseDep):
"""
Adds a DHCP entry for the network to give the instance a static
private IPv4 address.
"""
entry = IPAMEntry(
ipv4_addr_raw=ipv4_to_int(ipv4),
instance_id=instance_id,
# TODO
vpc_id="default",
)
db.add(entry)
# Tell libvirt about this mapping
conn = LibvirtSingleton.of().connection
conn.networkLookupByName("default").update(
libvirt.VIR_NETWORK_UPDATE_COMMAND_ADD_LAST,
libvirt.VIR_NETWORK_SECTION_IP_DHCP_HOST,
0,
_libvirt_host_update(instance_id, mac, ipv4),
flags=libvirt.VIR_NETWORK_UPDATE_AFFECT_LIVE,
)
def remove_instance_dhcp_mapping(instance_id: str, mac: str ,ipv4: str, db: DatabaseDep):
i = ipv4_to_int(ipv4)
entry = db.exec(select(IPAMEntry).where(IPAMEntry.ipv4_addr_raw == i, IPAMEntry.instance_id == instance_id)).first()
db.delete(entry)
# Tell libvirt about this mapping
conn = LibvirtSingleton.of().connection
conn.networkLookupByName("default").update(
libvirt.VIR_NETWORK_UPDATE_COMMAND_DELETE,
libvirt.VIR_NETWORK_SECTION_IP_DHCP_HOST,
0,
_libvirt_host_update(instance_id, mac, ipv4),
flags=libvirt.VIR_NETWORK_UPDATE_AFFECT_LIVE,
)
def is_ipv4_available(ipv4: str, db: DatabaseDep) -> bool:
i = ipv4_to_int(ipv4)
return db.exec(select(IPAMEntry).where(IPAMEntry.ipv4_addr_raw == i)).first() is None
def get_available_ipv4(db: DatabaseDep) -> str:
entries = db.exec(select(IPAMEntry)).all()
# TODO: Use the VPC's subnet
max_ip = max(e.ipv4_addr_raw for e in entries) if entries else ipv4_to_int("192.168.122.2")
# TODO: Check if we're still inside the subnet
return int_to_ipv4(max_ip + 1)