Add entry point: parse_network.py
This commit is contained in:
parent
cae5e2244c
commit
915875ecf2
3 changed files with 139 additions and 0 deletions
76
lxc_net/parse_network.py
Normal file
76
lxc_net/parse_network.py
Normal file
|
@ -0,0 +1,76 @@
|
|||
import yaml
|
||||
import sys
|
||||
from . import network, container
|
||||
|
||||
|
||||
class YamlTopology:
|
||||
""" Parse a YAML description of a network topology. The networks' links and domains
|
||||
are contained in the `links` and `domains` attributes, but their `create` methods
|
||||
are not called. """
|
||||
|
||||
class InvalidConfiguration(Exception):
|
||||
def __init__(self, reason):
|
||||
self.reason = reason
|
||||
|
||||
def __str__(self):
|
||||
return "Bad topology configuration: {}".format(self.reason)
|
||||
|
||||
def __init__(self, path, conn):
|
||||
self.path = path
|
||||
self.conn = conn
|
||||
|
||||
self.domains = None
|
||||
self.links = None
|
||||
|
||||
self._parse()
|
||||
|
||||
def _parse(self):
|
||||
with open(self.path, "r") as handle:
|
||||
topology = yaml.safe_load(handle)
|
||||
|
||||
if "links" not in topology:
|
||||
raise self.InvalidConfiguration("links definition is mandatory")
|
||||
|
||||
link_descr = topology["links"]
|
||||
self.links = []
|
||||
|
||||
dom_descr = {}
|
||||
for link_conf in link_descr:
|
||||
if "domains" not in link_conf:
|
||||
raise self.InvalidConfiguration(
|
||||
"a 'domains' attribute is mandatory for each link"
|
||||
)
|
||||
|
||||
cur_link = network.Network(self.conn)
|
||||
self.links.append(cur_link)
|
||||
|
||||
for dom in link_conf["domains"]:
|
||||
if dom not in dom_descr:
|
||||
dom_descr[dom] = {"links": []}
|
||||
dom_descr[dom]["links"].append(cur_link)
|
||||
|
||||
for dom_conf_name in topology.get("domains", None):
|
||||
if dom_conf_name not in dom_descr:
|
||||
# Domain does not participate in any link: warn and ignore
|
||||
print(
|
||||
(
|
||||
"WARNING: domain {} does not participate in any link. "
|
||||
"Ignored."
|
||||
).format(dom_conf_name),
|
||||
file=sys.stderr,
|
||||
)
|
||||
continue
|
||||
|
||||
dom_conf = topology["domains"][dom_conf_name]
|
||||
dom_descr[dom_conf_name]["enable_v4"] = dom_conf.get("enable_v4", True)
|
||||
|
||||
sorted_dom_names = sorted(list(dom_descr.keys()))
|
||||
|
||||
self.domains = [
|
||||
container.Container(
|
||||
self.conn,
|
||||
dom_descr[dom]["links"],
|
||||
enable_v4=dom_descr[dom].get("enable_v4", True),
|
||||
)
|
||||
for dom in sorted_dom_names
|
||||
]
|
|
@ -1,2 +1,3 @@
|
|||
libvirt-python
|
||||
jinja2
|
||||
pyyaml
|
||||
|
|
62
spawn_network.py
Executable file
62
spawn_network.py
Executable file
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from lxc_net import parse_network
|
||||
import sys
|
||||
import signal
|
||||
import libvirt
|
||||
import argparse
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description="Spawns a network of LXC containers.")
|
||||
parser.add_argument("topology", help="A YAML file defining the network topology")
|
||||
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
received_sigint = False
|
||||
|
||||
def handle_sigint(signum, frame):
|
||||
""" Called upon SIGINT (^C) """
|
||||
nonlocal received_sigint
|
||||
|
||||
print(" >> Received SIGINT, stopping network...")
|
||||
received_sigint = True
|
||||
|
||||
signal.signal(signal.SIGINT, handle_sigint)
|
||||
|
||||
conn = libvirt.open("lxc:///")
|
||||
|
||||
topology = parse_network.YamlTopology(args.topology, conn)
|
||||
|
||||
print(">> Spawning networks: ", end="")
|
||||
sys.stdout.flush()
|
||||
for link in topology.links:
|
||||
if received_sigint:
|
||||
return
|
||||
print(link.name, end="... ")
|
||||
sys.stdout.flush()
|
||||
link.create()
|
||||
print("Done.")
|
||||
|
||||
print(">> Spawning containers: ", end="")
|
||||
sys.stdout.flush()
|
||||
for c_dom in topology.domains:
|
||||
if received_sigint:
|
||||
return
|
||||
print(c_dom.name, end="... ")
|
||||
sys.stdout.flush()
|
||||
c_dom.create()
|
||||
print("Done.")
|
||||
|
||||
print("Network running. Press ^C to terminate.")
|
||||
while not received_sigint: # Wait for SIGINT
|
||||
signal.pause()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in a new issue