Merge pull request #158 from jonboulle/nettttt

cloudinit: retrieve IPv4 addresses from metadata
This commit is contained in:
Jonathan Boulle 2014-06-24 19:11:15 -07:00
commit 80d00cde94
5 changed files with 114 additions and 18 deletions

View File

@ -88,7 +88,16 @@ func main() {
die() die()
} }
env := initialize.NewEnvironment("/", ds.ConfigRoot(), workspace, convertNetconf, sshKeyName) var subs map[string]string
if len(metadataBytes) > 0 {
subs, err = initialize.ExtractIPsFromMetadata(metadataBytes)
if err != nil {
fmt.Printf("Failed extracting IPs from meta-data: %v\n", err)
die()
}
}
env := initialize.NewEnvironment("/", ds.ConfigRoot(), workspace, convertNetconf, sshKeyName, subs)
if len(userdataBytes) > 0 { if len(userdataBytes) > 0 {
if err := processUserdata(string(userdataBytes), env); err != nil { if err := processUserdata(string(userdataBytes), env); err != nil {
fmt.Printf("Failed to process user-data: %v\n", err) fmt.Printf("Failed to process user-data: %v\n", err)

View File

@ -17,10 +17,16 @@ type Environment struct {
substitutions map[string]string substitutions map[string]string
} }
func NewEnvironment(root, configRoot, workspace, netconfType, sshKeyName string) *Environment { // TODO(jonboulle): this is getting unwieldy, should be able to simplify the interface somehow
substitutions := map[string]string{ func NewEnvironment(root, configRoot, workspace, netconfType, sshKeyName string, substitutions map[string]string) *Environment {
// If certain values are not in the supplied substitution, fall back to retrieving them from the environment
for k, v := range map[string]string{
"$public_ipv4": os.Getenv("COREOS_PUBLIC_IPV4"), "$public_ipv4": os.Getenv("COREOS_PUBLIC_IPV4"),
"$private_ipv4": os.Getenv("COREOS_PRIVATE_IPV4"), "$private_ipv4": os.Getenv("COREOS_PRIVATE_IPV4"),
} {
if _, ok := substitutions[k]; !ok {
substitutions[k] = v
}
} }
return &Environment{root, configRoot, workspace, netconfType, sshKeyName, substitutions} return &Environment{root, configRoot, workspace, netconfType, sshKeyName, substitutions}
} }

View File

@ -6,22 +6,47 @@ import (
) )
func TestEnvironmentApply(t *testing.T) { func TestEnvironmentApply(t *testing.T) {
os.Setenv("COREOS_PUBLIC_IPV4", "192.0.2.3") os.Setenv("COREOS_PUBLIC_IPV4", "1.2.3.4")
os.Setenv("COREOS_PRIVATE_IPV4", "192.0.2.203") os.Setenv("COREOS_PRIVATE_IPV4", "5.6.7.8")
env := NewEnvironment("./", "./", "./", "", "") for _, tt := range []struct {
input := `[Service] subs map[string]string
input string
out string
}{
{
// Substituting both values directly should always take precedence
// over environment variables
map[string]string{
"$public_ipv4": "192.0.2.3",
"$private_ipv4": "192.0.2.203",
},
`[Service]
ExecStart=/usr/bin/echo "$public_ipv4" ExecStart=/usr/bin/echo "$public_ipv4"
ExecStop=/usr/bin/echo $private_ipv4 ExecStop=/usr/bin/echo $private_ipv4
ExecStop=/usr/bin/echo $unknown ExecStop=/usr/bin/echo $unknown`,
` `[Service]
expected := `[Service]
ExecStart=/usr/bin/echo "192.0.2.3" ExecStart=/usr/bin/echo "192.0.2.3"
ExecStop=/usr/bin/echo 192.0.2.203 ExecStop=/usr/bin/echo 192.0.2.203
ExecStop=/usr/bin/echo $unknown ExecStop=/usr/bin/echo $unknown`,
` },
{
// Substituting one value directly while falling back with the other
map[string]string{"$private_ipv4": "127.0.0.1"},
"$private_ipv4\n$public_ipv4",
"127.0.0.1\n1.2.3.4",
},
{
// Falling back to environment variables for both values
map[string]string{"foo": "bar"},
"$private_ipv4\n$public_ipv4",
"5.6.7.8\n1.2.3.4",
},
} {
output := env.Apply(input) env := NewEnvironment("./", "./", "./", "", "", tt.subs)
if output != expected { got := env.Apply(tt.input)
t.Fatalf("Environment incorrectly applied.\nOutput:\n%s\nExpected:\n%s", output, expected) if got != tt.out {
t.Fatalf("Environment incorrectly applied.\ngot:\n%s\nwant:\n%s", got, tt.out)
}
} }
} }

View File

@ -1,9 +1,9 @@
package initialize package initialize
import ( import "encoding/json"
"encoding/json"
)
// ParseMetaData parses a JSON blob in the OpenStack metadata service format, and
// converts it to a CloudConfig
func ParseMetaData(contents string) (cfg CloudConfig, err error) { func ParseMetaData(contents string) (cfg CloudConfig, err error) {
var metadata struct { var metadata struct {
SSHAuthorizedKeyMap map[string]string `json:"public_keys"` SSHAuthorizedKeyMap map[string]string `json:"public_keys"`
@ -24,3 +24,23 @@ func ParseMetaData(contents string) (cfg CloudConfig, err error) {
cfg.NetworkConfigPath = metadata.NetworkConfig.ContentPath cfg.NetworkConfigPath = metadata.NetworkConfig.ContentPath
return return
} }
// ExtractIPsFromMetaData parses a JSON blob in the OpenStack metadata service format,
// and returns a substitution map possibly containing private_ipv4 and public_ipv4 addresses
func ExtractIPsFromMetadata(contents []byte) (map[string]string, error) {
var ips struct {
Public string `json:"public-ipv4"`
Private string `json:"local-ipv4"`
}
if err := json.Unmarshal(contents, &ips); err != nil {
return nil, err
}
m := make(map[string]string)
if ips.Private != "" {
m["$private_ipv4"] = ips.Private
}
if ips.Public != "" {
m["$public_ipv4"] = ips.Public
}
return m, nil
}

View File

@ -0,0 +1,36 @@
package initialize
import "reflect"
import "testing"
func TestExtractIPsFromMetadata(t *testing.T) {
for i, tt := range []struct {
in []byte
err bool
out map[string]string
}{
{
[]byte(`{"public-ipv4": "12.34.56.78", "local-ipv4": "1.2.3.4"}`),
false,
map[string]string{"$public_ipv4": "12.34.56.78", "$private_ipv4": "1.2.3.4"},
},
{
[]byte(`{"local-ipv4": "127.0.0.1", "something_else": "don't care"}`),
false,
map[string]string{"$private_ipv4": "127.0.0.1"},
},
{
[]byte(`garbage`),
true,
nil,
},
} {
got, err := ExtractIPsFromMetadata(tt.in)
if (err != nil) != tt.err {
t.Errorf("bad error state (got %t, want %t)", err != nil, tt.err)
}
if !reflect.DeepEqual(got, tt.out) {
t.Errorf("case %d: got %s, want %s", i, got, tt.out)
}
}
}