digitalocean: Add DigitalOcean metadata service
Move debian-related processing into its own file.
This commit is contained in:
parent
2a8e6c9566
commit
3abd6b2225
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/coreos/coreos-cloudinit/datasource/configdrive"
|
"github.com/coreos/coreos-cloudinit/datasource/configdrive"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/file"
|
"github.com/coreos/coreos-cloudinit/datasource/file"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/metadata/cloudsigma"
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/cloudsigma"
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/metadata/ec2"
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/ec2"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/proc_cmdline"
|
"github.com/coreos/coreos-cloudinit/datasource/proc_cmdline"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/url"
|
"github.com/coreos/coreos-cloudinit/datasource/url"
|
||||||
@ -35,6 +36,7 @@ var (
|
|||||||
metadataService bool
|
metadataService bool
|
||||||
ec2MetadataService string
|
ec2MetadataService string
|
||||||
cloudSigmaMetadataService bool
|
cloudSigmaMetadataService bool
|
||||||
|
digitalOceanMetadataService string
|
||||||
url string
|
url string
|
||||||
procCmdLine bool
|
procCmdLine bool
|
||||||
}
|
}
|
||||||
@ -49,11 +51,12 @@ func init() {
|
|||||||
flag.StringVar(&sources.file, "from-file", "", "Read user-data from provided file")
|
flag.StringVar(&sources.file, "from-file", "", "Read user-data from provided file")
|
||||||
flag.StringVar(&sources.configDrive, "from-configdrive", "", "Read data from provided cloud-drive directory")
|
flag.StringVar(&sources.configDrive, "from-configdrive", "", "Read data from provided cloud-drive directory")
|
||||||
flag.BoolVar(&sources.metadataService, "from-metadata-service", false, "[DEPRECATED - Use -from-ec2-metadata] Download data from metadata service")
|
flag.BoolVar(&sources.metadataService, "from-metadata-service", false, "[DEPRECATED - Use -from-ec2-metadata] Download data from metadata service")
|
||||||
flag.StringVar(&sources.ec2MetadataService, "from-ec2-metadata", "", "Download data from the provided metadata service")
|
flag.StringVar(&sources.ec2MetadataService, "from-ec2-metadata", "", "Download EC2 data from the provided url")
|
||||||
flag.BoolVar(&sources.cloudSigmaMetadataService, "from-cloudsigma-metadata", false, "Download data from CloudSigma server context")
|
flag.BoolVar(&sources.cloudSigmaMetadataService, "from-cloudsigma-metadata", false, "Download data from CloudSigma server context")
|
||||||
|
flag.StringVar(&sources.digitalOceanMetadataService, "from-digitalocean-metadata", "", "Download DigitalOcean data from the provided url")
|
||||||
flag.StringVar(&sources.url, "from-url", "", "Download user-data from provided url")
|
flag.StringVar(&sources.url, "from-url", "", "Download user-data from provided url")
|
||||||
flag.BoolVar(&sources.procCmdLine, "from-proc-cmdline", false, fmt.Sprintf("Parse %s for '%s=<url>', using the cloud-config served by an HTTP GET to <url>", proc_cmdline.ProcCmdlineLocation, proc_cmdline.ProcCmdlineCloudConfigFlag))
|
flag.BoolVar(&sources.procCmdLine, "from-proc-cmdline", false, fmt.Sprintf("Parse %s for '%s=<url>', using the cloud-config served by an HTTP GET to <url>", proc_cmdline.ProcCmdlineLocation, proc_cmdline.ProcCmdlineCloudConfigFlag))
|
||||||
flag.StringVar(&convertNetconf, "convert-netconf", "", "Read the network config provided in cloud-drive and translate it from the specified format into networkd unit files (requires the -from-configdrive flag)")
|
flag.StringVar(&convertNetconf, "convert-netconf", "", "Read the network config provided in cloud-drive and translate it from the specified format into networkd unit files")
|
||||||
flag.StringVar(&workspace, "workspace", "/var/lib/coreos-cloudinit", "Base directory coreos-cloudinit should use to store data")
|
flag.StringVar(&workspace, "workspace", "/var/lib/coreos-cloudinit", "Base directory coreos-cloudinit should use to store data")
|
||||||
flag.StringVar(&sshKeyName, "ssh-key-name", initialize.DefaultSSHKeyName, "Add SSH keys to the system with the given name")
|
flag.StringVar(&sshKeyName, "ssh-key-name", initialize.DefaultSSHKeyName, "Add SSH keys to the system with the given name")
|
||||||
}
|
}
|
||||||
@ -73,16 +76,12 @@ func main() {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if convertNetconf != "" && sources.configDrive == "" {
|
|
||||||
fmt.Println("-convert-netconf flag requires -from-configdrive")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch convertNetconf {
|
switch convertNetconf {
|
||||||
case "":
|
case "":
|
||||||
case "debian":
|
case "debian":
|
||||||
|
case "digitalocean":
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Invalid option to -convert-netconf: '%s'. Supported options: 'debian'\n", convertNetconf)
|
fmt.Printf("Invalid option to -convert-netconf: '%s'. Supported options: 'debian, digitalocean'\n", convertNetconf)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,6 +240,9 @@ func getDatasources() []datasource.Datasource {
|
|||||||
if sources.cloudSigmaMetadataService {
|
if sources.cloudSigmaMetadataService {
|
||||||
dss = append(dss, cloudsigma.NewServerContextService())
|
dss = append(dss, cloudsigma.NewServerContextService())
|
||||||
}
|
}
|
||||||
|
if sources.digitalOceanMetadataService != "" {
|
||||||
|
dss = append(dss, digitalocean.NewDatasource(sources.digitalOceanMetadataService))
|
||||||
|
}
|
||||||
if sources.procCmdLine {
|
if sources.procCmdLine {
|
||||||
dss = append(dss, proc_cmdline.NewDatasource())
|
dss = append(dss, proc_cmdline.NewDatasource())
|
||||||
}
|
}
|
||||||
|
107
datasource/metadata/digitalocean/metadata.go
Normal file
107
datasource/metadata/digitalocean/metadata.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package digitalocean
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultAddress = "http://169.254.169.254/"
|
||||||
|
apiVersion = "metadata/v1"
|
||||||
|
userdataUrl = apiVersion + "/user-data"
|
||||||
|
metadataPath = apiVersion + ".json"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Address struct {
|
||||||
|
IPAddress string `json:"ip_address"`
|
||||||
|
Netmask string `json:"netmask"`
|
||||||
|
Cidr int `json:"cidr"`
|
||||||
|
Gateway string `json:"gateway"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Interface struct {
|
||||||
|
IPv4 *Address `json:"ipv4"`
|
||||||
|
IPv6 *Address `json:"ipv6"`
|
||||||
|
MAC string `json:"mac"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Interfaces struct {
|
||||||
|
Public []Interface `json:"public"`
|
||||||
|
Private []Interface `json:"private"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DNS struct {
|
||||||
|
Nameservers []string `json:"nameservers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metadata struct {
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
Interfaces Interfaces `json:"interfaces"`
|
||||||
|
PublicKeys []string `json:"public_keys"`
|
||||||
|
DNS DNS `json:"dns"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type metadataService struct {
|
||||||
|
interfaces Interfaces
|
||||||
|
dns DNS
|
||||||
|
metadata.MetadataService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDatasource(root string) *metadataService {
|
||||||
|
return &metadataService{MetadataService: metadata.NewDatasource(root, apiVersion, userdataUrl, metadataPath)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *metadataService) FetchMetadata() ([]byte, error) {
|
||||||
|
data, err := ms.FetchData(ms.MetadataUrl())
|
||||||
|
if err != nil || len(data) == 0 {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var metadata Metadata
|
||||||
|
if err := json.Unmarshal(data, &metadata); err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ms.interfaces = metadata.Interfaces
|
||||||
|
ms.dns = metadata.DNS
|
||||||
|
|
||||||
|
attrs := make(map[string]interface{})
|
||||||
|
if len(metadata.Interfaces.Public) > 0 {
|
||||||
|
if metadata.Interfaces.Public[0].IPv4 != nil {
|
||||||
|
attrs["public-ipv4"] = metadata.Interfaces.Public[0].IPv4.IPAddress
|
||||||
|
}
|
||||||
|
if metadata.Interfaces.Public[0].IPv6 != nil {
|
||||||
|
attrs["public-ipv6"] = metadata.Interfaces.Public[0].IPv6.IPAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(metadata.Interfaces.Private) > 0 {
|
||||||
|
if metadata.Interfaces.Private[0].IPv4 != nil {
|
||||||
|
attrs["local-ipv4"] = metadata.Interfaces.Private[0].IPv4.IPAddress
|
||||||
|
}
|
||||||
|
if metadata.Interfaces.Private[0].IPv6 != nil {
|
||||||
|
attrs["local-ipv6"] = metadata.Interfaces.Private[0].IPv6.IPAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attrs["hostname"] = metadata.Hostname
|
||||||
|
keys := make(map[string]string)
|
||||||
|
for i, key := range metadata.PublicKeys {
|
||||||
|
keys[strconv.Itoa(i)] = key
|
||||||
|
}
|
||||||
|
attrs["public_keys"] = keys
|
||||||
|
|
||||||
|
return json.Marshal(attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms metadataService) FetchNetworkConfig(filename string) ([]byte, error) {
|
||||||
|
return json.Marshal(Metadata{
|
||||||
|
Interfaces: ms.interfaces,
|
||||||
|
DNS: ms.dns,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms metadataService) Type() string {
|
||||||
|
return "digitalocean-metadata-service"
|
||||||
|
}
|
99
datasource/metadata/digitalocean/metadata_test.go
Normal file
99
datasource/metadata/digitalocean/metadata_test.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package digitalocean
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/test"
|
||||||
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestType(t *testing.T) {
|
||||||
|
want := "digitalocean-metadata-service"
|
||||||
|
if kind := (metadataService{}).Type(); kind != want {
|
||||||
|
t.Fatalf("bad type: want %q, got %q", want, kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetchMetadata(t *testing.T) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
root string
|
||||||
|
metadataPath string
|
||||||
|
resources map[string]string
|
||||||
|
expect []byte
|
||||||
|
clientErr error
|
||||||
|
expectErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
root: "/",
|
||||||
|
metadataPath: "v1.json",
|
||||||
|
resources: map[string]string{
|
||||||
|
"/v1.json": "bad",
|
||||||
|
},
|
||||||
|
expectErr: fmt.Errorf("invalid character 'b' looking for beginning of value"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: "/",
|
||||||
|
metadataPath: "v1.json",
|
||||||
|
resources: map[string]string{
|
||||||
|
"/v1.json": `{
|
||||||
|
"droplet_id": 1,
|
||||||
|
"user_data": "hello",
|
||||||
|
"vendor_data": "hello",
|
||||||
|
"public_keys": [
|
||||||
|
"publickey1",
|
||||||
|
"publickey2"
|
||||||
|
],
|
||||||
|
"region": "nyc2",
|
||||||
|
"interfaces": {
|
||||||
|
"public": [
|
||||||
|
{
|
||||||
|
"ipv4": {
|
||||||
|
"ip_address": "192.168.1.2",
|
||||||
|
"netmask": "255.255.255.0",
|
||||||
|
"gateway": "192.168.1.1"
|
||||||
|
},
|
||||||
|
"ipv6": {
|
||||||
|
"ip_address": "fe00::",
|
||||||
|
"cidr": 126,
|
||||||
|
"gateway": "fe00::"
|
||||||
|
},
|
||||||
|
"mac": "ab:cd:ef:gh:ij",
|
||||||
|
"type": "public"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
expect: []byte(`{"hostname":"","public-ipv4":"192.168.1.2","public-ipv6":"fe00::","public_keys":{"0":"publickey1","1":"publickey2"}}`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
clientErr: pkg.ErrTimeout{fmt.Errorf("test error")},
|
||||||
|
expectErr: pkg.ErrTimeout{fmt.Errorf("test error")},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
service := &metadataService{
|
||||||
|
MetadataService: metadata.MetadataService{
|
||||||
|
Root: tt.root,
|
||||||
|
Client: &test.HttpClient{tt.resources, tt.clientErr},
|
||||||
|
MetadataPath: tt.metadataPath,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
metadata, err := service.FetchMetadata()
|
||||||
|
if Error(err) != Error(tt.expectErr) {
|
||||||
|
t.Fatalf("bad error (%q): want %q, got %q", tt.resources, tt.expectErr, err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(metadata, tt.expect) {
|
||||||
|
t.Fatalf("bad fetch (%q): want %q, got %q", tt.resources, tt.expect, metadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(err error) string {
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
@ -263,6 +263,8 @@ func Apply(cfg CloudConfig, env *Environment) error {
|
|||||||
switch env.NetconfType() {
|
switch env.NetconfType() {
|
||||||
case "debian":
|
case "debian":
|
||||||
interfaces, err = network.ProcessDebianNetconf(cfg.NetworkConfig)
|
interfaces, err = network.ProcessDebianNetconf(cfg.NetworkConfig)
|
||||||
|
case "digitalocean":
|
||||||
|
interfaces, err = network.ProcessDigitalOceanNetconf(cfg.NetworkConfig)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Unsupported network config format %q", env.NetconfType())
|
return fmt.Errorf("Unsupported network config format %q", env.NetconfType())
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package network
|
package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProcessDebianNetconf(config string) ([]InterfaceGenerator, error) {
|
func ProcessDebianNetconf(config string) ([]InterfaceGenerator, error) {
|
||||||
|
log.Println("Processing Debian network config")
|
||||||
lines := formatConfig(config)
|
lines := formatConfig(config)
|
||||||
stanzas, err := parseStanzas(lines)
|
stanzas, err := parseStanzas(lines)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -18,7 +20,9 @@ func ProcessDebianNetconf(config string) ([]InterfaceGenerator, error) {
|
|||||||
interfaces = append(interfaces, s)
|
interfaces = append(interfaces, s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Printf("Parsed %d network interfaces\n", len(interfaces))
|
||||||
|
|
||||||
|
log.Println("Processed Debian network config")
|
||||||
return buildInterfaces(interfaces), nil
|
return buildInterfaces(interfaces), nil
|
||||||
}
|
}
|
||||||
|
|
142
network/digitalocean.go
Normal file
142
network/digitalocean.go
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ProcessDigitalOceanNetconf(config string) ([]InterfaceGenerator, error) {
|
||||||
|
log.Println("Processing DigitalOcean network config")
|
||||||
|
if config == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var cfg digitalocean.Metadata
|
||||||
|
if err := json.Unmarshal([]byte(config), &cfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Parsing nameservers")
|
||||||
|
nameservers, err := parseNameservers(cfg.DNS)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Printf("Parsed %d nameservers\n", len(nameservers))
|
||||||
|
|
||||||
|
log.Println("Parsing interfaces")
|
||||||
|
generators, err := parseInterfaces(cfg.Interfaces, nameservers)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Printf("Parsed %d network interfaces\n", len(generators))
|
||||||
|
|
||||||
|
log.Println("Processed DigitalOcean network config")
|
||||||
|
return generators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseNameservers(cfg digitalocean.DNS) ([]net.IP, error) {
|
||||||
|
nameservers := make([]net.IP, 0, len(cfg.Nameservers))
|
||||||
|
for _, ns := range cfg.Nameservers {
|
||||||
|
if ip := net.ParseIP(ns); ip == nil {
|
||||||
|
return nil, fmt.Errorf("could not parse %q as nameserver IP address", ns)
|
||||||
|
} else {
|
||||||
|
nameservers = append(nameservers, ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nameservers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInterfaces(cfg digitalocean.Interfaces, nameservers []net.IP) ([]InterfaceGenerator, error) {
|
||||||
|
generators := make([]InterfaceGenerator, 0, len(cfg.Public)+len(cfg.Private))
|
||||||
|
for _, iface := range cfg.Public {
|
||||||
|
if generator, err := parseInterface(iface, nameservers, true); err == nil {
|
||||||
|
generators = append(generators, &physicalInterface{*generator})
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, iface := range cfg.Private {
|
||||||
|
if generator, err := parseInterface(iface, []net.IP{}, false); err == nil {
|
||||||
|
generators = append(generators, &physicalInterface{*generator})
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return generators, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInterface(iface digitalocean.Interface, nameservers []net.IP, useRoute bool) (*logicalInterface, error) {
|
||||||
|
routes := make([]route, 0)
|
||||||
|
addresses := make([]net.IPNet, 0)
|
||||||
|
if iface.IPv4 != nil {
|
||||||
|
var ip, mask, gateway net.IP
|
||||||
|
if ip = net.ParseIP(iface.IPv4.IPAddress); ip == nil {
|
||||||
|
return nil, fmt.Errorf("could not parse %q as IPv4 address", iface.IPv4.IPAddress)
|
||||||
|
}
|
||||||
|
if mask = net.ParseIP(iface.IPv4.Netmask); mask == nil {
|
||||||
|
return nil, fmt.Errorf("could not parse %q as IPv4 mask", iface.IPv4.Netmask)
|
||||||
|
}
|
||||||
|
addresses = append(addresses, net.IPNet{
|
||||||
|
IP: ip,
|
||||||
|
Mask: net.IPMask(mask),
|
||||||
|
})
|
||||||
|
|
||||||
|
if useRoute {
|
||||||
|
if gateway = net.ParseIP(iface.IPv4.Gateway); gateway == nil {
|
||||||
|
return nil, fmt.Errorf("could not parse %q as IPv4 gateway", iface.IPv4.Gateway)
|
||||||
|
}
|
||||||
|
routes = append(routes, route{
|
||||||
|
destination: net.IPNet{
|
||||||
|
IP: net.IPv4zero,
|
||||||
|
Mask: net.IPMask(net.IPv4zero),
|
||||||
|
},
|
||||||
|
gateway: gateway,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if iface.IPv6 != nil {
|
||||||
|
var ip, gateway net.IP
|
||||||
|
if ip = net.ParseIP(iface.IPv6.IPAddress); ip == nil {
|
||||||
|
return nil, fmt.Errorf("could not parse %q as IPv6 address", iface.IPv6.IPAddress)
|
||||||
|
}
|
||||||
|
addresses = append(addresses, net.IPNet{
|
||||||
|
IP: ip,
|
||||||
|
Mask: net.CIDRMask(iface.IPv6.Cidr, net.IPv6len*8),
|
||||||
|
})
|
||||||
|
|
||||||
|
if useRoute {
|
||||||
|
if gateway = net.ParseIP(iface.IPv6.Gateway); gateway == nil {
|
||||||
|
return nil, fmt.Errorf("could not parse %q as IPv6 gateway", iface.IPv6.Gateway)
|
||||||
|
}
|
||||||
|
routes = append(routes, route{
|
||||||
|
destination: net.IPNet{
|
||||||
|
IP: net.IPv6zero,
|
||||||
|
Mask: net.IPMask(net.IPv6zero),
|
||||||
|
},
|
||||||
|
gateway: gateway,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hwaddr, err := net.ParseMAC(iface.MAC)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if nameservers == nil {
|
||||||
|
nameservers = []net.IP{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &logicalInterface{
|
||||||
|
hwaddr: hwaddr,
|
||||||
|
config: configMethodStatic{
|
||||||
|
addresses: addresses,
|
||||||
|
nameservers: nameservers,
|
||||||
|
routes: routes,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
1
test
1
test
@ -20,6 +20,7 @@ declare -a TESTPKGS=(initialize
|
|||||||
datasource/file
|
datasource/file
|
||||||
datasource/metadata
|
datasource/metadata
|
||||||
datasource/metadata/cloudsigma
|
datasource/metadata/cloudsigma
|
||||||
|
datasource/metadata/digitalocean
|
||||||
datasource/metadata/ec2
|
datasource/metadata/ec2
|
||||||
datasource/proc_cmdline
|
datasource/proc_cmdline
|
||||||
datasource/url
|
datasource/url
|
||||||
|
Loading…
Reference in New Issue
Block a user