initialize: change env to process from metadata

We don't use general substitutions so just have env pick the values it
wants to substitute.
This commit is contained in:
Alex Crawford 2015-01-26 15:45:15 -08:00
parent 650a239fdb
commit 42153edbbc
5 changed files with 43 additions and 139 deletions

View File

@ -182,11 +182,8 @@ func main() {
os.Exit(1) os.Exit(1)
} }
// Extract IPv4 addresses from metadata
subs := initialize.ExtractIPsFromMetadata(metadata)
// Apply environment to user-data // Apply environment to user-data
env := initialize.NewEnvironment("/", ds.ConfigRoot(), flags.workspace, flags.convertNetconf, flags.sshKeyName, subs) env := initialize.NewEnvironment("/", ds.ConfigRoot(), flags.workspace, flags.convertNetconf, flags.sshKeyName, metadata)
userdata := env.Apply(string(userdataBytes)) userdata := env.Apply(string(userdataBytes))
var ccu *config.CloudConfig var ccu *config.CloudConfig

View File

@ -15,12 +15,14 @@
package initialize package initialize
import ( import (
"net"
"os" "os"
"path" "path"
"regexp" "regexp"
"strings" "strings"
"github.com/coreos/coreos-cloudinit/config" "github.com/coreos/coreos-cloudinit/config"
"github.com/coreos/coreos-cloudinit/datasource"
"github.com/coreos/coreos-cloudinit/system" "github.com/coreos/coreos-cloudinit/system"
) )
@ -36,20 +38,18 @@ type Environment struct {
} }
// TODO(jonboulle): this is getting unwieldy, should be able to simplify the interface somehow // TODO(jonboulle): this is getting unwieldy, should be able to simplify the interface somehow
func NewEnvironment(root, configRoot, workspace, netconfType, sshKeyName string, substitutions map[string]string) *Environment { func NewEnvironment(root, configRoot, workspace, netconfType, sshKeyName string, metadata datasource.Metadata) *Environment {
if substitutions == nil { firstNonNull := func(ip net.IP, env string) string {
substitutions = make(map[string]string) if ip == nil {
return env
} }
// If certain values are not in the supplied substitution, fall back to retrieving them from the environment return ip.String()
for k, v := range map[string]string{
"$public_ipv4": os.Getenv("COREOS_PUBLIC_IPV4"),
"$private_ipv4": os.Getenv("COREOS_PRIVATE_IPV4"),
"$public_ipv6": os.Getenv("COREOS_PUBLIC_IPV6"),
"$private_ipv6": os.Getenv("COREOS_PRIVATE_IPV6"),
} {
if _, ok := substitutions[k]; !ok {
substitutions[k] = v
} }
substitutions := map[string]string{
"$public_ipv4": firstNonNull(metadata.PublicIPv4, os.Getenv("COREOS_PUBLIC_IPV4")),
"$private_ipv4": firstNonNull(metadata.PrivateIPv4, os.Getenv("COREOS_PRIVATE_IPV4")),
"$public_ipv6": firstNonNull(metadata.PublicIPv6, os.Getenv("COREOS_PUBLIC_IPV6")),
"$private_ipv6": firstNonNull(metadata.PrivateIPv6, os.Getenv("COREOS_PRIVATE_IPV6")),
} }
return &Environment{root, configRoot, workspace, netconfType, sshKeyName, substitutions} return &Environment{root, configRoot, workspace, netconfType, sshKeyName, substitutions}
} }

View File

@ -16,10 +16,12 @@ package initialize
import ( import (
"io/ioutil" "io/ioutil"
"net"
"os" "os"
"path" "path"
"testing" "testing"
"github.com/coreos/coreos-cloudinit/datasource"
"github.com/coreos/coreos-cloudinit/system" "github.com/coreos/coreos-cloudinit/system"
) )
@ -29,18 +31,18 @@ func TestEnvironmentApply(t *testing.T) {
os.Setenv("COREOS_PUBLIC_IPV6", "1234::") os.Setenv("COREOS_PUBLIC_IPV6", "1234::")
os.Setenv("COREOS_PRIVATE_IPV6", "5678::") os.Setenv("COREOS_PRIVATE_IPV6", "5678::")
for _, tt := range []struct { for _, tt := range []struct {
subs map[string]string metadata datasource.Metadata
input string input string
out string out string
}{ }{
{ {
// Substituting both values directly should always take precedence // Substituting both values directly should always take precedence
// over environment variables // over environment variables
map[string]string{ datasource.Metadata{
"$public_ipv4": "192.0.2.3", PublicIPv4: net.ParseIP("192.0.2.3"),
"$private_ipv4": "192.0.2.203", PrivateIPv4: net.ParseIP("192.0.2.203"),
"$public_ipv6": "fe00:1234::", PublicIPv6: net.ParseIP("fe00:1234::"),
"$private_ipv6": "fe00:5678::", PrivateIPv6: net.ParseIP("fe00:5678::"),
}, },
`[Service] `[Service]
ExecStart=/usr/bin/echo "$public_ipv4 $public_ipv6" ExecStart=/usr/bin/echo "$public_ipv4 $public_ipv6"
@ -53,25 +55,29 @@ ExecStop=/usr/bin/echo $unknown`,
}, },
{ {
// Substituting one value directly while falling back with the other // Substituting one value directly while falling back with the other
map[string]string{"$private_ipv4": "127.0.0.1"}, datasource.Metadata{
PrivateIPv4: net.ParseIP("127.0.0.1"),
},
"$private_ipv4\n$public_ipv4", "$private_ipv4\n$public_ipv4",
"127.0.0.1\n1.2.3.4", "127.0.0.1\n1.2.3.4",
}, },
{ {
// Falling back to environment variables for both values // Falling back to environment variables for both values
map[string]string{"foo": "bar"}, datasource.Metadata{},
"$private_ipv4\n$public_ipv4", "$private_ipv4\n$public_ipv4",
"5.6.7.8\n1.2.3.4", "5.6.7.8\n1.2.3.4",
}, },
{ {
// No substitutions // No substitutions
nil, datasource.Metadata{},
"$private_ipv4\nfoobar", "$private_ipv4\nfoobar",
"5.6.7.8\nfoobar", "5.6.7.8\nfoobar",
}, },
{ {
// Escaping substitutions // Escaping substitutions
map[string]string{"$private_ipv4": "127.0.0.1"}, datasource.Metadata{
PrivateIPv4: net.ParseIP("127.0.0.1"),
},
`\$private_ipv4 `\$private_ipv4
$private_ipv4 $private_ipv4
addr: \$private_ipv4 addr: \$private_ipv4
@ -83,13 +89,13 @@ addr: $private_ipv4
}, },
{ {
// No substitutions with escaping // No substitutions with escaping
nil, datasource.Metadata{},
"\\$test\n$test", "\\$test\n$test",
"\\$test\n$test", "\\$test\n$test",
}, },
} { } {
env := NewEnvironment("./", "./", "./", "", "", tt.subs) env := NewEnvironment("./", "./", "./", "", "", tt.metadata)
got := env.Apply(tt.input) got := env.Apply(tt.input)
if got != tt.out { if got != tt.out {
t.Fatalf("Environment incorrectly applied.\ngot:\n%s\nwant:\n%s", got, tt.out) t.Fatalf("Environment incorrectly applied.\ngot:\n%s\nwant:\n%s", got, tt.out)
@ -98,11 +104,11 @@ addr: $private_ipv4
} }
func TestEnvironmentFile(t *testing.T) { func TestEnvironmentFile(t *testing.T) {
subs := map[string]string{ metadata := datasource.Metadata{
"$public_ipv4": "1.2.3.4", PublicIPv4: net.ParseIP("1.2.3.4"),
"$private_ipv4": "5.6.7.8", PrivateIPv4: net.ParseIP("5.6.7.8"),
"$public_ipv6": "1234::", PublicIPv6: net.ParseIP("1234::"),
"$private_ipv6": "5678::", PrivateIPv6: net.ParseIP("5678::"),
} }
expect := "COREOS_PRIVATE_IPV4=5.6.7.8\nCOREOS_PRIVATE_IPV6=5678::\nCOREOS_PUBLIC_IPV4=1.2.3.4\nCOREOS_PUBLIC_IPV6=1234::\n" expect := "COREOS_PRIVATE_IPV4=5.6.7.8\nCOREOS_PRIVATE_IPV6=5678::\nCOREOS_PUBLIC_IPV4=1.2.3.4\nCOREOS_PUBLIC_IPV6=1234::\n"
@ -112,7 +118,7 @@ func TestEnvironmentFile(t *testing.T) {
} }
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
env := NewEnvironment("./", "./", "./", "", "", subs) env := NewEnvironment("./", "./", "./", "", "", metadata)
ef := env.DefaultEnvironmentFile() ef := env.DefaultEnvironmentFile()
err = system.WriteEnvFile(ef, dir) err = system.WriteEnvFile(ef, dir)
if err != nil { if err != nil {
@ -131,14 +137,10 @@ func TestEnvironmentFile(t *testing.T) {
} }
func TestEnvironmentFileNil(t *testing.T) { func TestEnvironmentFileNil(t *testing.T) {
subs := map[string]string{ os.Clearenv()
"$public_ipv4": "", metadata := datasource.Metadata{}
"$private_ipv4": "",
"$public_ipv6": "",
"$private_ipv6": "",
}
env := NewEnvironment("./", "./", "./", "", "", subs) env := NewEnvironment("./", "./", "./", "", "", metadata)
ef := env.DefaultEnvironmentFile() ef := env.DefaultEnvironmentFile()
if ef != nil { if ef != nil {
t.Fatalf("Environment file not nil: %v", ef) t.Fatalf("Environment file not nil: %v", ef)

View File

@ -1,50 +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 initialize
import (
"sort"
"github.com/coreos/coreos-cloudinit/datasource"
)
// ExtractIPsFromMetaData parses a JSON blob in the OpenStack metadata service
// format and returns a substitution map possibly containing private_ipv4,
// public_ipv4, private_ipv6, and public_ipv6 addresses.
func ExtractIPsFromMetadata(metadata datasource.Metadata) map[string]string {
subs := map[string]string{}
if metadata.PrivateIPv4 != nil {
subs["$private_ipv4"] = metadata.PrivateIPv4.String()
}
if metadata.PublicIPv4 != nil {
subs["$public_ipv4"] = metadata.PublicIPv4.String()
}
if metadata.PrivateIPv6 != nil {
subs["$private_ipv6"] = metadata.PrivateIPv6.String()
}
if metadata.PublicIPv6 != nil {
subs["$public_ipv6"] = metadata.PublicIPv6.String()
}
return subs
}
func sortedKeys(m map[string]string) (keys []string) {
for key := range m {
keys = append(keys, key)
}
sort.Strings(keys)
return
}

View File

@ -1,45 +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 initialize
import (
"net"
"reflect"
"testing"
"github.com/coreos/coreos-cloudinit/datasource"
)
func TestExtractIPsFromMetadata(t *testing.T) {
for i, tt := range []struct {
in datasource.Metadata
out map[string]string
}{
{
datasource.Metadata{
PublicIPv4: net.ParseIP("12.34.56.78"),
PrivateIPv4: net.ParseIP("1.2.3.4"),
PublicIPv6: net.ParseIP("1234::"),
PrivateIPv6: net.ParseIP("5678::"),
},
map[string]string{"$public_ipv4": "12.34.56.78", "$private_ipv4": "1.2.3.4", "$public_ipv6": "1234::", "$private_ipv6": "5678::"},
},
} {
got := ExtractIPsFromMetadata(tt.in)
if !reflect.DeepEqual(got, tt.out) {
t.Errorf("case %d: got %s, want %s", i, got, tt.out)
}
}
}