Compare commits
3 commits
8a1ee721f3
...
260417bcd0
Author | SHA1 | Date | |
---|---|---|---|
Théophile Bastian | 260417bcd0 | ||
Théophile Bastian | b06ce7c12b | ||
Théophile Bastian | 90baaa8d03 |
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
78
src/network.py
Normal file
78
src/network.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
""" Network objects """
|
||||
|
||||
import settings
|
||||
import util
|
||||
from xml_template import XMLTemplate
|
||||
|
||||
import uuid
|
||||
import libvirt
|
||||
|
||||
|
||||
class Network(util.NumberedClass):
|
||||
class AlreadyExists(Exception):
|
||||
def __str__(self):
|
||||
return "This network is already instanciated"
|
||||
|
||||
class TooMany(Exception):
|
||||
def __init__(self, count):
|
||||
self.count = count
|
||||
|
||||
def __str__(self):
|
||||
return (
|
||||
"Limit number reached. The current instance #{} does not fit in IPv4"
|
||||
).format(self.count)
|
||||
|
||||
def __init__(self, conn, name=None):
|
||||
super().__init__()
|
||||
|
||||
if self.id > 250:
|
||||
raise self.TooMany(self.id)
|
||||
|
||||
if not name:
|
||||
name = str(self.id)
|
||||
|
||||
self.conn = conn
|
||||
self.uuid = uuid.uuid4()
|
||||
self.name = settings.PREFIX + "_" + name
|
||||
self.bridge_id = settings.NETWORK_ID * 0xFF + self.id
|
||||
self.bridge_mac = util.MACAddress(self.id, None)
|
||||
self.ipv4 = util.Addrv4(self.id, None)
|
||||
self.ipv6 = util.Addrv6(self.id, None)
|
||||
self.lxc_network = None
|
||||
|
||||
try:
|
||||
if self.conn.networkLookupByName(self.name):
|
||||
raise self.AlreadyExists()
|
||||
except libvirt.libvirtError:
|
||||
pass
|
||||
|
||||
def create(self):
|
||||
if self.lxc_network:
|
||||
raise self.AlreadyExists()
|
||||
|
||||
xml = XMLTemplate("templates/network.xml").inst(
|
||||
name=self.name,
|
||||
uuid=self.uuid,
|
||||
bridge_id=self.bridge_id,
|
||||
mac=self.bridge_mac,
|
||||
addrv4=self.ipv4,
|
||||
netmaskv4=self.ipv4.netmask,
|
||||
addrv6=self.ipv6,
|
||||
prefixv6=self.ipv6.prefix,
|
||||
)
|
||||
|
||||
self.lxc_network = self.conn.networkCreateXML(xml)
|
||||
|
||||
def cleanup(self):
|
||||
if self.lxc_network:
|
||||
self.lxc_network.destroy()
|
||||
|
||||
def __enter__(self):
|
||||
self.create()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.cleanup()
|
||||
|
||||
def __del__(self):
|
||||
self.cleanup()
|
19
src/settings.py
Normal file
19
src/settings.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
""" General settings """
|
||||
|
||||
# Prefix to all the networks and containers created
|
||||
PREFIX = "testnw"
|
||||
|
||||
# Container base installation path -- will be overlaid
|
||||
CONTAINER_BASE_ROOT = "/var/lib/machines/lxc-base-" + PREFIX
|
||||
|
||||
# Overlayfs mount dir
|
||||
OVERLAYFS_MOUNT_DIR = "/tmp/{}-overlays/".format(PREFIX)
|
||||
|
||||
# The ID of the whole generated network -- below 0xff
|
||||
NETWORK_ID = 132
|
||||
|
||||
# IPv4 /16 range
|
||||
IPV4_RANGE = "10.{}".format(NETWORK_ID)
|
||||
|
||||
# IPv6 /32 range
|
||||
IPV6_RANGE = "fd80:ba{:02x}".format(NETWORK_ID)
|
11
src/templates/network.xml
Normal file
11
src/templates/network.xml
Normal file
|
@ -0,0 +1,11 @@
|
|||
<network>
|
||||
<name>{name}</name>
|
||||
<uuid>{uuid}</uuid>
|
||||
<bridge name='virbr{bridge_id}' stp='on' delay='0'/>
|
||||
<mac address='{mac}'/>
|
||||
<domain name='{name}'/>
|
||||
<ip address='{addrv4}' netmask='{netmaskv4}'>
|
||||
</ip>
|
||||
<ip family='ipv6' address='{addrv6}' prefix='{prefixv6}'>
|
||||
</ip>
|
||||
</network>
|
84
src/util.py
Normal file
84
src/util.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
""" Various utils """
|
||||
|
||||
import settings
|
||||
|
||||
|
||||
class NumberedClass:
|
||||
""" A class that counts its current instance number """
|
||||
|
||||
next_id = 0
|
||||
|
||||
@classmethod
|
||||
def get_id(cls):
|
||||
out = cls.next_id
|
||||
cls.next_id += 1
|
||||
return out
|
||||
|
||||
def __init__(self):
|
||||
self.id = self.get_id()
|
||||
|
||||
|
||||
class MACAddress:
|
||||
""" A MAC address for a NIC or bridge """
|
||||
|
||||
def __init__(self, link_id, dev_id):
|
||||
""" link_id: id of the current link
|
||||
dev_id: id of the current NIC. If the device is a bridge, use None
|
||||
"""
|
||||
if not dev_id:
|
||||
dev_id = 0xFF
|
||||
|
||||
self.link_id = link_id
|
||||
self.dev_id = dev_id
|
||||
|
||||
def __str__(self):
|
||||
return "52:54:00:{nwid:02x}:{link_id:02x}:{dev_id:02x}".format(
|
||||
nwid=settings.NETWORK_ID, link_id=self.link_id, dev_id=self.dev_id
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return str(self)
|
||||
|
||||
|
||||
class Addrv4:
|
||||
""" An address in IPv4 """
|
||||
|
||||
def __init__(self, link_id, dev_id):
|
||||
""" link_id: id of the current link
|
||||
dev_id: id of the current NIC. Use None to get the base address
|
||||
"""
|
||||
if not dev_id:
|
||||
dev_id = 0
|
||||
|
||||
self.link_id = link_id
|
||||
self.dev_id = dev_id
|
||||
self.netmask = "255.255.255.0"
|
||||
self.prefix = 24
|
||||
|
||||
def __str__(self):
|
||||
return "{base_range}.{link_id}.{dev_id}".format(
|
||||
base_range=settings.IPV4_RANGE, link_id=self.link_id, dev_id=self.dev_id
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return str(self)
|
||||
|
||||
|
||||
class Addrv6:
|
||||
""" An address in IPv6 """
|
||||
|
||||
def __init__(self, link_id, dev_id):
|
||||
""" link_id: id of the current link
|
||||
dev_id: id of the current NIC. Use None to get the base address
|
||||
"""
|
||||
if not dev_id:
|
||||
dev_id = 0
|
||||
|
||||
self.link_id = link_id
|
||||
self.dev_id = dev_id
|
||||
self.prefix = 64
|
||||
|
||||
def __str__(self):
|
||||
return "{base_range}:{link_id:04x}::{dev_id:04x}".format(
|
||||
base_range=settings.IPV6_RANGE, link_id=self.link_id, dev_id=self.dev_id
|
||||
)
|
16
src/xml_template.py
Normal file
16
src/xml_template.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
""" Reads an XML template from a file """
|
||||
|
||||
import os
|
||||
|
||||
|
||||
class XMLTemplate:
|
||||
""" Reads and instanciates a template from a file """
|
||||
|
||||
def __init__(self, path):
|
||||
self.path = os.path.join(os.path.dirname(os.path.abspath(__file__)), path)
|
||||
with open(self.path, "r") as handle:
|
||||
self.template_str = handle.read()
|
||||
|
||||
def inst(self, *args, **kwargs):
|
||||
""" instanciates the template """
|
||||
return self.template_str.format(*args, **kwargs)
|
Loading…
Reference in a new issue