Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the libvirt API to obtain domain IP address #40

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/docker-machine-driver-kvm/Makefile
Original file line number Diff line number Diff line change
@@ -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
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately I don't have a physical ubuntu 14.04 box (or other older LTS distro) to try this out at the moment. Was this alone sufficient to have this all hold together where it both compiles and doesn't do something nasty at runtime when the underlying API isn't present? Maybe enough time has passed that we can ignore the older LTS distros, but I was hoping to keep this compatible for a while if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have access to such a machine. However latest Ubuntu LTS (xenial 16.04LTS) has version 1.3.1 available.

Personally I would ignore 14.04.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been meaning to improve the build a bit... and this helped motivate me to get some extra build support in place to generate binaries for various host systems. f328c4b

I think we should be able to at least partially answer the compatibility question on this PR by seeing if it builds on ubuntu14.04. Then we could try to do a create in a container, which should fail due to the missing libvirt socket, but as long as it errors that way and not with some obscure C lib link problem, then I think we're good.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rebased my changes against your master, this is the error I get when I try to build the code inside of 14.04:

# github.com/dhiltgen/docker-machine-kvm
./kvm.go:596: cannot use uint(libvirt.DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE) (type uint) as type libvirt.DomainInterfaceAddressesSource in argument to d.VM.ListAllInterfaceAddresses

Do you think it's acceptable?

46 changes: 37 additions & 9 deletions kvm.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,24 @@ func (d *Driver) getMAC() (string, error) {
return dom.Devices.Interfaces[1].Mac.Address, nil
}

func (d *Driver) getIPByMACFromAPI(mac string) (string, error) {
interfaces, err := d.VM.ListAllInterfaceAddresses(uint(libvirt.DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE))
if err != nil {
return "", err
}
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")
}

func (d *Driver) getIPByMACFromLeaseFile(mac string) (string, error) {
leaseFile := fmt.Sprintf(dnsmasqLeases, d.PrivateNetwork)
data, err := ioutil.ReadFile(leaseFile)
Expand Down Expand Up @@ -633,6 +651,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"`
Expand All @@ -659,22 +682,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.getIPByMACFromAPI,
d.getIPByMACFromLeaseFile,
d.getIPByMacFromSettings,
}
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 {
Expand Down