Skip to content

Instantly share code, notes, and snippets.

@ekohl
Last active November 9, 2023 15:40
Show Gist options
  • Save ekohl/e487422d4aaad8ab176c19ec713b700a to your computer and use it in GitHub Desktop.
Save ekohl/e487422d4aaad8ab176c19ec713b700a to your computer and use it in GitHub Desktop.
Libvirt with domain and resolvectl
#!/usr/bin/env python3
# https://www.libvirt.org/hooks.html#network
# Place this as /etc/libvirt/hooks/network
import logging
import sys
from argparse import ArgumentParser
from subprocess import CalledProcessError, check_output
from xml.etree.ElementTree import ElementTree, fromstring, parse, dump
from xml.etree import ElementTree
logger = logging.getLogger('network-hook')
def read_xml(path: str) -> ElementTree.Element:
if path == '-':
root = ElementTree.fromstring(sys.stdin.read())
return root.find('network')
else:
with open(path) as f:
return ElementTree.parse(f)
def handle_xml(xml: ElementTree) -> None:
domain = xml.find('domain')
if domain is None:
logger.debug('No domain found')
return
domain_name = domain.attrib['name']
if domain_name is None:
logger.debug('No domain name found')
return
bridge = xml.find('bridge')
if bridge is None:
logger.debug('No bridge found')
return
interface = bridge.attrib['name']
if interface is None:
logger.debug('No interface found')
return
ip = xml.find('ip')
if ip is None:
logger.debug('No ip found')
return
ip_address = ip.attrib['address']
if ip_address is None:
logger.debug('No address found')
return
set_resolver(interface, ip_address, domain_name)
def set_resolver(interface: str, ip: str, domain: str) -> None:
logger.info('Setting resolver on %s to %s with %s', interface, ip, domain)
try:
check_output(['resolvectl', 'dns', interface, ip])
except CalledProcessError:
logger.exception('Failed to set DNS resolver on interface %s to %s', interface, ip)
try:
check_output(['resolvectl', 'domain', interface, domain])
except CalledProcessError:
logger.exception('Failed to set DNS domain on interface %s to %s', interface, domain)
def main():
logging.basicConfig(level=logging.DEBUG)
parser = ArgumentParser()
parser.add_argument('network_name')
parser.add_argument('action')
parser.add_argument('phase')
parser.add_argument('xml')
args = parser.parse_args()
if args.action == 'started':
try:
xml = read_xml(args.xml)
except:
logger.exception('Failed to read XML from %s', args.xml)
raise
handle_xml(xml)
if __name__ == '__main__':
main()
<network xmlns:dnsmasq='http://libvirt.org/schemas/network/dnsmasq/1.0'>
<bridge name='virbr0' stp='on' delay='0'/>
<!-- change your domain name here -->
<domain name="sub.example.com" localOnly="yes"/>
<ip address='192.168.122.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.122.2' end='192.168.122.254'/>
</dhcp>
</ip>
</network>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment