From 86938fcb1f1108c67a7b889c2aadd216913fecd2 Mon Sep 17 00:00:00 2001 From: Flavio Castelli Date: Wed, 5 Apr 2017 09:49:16 +0200 Subject: [PATCH 1/2] Add libvirt API method to obtain DHCP leases. Requires libvirt >= 1.2.6. The tag libvirt.1.2.14 is required by libvirt-go to enable its use, since a wider range of libvirt versions are supported there. Initial patch provided by Casey Marshall --- cmd/docker-machine-driver-kvm/Makefile | 2 +- kvm.go | 47 +++++++++++++++++++++----- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/cmd/docker-machine-driver-kvm/Makefile b/cmd/docker-machine-driver-kvm/Makefile index c20acf8da65..a6defed8fe8 100644 --- a/cmd/docker-machine-driver-kvm/Makefile +++ b/cmd/docker-machine-driver-kvm/Makefile @@ -1,4 +1,4 @@ default: build build: - GOGC=off go build -i -o docker-machine-driver-kvm + GOGC=off go build -tags libvirt.1.2.14 -i -o docker-machine-driver-kvm diff --git a/kvm.go b/kvm.go index 1e6c89156e7..f8c1e2e0773 100644 --- a/kvm.go +++ b/kvm.go @@ -592,6 +592,25 @@ func (d *Driver) getMAC() (string, error) { return dom.Devices.Interfaces[1].Mac.Address, nil } +func (d *Driver) getIPByMACFromAPI(mac string) (string, error) { + network, err := d.conn.LookupNetworkByName(d.PrivateNetwork) + if err != nil { + log.Errorf("Failed to lookup network %s", d.PrivateNetwork) + return "", err + } + leases, err := network.GetDHCPLeases() + if err != nil { + log.Warnf("Failed to retrieve DHCP leases from libvirt: %v", err) + return "", err + } + for _, lease := range leases { + if strings.ToLower(mac) == strings.ToLower(lease.GetMACAddress()) { + return lease.GetIPAddress(), nil + } + } + return "", errors.New("failed to match IP for MAC address") +} + func (d *Driver) getIPByMACFromLeaseFile(mac string) (string, error) { leaseFile := fmt.Sprintf(dnsmasqLeases, d.PrivateNetwork) data, err := ioutil.ReadFile(leaseFile) @@ -633,6 +652,11 @@ func (d *Driver) getIPByMacFromSettings(mac string) (string, error) { } statusFile := fmt.Sprintf(dnsmasqStatus, bridge_name) data, err := ioutil.ReadFile(statusFile) + if err != nil { + log.Debugf("Failed to read dnsmasq status from %s", statusFile) + return "", err + } + type Lease struct { Ip_address string `json:"ip-address"` Mac_address string `json:"mac-address"` @@ -659,22 +683,27 @@ func (d *Driver) getIPByMacFromSettings(mac string) (string, error) { return ipAddr, nil } +type ipLookupFunc func(mac string) (string, error) + func (d *Driver) GetIP() (string, error) { log.Debugf("GetIP called for %s", d.MachineName) mac, err := d.getMAC() if err != nil { return "", err } - /* - * TODO - Figure out what version of libvirt changed behavior and - * be smarter about selecting which algorithm to use - */ - ip, err := d.getIPByMACFromLeaseFile(mac) - if ip == "" { - ip, err = d.getIPByMacFromSettings(mac) + + methods := []ipLookupFunc{ + d.getIPByMACFromLeaseFile, + d.getIPByMacFromSettings, + d.getIPByMACFromAPI, + } + for _, method := range methods { + ip, err := method(mac) + if err == nil { + return ip, nil + } } - log.Debugf("Unable to locate IP address for MAC %s", mac) - return ip, err + return "", fmt.Errorf("unable to locate IP address for MAC %s") } func (d *Driver) publicSSHKeyPath() string { From f7201107226368e6ff7bce4208287a789c8f49e5 Mon Sep 17 00:00:00 2001 From: Flavio Castelli Date: Wed, 5 Apr 2017 17:09:26 +0200 Subject: [PATCH 2/2] Rework patch that gets the VM IP address using libvirt API Changed the code to use the native libvirt API provided by the official Go bindings. Signed-off-by: Flavio Castelli --- kvm.go | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/kvm.go b/kvm.go index f8c1e2e0773..edb73c5696f 100644 --- a/kvm.go +++ b/kvm.go @@ -593,21 +593,20 @@ func (d *Driver) getMAC() (string, error) { } func (d *Driver) getIPByMACFromAPI(mac string) (string, error) { - network, err := d.conn.LookupNetworkByName(d.PrivateNetwork) + interfaces, err := d.VM.ListAllInterfaceAddresses(uint(libvirt.DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE)) if err != nil { - log.Errorf("Failed to lookup network %s", d.PrivateNetwork) return "", err } - leases, err := network.GetDHCPLeases() - if err != nil { - log.Warnf("Failed to retrieve DHCP leases from libvirt: %v", err) - return "", err - } - for _, lease := range leases { - if strings.ToLower(mac) == strings.ToLower(lease.GetMACAddress()) { - return lease.GetIPAddress(), nil + for _, domainInterface := range interfaces { + if strings.ToUpper(domainInterface.Hwaddr) == strings.ToUpper(mac) { + // An interface can have multiple addresses (eg: ipv4 and ipv6) + // Just returns the first one right now... + for _, addr := range domainInterface.Addrs { + return addr.Addr, nil + } } } + return "", errors.New("failed to match IP for MAC address") } @@ -693,9 +692,9 @@ func (d *Driver) GetIP() (string, error) { } methods := []ipLookupFunc{ + d.getIPByMACFromAPI, d.getIPByMACFromLeaseFile, d.getIPByMacFromSettings, - d.getIPByMACFromAPI, } for _, method := range methods { ip, err := method(mac)