From b4d45306b2ae338ea621b7cacd9701e801abb392 Mon Sep 17 00:00:00 2001 From: Matt Layher Date: Fri, 9 Oct 2015 10:52:05 -0400 Subject: [PATCH] datasource, network: add support for DigitalOcean floating IPs --- datasource/metadata/digitalocean/metadata.go | 9 ++- network/digitalocean.go | 26 +++++++ network/digitalocean_test.go | 79 ++++++++++++++++++++ 3 files changed, 110 insertions(+), 4 deletions(-) diff --git a/datasource/metadata/digitalocean/metadata.go b/datasource/metadata/digitalocean/metadata.go index d8b71ae..fa6c605 100644 --- a/datasource/metadata/digitalocean/metadata.go +++ b/datasource/metadata/digitalocean/metadata.go @@ -38,10 +38,11 @@ type Address struct { } type Interface struct { - IPv4 *Address `json:"ipv4"` - IPv6 *Address `json:"ipv6"` - MAC string `json:"mac"` - Type string `json:"type"` + IPv4 *Address `json:"ipv4"` + IPv6 *Address `json:"ipv6"` + AnchorIPv4 *Address `json:"anchor_ipv4"` + MAC string `json:"mac"` + Type string `json:"type"` } type Interfaces struct { diff --git a/network/digitalocean.go b/network/digitalocean.go index f31f989..c3d5daa 100644 --- a/network/digitalocean.go +++ b/network/digitalocean.go @@ -126,6 +126,32 @@ func parseInterface(iface digitalocean.Interface, nameservers []net.IP, useRoute }) } } + if iface.AnchorIPv4 != nil { + var ip, mask, gateway net.IP + if ip = net.ParseIP(iface.AnchorIPv4.IPAddress); ip == nil { + return nil, fmt.Errorf("could not parse %q as anchor IPv4 address", iface.AnchorIPv4.IPAddress) + } + if mask = net.ParseIP(iface.AnchorIPv4.Netmask); mask == nil { + return nil, fmt.Errorf("could not parse %q as anchor IPv4 mask", iface.AnchorIPv4.Netmask) + } + addresses = append(addresses, net.IPNet{ + IP: ip, + Mask: net.IPMask(mask), + }) + + if useRoute { + if gateway = net.ParseIP(iface.AnchorIPv4.Gateway); gateway == nil { + return nil, fmt.Errorf("could not parse %q as anchor IPv4 gateway", iface.AnchorIPv4.Gateway) + } + routes = append(routes, route{ + destination: net.IPNet{ + IP: net.IPv4zero, + Mask: net.IPMask(net.IPv4zero), + }, + gateway: gateway, + }) + } + } hwaddr, err := net.ParseMAC(iface.MAC) if err != nil { diff --git a/network/digitalocean_test.go b/network/digitalocean_test.go index ec07c9b..78aca54 100644 --- a/network/digitalocean_test.go +++ b/network/digitalocean_test.go @@ -258,6 +258,85 @@ func TestParseInterface(t *testing.T) { }, }, }, + + { + cfg: digitalocean.Interface{ + MAC: "01:23:45:67:89:AB", + AnchorIPv4: &digitalocean.Address{ + IPAddress: "bad", + Netmask: "255.255.0.0", + }, + }, + nss: []net.IP{}, + err: errors.New("could not parse \"bad\" as anchor IPv4 address"), + }, + { + cfg: digitalocean.Interface{ + MAC: "01:23:45:67:89:AB", + AnchorIPv4: &digitalocean.Address{ + IPAddress: "1.2.3.4", + Netmask: "bad", + }, + }, + nss: []net.IP{}, + err: errors.New("could not parse \"bad\" as anchor IPv4 mask"), + }, + { + cfg: digitalocean.Interface{ + MAC: "01:23:45:67:89:AB", + AnchorIPv4: &digitalocean.Address{ + IPAddress: "1.2.3.4", + Netmask: "255.255.0.0", + Gateway: "bad", + }, + }, + useRoute: true, + nss: []net.IP{}, + err: errors.New("could not parse \"bad\" as anchor IPv4 gateway"), + }, + { + cfg: digitalocean.Interface{ + MAC: "01:23:45:67:89:AB", + IPv4: &digitalocean.Address{ + IPAddress: "1.2.3.4", + Netmask: "255.255.0.0", + Gateway: "5.6.7.8", + }, + AnchorIPv4: &digitalocean.Address{ + IPAddress: "7.8.9.10", + Netmask: "255.255.0.0", + Gateway: "11.12.13.14", + }, + }, + useRoute: true, + nss: []net.IP{}, + iface: &logicalInterface{ + hwaddr: net.HardwareAddr([]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}), + config: configMethodStatic{ + addresses: []net.IPNet{ + { + IP: net.ParseIP("1.2.3.4"), + Mask: net.IPMask(net.ParseIP("255.255.0.0")), + }, + { + IP: net.ParseIP("7.8.9.10"), + Mask: net.IPMask(net.ParseIP("255.255.0.0")), + }, + }, + nameservers: []net.IP{}, + routes: []route{ + { + net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)}, + net.ParseIP("5.6.7.8"), + }, + { + net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)}, + net.ParseIP("11.12.13.14"), + }, + }, + }, + }, + }, } { iface, err := parseInterface(tt.cfg, tt.nss, tt.useRoute) if !errorsEqual(tt.err, err) {