From d0c20c8d9541d75c9df84b4b706781e840bc686a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=B6hmwalder?= Date: Wed, 29 Jul 2020 12:19:08 +0200 Subject: [PATCH] vm rm: try releasing the VMs DHCP lease We have seen some strange effects when IP/MAC addresses are reused. A solution for this problem is to get rid of the DHCP lease when destroying the VM. In order to do that, we have to run dhcp_release, which can only run as root. We try running it with sudo when removing the machine. If it doesn't work, we don't complain either. Note that this requires passwordless sudo for the executing user, at least for the dhcp_release command. Something along the lines of: %libvirt ALL=(ALL) NOPASSWD: /usr/bin/dhcp_release To allow all users in the libvirt group to execute it. --- internal/virter/dhcp.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/internal/virter/dhcp.go b/internal/virter/dhcp.go index bebb01f..d74ae0d 100644 --- a/internal/virter/dhcp.go +++ b/internal/virter/dhcp.go @@ -3,6 +3,7 @@ package virter import ( "fmt" "net" + "os/exec" libvirt "github.com/digitalocean/go-libvirt" log "github.com/sirupsen/logrus" @@ -146,6 +147,11 @@ func (v *Virter) rmDHCPEntry(domain libvirt.Domain) error { } } + err = v.tryReleaseDHCP(mac, ips, network) + if err != nil { + log.Debugf("Could not release DHCP lease: %v", err) + } + return nil } @@ -283,3 +289,30 @@ func (v *Virter) getVMID(wantedID uint) (uint, error) { return 0, fmt.Errorf("could not find unused VM id") } + +func (v *Virter) tryReleaseDHCP(mac string, addrs []string, network libvirt.Network) error { + networkDescription, err := getNetworkDescription(v.libvirt, network) + if err != nil { + return err + } + + if networkDescription.Bridge == nil { + return fmt.Errorf("network %q is not a bridge, cannot release dhcp", networkDescription.Name) + } + iface := networkDescription.Bridge.Name + + for _, addr := range addrs { + log.Debugf("Releasing DHCP lease from %v to %v", mac, addr) + cmd := exec.Command("sudo", "--non-interactive", "dhcp_release", iface, addr, mac) + _, err = cmd.Output() + if err != nil { + if e, ok := err.(*exec.ExitError); ok { + log.Debugf("dhcp_release stderr:\n%s", string(e.Stderr)) + } + + return fmt.Errorf("failed to run dhcp_release: %w", err) + } + } + + return nil +}