Merge pull request #212 from crawford/metadata
refactor: Refactor metadata and datasources to be more testable
This commit is contained in:
commit
e8d0021140
@ -132,6 +132,17 @@ func main() {
|
|||||||
fmt.Printf("Failed to parse meta-data: %v\n", err)
|
fmt.Printf("Failed to parse meta-data: %v\n", err)
|
||||||
die()
|
die()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ccm != nil {
|
||||||
|
fmt.Printf("Fetching network config from datasource of type %q\n", ds.Type())
|
||||||
|
netconfBytes, err := ds.FetchNetworkConfig(ccm.NetworkConfigPath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed fetching network config from datasource: %v\n", err)
|
||||||
|
die()
|
||||||
|
}
|
||||||
|
ccm.NetworkConfig = string(netconfBytes)
|
||||||
|
}
|
||||||
|
|
||||||
if ud, err := initialize.ParseUserData(userdata); err != nil {
|
if ud, err := initialize.ParseUserData(userdata); err != nil {
|
||||||
fmt.Printf("Failed to parse user-data: %v\n", err)
|
fmt.Printf("Failed to parse user-data: %v\n", err)
|
||||||
die()
|
die()
|
||||||
|
@ -41,6 +41,10 @@ func (cd *configDrive) FetchUserdata() ([]byte, error) {
|
|||||||
return cd.tryReadFile(path.Join(cd.openstackVersionRoot(), "user_data"))
|
return cd.tryReadFile(path.Join(cd.openstackVersionRoot(), "user_data"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cd *configDrive) FetchNetworkConfig(filename string) ([]byte, error) {
|
||||||
|
return cd.tryReadFile(path.Join(cd.openstackRoot(), filename))
|
||||||
|
}
|
||||||
|
|
||||||
func (cd *configDrive) Type() string {
|
func (cd *configDrive) Type() string {
|
||||||
return "cloud-drive"
|
return "cloud-drive"
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
package datasource
|
package datasource
|
||||||
|
|
||||||
const (
|
|
||||||
Ec2ApiVersion = "2009-04-04"
|
|
||||||
OpenstackApiVersion = "2012-08-10"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Datasource interface {
|
type Datasource interface {
|
||||||
IsAvailable() bool
|
IsAvailable() bool
|
||||||
AvailabilityChanges() bool
|
AvailabilityChanges() bool
|
||||||
ConfigRoot() string
|
ConfigRoot() string
|
||||||
FetchMetadata() ([]byte, error)
|
FetchMetadata() ([]byte, error)
|
||||||
FetchUserdata() ([]byte, error)
|
FetchUserdata() ([]byte, error)
|
||||||
|
FetchNetworkConfig(string) ([]byte, error)
|
||||||
Type() string
|
Type() string
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,10 @@ func (f *localFile) FetchUserdata() ([]byte, error) {
|
|||||||
return ioutil.ReadFile(f.path)
|
return ioutil.ReadFile(f.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *localFile) FetchNetworkConfig(filename string) ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *localFile) Type() string {
|
func (f *localFile) Type() string {
|
||||||
return "local-file"
|
return "local-file"
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,10 @@ func (scs *serverContextService) FetchUserdata() ([]byte, error) {
|
|||||||
return []byte(userData), nil
|
return []byte(userData), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (scs *serverContextService) FetchNetworkConfig(a string) ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func isBase64Encoded(field string, userdata map[string]string) bool {
|
func isBase64Encoded(field string, userdata map[string]string) bool {
|
||||||
base64Fields, ok := userdata["base64_fields"]
|
base64Fields, ok := userdata["base64_fields"]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -7,44 +7,28 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
||||||
"github.com/coreos/coreos-cloudinit/pkg"
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefaultAddress = "http://169.254.169.254/"
|
DefaultAddress = "http://169.254.169.254/"
|
||||||
apiVersion = "2009-04-04"
|
apiVersion = "2009-04-04"
|
||||||
userdataUrl = apiVersion + "/user-data"
|
userdataPath = apiVersion + "/user-data"
|
||||||
metadataUrl = apiVersion + "/meta-data"
|
metadataPath = apiVersion + "/meta-data"
|
||||||
)
|
)
|
||||||
|
|
||||||
type metadataService struct {
|
type metadataService struct {
|
||||||
root string
|
metadata.MetadataService
|
||||||
client pkg.Getter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDatasource(root string) *metadataService {
|
func NewDatasource(root string) *metadataService {
|
||||||
if !strings.HasSuffix(root, "/") {
|
return &metadataService{metadata.NewDatasource(root, apiVersion, userdataPath, metadataPath)}
|
||||||
root += "/"
|
|
||||||
}
|
|
||||||
return &metadataService{root, pkg.NewHttpClient()}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms metadataService) IsAvailable() bool {
|
|
||||||
_, err := ms.client.Get(ms.root + apiVersion)
|
|
||||||
return (err == nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms metadataService) AvailabilityChanges() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms metadataService) ConfigRoot() string {
|
|
||||||
return ms.root
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms metadataService) FetchMetadata() ([]byte, error) {
|
func (ms metadataService) FetchMetadata() ([]byte, error) {
|
||||||
attrs := make(map[string]interface{})
|
attrs := make(map[string]interface{})
|
||||||
if keynames, err := fetchAttributes(ms.client, fmt.Sprintf("%s/public-keys", ms.metadataUrl())); err == nil {
|
if keynames, err := ms.fetchAttributes(fmt.Sprintf("%s/public-keys", ms.MetadataUrl())); err == nil {
|
||||||
keyIDs := make(map[string]string)
|
keyIDs := make(map[string]string)
|
||||||
for _, keyname := range keynames {
|
for _, keyname := range keynames {
|
||||||
tokens := strings.SplitN(keyname, "=", 2)
|
tokens := strings.SplitN(keyname, "=", 2)
|
||||||
@ -56,7 +40,7 @@ func (ms metadataService) FetchMetadata() ([]byte, error) {
|
|||||||
|
|
||||||
keys := make(map[string]string)
|
keys := make(map[string]string)
|
||||||
for name, id := range keyIDs {
|
for name, id := range keyIDs {
|
||||||
sshkey, err := fetchAttribute(ms.client, fmt.Sprintf("%s/public-keys/%s/openssh-key", ms.metadataUrl(), id))
|
sshkey, err := ms.fetchAttribute(fmt.Sprintf("%s/public-keys/%s/openssh-key", ms.MetadataUrl(), id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -68,25 +52,25 @@ func (ms metadataService) FetchMetadata() ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if hostname, err := fetchAttribute(ms.client, fmt.Sprintf("%s/hostname", ms.metadataUrl())); err == nil {
|
if hostname, err := ms.fetchAttribute(fmt.Sprintf("%s/hostname", ms.MetadataUrl())); err == nil {
|
||||||
attrs["hostname"] = hostname
|
attrs["hostname"] = hostname
|
||||||
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if localAddr, err := fetchAttribute(ms.client, fmt.Sprintf("%s/local-ipv4", ms.metadataUrl())); err == nil {
|
if localAddr, err := ms.fetchAttribute(fmt.Sprintf("%s/local-ipv4", ms.MetadataUrl())); err == nil {
|
||||||
attrs["local-ipv4"] = localAddr
|
attrs["local-ipv4"] = localAddr
|
||||||
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if publicAddr, err := fetchAttribute(ms.client, fmt.Sprintf("%s/public-ipv4", ms.metadataUrl())); err == nil {
|
if publicAddr, err := ms.fetchAttribute(fmt.Sprintf("%s/public-ipv4", ms.MetadataUrl())); err == nil {
|
||||||
attrs["public-ipv4"] = publicAddr
|
attrs["public-ipv4"] = publicAddr
|
||||||
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if content_path, err := fetchAttribute(ms.client, fmt.Sprintf("%s/network_config/content_path", ms.metadataUrl())); err == nil {
|
if content_path, err := ms.fetchAttribute(fmt.Sprintf("%s/network_config/content_path", ms.MetadataUrl())); err == nil {
|
||||||
attrs["network_config"] = map[string]string{
|
attrs["network_config"] = map[string]string{
|
||||||
"content_path": content_path,
|
"content_path": content_path,
|
||||||
}
|
}
|
||||||
@ -97,30 +81,12 @@ func (ms metadataService) FetchMetadata() ([]byte, error) {
|
|||||||
return json.Marshal(attrs)
|
return json.Marshal(attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms metadataService) FetchUserdata() ([]byte, error) {
|
|
||||||
if data, err := ms.client.GetRetry(ms.userdataUrl()); err == nil {
|
|
||||||
return data, err
|
|
||||||
} else if _, ok := err.(pkg.ErrNotFound); ok {
|
|
||||||
return []byte{}, nil
|
|
||||||
} else {
|
|
||||||
return data, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms metadataService) Type() string {
|
func (ms metadataService) Type() string {
|
||||||
return "ec2-metadata-service"
|
return "ec2-metadata-service"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms metadataService) metadataUrl() string {
|
func (ms metadataService) fetchAttributes(url string) ([]string, error) {
|
||||||
return (ms.root + metadataUrl)
|
resp, err := ms.FetchData(url)
|
||||||
}
|
|
||||||
|
|
||||||
func (ms metadataService) userdataUrl() string {
|
|
||||||
return (ms.root + userdataUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchAttributes(client pkg.Getter, url string) ([]string, error) {
|
|
||||||
resp, err := client.GetRetry(url)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -132,8 +98,8 @@ func fetchAttributes(client pkg.Getter, url string) ([]string, error) {
|
|||||||
return data, scanner.Err()
|
return data, scanner.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchAttribute(client pkg.Getter, url string) (string, error) {
|
func (ms metadataService) fetchAttribute(url string) (string, error) {
|
||||||
if attrs, err := fetchAttributes(client, url); err == nil && len(attrs) > 0 {
|
if attrs, err := ms.fetchAttributes(url); err == nil && len(attrs) > 0 {
|
||||||
return attrs[0], nil
|
return attrs[0], nil
|
||||||
} else {
|
} else {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -6,36 +6,11 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/test"
|
||||||
"github.com/coreos/coreos-cloudinit/pkg"
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testHttpClient struct {
|
|
||||||
resources map[string]string
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *testHttpClient) GetRetry(url string) ([]byte, error) {
|
|
||||||
if t.err != nil {
|
|
||||||
return nil, t.err
|
|
||||||
}
|
|
||||||
if val, ok := t.resources[url]; ok {
|
|
||||||
return []byte(val), nil
|
|
||||||
} else {
|
|
||||||
return nil, pkg.ErrNotFound{fmt.Errorf("not found: %q", url)}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *testHttpClient) Get(url string) ([]byte, error) {
|
|
||||||
return t.GetRetry(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAvailabilityChanges(t *testing.T) {
|
|
||||||
want := true
|
|
||||||
if ac := (metadataService{}).AvailabilityChanges(); ac != want {
|
|
||||||
t.Fatalf("bad AvailabilityChanges: want %q, got %q", want, ac)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestType(t *testing.T) {
|
func TestType(t *testing.T) {
|
||||||
want := "ec2-metadata-service"
|
want := "ec2-metadata-service"
|
||||||
if kind := (metadataService{}).Type(); kind != want {
|
if kind := (metadataService{}).Type(); kind != want {
|
||||||
@ -43,102 +18,6 @@ func TestType(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsAvailable(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
root string
|
|
||||||
resources map[string]string
|
|
||||||
expect bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
root: "/",
|
|
||||||
resources: map[string]string{
|
|
||||||
"/2009-04-04": "",
|
|
||||||
},
|
|
||||||
expect: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
root: "/",
|
|
||||||
resources: map[string]string{},
|
|
||||||
expect: false,
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
service := &metadataService{tt.root, &testHttpClient{tt.resources, nil}}
|
|
||||||
if a := service.IsAvailable(); a != tt.expect {
|
|
||||||
t.Fatalf("bad isAvailable (%q): want %q, got %q", tt.resources, tt.expect, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFetchUserdata(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
root string
|
|
||||||
resources map[string]string
|
|
||||||
userdata []byte
|
|
||||||
clientErr error
|
|
||||||
expectErr error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
root: "/",
|
|
||||||
resources: map[string]string{
|
|
||||||
"/2009-04-04/user-data": "hello",
|
|
||||||
},
|
|
||||||
userdata: []byte("hello"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
root: "/",
|
|
||||||
clientErr: pkg.ErrNotFound{fmt.Errorf("test not found error")},
|
|
||||||
userdata: []byte{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
root: "/",
|
|
||||||
clientErr: pkg.ErrTimeout{fmt.Errorf("test timeout error")},
|
|
||||||
expectErr: pkg.ErrTimeout{fmt.Errorf("test timeout error")},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
service := &metadataService{tt.root, &testHttpClient{tt.resources, tt.clientErr}}
|
|
||||||
data, err := service.FetchUserdata()
|
|
||||||
if Error(err) != Error(tt.expectErr) {
|
|
||||||
t.Fatalf("bad error (%q): want %q, got %q", tt.resources, tt.expectErr, err)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(data, tt.userdata) {
|
|
||||||
t.Fatalf("bad userdata (%q): want %q, got %q", tt.resources, tt.userdata, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUrls(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
root string
|
|
||||||
expectRoot string
|
|
||||||
userdata string
|
|
||||||
metadata string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
root: "/",
|
|
||||||
expectRoot: "/",
|
|
||||||
userdata: "/2009-04-04/user-data",
|
|
||||||
metadata: "/2009-04-04/meta-data",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
root: "http://169.254.169.254/",
|
|
||||||
expectRoot: "http://169.254.169.254/",
|
|
||||||
userdata: "http://169.254.169.254/2009-04-04/user-data",
|
|
||||||
metadata: "http://169.254.169.254/2009-04-04/meta-data",
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
service := &metadataService{tt.root, nil}
|
|
||||||
if url := service.userdataUrl(); url != tt.userdata {
|
|
||||||
t.Fatalf("bad url (%q): want %q, got %q", tt.root, tt.userdata, url)
|
|
||||||
}
|
|
||||||
if url := service.metadataUrl(); url != tt.metadata {
|
|
||||||
t.Fatalf("bad url (%q): want %q, got %q", tt.root, tt.metadata, url)
|
|
||||||
}
|
|
||||||
if url := service.ConfigRoot(); url != tt.expectRoot {
|
|
||||||
t.Fatalf("bad url (%q): want %q, got %q", tt.root, tt.expectRoot, url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFetchAttributes(t *testing.T) {
|
func TestFetchAttributes(t *testing.T) {
|
||||||
for _, s := range []struct {
|
for _, s := range []struct {
|
||||||
resources map[string]string
|
resources map[string]string
|
||||||
@ -169,7 +48,7 @@ func TestFetchAttributes(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
err: pkg.ErrNotFound{fmt.Errorf("test error")},
|
err: fmt.Errorf("test error"),
|
||||||
tests: []struct {
|
tests: []struct {
|
||||||
path string
|
path string
|
||||||
val []string
|
val []string
|
||||||
@ -178,9 +57,11 @@ func TestFetchAttributes(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
client := &testHttpClient{s.resources, s.err}
|
service := metadataService{metadata.MetadataService{
|
||||||
|
Client: &test.HttpClient{s.resources, s.err},
|
||||||
|
}}
|
||||||
for _, tt := range s.tests {
|
for _, tt := range s.tests {
|
||||||
attrs, err := fetchAttributes(client, tt.path)
|
attrs, err := service.fetchAttributes(tt.path)
|
||||||
if err != s.err {
|
if err != s.err {
|
||||||
t.Fatalf("bad error for %q (%q): want %q, got %q", tt.path, s.resources, s.err, err)
|
t.Fatalf("bad error for %q (%q): want %q, got %q", tt.path, s.resources, s.err, err)
|
||||||
}
|
}
|
||||||
@ -221,7 +102,7 @@ func TestFetchAttribute(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
err: pkg.ErrNotFound{fmt.Errorf("test error")},
|
err: fmt.Errorf("test error"),
|
||||||
tests: []struct {
|
tests: []struct {
|
||||||
path string
|
path string
|
||||||
val string
|
val string
|
||||||
@ -230,9 +111,11 @@ func TestFetchAttribute(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
client := &testHttpClient{s.resources, s.err}
|
service := metadataService{metadata.MetadataService{
|
||||||
|
Client: &test.HttpClient{s.resources, s.err},
|
||||||
|
}}
|
||||||
for _, tt := range s.tests {
|
for _, tt := range s.tests {
|
||||||
attr, err := fetchAttribute(client, tt.path)
|
attr, err := service.fetchAttribute(tt.path)
|
||||||
if err != s.err {
|
if err != s.err {
|
||||||
t.Fatalf("bad error for %q (%q): want %q, got %q", tt.path, s.resources, s.err, err)
|
t.Fatalf("bad error for %q (%q): want %q, got %q", tt.path, s.resources, s.err, err)
|
||||||
}
|
}
|
||||||
@ -245,21 +128,24 @@ func TestFetchAttribute(t *testing.T) {
|
|||||||
|
|
||||||
func TestFetchMetadata(t *testing.T) {
|
func TestFetchMetadata(t *testing.T) {
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
root string
|
root string
|
||||||
resources map[string]string
|
metadataPath string
|
||||||
expect []byte
|
resources map[string]string
|
||||||
clientErr error
|
expect []byte
|
||||||
expectErr error
|
clientErr error
|
||||||
|
expectErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
root: "/",
|
root: "/",
|
||||||
|
metadataPath: "2009-04-04/meta-data",
|
||||||
resources: map[string]string{
|
resources: map[string]string{
|
||||||
"/2009-04-04/meta-data/public-keys": "bad\n",
|
"/2009-04-04/meta-data/public-keys": "bad\n",
|
||||||
},
|
},
|
||||||
expectErr: fmt.Errorf("malformed public key: \"bad\""),
|
expectErr: fmt.Errorf("malformed public key: \"bad\""),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
root: "/",
|
root: "/",
|
||||||
|
metadataPath: "2009-04-04/meta-data",
|
||||||
resources: map[string]string{
|
resources: map[string]string{
|
||||||
"/2009-04-04/meta-data/hostname": "host",
|
"/2009-04-04/meta-data/hostname": "host",
|
||||||
"/2009-04-04/meta-data/local-ipv4": "1.2.3.4",
|
"/2009-04-04/meta-data/local-ipv4": "1.2.3.4",
|
||||||
@ -276,7 +162,11 @@ func TestFetchMetadata(t *testing.T) {
|
|||||||
expectErr: pkg.ErrTimeout{fmt.Errorf("test error")},
|
expectErr: pkg.ErrTimeout{fmt.Errorf("test error")},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
service := &metadataService{tt.root, &testHttpClient{tt.resources, tt.clientErr}}
|
service := &metadataService{metadata.MetadataService{
|
||||||
|
Root: tt.root,
|
||||||
|
Client: &test.HttpClient{tt.resources, tt.clientErr},
|
||||||
|
MetadataPath: tt.metadataPath,
|
||||||
|
}}
|
||||||
metadata, err := service.FetchMetadata()
|
metadata, err := service.FetchMetadata()
|
||||||
if Error(err) != Error(tt.expectErr) {
|
if Error(err) != Error(tt.expectErr) {
|
||||||
t.Fatalf("bad error (%q): want %q, got %q", tt.resources, tt.expectErr, err)
|
t.Fatalf("bad error (%q): want %q, got %q", tt.resources, tt.expectErr, err)
|
||||||
@ -287,35 +177,6 @@ func TestFetchMetadata(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewDatasource(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
root string
|
|
||||||
expectRoot string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
root: "",
|
|
||||||
expectRoot: "/",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
root: "/",
|
|
||||||
expectRoot: "/",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
root: "http://169.254.169.254",
|
|
||||||
expectRoot: "http://169.254.169.254/",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
root: "http://169.254.169.254/",
|
|
||||||
expectRoot: "http://169.254.169.254/",
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
service := NewDatasource(tt.root)
|
|
||||||
if service.root != tt.expectRoot {
|
|
||||||
t.Fatalf("bad root (%q): want %q, got %q", tt.root, tt.expectRoot, service.root)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Error(err error) string {
|
func Error(err error) string {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err.Error()
|
return err.Error()
|
||||||
|
61
datasource/metadata/metadata.go
Normal file
61
datasource/metadata/metadata.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MetadataService struct {
|
||||||
|
Root string
|
||||||
|
Client pkg.Getter
|
||||||
|
ApiVersion string
|
||||||
|
UserdataPath string
|
||||||
|
MetadataPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDatasource(root, apiVersion, userdataPath, metadataPath string) MetadataService {
|
||||||
|
if !strings.HasSuffix(root, "/") {
|
||||||
|
root += "/"
|
||||||
|
}
|
||||||
|
return MetadataService{root, pkg.NewHttpClient(), apiVersion, userdataPath, metadataPath}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms MetadataService) IsAvailable() bool {
|
||||||
|
_, err := ms.Client.Get(ms.Root + ms.ApiVersion)
|
||||||
|
return (err == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms MetadataService) AvailabilityChanges() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms MetadataService) ConfigRoot() string {
|
||||||
|
return ms.Root
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms MetadataService) FetchUserdata() ([]byte, error) {
|
||||||
|
return ms.FetchData(ms.UserdataUrl())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms MetadataService) FetchNetworkConfig(filename string) ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms MetadataService) FetchData(url string) ([]byte, error) {
|
||||||
|
if data, err := ms.Client.GetRetry(url); err == nil {
|
||||||
|
return data, err
|
||||||
|
} else if _, ok := err.(pkg.ErrNotFound); ok {
|
||||||
|
return []byte{}, nil
|
||||||
|
} else {
|
||||||
|
return data, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms MetadataService) MetadataUrl() string {
|
||||||
|
return (ms.Root + ms.MetadataPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms MetadataService) UserdataUrl() string {
|
||||||
|
return (ms.Root + ms.UserdataPath)
|
||||||
|
}
|
171
datasource/metadata/metadata_test.go
Normal file
171
datasource/metadata/metadata_test.go
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package metadata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/test"
|
||||||
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAvailabilityChanges(t *testing.T) {
|
||||||
|
want := true
|
||||||
|
if ac := (MetadataService{}).AvailabilityChanges(); ac != want {
|
||||||
|
t.Fatalf("bad AvailabilityChanges: want %q, got %q", want, ac)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsAvailable(t *testing.T) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
root string
|
||||||
|
apiVersion string
|
||||||
|
resources map[string]string
|
||||||
|
expect bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
root: "/",
|
||||||
|
apiVersion: "2009-04-04",
|
||||||
|
resources: map[string]string{
|
||||||
|
"/2009-04-04": "",
|
||||||
|
},
|
||||||
|
expect: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: "/",
|
||||||
|
resources: map[string]string{},
|
||||||
|
expect: false,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
service := &MetadataService{
|
||||||
|
Root: tt.root,
|
||||||
|
Client: &test.HttpClient{tt.resources, nil},
|
||||||
|
ApiVersion: tt.apiVersion,
|
||||||
|
}
|
||||||
|
if a := service.IsAvailable(); a != tt.expect {
|
||||||
|
t.Fatalf("bad isAvailable (%q): want %q, got %q", tt.resources, tt.expect, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetchUserdata(t *testing.T) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
root string
|
||||||
|
userdataPath string
|
||||||
|
resources map[string]string
|
||||||
|
userdata []byte
|
||||||
|
clientErr error
|
||||||
|
expectErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
root: "/",
|
||||||
|
userdataPath: "2009-04-04/user-data",
|
||||||
|
resources: map[string]string{
|
||||||
|
"/2009-04-04/user-data": "hello",
|
||||||
|
},
|
||||||
|
userdata: []byte("hello"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: "/",
|
||||||
|
clientErr: pkg.ErrNotFound{fmt.Errorf("test not found error")},
|
||||||
|
userdata: []byte{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: "/",
|
||||||
|
clientErr: pkg.ErrTimeout{fmt.Errorf("test timeout error")},
|
||||||
|
expectErr: pkg.ErrTimeout{fmt.Errorf("test timeout error")},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
service := &MetadataService{
|
||||||
|
Root: tt.root,
|
||||||
|
Client: &test.HttpClient{tt.resources, tt.clientErr},
|
||||||
|
UserdataPath: tt.userdataPath,
|
||||||
|
}
|
||||||
|
data, err := service.FetchUserdata()
|
||||||
|
if Error(err) != Error(tt.expectErr) {
|
||||||
|
t.Fatalf("bad error (%q): want %q, got %q", tt.resources, tt.expectErr, err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(data, tt.userdata) {
|
||||||
|
t.Fatalf("bad userdata (%q): want %q, got %q", tt.resources, tt.userdata, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUrls(t *testing.T) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
root string
|
||||||
|
userdataPath string
|
||||||
|
metadataPath string
|
||||||
|
expectRoot string
|
||||||
|
userdata string
|
||||||
|
metadata string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
root: "/",
|
||||||
|
userdataPath: "2009-04-04/user-data",
|
||||||
|
metadataPath: "2009-04-04/meta-data",
|
||||||
|
expectRoot: "/",
|
||||||
|
userdata: "/2009-04-04/user-data",
|
||||||
|
metadata: "/2009-04-04/meta-data",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: "http://169.254.169.254/",
|
||||||
|
userdataPath: "2009-04-04/user-data",
|
||||||
|
metadataPath: "2009-04-04/meta-data",
|
||||||
|
expectRoot: "http://169.254.169.254/",
|
||||||
|
userdata: "http://169.254.169.254/2009-04-04/user-data",
|
||||||
|
metadata: "http://169.254.169.254/2009-04-04/meta-data",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
service := &MetadataService{
|
||||||
|
Root: tt.root,
|
||||||
|
UserdataPath: tt.userdataPath,
|
||||||
|
MetadataPath: tt.metadataPath,
|
||||||
|
}
|
||||||
|
if url := service.UserdataUrl(); url != tt.userdata {
|
||||||
|
t.Fatalf("bad url (%q): want %q, got %q", tt.root, tt.userdata, url)
|
||||||
|
}
|
||||||
|
if url := service.MetadataUrl(); url != tt.metadata {
|
||||||
|
t.Fatalf("bad url (%q): want %q, got %q", tt.root, tt.metadata, url)
|
||||||
|
}
|
||||||
|
if url := service.ConfigRoot(); url != tt.expectRoot {
|
||||||
|
t.Fatalf("bad url (%q): want %q, got %q", tt.root, tt.expectRoot, url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewDatasource(t *testing.T) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
root string
|
||||||
|
expectRoot string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
root: "",
|
||||||
|
expectRoot: "/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: "/",
|
||||||
|
expectRoot: "/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: "http://169.254.169.254",
|
||||||
|
expectRoot: "http://169.254.169.254/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: "http://169.254.169.254/",
|
||||||
|
expectRoot: "http://169.254.169.254/",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
service := NewDatasource(tt.root, "", "", "")
|
||||||
|
if service.Root != tt.expectRoot {
|
||||||
|
t.Fatalf("bad root (%q): want %q, got %q", tt.root, tt.expectRoot, service.Root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(err error) string {
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
27
datasource/metadata/test/test.go
Normal file
27
datasource/metadata/test/test.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HttpClient struct {
|
||||||
|
Resources map[string]string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *HttpClient) GetRetry(url string) ([]byte, error) {
|
||||||
|
if t.Err != nil {
|
||||||
|
return nil, t.Err
|
||||||
|
}
|
||||||
|
if val, ok := t.Resources[url]; ok {
|
||||||
|
return []byte(val), nil
|
||||||
|
} else {
|
||||||
|
return nil, pkg.ErrNotFound{fmt.Errorf("not found: %q", url)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *HttpClient) Get(url string) ([]byte, error) {
|
||||||
|
return t.GetRetry(url)
|
||||||
|
}
|
@ -66,6 +66,10 @@ func (c *procCmdline) FetchUserdata() ([]byte, error) {
|
|||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *procCmdline) FetchNetworkConfig(filename string) ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *procCmdline) Type() string {
|
func (c *procCmdline) Type() string {
|
||||||
return "proc-cmdline"
|
return "proc-cmdline"
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package url
|
package url
|
||||||
|
|
||||||
import "github.com/coreos/coreos-cloudinit/pkg"
|
import (
|
||||||
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
type remoteFile struct {
|
type remoteFile struct {
|
||||||
url string
|
url string
|
||||||
@ -33,6 +35,10 @@ func (f *remoteFile) FetchUserdata() ([]byte, error) {
|
|||||||
return client.GetRetry(f.url)
|
return client.GetRetry(f.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *remoteFile) FetchNetworkConfig(filename string) ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *remoteFile) Type() string {
|
func (f *remoteFile) Type() string {
|
||||||
return "url"
|
return "url"
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package initialize
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
@ -42,6 +41,7 @@ type CloudConfig struct {
|
|||||||
Users []system.User
|
Users []system.User
|
||||||
ManageEtcHosts EtcHosts `yaml:"manage_etc_hosts"`
|
ManageEtcHosts EtcHosts `yaml:"manage_etc_hosts"`
|
||||||
NetworkConfigPath string
|
NetworkConfigPath string
|
||||||
|
NetworkConfig string
|
||||||
}
|
}
|
||||||
|
|
||||||
type warner func(format string, v ...interface{})
|
type warner func(format string, v ...interface{})
|
||||||
@ -258,17 +258,11 @@ func Apply(cfg CloudConfig, env *Environment) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if env.NetconfType() != "" {
|
if env.NetconfType() != "" {
|
||||||
filename := path.Join(env.ConfigRoot(), cfg.NetworkConfigPath)
|
|
||||||
log.Printf("Attempting to read config from %q\n", filename)
|
|
||||||
netconfBytes, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var interfaces []network.InterfaceGenerator
|
var interfaces []network.InterfaceGenerator
|
||||||
|
var err error
|
||||||
switch env.NetconfType() {
|
switch env.NetconfType() {
|
||||||
case "debian":
|
case "debian":
|
||||||
interfaces, err = network.ProcessDebianNetconf(string(netconfBytes))
|
interfaces, err = network.ProcessDebianNetconf(cfg.NetworkConfig)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Unsupported network config format %q", env.NetconfType())
|
return fmt.Errorf("Unsupported network config format %q", env.NetconfType())
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package network
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -25,13 +26,25 @@ type networkInterface interface {
|
|||||||
|
|
||||||
type logicalInterface struct {
|
type logicalInterface struct {
|
||||||
name string
|
name string
|
||||||
|
hwaddr net.HardwareAddr
|
||||||
config configMethod
|
config configMethod
|
||||||
children []networkInterface
|
children []networkInterface
|
||||||
configDepth int
|
configDepth int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *logicalInterface) Name() string {
|
||||||
|
return i.name
|
||||||
|
}
|
||||||
|
|
||||||
func (i *logicalInterface) Network() string {
|
func (i *logicalInterface) Network() string {
|
||||||
config := fmt.Sprintf("[Match]\nName=%s\n\n[Network]\n", i.name)
|
config := fmt.Sprintln("[Match]")
|
||||||
|
if i.name != "" {
|
||||||
|
config += fmt.Sprintf("Name=%s\n", i.name)
|
||||||
|
}
|
||||||
|
if i.hwaddr != nil {
|
||||||
|
config += fmt.Sprintf("MACAddress=%s\n", i.hwaddr)
|
||||||
|
}
|
||||||
|
config += "\n[Network]\n"
|
||||||
|
|
||||||
for _, child := range i.children {
|
for _, child := range i.children {
|
||||||
switch iface := child.(type) {
|
switch iface := child.(type) {
|
||||||
@ -47,8 +60,8 @@ func (i *logicalInterface) Network() string {
|
|||||||
for _, nameserver := range conf.nameservers {
|
for _, nameserver := range conf.nameservers {
|
||||||
config += fmt.Sprintf("DNS=%s\n", nameserver)
|
config += fmt.Sprintf("DNS=%s\n", nameserver)
|
||||||
}
|
}
|
||||||
if conf.address.IP != nil {
|
for _, addr := range conf.addresses {
|
||||||
config += fmt.Sprintf("\n[Address]\nAddress=%s\n", conf.address.String())
|
config += fmt.Sprintf("\n[Address]\nAddress=%s\n", addr.String())
|
||||||
}
|
}
|
||||||
for _, route := range conf.routes {
|
for _, route := range conf.routes {
|
||||||
config += fmt.Sprintf("\n[Route]\nDestination=%s\nGateway=%s\n", route.destination.String(), route.gateway)
|
config += fmt.Sprintf("\n[Route]\nDestination=%s\nGateway=%s\n", route.destination.String(), route.gateway)
|
||||||
@ -64,6 +77,10 @@ func (i *logicalInterface) Link() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *logicalInterface) Netdev() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (i *logicalInterface) Filename() string {
|
func (i *logicalInterface) Filename() string {
|
||||||
return fmt.Sprintf("%02x-%s", i.configDepth, i.name)
|
return fmt.Sprintf("%02x-%s", i.configDepth, i.name)
|
||||||
}
|
}
|
||||||
@ -84,14 +101,6 @@ type physicalInterface struct {
|
|||||||
logicalInterface
|
logicalInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *physicalInterface) Name() string {
|
|
||||||
return p.name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *physicalInterface) Netdev() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *physicalInterface) Type() string {
|
func (p *physicalInterface) Type() string {
|
||||||
return "physical"
|
return "physical"
|
||||||
}
|
}
|
||||||
@ -102,10 +111,6 @@ type bondInterface struct {
|
|||||||
options map[string]string
|
options map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bondInterface) Name() string {
|
|
||||||
return b.name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *bondInterface) Netdev() string {
|
func (b *bondInterface) Netdev() string {
|
||||||
return fmt.Sprintf("[NetDev]\nKind=bond\nName=%s\n", b.name)
|
return fmt.Sprintf("[NetDev]\nKind=bond\nName=%s\n", b.name)
|
||||||
}
|
}
|
||||||
@ -129,10 +134,6 @@ type vlanInterface struct {
|
|||||||
rawDevice string
|
rawDevice string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *vlanInterface) Name() string {
|
|
||||||
return v.name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *vlanInterface) Netdev() string {
|
func (v *vlanInterface) Netdev() string {
|
||||||
config := fmt.Sprintf("[NetDev]\nKind=vlan\nName=%s\n", v.name)
|
config := fmt.Sprintf("[NetDev]\nKind=vlan\nName=%s\n", v.name)
|
||||||
switch c := v.config.(type) {
|
switch c := v.config.(type) {
|
||||||
|
@ -6,241 +6,101 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPhysicalInterfaceName(t *testing.T) {
|
func TestInterfaceGenerators(t *testing.T) {
|
||||||
p := physicalInterface{logicalInterface{name: "testname"}}
|
|
||||||
if p.Name() != "testname" {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPhysicalInterfaceNetdev(t *testing.T) {
|
|
||||||
p := physicalInterface{}
|
|
||||||
if p.Netdev() != "" {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPhysicalInterfaceLink(t *testing.T) {
|
|
||||||
p := physicalInterface{}
|
|
||||||
if p.Link() != "" {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPhysicalInterfaceNetwork(t *testing.T) {
|
|
||||||
p := physicalInterface{logicalInterface{
|
|
||||||
name: "testname",
|
|
||||||
children: []networkInterface{
|
|
||||||
&bondInterface{
|
|
||||||
logicalInterface{
|
|
||||||
name: "testbond1",
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
&vlanInterface{
|
|
||||||
logicalInterface{
|
|
||||||
name: "testvlan1",
|
|
||||||
},
|
|
||||||
1,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
&vlanInterface{
|
|
||||||
logicalInterface{
|
|
||||||
name: "testvlan2",
|
|
||||||
},
|
|
||||||
1,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
network := `[Match]
|
|
||||||
Name=testname
|
|
||||||
|
|
||||||
[Network]
|
|
||||||
Bond=testbond1
|
|
||||||
VLAN=testvlan1
|
|
||||||
VLAN=testvlan2
|
|
||||||
`
|
|
||||||
if p.Network() != network {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBondInterfaceName(t *testing.T) {
|
|
||||||
b := bondInterface{logicalInterface{name: "testname"}, nil, nil}
|
|
||||||
if b.Name() != "testname" {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBondInterfaceNetdev(t *testing.T) {
|
|
||||||
b := bondInterface{logicalInterface{name: "testname"}, nil, nil}
|
|
||||||
netdev := `[NetDev]
|
|
||||||
Kind=bond
|
|
||||||
Name=testname
|
|
||||||
`
|
|
||||||
if b.Netdev() != netdev {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBondInterfaceLink(t *testing.T) {
|
|
||||||
b := bondInterface{}
|
|
||||||
if b.Link() != "" {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBondInterfaceNetwork(t *testing.T) {
|
|
||||||
b := bondInterface{
|
|
||||||
logicalInterface{
|
|
||||||
name: "testname",
|
|
||||||
config: configMethodDHCP{},
|
|
||||||
children: []networkInterface{
|
|
||||||
&bondInterface{
|
|
||||||
logicalInterface{
|
|
||||||
name: "testbond1",
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
&vlanInterface{
|
|
||||||
logicalInterface{
|
|
||||||
name: "testvlan1",
|
|
||||||
},
|
|
||||||
1,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
&vlanInterface{
|
|
||||||
logicalInterface{
|
|
||||||
name: "testvlan2",
|
|
||||||
},
|
|
||||||
1,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
nil,
|
|
||||||
}
|
|
||||||
network := `[Match]
|
|
||||||
Name=testname
|
|
||||||
|
|
||||||
[Network]
|
|
||||||
Bond=testbond1
|
|
||||||
VLAN=testvlan1
|
|
||||||
VLAN=testvlan2
|
|
||||||
DHCP=true
|
|
||||||
`
|
|
||||||
if b.Network() != network {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVLANInterfaceName(t *testing.T) {
|
|
||||||
v := vlanInterface{logicalInterface{name: "testname"}, 1, ""}
|
|
||||||
if v.Name() != "testname" {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVLANInterfaceNetdev(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
i vlanInterface
|
name string
|
||||||
l string
|
netdev string
|
||||||
|
link string
|
||||||
|
network string
|
||||||
|
kind string
|
||||||
|
iface InterfaceGenerator
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
vlanInterface{logicalInterface{name: "testname"}, 1, ""},
|
name: "",
|
||||||
"[NetDev]\nKind=vlan\nName=testname\n\n[VLAN]\nId=1\n",
|
network: "[Match]\nMACAddress=00:01:02:03:04:05\n\n[Network]\n",
|
||||||
|
kind: "physical",
|
||||||
|
iface: &physicalInterface{logicalInterface{
|
||||||
|
hwaddr: net.HardwareAddr([]byte{0, 1, 2, 3, 4, 5}),
|
||||||
|
}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
vlanInterface{logicalInterface{name: "testname", config: configMethodStatic{hwaddress: net.HardwareAddr([]byte{0, 1, 2, 3, 4, 5})}}, 1, ""},
|
name: "testname",
|
||||||
"[NetDev]\nKind=vlan\nName=testname\nMACAddress=00:01:02:03:04:05\n\n[VLAN]\nId=1\n",
|
network: "[Match]\nName=testname\n\n[Network]\nBond=testbond1\nVLAN=testvlan1\nVLAN=testvlan2\n",
|
||||||
|
kind: "physical",
|
||||||
|
iface: &physicalInterface{logicalInterface{
|
||||||
|
name: "testname",
|
||||||
|
children: []networkInterface{
|
||||||
|
&bondInterface{logicalInterface: logicalInterface{name: "testbond1"}},
|
||||||
|
&vlanInterface{logicalInterface: logicalInterface{name: "testvlan1"}, id: 1},
|
||||||
|
&vlanInterface{logicalInterface: logicalInterface{name: "testvlan2"}, id: 1},
|
||||||
|
},
|
||||||
|
}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
vlanInterface{logicalInterface{name: "testname", config: configMethodDHCP{hwaddress: net.HardwareAddr([]byte{0, 1, 2, 3, 4, 5})}}, 1, ""},
|
name: "testname",
|
||||||
"[NetDev]\nKind=vlan\nName=testname\nMACAddress=00:01:02:03:04:05\n\n[VLAN]\nId=1\n",
|
netdev: "[NetDev]\nKind=bond\nName=testname\n",
|
||||||
|
network: "[Match]\nName=testname\n\n[Network]\nBond=testbond1\nVLAN=testvlan1\nVLAN=testvlan2\nDHCP=true\n",
|
||||||
|
kind: "bond",
|
||||||
|
iface: &bondInterface{logicalInterface: logicalInterface{
|
||||||
|
name: "testname",
|
||||||
|
config: configMethodDHCP{},
|
||||||
|
children: []networkInterface{
|
||||||
|
&bondInterface{logicalInterface: logicalInterface{name: "testbond1"}},
|
||||||
|
&vlanInterface{logicalInterface: logicalInterface{name: "testvlan1"}, id: 1},
|
||||||
|
&vlanInterface{logicalInterface: logicalInterface{name: "testvlan2"}, id: 1},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "testname",
|
||||||
|
netdev: "[NetDev]\nKind=vlan\nName=testname\n\n[VLAN]\nId=1\n",
|
||||||
|
network: "[Match]\nName=testname\n\n[Network]\n",
|
||||||
|
kind: "vlan",
|
||||||
|
iface: &vlanInterface{logicalInterface{name: "testname"}, 1, ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "testname",
|
||||||
|
netdev: "[NetDev]\nKind=vlan\nName=testname\nMACAddress=00:01:02:03:04:05\n\n[VLAN]\nId=1\n",
|
||||||
|
network: "[Match]\nName=testname\n\n[Network]\n",
|
||||||
|
kind: "vlan",
|
||||||
|
iface: &vlanInterface{logicalInterface{name: "testname", config: configMethodStatic{hwaddress: net.HardwareAddr([]byte{0, 1, 2, 3, 4, 5})}}, 1, ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "testname",
|
||||||
|
netdev: "[NetDev]\nKind=vlan\nName=testname\nMACAddress=00:01:02:03:04:05\n\n[VLAN]\nId=1\n",
|
||||||
|
network: "[Match]\nName=testname\n\n[Network]\nDHCP=true\n",
|
||||||
|
kind: "vlan",
|
||||||
|
iface: &vlanInterface{logicalInterface{name: "testname", config: configMethodDHCP{hwaddress: net.HardwareAddr([]byte{0, 1, 2, 3, 4, 5})}}, 1, ""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "testname",
|
||||||
|
netdev: "[NetDev]\nKind=vlan\nName=testname\n\n[VLAN]\nId=0\n",
|
||||||
|
network: "[Match]\nName=testname\n\n[Network]\nDNS=8.8.8.8\n\n[Address]\nAddress=192.168.1.100/24\n\n[Route]\nDestination=0.0.0.0/0\nGateway=1.2.3.4\n",
|
||||||
|
kind: "vlan",
|
||||||
|
iface: &vlanInterface{logicalInterface: logicalInterface{
|
||||||
|
name: "testname",
|
||||||
|
config: configMethodStatic{
|
||||||
|
addresses: []net.IPNet{{IP: []byte{192, 168, 1, 100}, Mask: []byte{255, 255, 255, 0}}},
|
||||||
|
nameservers: []net.IP{[]byte{8, 8, 8, 8}},
|
||||||
|
routes: []route{route{destination: net.IPNet{IP: []byte{0, 0, 0, 0}, Mask: []byte{0, 0, 0, 0}}, gateway: []byte{1, 2, 3, 4}}},
|
||||||
|
},
|
||||||
|
}},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
if tt.i.Netdev() != tt.l {
|
if name := tt.iface.Name(); name != tt.name {
|
||||||
t.Fatalf("bad netdev config (%q): got %q, want %q", tt.i, tt.i.Netdev(), tt.l)
|
t.Fatalf("bad name (%q): want %q, got %q", tt.iface, tt.name, name)
|
||||||
}
|
}
|
||||||
}
|
if netdev := tt.iface.Netdev(); netdev != tt.netdev {
|
||||||
}
|
t.Fatalf("bad netdev (%q): want %q, got %q", tt.iface, tt.netdev, netdev)
|
||||||
|
}
|
||||||
func TestVLANInterfaceLink(t *testing.T) {
|
if link := tt.iface.Link(); link != tt.link {
|
||||||
v := vlanInterface{}
|
t.Fatalf("bad link (%q): want %q, got %q", tt.iface, tt.link, link)
|
||||||
if v.Link() != "" {
|
}
|
||||||
t.FailNow()
|
if network := tt.iface.Network(); network != tt.network {
|
||||||
}
|
t.Fatalf("bad network (%q): want %q, got %q", tt.iface, tt.network, network)
|
||||||
}
|
}
|
||||||
|
if kind := tt.iface.Type(); kind != tt.kind {
|
||||||
func TestVLANInterfaceNetwork(t *testing.T) {
|
t.Fatalf("bad type (%q): want %q, got %q", tt.iface, tt.kind, kind)
|
||||||
v := vlanInterface{
|
|
||||||
logicalInterface{
|
|
||||||
name: "testname",
|
|
||||||
config: configMethodStatic{
|
|
||||||
address: net.IPNet{
|
|
||||||
IP: []byte{192, 168, 1, 100},
|
|
||||||
Mask: []byte{255, 255, 255, 0},
|
|
||||||
},
|
|
||||||
nameservers: []net.IP{
|
|
||||||
[]byte{8, 8, 8, 8},
|
|
||||||
},
|
|
||||||
routes: []route{
|
|
||||||
route{
|
|
||||||
destination: net.IPNet{
|
|
||||||
IP: []byte{0, 0, 0, 0},
|
|
||||||
Mask: []byte{0, 0, 0, 0},
|
|
||||||
},
|
|
||||||
gateway: []byte{1, 2, 3, 4},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
0,
|
|
||||||
"",
|
|
||||||
}
|
|
||||||
network := `[Match]
|
|
||||||
Name=testname
|
|
||||||
|
|
||||||
[Network]
|
|
||||||
DNS=8.8.8.8
|
|
||||||
|
|
||||||
[Address]
|
|
||||||
Address=192.168.1.100/24
|
|
||||||
|
|
||||||
[Route]
|
|
||||||
Destination=0.0.0.0/0
|
|
||||||
Gateway=1.2.3.4
|
|
||||||
`
|
|
||||||
if v.Network() != network {
|
|
||||||
t.Log(v.Network())
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestType(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
i InterfaceGenerator
|
|
||||||
t string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
i: &physicalInterface{},
|
|
||||||
t: "physical",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
i: &vlanInterface{},
|
|
||||||
t: "vlan",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
i: &bondInterface{},
|
|
||||||
t: "bond",
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
if tp := tt.i.Type(); tp != tt.t {
|
|
||||||
t.Fatalf("bad type (%q): got %s, want %s", tt.i, tp, tt.t)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ type route struct {
|
|||||||
type configMethod interface{}
|
type configMethod interface{}
|
||||||
|
|
||||||
type configMethodStatic struct {
|
type configMethodStatic struct {
|
||||||
address net.IPNet
|
addresses []net.IPNet
|
||||||
nameservers []net.IP
|
nameservers []net.IP
|
||||||
routes []route
|
routes []route
|
||||||
hwaddress net.HardwareAddr
|
hwaddress net.HardwareAddr
|
||||||
@ -193,20 +193,21 @@ func parseInterfaceStanza(attributes []string, options []string) (*stanzaInterfa
|
|||||||
switch confMethod {
|
switch confMethod {
|
||||||
case "static":
|
case "static":
|
||||||
config := configMethodStatic{
|
config := configMethodStatic{
|
||||||
|
addresses: make([]net.IPNet, 1),
|
||||||
routes: make([]route, 0),
|
routes: make([]route, 0),
|
||||||
nameservers: make([]net.IP, 0),
|
nameservers: make([]net.IP, 0),
|
||||||
}
|
}
|
||||||
if addresses, ok := optionMap["address"]; ok {
|
if addresses, ok := optionMap["address"]; ok {
|
||||||
if len(addresses) == 1 {
|
if len(addresses) == 1 {
|
||||||
config.address.IP = net.ParseIP(addresses[0])
|
config.addresses[0].IP = net.ParseIP(addresses[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if netmasks, ok := optionMap["netmask"]; ok {
|
if netmasks, ok := optionMap["netmask"]; ok {
|
||||||
if len(netmasks) == 1 {
|
if len(netmasks) == 1 {
|
||||||
config.address.Mask = net.IPMask(net.ParseIP(netmasks[0]).To4())
|
config.addresses[0].Mask = net.IPMask(net.ParseIP(netmasks[0]).To4())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if config.address.IP == nil || config.address.Mask == nil {
|
if config.addresses[0].IP == nil || config.addresses[0].Mask == nil {
|
||||||
return nil, fmt.Errorf("malformed static network config for %q", iface)
|
return nil, fmt.Errorf("malformed static network config for %q", iface)
|
||||||
}
|
}
|
||||||
if gateways, ok := optionMap["gateway"]; ok {
|
if gateways, ok := optionMap["gateway"]; ok {
|
||||||
|
@ -194,9 +194,11 @@ func TestParseVLANStanzas(t *testing.T) {
|
|||||||
|
|
||||||
func TestParseInterfaceStanzaStaticAddress(t *testing.T) {
|
func TestParseInterfaceStanzaStaticAddress(t *testing.T) {
|
||||||
options := []string{"address 192.168.1.100", "netmask 255.255.255.0"}
|
options := []string{"address 192.168.1.100", "netmask 255.255.255.0"}
|
||||||
expect := net.IPNet{
|
expect := []net.IPNet{
|
||||||
IP: net.IPv4(192, 168, 1, 100),
|
{
|
||||||
Mask: net.IPv4Mask(255, 255, 255, 0),
|
IP: net.IPv4(192, 168, 1, 100),
|
||||||
|
Mask: net.IPv4Mask(255, 255, 255, 0),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
iface, err := parseInterfaceStanza([]string{"eth", "inet", "static"}, options)
|
iface, err := parseInterfaceStanza([]string{"eth", "inet", "static"}, options)
|
||||||
@ -207,7 +209,7 @@ func TestParseInterfaceStanzaStaticAddress(t *testing.T) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(static.address, expect) {
|
if !reflect.DeepEqual(static.addresses, expect) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,15 +74,14 @@ func maybeProbe8012q(interfaces []network.InterfaceGenerator) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func maybeProbeBonding(interfaces []network.InterfaceGenerator) error {
|
func maybeProbeBonding(interfaces []network.InterfaceGenerator) error {
|
||||||
args := []string{"bonding"}
|
|
||||||
for _, iface := range interfaces {
|
for _, iface := range interfaces {
|
||||||
if iface.Type() == "bond" {
|
if iface.Type() == "bond" {
|
||||||
args = append(args, strings.Split(iface.ModprobeParams(), " ")...)
|
args := append([]string{"bonding"}, strings.Split(iface.ModprobeParams(), " ")...)
|
||||||
break
|
log.Printf("Probing LKM %q (%q)\n", "bonding", args)
|
||||||
|
return exec.Command("modprobe", args...).Run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Printf("Probing LKM %q (%q)\n", "bonding", args)
|
return nil
|
||||||
return exec.Command("modprobe", args...).Run()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func restartNetworkd() error {
|
func restartNetworkd() error {
|
||||||
|
1
test
1
test
@ -18,6 +18,7 @@ declare -a TESTPKGS=(initialize
|
|||||||
datasource
|
datasource
|
||||||
datasource/configdrive
|
datasource/configdrive
|
||||||
datasource/file
|
datasource/file
|
||||||
|
datasource/metadata
|
||||||
datasource/metadata/cloudsigma
|
datasource/metadata/cloudsigma
|
||||||
datasource/metadata/ec2
|
datasource/metadata/ec2
|
||||||
datasource/proc_cmdline
|
datasource/proc_cmdline
|
||||||
|
Loading…
Reference in New Issue
Block a user