Files
athq-vm-management/vm.py

121 lines
4.5 KiB
Python

import libvirt
import jinja2
class VM:
environment = jinja2.Environment(loader=jinja2.FileSystemLoader(searchpath="./templates"))
def __init__(self, args):
self.hostname = args.get("hostname")
self.subdomains = args.get("subdomains")
self.ports = args.get("ports")
self.terminateSSL = args.get("terminate-ssl")
self.network = args.get("network") or "default"
self.isExternal = args.get("external")
self.noTerminateACME = args.get("no-terminate-acme")
print(self.noTerminateACME)
if self.isExternal:
self.lease = None
self.ip = None
else:
self.lease = self._get_lease_for_hostname()
self.ip = self.lease.get("ipaddr")
self.proxy_pass_options = args.get("proxy_pass_options")
self.proxy_pass_blob = ""
if self.proxy_pass_options:
self.proxy_pass_blob = "\n".join(self.proxy_pass_options)
def _get_lease_for_hostname(self):
with libvirt.open() as con:
network = con.networkLookupByName(self.network)
leases = network.DHCPLeases()
for l in leases:
if l.get("hostname") == self.hostname:
return l
raise ValueError("Hostname {} doesn't have a DHCP lease".format(self.hostname))
def dumpStreamComponents(self):
# port forwarding components #
components = []
template = self.environment.get_template("nginx_stream_block.conf.j2")
for portStruct in self.ports:
name = str(portStruct.get("name")).replace(" ", "")
portstring = str(portStruct.get("port")).replace(" ", "")
transparent = portStruct.get("transparent")
proto = portStruct.get("proto") or "tcp"
isUDP = proto == "udp"
proxy_timeout = portStruct.get("proxy_timeout") or "10s"
compositeName = "-".join((self.hostname, name, portstring, proto))
if self.isExternal:
self.ip = portStruct["ip"]
component = template.render(targetip=self.ip, udp=isUDP, portstring=portstring,
transparent=transparent, proxy_timeout=proxy_timeout)
components.append(component)
return components
def dumpIptables(self, remove=False):
entries = []
BASE = "iptables -t mangle -{option} "
RULE = "PREROUTING -p {proto} -s {ip} {port} -j MARK --set-xmark 0x1/0xffffffff\n"
PORT_SIMPLE = "--sport {port}"
option = "A"
if remove:
option = "D"
for portStruct in filter(lambda p: p.get("transparent"), self.ports):
# port match #
port = portStruct.get("port")
partport = PORT_SIMPLE.format(port=port)
if type(port) == str and "-" in port:
port = port.replace("-", ":").replace(" ","")
partport = PORT_SIMPLE.format(port=port)
entry = BASE.format(option=option)
entry += RULE.format(ip=self.ip, port=partport, proto=portStruct.get("proto", "tcp"))
entries.append(entry)
return entries
def dumpServerComponents(self):
# https components #
components = []
template = self.environment.get_template("nginx_server_block.conf.j2")
targetport = 80
if all([type(e) == dict for e in self.subdomains]):
for subdomain in self.subdomains:
compositeName = "-".join((self.hostname, subdomain["name"].replace(".","-")))
targetport = subdomain["port"]
component = template.render(targetip=self.ip, targetport=targetport,
servernames=[subdomain["name"]], comment=compositeName,
proxy_pass_blob=self.proxy_pass_blob, acme=not self.noTerminateACME)
components.append(component)
elif any([type(e) == dict for e in self.subdomains]):
raise ValueError("Mixed subdomains not allowed - must be all complex or all simple")
else:
compositeName = "-".join((self.hostname, self.subdomains[0].replace(".","-")))
component = template.render(targetip=self.ip, targetport=targetport,
servernames=self.subdomains, comment=compositeName,
proxy_pass_blob=self.proxy_pass_blob, acme= not self.noTerminateACME)
components.append(component)
return components