Merge pull request #318 from crawford/filesystem

configdrive: correct network config reading and improve tests
This commit is contained in:
Alex Crawford 2015-02-17 13:40:05 -08:00
commit 78b0f82918
7 changed files with 200 additions and 54 deletions

View File

@ -69,7 +69,9 @@ func (cd *configDrive) FetchMetadata() (metadata datasource.Metadata, err error)
metadata.SSHPublicKeys = m.SSHAuthorizedKeyMap
metadata.Hostname = m.Hostname
if m.NetworkConfig.ContentPath != "" {
metadata.NetworkConfig, err = cd.tryReadFile(path.Join(cd.openstackRoot(), m.NetworkConfig.ContentPath))
}
return
}

View File

@ -31,23 +31,22 @@ func TestFetchMetadata(t *testing.T) {
}{
{
root: "/",
files: test.MockFilesystem{"/openstack/latest/meta_data.json": ""},
files: test.NewMockFilesystem(test.File{Path: "/openstack/latest/meta_data.json", Contents: ""}),
},
{
root: "/",
files: test.MockFilesystem{"/openstack/latest/meta_data.json": `{"ignore": "me"}`},
files: test.NewMockFilesystem(test.File{Path: "/openstack/latest/meta_data.json", Contents: `{"ignore": "me"}`}),
},
{
root: "/",
files: test.MockFilesystem{"/openstack/latest/meta_data.json": `{"hostname": "host"}`},
files: test.NewMockFilesystem(test.File{Path: "/openstack/latest/meta_data.json", Contents: `{"hostname": "host"}`}),
metadata: datasource.Metadata{Hostname: "host"},
},
{
root: "/media/configdrive",
files: test.MockFilesystem{
"/media/configdrive/openstack/latest/meta_data.json": `{"hostname": "host", "network_config": {"content_path": "config_file.json"}, "public_keys":{"1": "key1", "2": "key2"}}`,
"/media/configdrive/openstack/config_file.json": "make it work",
},
files: test.NewMockFilesystem(test.File{Path: "/media/configdrive/openstack/latest/meta_data.json", Contents: `{"hostname": "host", "network_config": {"content_path": "config_file.json"}, "public_keys":{"1": "key1", "2": "key2"}}`},
test.File{Path: "/media/configdrive/openstack/config_file.json", Contents: "make it work"},
),
metadata: datasource.Metadata{
Hostname: "host",
NetworkConfig: []byte("make it work"),
@ -61,10 +60,10 @@ func TestFetchMetadata(t *testing.T) {
cd := configDrive{tt.root, tt.files.ReadFile}
metadata, err := cd.FetchMetadata()
if err != nil {
t.Fatalf("bad error for %q: want %v, got %q", tt, nil, err)
t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err)
}
if !reflect.DeepEqual(tt.metadata, metadata) {
t.Fatalf("bad metadata for %q: want %#v, got %#v", tt, tt.metadata, metadata)
t.Fatalf("bad metadata for %+v: want %#v, got %#v", tt, tt.metadata, metadata)
}
}
}
@ -78,27 +77,27 @@ func TestFetchUserdata(t *testing.T) {
}{
{
"/",
test.MockFilesystem{},
test.NewMockFilesystem(),
"",
},
{
"/",
test.MockFilesystem{"/openstack/latest/user_data": "userdata"},
test.NewMockFilesystem(test.File{Path: "/openstack/latest/user_data", Contents: "userdata"}),
"userdata",
},
{
"/media/configdrive",
test.MockFilesystem{"/media/configdrive/openstack/latest/user_data": "userdata"},
test.NewMockFilesystem(test.File{Path: "/media/configdrive/openstack/latest/user_data", Contents: "userdata"}),
"userdata",
},
} {
cd := configDrive{tt.root, tt.files.ReadFile}
userdata, err := cd.FetchUserdata()
if err != nil {
t.Fatalf("bad error for %q: want %v, got %q", tt, nil, err)
t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err)
}
if string(userdata) != tt.userdata {
t.Fatalf("bad userdata for %q: want %q, got %q", tt, tt.userdata, userdata)
t.Fatalf("bad userdata for %+v: want %q, got %q", tt, tt.userdata, userdata)
}
}
}

View File

@ -0,0 +1,57 @@
// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package test
import (
"fmt"
"os"
"path"
)
type MockFilesystem map[string]File
type File struct {
Path string
Contents string
Directory bool
}
func (m MockFilesystem) ReadFile(filename string) ([]byte, error) {
if f, ok := m[path.Clean(filename)]; ok {
if f.Directory {
return nil, fmt.Errorf("read %s: is a directory", filename)
}
return []byte(f.Contents), nil
}
return nil, os.ErrNotExist
}
func NewMockFilesystem(files ...File) MockFilesystem {
fs := MockFilesystem{}
for _, file := range files {
fs[file.Path] = file
// Create the directories leading up to the file
p := path.Dir(file.Path)
for p != "/" && p != "." {
if f, ok := fs[p]; ok && !f.Directory {
panic(fmt.Sprintf("%q already exists and is not a directory (%#v)", p, f))
}
fs[p] = File{Path: p, Directory: true}
p = path.Dir(p)
}
}
return fs
}

View File

@ -0,0 +1,115 @@
// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package test
import (
"errors"
"os"
"reflect"
"testing"
)
func TestReadFile(t *testing.T) {
tests := []struct {
filesystem MockFilesystem
filename string
contents string
err error
}{
{
filename: "dne",
err: os.ErrNotExist,
},
{
filesystem: MockFilesystem{
"exists": File{Contents: "hi"},
},
filename: "exists",
contents: "hi",
},
{
filesystem: MockFilesystem{
"dir": File{Directory: true},
},
filename: "dir",
err: errors.New("read dir: is a directory"),
},
}
for i, tt := range tests {
contents, err := tt.filesystem.ReadFile(tt.filename)
if tt.contents != string(contents) {
t.Errorf("bad contents (test %d): want %q, got %q", i, tt.contents, string(contents))
}
if !reflect.DeepEqual(tt.err, err) {
t.Errorf("bad error (test %d): want %v, got %v", i, tt.err, err)
}
}
}
func TestNewMockFilesystem(t *testing.T) {
tests := []struct {
files []File
filesystem MockFilesystem
}{
{
filesystem: MockFilesystem{},
},
{
files: []File{File{Path: "file"}},
filesystem: MockFilesystem{
"file": File{Path: "file"},
},
},
{
files: []File{File{Path: "/file"}},
filesystem: MockFilesystem{
"/file": File{Path: "/file"},
},
},
{
files: []File{File{Path: "/dir/file"}},
filesystem: MockFilesystem{
"/dir": File{Path: "/dir", Directory: true},
"/dir/file": File{Path: "/dir/file"},
},
},
{
files: []File{File{Path: "/dir/dir/file"}},
filesystem: MockFilesystem{
"/dir": File{Path: "/dir", Directory: true},
"/dir/dir": File{Path: "/dir/dir", Directory: true},
"/dir/dir/file": File{Path: "/dir/dir/file"},
},
},
{
files: []File{File{Path: "/dir/dir/dir", Directory: true}},
filesystem: MockFilesystem{
"/dir": File{Path: "/dir", Directory: true},
"/dir/dir": File{Path: "/dir/dir", Directory: true},
"/dir/dir/dir": File{Path: "/dir/dir/dir", Directory: true},
},
},
}
for i, tt := range tests {
filesystem := NewMockFilesystem(tt.files...)
if !reflect.DeepEqual(tt.filesystem, filesystem) {
t.Errorf("bad filesystem (test %d): want %#v, got %#v", i, tt.filesystem, filesystem)
}
}
}

View File

@ -1,28 +0,0 @@
// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package test
import (
"os"
)
type MockFilesystem map[string]string
func (m MockFilesystem) ReadFile(filename string) ([]byte, error) {
if contents, ok := m[filename]; ok {
return []byte(contents), nil
}
return nil, os.ErrNotExist
}

View File

@ -31,19 +31,19 @@ func TestFetchMetadata(t *testing.T) {
}{
{
root: "/",
files: test.MockFilesystem{},
files: test.NewMockFilesystem(),
},
{
root: "/",
files: test.MockFilesystem{"/SharedConfig.xml": ""},
files: test.NewMockFilesystem(test.File{Path: "/SharedConfig.xml", Contents: ""}),
},
{
root: "/var/lib/waagent",
files: test.MockFilesystem{"/var/lib/waagent/SharedConfig.xml": ""},
files: test.NewMockFilesystem(test.File{Path: "/var/lib/waagent/SharedConfig.xml", Contents: ""}),
},
{
root: "/var/lib/waagent",
files: test.MockFilesystem{"/var/lib/waagent/SharedConfig.xml": `<?xml version="1.0" encoding="utf-8"?>
files: test.NewMockFilesystem(test.File{Path: "/var/lib/waagent/SharedConfig.xml", Contents: `<?xml version="1.0" encoding="utf-8"?>
<SharedConfig version="1.0.0.0" goalStateIncarnation="1">
<Deployment name="c8f9e4c9c18948e1bebf57c5685da756" guid="{1d10394f-c741-4a1a-a6bb-278f213c5a5e}" incarnation="0" isNonCancellableTopologyChangeEnabled="false">
<Service name="core-test-1" guid="{00000000-0000-0000-0000-000000000000}" />
@ -79,7 +79,7 @@ func TestFetchMetadata(t *testing.T) {
</InputEndpoints>
</Instance>
</Instances>
</SharedConfig>`},
</SharedConfig>`}),
metadata: datasource.Metadata{
PrivateIPv4: net.ParseIP("100.73.202.64"),
PublicIPv4: net.ParseIP("191.239.39.77"),
@ -89,10 +89,10 @@ func TestFetchMetadata(t *testing.T) {
a := waagent{tt.root, tt.files.ReadFile}
metadata, err := a.FetchMetadata()
if err != nil {
t.Fatalf("bad error for %q: want %v, got %q", tt, nil, err)
t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err)
}
if !reflect.DeepEqual(tt.metadata, metadata) {
t.Fatalf("bad metadata for %q: want %#v, got %#v", tt, tt.metadata, metadata)
t.Fatalf("bad metadata for %+v: want %#v, got %#v", tt, tt.metadata, metadata)
}
}
}
@ -104,21 +104,21 @@ func TestFetchUserdata(t *testing.T) {
}{
{
"/",
test.MockFilesystem{},
test.NewMockFilesystem(),
},
{
"/",
test.MockFilesystem{"/CustomData": ""},
test.NewMockFilesystem(test.File{Path: "/CustomData", Contents: ""}),
},
{
"/var/lib/waagent/",
test.MockFilesystem{"/var/lib/waagent/CustomData": ""},
test.NewMockFilesystem(test.File{Path: "/var/lib/waagent/CustomData", Contents: ""}),
},
} {
a := waagent{tt.root, tt.files.ReadFile}
_, err := a.FetchUserdata()
if err != nil {
t.Fatalf("bad error for %q: want %v, got %q", tt, nil, err)
t.Fatalf("bad error for %+v: want %v, got %q", tt, nil, err)
}
}
}

1
test
View File

@ -24,6 +24,7 @@ declare -a TESTPKGS=(
datasource/metadata/digitalocean
datasource/metadata/ec2
datasource/proc_cmdline
datasource/test
datasource/url
datasource/waagent
initialize