Merge branch 'master' into generic
This commit is contained in:
commit
0bc1edbd9d
@ -109,7 +109,7 @@ flanneld. For example, the following cloud-config...
|
|||||||
|
|
||||||
coreos:
|
coreos:
|
||||||
flannel:
|
flannel:
|
||||||
etcd-prefix: /coreos.com/network2
|
etcd_prefix: /coreos.com/network2
|
||||||
```
|
```
|
||||||
|
|
||||||
...will generate a systemd unit drop-in like so:
|
...will generate a systemd unit drop-in like so:
|
||||||
@ -119,7 +119,16 @@ coreos:
|
|||||||
Environment="FLANNELD_ETCD_PREFIX=/coreos.com/network2"
|
Environment="FLANNELD_ETCD_PREFIX=/coreos.com/network2"
|
||||||
```
|
```
|
||||||
|
|
||||||
For the complete list of flannel configuraion parameters, see the [flannel documentation][flannel-readme].
|
List of flannel configuration parameters:
|
||||||
|
|
||||||
|
- **etcd_endpoints**: Comma separated list of etcd endpoints
|
||||||
|
- **etcd_cafile**: Path to CA file used for TLS communication with etcd
|
||||||
|
- **etcd_certfile**: Path to certificate file used for TLS communication with etcd
|
||||||
|
- **etcd_keyfile**: Path to private key file used for TLS communication with etcd
|
||||||
|
- **etcd_prefix**: Etcd prefix path to be used for flannel keys
|
||||||
|
- **ip_masq**: Install IP masquerade rules for traffic outside of flannel subnet
|
||||||
|
- **subnet_file**: Path to flannel subnet file to write out
|
||||||
|
- **interface**: Interface (name or IP) that should be used for inter-host communication
|
||||||
|
|
||||||
[flannel-readme]: https://github.com/coreos/flannel/blob/master/README.md
|
[flannel-readme]: https://github.com/coreos/flannel/blob/master/README.md
|
||||||
|
|
||||||
@ -143,7 +152,7 @@ coreos:
|
|||||||
Environment="LOCKSMITHD_ENDPOINT=example.com:4001"
|
Environment="LOCKSMITHD_ENDPOINT=example.com:4001"
|
||||||
```
|
```
|
||||||
|
|
||||||
For the complete list of locksmith configuraion parameters, see the [locksmith documentation][locksmith-readme].
|
For the complete list of locksmith configuration parameters, see the [locksmith documentation][locksmith-readme].
|
||||||
|
|
||||||
[locksmith-readme]: https://github.com/coreos/locksmith/blob/master/README.md
|
[locksmith-readme]: https://github.com/coreos/locksmith/blob/master/README.md
|
||||||
|
|
||||||
@ -159,9 +168,12 @@ The `reboot-strategy` parameter also affects the behaviour of [locksmith](https:
|
|||||||
- _etcd-lock_: Reboot after first taking a distributed lock in etcd, this guarantees that only one host will reboot concurrently and that the cluster will remain available during the update.
|
- _etcd-lock_: Reboot after first taking a distributed lock in etcd, this guarantees that only one host will reboot concurrently and that the cluster will remain available during the update.
|
||||||
- _best-effort_ - If etcd is running, "etcd-lock", otherwise simply "reboot".
|
- _best-effort_ - If etcd is running, "etcd-lock", otherwise simply "reboot".
|
||||||
- _off_ - Disable rebooting after updates are applied (not recommended).
|
- _off_ - Disable rebooting after updates are applied (not recommended).
|
||||||
- **server**: is the omaha endpoint URL which will be queried for updates.
|
- **server**: The location of the [CoreUpdate][coreupdate] server which will be queried for updates. Also known as the [omaha][omaha-docs] server endpoint.
|
||||||
- **group**: signifies the channel which should be used for automatic updates. This value defaults to the version of the image initially downloaded. (one of "master", "alpha", "beta", "stable")
|
- **group**: signifies the channel which should be used for automatic updates. This value defaults to the version of the image initially downloaded. (one of "master", "alpha", "beta", "stable")
|
||||||
|
|
||||||
|
[coreupdate]: https://coreos.com/products/coreupdate
|
||||||
|
[omaha-docs]: https://coreos.com/docs/coreupdate/custom-apps/coreupdate-protocol/
|
||||||
|
|
||||||
*Note: cloudinit will only manipulate the locksmith unit file in the systemd runtime directory (`/run/systemd/system/locksmithd.service`). If any manual modifications are made to an overriding unit configuration file (e.g. `/etc/systemd/system/locksmithd.service`), cloudinit will no longer be able to control the locksmith service unit.*
|
*Note: cloudinit will only manipulate the locksmith unit file in the systemd runtime directory (`/run/systemd/system/locksmithd.service`). If any manual modifications are made to an overriding unit configuration file (e.g. `/etc/systemd/system/locksmithd.service`), cloudinit will no longer be able to control the locksmith service unit.*
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
@ -282,7 +294,8 @@ All but the `passwd` and `ssh-authorized-keys` fields will be ignored if the use
|
|||||||
- **groups**: Add user to these additional groups
|
- **groups**: Add user to these additional groups
|
||||||
- **no-user-group**: Boolean. Skip default group creation.
|
- **no-user-group**: Boolean. Skip default group creation.
|
||||||
- **ssh-authorized-keys**: List of public SSH keys to authorize for this user
|
- **ssh-authorized-keys**: List of public SSH keys to authorize for this user
|
||||||
- **coreos-ssh-import-github**: Authorize SSH keys from Github user
|
- **coreos-ssh-import-github**: Authorize SSH keys from GitHub user
|
||||||
|
- **coreos-ssh-import-github-users**: Authorize SSH keys from a list of GitHub users
|
||||||
- **coreos-ssh-import-url**: Authorize SSH keys imported from a url endpoint.
|
- **coreos-ssh-import-url**: Authorize SSH keys imported from a url endpoint.
|
||||||
- **system**: Create the user as a system user. No home directory will be created.
|
- **system**: Create the user as a system user. No home directory will be created.
|
||||||
- **no-log-init**: Boolean. Skip initialization of lastlog and faillog databases.
|
- **no-log-init**: Boolean. Skip initialization of lastlog and faillog databases.
|
||||||
|
2
Godeps/Godeps.json
generated
2
Godeps/Godeps.json
generated
@ -15,7 +15,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/coreos/yaml",
|
"ImportPath": "github.com/coreos/yaml",
|
||||||
"Rev": "9f9df34309c04878acc86042b16630b0f696e1de"
|
"Rev": "6b16a5714269b2f70720a45406b1babd947a17ef"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/dotcloud/docker/pkg/netlink",
|
"ImportPath": "github.com/dotcloud/docker/pkg/netlink",
|
||||||
|
3
Godeps/_workspace/src/github.com/coreos/yaml/README.md
generated
vendored
3
Godeps/_workspace/src/github.com/coreos/yaml/README.md
generated
vendored
@ -1,3 +1,6 @@
|
|||||||
|
Note: This is a fork of https://github.com/go-yaml/yaml. The following README
|
||||||
|
doesn't necessarily apply to this fork.
|
||||||
|
|
||||||
# YAML support for the Go language
|
# YAML support for the Go language
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
|
11
Godeps/_workspace/src/github.com/coreos/yaml/decode.go
generated
vendored
11
Godeps/_workspace/src/github.com/coreos/yaml/decode.go
generated
vendored
@ -33,10 +33,12 @@ type parser struct {
|
|||||||
parser yaml_parser_t
|
parser yaml_parser_t
|
||||||
event yaml_event_t
|
event yaml_event_t
|
||||||
doc *node
|
doc *node
|
||||||
|
transform transformString
|
||||||
}
|
}
|
||||||
|
|
||||||
func newParser(b []byte) *parser {
|
func newParser(b []byte, t transformString) *parser {
|
||||||
p := parser{}
|
p := parser{transform: t}
|
||||||
|
|
||||||
if !yaml_parser_initialize(&p.parser) {
|
if !yaml_parser_initialize(&p.parser) {
|
||||||
panic("Failed to initialize YAML emitter")
|
panic("Failed to initialize YAML emitter")
|
||||||
}
|
}
|
||||||
@ -175,7 +177,10 @@ func (p *parser) mapping() *node {
|
|||||||
p.anchor(n, p.event.anchor)
|
p.anchor(n, p.event.anchor)
|
||||||
p.skip()
|
p.skip()
|
||||||
for p.event.typ != yaml_MAPPING_END_EVENT {
|
for p.event.typ != yaml_MAPPING_END_EVENT {
|
||||||
n.children = append(n.children, p.parse(), p.parse())
|
key := p.parse()
|
||||||
|
key.value = p.transform(key.value)
|
||||||
|
value := p.parse()
|
||||||
|
n.children = append(n.children, key, value)
|
||||||
}
|
}
|
||||||
p.skip()
|
p.skip()
|
||||||
return n
|
return n
|
||||||
|
19
Godeps/_workspace/src/github.com/coreos/yaml/decode_test.go
generated
vendored
19
Godeps/_workspace/src/github.com/coreos/yaml/decode_test.go
generated
vendored
@ -1,8 +1,8 @@
|
|||||||
package yaml_test
|
package yaml_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/coreos/yaml"
|
||||||
. "gopkg.in/check.v1"
|
. "gopkg.in/check.v1"
|
||||||
"gopkg.in/yaml.v1"
|
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@ -557,6 +557,23 @@ func (s *S) TestUnmarshalWithFalseSetterIgnoresValue(c *C) {
|
|||||||
c.Assert(m["ghi"].value, Equals, 3)
|
c.Assert(m["ghi"].value, Equals, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *S) TestUnmarshalWithTransform(c *C) {
|
||||||
|
data := `{a_b: 1, c-d: 2, e-f_g: 3, h_i-j: 4}`
|
||||||
|
expect := map[string]int{
|
||||||
|
"a_b": 1,
|
||||||
|
"c_d": 2,
|
||||||
|
"e_f_g": 3,
|
||||||
|
"h_i_j": 4,
|
||||||
|
}
|
||||||
|
m := map[string]int{}
|
||||||
|
yaml.UnmarshalMappingKeyTransform = func(i string) string {
|
||||||
|
return strings.Replace(i, "-", "_", -1)
|
||||||
|
}
|
||||||
|
err := yaml.Unmarshal([]byte(data), m)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(m, DeepEquals, expect)
|
||||||
|
}
|
||||||
|
|
||||||
// From http://yaml.org/type/merge.html
|
// From http://yaml.org/type/merge.html
|
||||||
var mergeTests = `
|
var mergeTests = `
|
||||||
anchors:
|
anchors:
|
||||||
|
2
Godeps/_workspace/src/github.com/coreos/yaml/encode_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/coreos/yaml/encode_test.go
generated
vendored
@ -7,8 +7,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/yaml"
|
||||||
. "gopkg.in/check.v1"
|
. "gopkg.in/check.v1"
|
||||||
"gopkg.in/yaml.v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var marshalIntTest = 123
|
var marshalIntTest = 123
|
||||||
|
13
Godeps/_workspace/src/github.com/coreos/yaml/yaml.go
generated
vendored
13
Godeps/_workspace/src/github.com/coreos/yaml/yaml.go
generated
vendored
@ -84,7 +84,7 @@ type Getter interface {
|
|||||||
func Unmarshal(in []byte, out interface{}) (err error) {
|
func Unmarshal(in []byte, out interface{}) (err error) {
|
||||||
defer handleErr(&err)
|
defer handleErr(&err)
|
||||||
d := newDecoder()
|
d := newDecoder()
|
||||||
p := newParser(in)
|
p := newParser(in, UnmarshalMappingKeyTransform)
|
||||||
defer p.destroy()
|
defer p.destroy()
|
||||||
node := p.parse()
|
node := p.parse()
|
||||||
if node != nil {
|
if node != nil {
|
||||||
@ -146,6 +146,17 @@ func Marshal(in interface{}) (out []byte, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalMappingKeyTransform is a string transformation that is applied to
|
||||||
|
// each mapping key in a YAML document before it is unmarshalled. By default,
|
||||||
|
// UnmarshalMappingKeyTransform is an identity transform (no modification).
|
||||||
|
var UnmarshalMappingKeyTransform transformString = identityTransform
|
||||||
|
|
||||||
|
type transformString func(in string) (out string)
|
||||||
|
|
||||||
|
func identityTransform(in string) (out string) {
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// Maintain a mapping of keys to structure field indexes
|
// Maintain a mapping of keys to structure field indexes
|
||||||
|
|
||||||
|
109
config/config.go
109
config/config.go
@ -1,24 +1,23 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/Godeps/_workspace/src/github.com/coreos/yaml"
|
"github.com/coreos/coreos-cloudinit/Godeps/_workspace/src/github.com/coreos/yaml"
|
||||||
@ -29,7 +28,22 @@ import (
|
|||||||
// used for internal use) have the YAML tag '-' so that they aren't marshalled.
|
// used for internal use) have the YAML tag '-' so that they aren't marshalled.
|
||||||
type CloudConfig struct {
|
type CloudConfig struct {
|
||||||
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"`
|
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"`
|
||||||
Coreos struct {
|
Debug bool `yaml:"debug"`
|
||||||
|
RunCMD []string `yaml:"runcmd"`
|
||||||
|
NetworkConfigPath string `yaml:"-"`
|
||||||
|
NetworkConfig string `yaml:"-"`
|
||||||
|
SystemInfo SystemInfo `yaml:"system_info"`
|
||||||
|
DisableRoot bool `yaml:"disable_root"`
|
||||||
|
SSHPasswdAuth bool `yaml:"ssh_pwauth"`
|
||||||
|
ResizeRootfs bool `yaml:"resize_rootfs"`
|
||||||
|
CoreOS CoreOS `yaml:"coreos"`
|
||||||
|
WriteFiles []File `yaml:"write_files"`
|
||||||
|
Hostname string `yaml:"hostname"`
|
||||||
|
Users []User `yaml:"users"`
|
||||||
|
ManageEtcHosts EtcHosts `yaml:"manage_etc_hosts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CoreOS struct {
|
||||||
Etcd Etcd `yaml:"etcd"`
|
Etcd Etcd `yaml:"etcd"`
|
||||||
Flannel Flannel `yaml:"flannel"`
|
Flannel Flannel `yaml:"flannel"`
|
||||||
Fleet Fleet `yaml:"fleet"`
|
Fleet Fleet `yaml:"fleet"`
|
||||||
@ -37,19 +51,6 @@ type CloudConfig struct {
|
|||||||
OEM OEM `yaml:"oem"`
|
OEM OEM `yaml:"oem"`
|
||||||
Update Update `yaml:"update"`
|
Update Update `yaml:"update"`
|
||||||
Units []Unit `yaml:"units"`
|
Units []Unit `yaml:"units"`
|
||||||
} `yaml:"coreos"`
|
|
||||||
WriteFiles []File `yaml:"write_files"`
|
|
||||||
Debug bool `yaml:"debug"`
|
|
||||||
RunCMD []string `yaml:"runcmd"`
|
|
||||||
Hostname string `yaml:"hostname"`
|
|
||||||
Users []User `yaml:"users"`
|
|
||||||
ManageEtcHosts EtcHosts `yaml:"manage_etc_hosts"`
|
|
||||||
NetworkConfigPath string `yaml:"-"`
|
|
||||||
NetworkConfig string `yaml:"-"`
|
|
||||||
SystemInfo SystemInfo `yaml:"system_info"`
|
|
||||||
DisableRoot bool `yaml:"disable_root"`
|
|
||||||
SSHPasswdAuth bool `yaml:"ssh_pwauth"`
|
|
||||||
ResizeRootfs bool `yaml:"resize_rootfs"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsCloudConfig(userdata string) bool {
|
func IsCloudConfig(userdata string) bool {
|
||||||
@ -67,15 +68,12 @@ func IsCloudConfig(userdata string) bool {
|
|||||||
// string of YAML), returning any error encountered. It will ignore unknown
|
// string of YAML), returning any error encountered. It will ignore unknown
|
||||||
// fields but log encountering them.
|
// fields but log encountering them.
|
||||||
func NewCloudConfig(contents string) (*CloudConfig, error) {
|
func NewCloudConfig(contents string) (*CloudConfig, error) {
|
||||||
|
yaml.UnmarshalMappingKeyTransform = func(nameIn string) (nameOut string) {
|
||||||
|
return strings.Replace(nameIn, "-", "_", -1)
|
||||||
|
}
|
||||||
var cfg CloudConfig
|
var cfg CloudConfig
|
||||||
ncontents, err := normalizeConfig(contents)
|
err := yaml.Unmarshal([]byte(contents), &cfg)
|
||||||
if err != nil {
|
|
||||||
return &cfg, err
|
return &cfg, err
|
||||||
}
|
|
||||||
if err = yaml.Unmarshal(ncontents, &cfg); err != nil {
|
|
||||||
return &cfg, err
|
|
||||||
}
|
|
||||||
return &cfg, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc CloudConfig) String() string {
|
func (cc CloudConfig) String() string {
|
||||||
@ -98,7 +96,7 @@ func IsZero(c interface{}) bool {
|
|||||||
|
|
||||||
type ErrorValid struct {
|
type ErrorValid struct {
|
||||||
Value string
|
Value string
|
||||||
Valid []string
|
Valid string
|
||||||
Field string
|
Field string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,16 +130,15 @@ func AssertValid(value reflect.Value, valid string) *ErrorValid {
|
|||||||
if valid == "" || isZero(value) {
|
if valid == "" || isZero(value) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
vs := fmt.Sprintf("%v", value.Interface())
|
vs := fmt.Sprintf("%v", value.Interface())
|
||||||
valids := strings.Split(valid, ",")
|
if m, _ := regexp.MatchString(valid, vs); m {
|
||||||
for _, valid := range valids {
|
|
||||||
if vs == valid {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return &ErrorValid{
|
return &ErrorValid{
|
||||||
Value: vs,
|
Value: vs,
|
||||||
Valid: valids,
|
Valid: valid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,31 +160,3 @@ func isZero(v reflect.Value) bool {
|
|||||||
func isFieldExported(f reflect.StructField) bool {
|
func isFieldExported(f reflect.StructField) bool {
|
||||||
return f.PkgPath == ""
|
return f.PkgPath == ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizeConfig(config string) ([]byte, error) {
|
|
||||||
var cfg map[interface{}]interface{}
|
|
||||||
if err := yaml.Unmarshal([]byte(config), &cfg); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return yaml.Marshal(normalizeKeys(cfg))
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalizeKeys(m map[interface{}]interface{}) map[interface{}]interface{} {
|
|
||||||
for k, v := range m {
|
|
||||||
if m, ok := m[k].(map[interface{}]interface{}); ok {
|
|
||||||
normalizeKeys(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
if s, ok := m[k].([]interface{}); ok {
|
|
||||||
for _, e := range s {
|
|
||||||
if m, ok := e.(map[interface{}]interface{}); ok {
|
|
||||||
normalizeKeys(m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(m, k)
|
|
||||||
m[strings.Replace(fmt.Sprint(k), "-", "_", -1)] = v
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
@ -1,30 +1,82 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestNewCloudConfig(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
contents string
|
||||||
|
|
||||||
|
config CloudConfig
|
||||||
|
}{
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
contents: "#cloud-config\nwrite_files:\n - path: underscore",
|
||||||
|
config: CloudConfig{WriteFiles: []File{File{Path: "underscore"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contents: "#cloud-config\nwrite-files:\n - path: hyphen",
|
||||||
|
config: CloudConfig{WriteFiles: []File{File{Path: "hyphen"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contents: "#cloud-config\ncoreos:\n update:\n reboot-strategy: off",
|
||||||
|
config: CloudConfig{CoreOS: CoreOS{Update: Update{RebootStrategy: "off"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contents: "#cloud-config\ncoreos:\n update:\n reboot-strategy: false",
|
||||||
|
config: CloudConfig{CoreOS: CoreOS{Update: Update{RebootStrategy: "false"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contents: "#cloud-config\nwrite_files:\n - permissions: 0744",
|
||||||
|
config: CloudConfig{WriteFiles: []File{File{RawFilePermissions: "0744"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contents: "#cloud-config\nwrite_files:\n - permissions: 744",
|
||||||
|
config: CloudConfig{WriteFiles: []File{File{RawFilePermissions: "744"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contents: "#cloud-config\nwrite_files:\n - permissions: '0744'",
|
||||||
|
config: CloudConfig{WriteFiles: []File{File{RawFilePermissions: "0744"}}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
contents: "#cloud-config\nwrite_files:\n - permissions: '744'",
|
||||||
|
config: CloudConfig{WriteFiles: []File{File{RawFilePermissions: "744"}}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
config, err := NewCloudConfig(tt.contents)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("bad error (test case #%d): want %v, got %s", i, nil, err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(&tt.config, config) {
|
||||||
|
t.Errorf("bad config (test case #%d): want %#v, got %#v", i, tt.config, config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestIsZero(t *testing.T) {
|
func TestIsZero(t *testing.T) {
|
||||||
for _, tt := range []struct {
|
tests := []struct {
|
||||||
c interface{}
|
c interface{}
|
||||||
|
|
||||||
empty bool
|
empty bool
|
||||||
}{
|
}{
|
||||||
{struct{}{}, true},
|
{struct{}{}, true},
|
||||||
@ -34,7 +86,9 @@ func TestIsZero(t *testing.T) {
|
|||||||
{struct{ A string }{A: "hello"}, false},
|
{struct{ A string }{A: "hello"}, false},
|
||||||
{struct{ A int }{}, true},
|
{struct{ A int }{}, true},
|
||||||
{struct{ A int }{A: 1}, false},
|
{struct{ A int }{A: 1}, false},
|
||||||
} {
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
if empty := IsZero(tt.c); tt.empty != empty {
|
if empty := IsZero(tt.c); tt.empty != empty {
|
||||||
t.Errorf("bad result (%q): want %t, got %t", tt.c, tt.empty, empty)
|
t.Errorf("bad result (%q): want %t, got %t", tt.c, tt.empty, empty)
|
||||||
}
|
}
|
||||||
@ -42,66 +96,68 @@ func TestIsZero(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAssertStructValid(t *testing.T) {
|
func TestAssertStructValid(t *testing.T) {
|
||||||
for _, tt := range []struct {
|
tests := []struct {
|
||||||
c interface{}
|
c interface{}
|
||||||
|
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
{struct{}{}, nil},
|
{struct{}{}, nil},
|
||||||
{struct {
|
{struct {
|
||||||
A, b string `valid:"1,2"`
|
A, b string `valid:"^1|2$"`
|
||||||
}{}, nil},
|
}{}, nil},
|
||||||
{struct {
|
{struct {
|
||||||
A, b string `valid:"1,2"`
|
A, b string `valid:"^1|2$"`
|
||||||
}{A: "1", b: "2"}, nil},
|
}{A: "1", b: "2"}, nil},
|
||||||
{struct {
|
{struct {
|
||||||
A, b string `valid:"1,2"`
|
A, b string `valid:"^1|2$"`
|
||||||
}{A: "1", b: "hello"}, nil},
|
}{A: "1", b: "hello"}, nil},
|
||||||
{struct {
|
{struct {
|
||||||
A, b string `valid:"1,2"`
|
A, b string `valid:"^1|2$"`
|
||||||
}{A: "hello", b: "2"}, &ErrorValid{Value: "hello", Field: "A", Valid: []string{"1", "2"}}},
|
}{A: "hello", b: "2"}, &ErrorValid{Value: "hello", Field: "A", Valid: "^1|2$"}},
|
||||||
{struct {
|
{struct {
|
||||||
A, b int `valid:"1,2"`
|
A, b int `valid:"^1|2$"`
|
||||||
}{}, nil},
|
}{}, nil},
|
||||||
{struct {
|
{struct {
|
||||||
A, b int `valid:"1,2"`
|
A, b int `valid:"^1|2$"`
|
||||||
}{A: 1, b: 2}, nil},
|
}{A: 1, b: 2}, nil},
|
||||||
{struct {
|
{struct {
|
||||||
A, b int `valid:"1,2"`
|
A, b int `valid:"^1|2$"`
|
||||||
}{A: 1, b: 9}, nil},
|
}{A: 1, b: 9}, nil},
|
||||||
{struct {
|
{struct {
|
||||||
A, b int `valid:"1,2"`
|
A, b int `valid:"^1|2$"`
|
||||||
}{A: 9, b: 2}, &ErrorValid{Value: "9", Field: "A", Valid: []string{"1", "2"}}},
|
}{A: 9, b: 2}, &ErrorValid{Value: "9", Field: "A", Valid: "^1|2$"}},
|
||||||
} {
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
if err := AssertStructValid(tt.c); !reflect.DeepEqual(tt.err, err) {
|
if err := AssertStructValid(tt.c); !reflect.DeepEqual(tt.err, err) {
|
||||||
t.Errorf("bad result (%q): want %q, got %q", tt.c, tt.err, err)
|
t.Errorf("bad result (%q): want %q, got %q", tt.c, tt.err, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCloudConfigInvalidKeys(t *testing.T) {
|
func TestConfigCompile(t *testing.T) {
|
||||||
defer func() {
|
tests := []interface{}{
|
||||||
if r := recover(); r != nil {
|
Etcd{},
|
||||||
t.Fatalf("panic while instantiating CloudConfig with nil keys: %v", r)
|
File{},
|
||||||
|
Flannel{},
|
||||||
|
Fleet{},
|
||||||
|
Locksmith{},
|
||||||
|
OEM{},
|
||||||
|
Unit{},
|
||||||
|
Update{},
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
|
||||||
for _, tt := range []struct {
|
for _, tt := range tests {
|
||||||
contents string
|
ttt := reflect.TypeOf(tt)
|
||||||
}{
|
for i := 0; i < ttt.NumField(); i++ {
|
||||||
{"coreos:"},
|
ft := ttt.Field(i)
|
||||||
{"ssh_authorized_keys:"},
|
if !isFieldExported(ft) {
|
||||||
{"ssh_authorized_keys:\n -"},
|
continue
|
||||||
{"ssh_authorized_keys:\n - 0:"},
|
}
|
||||||
{"write_files:"},
|
|
||||||
{"write_files:\n -"},
|
if _, err := regexp.Compile(ft.Tag.Get("valid")); err != nil {
|
||||||
{"write_files:\n - 0:"},
|
t.Errorf("bad regexp(%s.%s): want %v, got %s", ttt.Name(), ft.Name, nil, err)
|
||||||
{"users:"},
|
}
|
||||||
{"users:\n -"},
|
|
||||||
{"users:\n - 0:"},
|
|
||||||
} {
|
|
||||||
_, err := NewCloudConfig(tt.contents)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error instantiating CloudConfig with invalid keys: %v", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,7 +192,7 @@ hostname:
|
|||||||
if cfg.Hostname != "foo" {
|
if cfg.Hostname != "foo" {
|
||||||
t.Fatalf("hostname not correctly set when invalid keys are present")
|
t.Fatalf("hostname not correctly set when invalid keys are present")
|
||||||
}
|
}
|
||||||
if cfg.Coreos.Etcd.Discovery != "https://discovery.etcd.io/827c73219eeb2fa5530027c37bf18877" {
|
if cfg.CoreOS.Etcd.Discovery != "https://discovery.etcd.io/827c73219eeb2fa5530027c37bf18877" {
|
||||||
t.Fatalf("etcd section not correctly set when invalid keys are present")
|
t.Fatalf("etcd section not correctly set when invalid keys are present")
|
||||||
}
|
}
|
||||||
if len(cfg.WriteFiles) < 1 || cfg.WriteFiles[0].Content != "fun" || cfg.WriteFiles[0].Path != "/var/party" {
|
if len(cfg.WriteFiles) < 1 || cfg.WriteFiles[0].Content != "fun" || cfg.WriteFiles[0].Path != "/var/party" {
|
||||||
@ -242,10 +298,10 @@ hostname: trontastic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(cfg.Coreos.Units) != 1 {
|
if len(cfg.CoreOS.Units) != 1 {
|
||||||
t.Error("Failed to parse correct number of units")
|
t.Error("Failed to parse correct number of units")
|
||||||
} else {
|
} else {
|
||||||
u := cfg.Coreos.Units[0]
|
u := cfg.CoreOS.Units[0]
|
||||||
expect := `[Match]
|
expect := `[Match]
|
||||||
Name=eth47
|
Name=eth47
|
||||||
|
|
||||||
@ -263,50 +319,16 @@ Address=10.209.171.177/19
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Coreos.OEM.ID != "rackspace" {
|
if cfg.CoreOS.OEM.ID != "rackspace" {
|
||||||
t.Errorf("Failed parsing coreos.oem. Expected ID 'rackspace', got %q.", cfg.Coreos.OEM.ID)
|
t.Errorf("Failed parsing coreos.oem. Expected ID 'rackspace', got %q.", cfg.CoreOS.OEM.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Hostname != "trontastic" {
|
if cfg.Hostname != "trontastic" {
|
||||||
t.Errorf("Failed to parse hostname")
|
t.Errorf("Failed to parse hostname")
|
||||||
}
|
}
|
||||||
if cfg.Coreos.Update.RebootStrategy != "reboot" {
|
if cfg.CoreOS.Update.RebootStrategy != "reboot" {
|
||||||
t.Errorf("Failed to parse locksmith strategy")
|
t.Errorf("Failed to parse locksmith strategy")
|
||||||
}
|
}
|
||||||
|
|
||||||
contents = `
|
|
||||||
coreos:
|
|
||||||
write_files:
|
|
||||||
- path: /home/me/notes
|
|
||||||
permissions: 0744
|
|
||||||
`
|
|
||||||
cfg, err = NewCloudConfig(contents)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Encountered unexpected error :%v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cfg.WriteFiles) != 1 {
|
|
||||||
t.Error("Failed to parse correct number of write_files")
|
|
||||||
} else {
|
|
||||||
wf := cfg.WriteFiles[0]
|
|
||||||
if wf.Content != "" {
|
|
||||||
t.Errorf("WriteFile has incorrect contents '%s'", wf.Content)
|
|
||||||
}
|
|
||||||
if wf.Encoding != "" {
|
|
||||||
t.Errorf("WriteFile has incorrect encoding %s", wf.Encoding)
|
|
||||||
}
|
|
||||||
// Verify that the normalization of the config converted 0744 to its decimal
|
|
||||||
// representation, 484.
|
|
||||||
if wf.RawFilePermissions != "484" {
|
|
||||||
t.Errorf("WriteFile has incorrect permissions %s", wf.RawFilePermissions)
|
|
||||||
}
|
|
||||||
if wf.Path != "/home/me/notes" {
|
|
||||||
t.Errorf("WriteFile has incorrect path %s", wf.Path)
|
|
||||||
}
|
|
||||||
if wf.Owner != "" {
|
|
||||||
t.Errorf("WriteFile has incorrect owner %s", wf.Owner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert that our interface conversion doesn't panic
|
// Assert that our interface conversion doesn't panic
|
||||||
@ -473,31 +495,3 @@ users:
|
|||||||
t.Errorf("ssh import url is %q, expected 'https://token:x-auth-token@github.enterprise.com/api/v3/polvi/keys'", user.SSHImportURL)
|
t.Errorf("ssh import url is %q, expected 'https://token:x-auth-token@github.enterprise.com/api/v3/polvi/keys'", user.SSHImportURL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNormalizeKeys(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
in string
|
|
||||||
out string
|
|
||||||
}{
|
|
||||||
{"my_key_name: the-value\n", "my_key_name: the-value\n"},
|
|
||||||
{"my-key_name: the-value\n", "my_key_name: the-value\n"},
|
|
||||||
{"my-key-name: the-value\n", "my_key_name: the-value\n"},
|
|
||||||
|
|
||||||
{"a:\n- key_name: the-value\n", "a:\n- key_name: the-value\n"},
|
|
||||||
{"a:\n- key-name: the-value\n", "a:\n- key_name: the-value\n"},
|
|
||||||
|
|
||||||
{"a:\n b:\n - key_name: the-value\n", "a:\n b:\n - key_name: the-value\n"},
|
|
||||||
{"a:\n b:\n - key-name: the-value\n", "a:\n b:\n - key_name: the-value\n"},
|
|
||||||
|
|
||||||
{"coreos:\n update:\n reboot-strategy: off\n", "coreos:\n update:\n reboot_strategy: false\n"},
|
|
||||||
{"coreos:\n update:\n reboot-strategy: 'off'\n", "coreos:\n update:\n reboot_strategy: \"off\"\n"},
|
|
||||||
} {
|
|
||||||
out, err := normalizeConfig(tt.in)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("bad error (%q): want nil, got %s", tt.in, err)
|
|
||||||
}
|
|
||||||
if string(out) != tt.out {
|
|
||||||
t.Fatalf("bad normalization (%q): want %q, got %q", tt.in, tt.out, out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
56
config/decode.go
Normal file
56
config/decode.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DecodeBase64Content(content string) ([]byte, error) {
|
||||||
|
output, err := base64.StdEncoding.DecodeString(content)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to decode base64: %q", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeGzipContent(content string) ([]byte, error) {
|
||||||
|
gzr, err := gzip.NewReader(bytes.NewReader([]byte(content)))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to decode gzip: %q", err)
|
||||||
|
}
|
||||||
|
defer gzr.Close()
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
buf.ReadFrom(gzr)
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeContent(content string, encoding string) ([]byte, error) {
|
||||||
|
switch encoding {
|
||||||
|
case "":
|
||||||
|
return []byte(content), nil
|
||||||
|
|
||||||
|
case "b64", "base64":
|
||||||
|
return DecodeBase64Content(content)
|
||||||
|
|
||||||
|
case "gz", "gzip":
|
||||||
|
return DecodeGzipContent(content)
|
||||||
|
|
||||||
|
case "gz+base64", "gzip+base64", "gz+b64", "gzip+b64":
|
||||||
|
gz, err := DecodeBase64Content(content)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return DecodeGzipContent(string(gz))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("Unsupported encoding %q", encoding)
|
||||||
|
}
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
type Etcd struct {
|
type Etcd struct {
|
||||||
Addr string `yaml:"addr" env:"ETCD_ADDR"`
|
Addr string `yaml:"addr" env:"ETCD_ADDR"`
|
||||||
|
AdvertiseClientURLs string `yaml:"advertise_client_urls" env:"ETCD_ADVERTISE_CLIENT_URLS"`
|
||||||
BindAddr string `yaml:"bind_addr" env:"ETCD_BIND_ADDR"`
|
BindAddr string `yaml:"bind_addr" env:"ETCD_BIND_ADDR"`
|
||||||
CAFile string `yaml:"ca_file" env:"ETCD_CA_FILE"`
|
CAFile string `yaml:"ca_file" env:"ETCD_CA_FILE"`
|
||||||
CertFile string `yaml:"cert_file" env:"ETCD_CERT_FILE"`
|
CertFile string `yaml:"cert_file" env:"ETCD_CERT_FILE"`
|
||||||
@ -27,12 +26,26 @@ type Etcd struct {
|
|||||||
CorsOrigins string `yaml:"cors" env:"ETCD_CORS"`
|
CorsOrigins string `yaml:"cors" env:"ETCD_CORS"`
|
||||||
DataDir string `yaml:"data_dir" env:"ETCD_DATA_DIR"`
|
DataDir string `yaml:"data_dir" env:"ETCD_DATA_DIR"`
|
||||||
Discovery string `yaml:"discovery" env:"ETCD_DISCOVERY"`
|
Discovery string `yaml:"discovery" env:"ETCD_DISCOVERY"`
|
||||||
|
DiscoveryFallback string `yaml:"discovery_fallback" env:"ETCD_DISCOVERY_FALLBACK"`
|
||||||
|
DiscoverySRV string `yaml:"discovery_srv" env:"ETCD_DISCOVERY_SRV"`
|
||||||
|
DiscoveryProxy string `yaml:"discovery_proxy" env:"ETCD_DISCOVERY_PROXY"`
|
||||||
|
ElectionTimeout int `yaml:"election_timeout" env:"ETCD_ELECTION_TIMEOUT"`
|
||||||
|
ForceNewCluster bool `yaml:"force_new_cluster" env:"ETCD_FORCE_NEW_CLUSTER"`
|
||||||
GraphiteHost string `yaml:"graphite_host" env:"ETCD_GRAPHITE_HOST"`
|
GraphiteHost string `yaml:"graphite_host" env:"ETCD_GRAPHITE_HOST"`
|
||||||
|
HeartbeatInterval int `yaml:"heartbeat_interval" env:"ETCD_HEARTBEAT_INTERVAL"`
|
||||||
HTTPReadTimeout float64 `yaml:"http_read_timeout" env:"ETCD_HTTP_READ_TIMEOUT"`
|
HTTPReadTimeout float64 `yaml:"http_read_timeout" env:"ETCD_HTTP_READ_TIMEOUT"`
|
||||||
HTTPWriteTimeout float64 `yaml:"http_write_timeout" env:"ETCD_HTTP_WRITE_TIMEOUT"`
|
HTTPWriteTimeout float64 `yaml:"http_write_timeout" env:"ETCD_HTTP_WRITE_TIMEOUT"`
|
||||||
|
InitialAdvertisePeerURLs string `yaml:"initial_advertise_peer_urls" env:"ETCD_INITIAL_ADVERTISE_PEER_URLS"`
|
||||||
|
InitialCluster string `yaml:"initial_cluster" env:"ETCD_INITIAL_CLUSTER"`
|
||||||
|
InitialClusterState string `yaml:"initial_cluster_state" env:"ETCD_INITIAL_CLUSTER_STATE"`
|
||||||
|
InitialClusterToken string `yaml:"initial_cluster_token" env:"ETCD_INITIAL_CLUSTER_TOKEN"`
|
||||||
KeyFile string `yaml:"key_file" env:"ETCD_KEY_FILE"`
|
KeyFile string `yaml:"key_file" env:"ETCD_KEY_FILE"`
|
||||||
|
ListenClientURLs string `yaml:"listen_client_urls" env:"ETCD_LISTEN_CLIENT_URLS"`
|
||||||
|
ListenPeerURLs string `yaml:"listen_peer_urls" env:"ETCD_LISTEN_PEER_URLS"`
|
||||||
MaxResultBuffer int `yaml:"max_result_buffer" env:"ETCD_MAX_RESULT_BUFFER"`
|
MaxResultBuffer int `yaml:"max_result_buffer" env:"ETCD_MAX_RESULT_BUFFER"`
|
||||||
MaxRetryAttempts int `yaml:"max_retry_attempts" env:"ETCD_MAX_RETRY_ATTEMPTS"`
|
MaxRetryAttempts int `yaml:"max_retry_attempts" env:"ETCD_MAX_RETRY_ATTEMPTS"`
|
||||||
|
MaxSnapshots int `yaml:"max_snapshots" env:"ETCD_MAX_SNAPSHOTS"`
|
||||||
|
MaxWALs int `yaml:"max_wals" env:"ETCD_MAX_WALS"`
|
||||||
Name string `yaml:"name" env:"ETCD_NAME"`
|
Name string `yaml:"name" env:"ETCD_NAME"`
|
||||||
PeerAddr string `yaml:"peer_addr" env:"ETCD_PEER_ADDR"`
|
PeerAddr string `yaml:"peer_addr" env:"ETCD_PEER_ADDR"`
|
||||||
PeerBindAddr string `yaml:"peer_bind_addr" env:"ETCD_PEER_BIND_ADDR"`
|
PeerBindAddr string `yaml:"peer_bind_addr" env:"ETCD_PEER_BIND_ADDR"`
|
||||||
@ -43,6 +56,7 @@ type Etcd struct {
|
|||||||
PeerKeyFile string `yaml:"peer_key_file" env:"ETCD_PEER_KEY_FILE"`
|
PeerKeyFile string `yaml:"peer_key_file" env:"ETCD_PEER_KEY_FILE"`
|
||||||
Peers string `yaml:"peers" env:"ETCD_PEERS"`
|
Peers string `yaml:"peers" env:"ETCD_PEERS"`
|
||||||
PeersFile string `yaml:"peers_file" env:"ETCD_PEERS_FILE"`
|
PeersFile string `yaml:"peers_file" env:"ETCD_PEERS_FILE"`
|
||||||
|
Proxy string `yaml:"proxy" env:"ETCD_PROXY"`
|
||||||
RetryInterval float64 `yaml:"retry_interval" env:"ETCD_RETRY_INTERVAL"`
|
RetryInterval float64 `yaml:"retry_interval" env:"ETCD_RETRY_INTERVAL"`
|
||||||
Snapshot bool `yaml:"snapshot" env:"ETCD_SNAPSHOT"`
|
Snapshot bool `yaml:"snapshot" env:"ETCD_SNAPSHOT"`
|
||||||
SnapshotCount int `yaml:"snapshot_count" env:"ETCD_SNAPSHOTCOUNT"`
|
SnapshotCount int `yaml:"snapshot_count" env:"ETCD_SNAPSHOTCOUNT"`
|
||||||
|
@ -1,25 +1,23 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
type File struct {
|
type File struct {
|
||||||
Encoding string `yaml:"encoding" valid:"base64,b64,gz,gzip,gz+base64,gzip+base64,gz+b64,gzip+b64"`
|
Encoding string `yaml:"encoding" valid:"^(base64|b64|gz|gzip|gz\\+base64|gzip\\+base64|gz\\+b64|gzip\\+b64)$"`
|
||||||
Content string `yaml:"content"`
|
Content string `yaml:"content"`
|
||||||
Owner string `yaml:"owner"`
|
Owner string `yaml:"owner"`
|
||||||
Path string `yaml:"path"`
|
Path string `yaml:"path"`
|
||||||
RawFilePermissions string `yaml:"permissions"`
|
RawFilePermissions string `yaml:"permissions" valid:"^0?[0-7]{3,4}$"`
|
||||||
}
|
}
|
||||||
|
71
config/file_test.go
Normal file
71
config/file_test.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEncodingValid(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
value string
|
||||||
|
|
||||||
|
isValid bool
|
||||||
|
}{
|
||||||
|
{value: "base64", isValid: true},
|
||||||
|
{value: "b64", isValid: true},
|
||||||
|
{value: "gz", isValid: true},
|
||||||
|
{value: "gzip", isValid: true},
|
||||||
|
{value: "gz+base64", isValid: true},
|
||||||
|
{value: "gzip+base64", isValid: true},
|
||||||
|
{value: "gz+b64", isValid: true},
|
||||||
|
{value: "gzip+b64", isValid: true},
|
||||||
|
{value: "gzzzzbase64", isValid: false},
|
||||||
|
{value: "gzipppbase64", isValid: false},
|
||||||
|
{value: "unknown", isValid: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
isValid := (nil == AssertStructValid(File{Encoding: tt.value}))
|
||||||
|
if tt.isValid != isValid {
|
||||||
|
t.Errorf("bad assert (%s): want %t, got %t", tt.value, tt.isValid, isValid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRawFilePermissionsValid(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
value string
|
||||||
|
|
||||||
|
isValid bool
|
||||||
|
}{
|
||||||
|
{value: "744", isValid: true},
|
||||||
|
{value: "0744", isValid: true},
|
||||||
|
{value: "1744", isValid: true},
|
||||||
|
{value: "01744", isValid: true},
|
||||||
|
{value: "11744", isValid: false},
|
||||||
|
{value: "rwxr--r--", isValid: false},
|
||||||
|
{value: "800", isValid: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
isValid := (nil == AssertStructValid(File{RawFilePermissions: tt.value}))
|
||||||
|
if tt.isValid != isValid {
|
||||||
|
t.Errorf("bad assert (%s): want %t, got %t", tt.value, tt.isValid, isValid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,24 @@
|
|||||||
|
// 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 config
|
package config
|
||||||
|
|
||||||
type Flannel struct {
|
type Flannel struct {
|
||||||
EtcdEndpoint string `yaml:"etcd_endpoint" env:"FLANNELD_ETCD_ENDPOINT"`
|
EtcdEndpoints string `yaml:"etcd_endpoints" env:"FLANNELD_ETCD_ENDPOINTS"`
|
||||||
|
EtcdCAFile string `yaml:"etcd_cafile" env:"FLANNELD_ETCD_CAFILE"`
|
||||||
|
EtcdCertFile string `yaml:"etcd_certfile" env:"FLANNELD_ETCD_CERTFILE"`
|
||||||
|
EtcdKeyFile string `yaml:"etcd_keyfile" env:"FLANNELD_ETCD_KEYFILE"`
|
||||||
EtcdPrefix string `yaml:"etcd_prefix" env:"FLANNELD_ETCD_PREFIX"`
|
EtcdPrefix string `yaml:"etcd_prefix" env:"FLANNELD_ETCD_PREFIX"`
|
||||||
IPMasq string `yaml:"ip_masq" env:"FLANNELD_IP_MASQ"`
|
IPMasq string `yaml:"ip_masq" env:"FLANNELD_IP_MASQ"`
|
||||||
SubnetFile string `yaml:"subnet_file" env:"FLANNELD_SUBNET_FILE"`
|
SubnetFile string `yaml:"subnet_file" env:"FLANNELD_SUBNET_FILE"`
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
@ -1,3 +1,17 @@
|
|||||||
|
// 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 config
|
package config
|
||||||
|
|
||||||
type Locksmith struct {
|
type Locksmith struct {
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
@ -27,6 +25,7 @@ func IsScript(userdata string) bool {
|
|||||||
return strings.HasPrefix(header, "#!")
|
return strings.HasPrefix(header, "#!")
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewScript(userdata string) (Script, error) {
|
func NewScript(userdata string) (*Script, error) {
|
||||||
return Script(userdata), nil
|
s := Script(userdata)
|
||||||
|
return &s, nil
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
@ -22,7 +20,7 @@ type Unit struct {
|
|||||||
Enable bool `yaml:"enable"`
|
Enable bool `yaml:"enable"`
|
||||||
Runtime bool `yaml:"runtime"`
|
Runtime bool `yaml:"runtime"`
|
||||||
Content string `yaml:"content"`
|
Content string `yaml:"content"`
|
||||||
Command string `yaml:"command" valid:"start,stop,restart,reload,try-restart,reload-or-restart,reload-or-try-restart"`
|
Command string `yaml:"command" valid:"^(start|stop|restart|reload|try-restart|reload-or-restart|reload-or-try-restart)$"`
|
||||||
DropIns []UnitDropIn `yaml:"drop_ins"`
|
DropIns []UnitDropIn `yaml:"drop_ins"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
46
config/unit_test.go
Normal file
46
config/unit_test.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCommandValid(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
value string
|
||||||
|
|
||||||
|
isValid bool
|
||||||
|
}{
|
||||||
|
{value: "start", isValid: true},
|
||||||
|
{value: "stop", isValid: true},
|
||||||
|
{value: "restart", isValid: true},
|
||||||
|
{value: "reload", isValid: true},
|
||||||
|
{value: "try-restart", isValid: true},
|
||||||
|
{value: "reload-or-restart", isValid: true},
|
||||||
|
{value: "reload-or-try-restart", isValid: true},
|
||||||
|
{value: "tryrestart", isValid: false},
|
||||||
|
{value: "unknown", isValid: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
isValid := (nil == AssertStructValid(Unit{Command: tt.value}))
|
||||||
|
if tt.isValid != isValid {
|
||||||
|
t.Errorf("bad assert (%s): want %t, got %t", tt.value, tt.isValid, isValid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,23 +1,21 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
type Update struct {
|
type Update struct {
|
||||||
RebootStrategy string `yaml:"reboot_strategy" env:"REBOOT_STRATEGY" valid:"best-effort,etcd-lock,reboot,off,false"`
|
RebootStrategy string `yaml:"reboot_strategy" env:"REBOOT_STRATEGY" valid:"^(best-effort|etcd-lock|reboot|off)$"`
|
||||||
Group string `yaml:"group" env:"GROUP"`
|
Group string `yaml:"group" env:"GROUP"`
|
||||||
Server string `yaml:"server" env:"SERVER"`
|
Server string `yaml:"server" env:"SERVER"`
|
||||||
}
|
}
|
||||||
|
43
config/update_test.go
Normal file
43
config/update_test.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRebootStrategyValid(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
value string
|
||||||
|
|
||||||
|
isValid bool
|
||||||
|
}{
|
||||||
|
{value: "best-effort", isValid: true},
|
||||||
|
{value: "etcd-lock", isValid: true},
|
||||||
|
{value: "reboot", isValid: true},
|
||||||
|
{value: "off", isValid: true},
|
||||||
|
{value: "besteffort", isValid: false},
|
||||||
|
{value: "unknown", isValid: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
isValid := (nil == AssertStructValid(Update{RebootStrategy: tt.value}))
|
||||||
|
if tt.isValid != isValid {
|
||||||
|
t.Errorf("bad assert (%s): want %t, got %t", tt.value, tt.isValid, isValid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
@ -21,6 +19,7 @@ type User struct {
|
|||||||
PasswordHash string `yaml:"passwd"`
|
PasswordHash string `yaml:"passwd"`
|
||||||
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"`
|
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"`
|
||||||
SSHImportGithubUser string `yaml:"coreos_ssh_import_github"`
|
SSHImportGithubUser string `yaml:"coreos_ssh_import_github"`
|
||||||
|
SSHImportGithubUsers []string `yaml:"coreos_ssh_import_github_users"`
|
||||||
SSHImportURL string `yaml:"coreos_ssh_import_url"`
|
SSHImportURL string `yaml:"coreos_ssh_import_url"`
|
||||||
GECOS string `yaml:"gecos"`
|
GECOS string `yaml:"gecos"`
|
||||||
Homedir string `yaml:"homedir"`
|
Homedir string `yaml:"homedir"`
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
|
@ -1,24 +1,25 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
"github.com/coreos/coreos-cloudinit/config"
|
||||||
)
|
)
|
||||||
@ -27,8 +28,40 @@ type rule func(config node, report *Report)
|
|||||||
|
|
||||||
// Rules contains all of the validation rules.
|
// Rules contains all of the validation rules.
|
||||||
var Rules []rule = []rule{
|
var Rules []rule = []rule{
|
||||||
|
checkDiscoveryUrl,
|
||||||
|
checkEncoding,
|
||||||
checkStructure,
|
checkStructure,
|
||||||
checkValidity,
|
checkValidity,
|
||||||
|
checkWriteFiles,
|
||||||
|
checkWriteFilesUnderCoreos,
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkDiscoveryUrl verifies that the string is a valid url.
|
||||||
|
func checkDiscoveryUrl(cfg node, report *Report) {
|
||||||
|
c := cfg.Child("coreos").Child("etcd").Child("discovery")
|
||||||
|
if !c.IsValid() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := url.ParseRequestURI(c.String()); err != nil {
|
||||||
|
report.Warning(c.line, "discovery URL is not valid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkEncoding validates that, for each file under 'write_files', the
|
||||||
|
// content can be decoded given the specified encoding.
|
||||||
|
func checkEncoding(cfg node, report *Report) {
|
||||||
|
for _, f := range cfg.Child("write_files").children {
|
||||||
|
e := f.Child("encoding")
|
||||||
|
if !e.IsValid() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
c := f.Child("content")
|
||||||
|
if _, err := config.DecodeContent(c.String(), e.String()); err != nil {
|
||||||
|
report.Error(c.line, fmt.Sprintf("content cannot be decoded as %q", e.String()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkStructure compares the provided config to the empty config.CloudConfig
|
// checkStructure compares the provided config to the empty config.CloudConfig
|
||||||
@ -67,6 +100,24 @@ func checkNodeStructure(n, g node, r *Report) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isCompatible determines if the type of kind n can be converted to the type
|
||||||
|
// of kind g in the context of YAML. This is not an exhaustive list, but its
|
||||||
|
// enough for the purposes of cloud-config validation.
|
||||||
|
func isCompatible(n, g reflect.Kind) bool {
|
||||||
|
switch g {
|
||||||
|
case reflect.String:
|
||||||
|
return n == reflect.String || n == reflect.Int || n == reflect.Float64 || n == reflect.Bool
|
||||||
|
case reflect.Struct:
|
||||||
|
return n == reflect.Struct || n == reflect.Map
|
||||||
|
case reflect.Float64:
|
||||||
|
return n == reflect.Float64 || n == reflect.Int
|
||||||
|
case reflect.Bool, reflect.Slice, reflect.Int:
|
||||||
|
return n == g
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("isCompatible(): unhandled kind %s", g))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// checkValidity checks the value of every node in the provided config by
|
// checkValidity checks the value of every node in the provided config by
|
||||||
// running config.AssertValid() on it.
|
// running config.AssertValid() on it.
|
||||||
func checkValidity(cfg node, report *Report) {
|
func checkValidity(cfg node, report *Report) {
|
||||||
@ -76,7 +127,7 @@ func checkValidity(cfg node, report *Report) {
|
|||||||
|
|
||||||
func checkNodeValidity(n, g node, r *Report) {
|
func checkNodeValidity(n, g node, r *Report) {
|
||||||
if err := config.AssertValid(n.Value, g.field.Tag.Get("valid")); err != nil {
|
if err := config.AssertValid(n.Value, g.field.Tag.Get("valid")); err != nil {
|
||||||
r.Error(n.line, fmt.Sprintf("invalid value %v", n.Value))
|
r.Error(n.line, fmt.Sprintf("invalid value %v", n.Value.Interface()))
|
||||||
}
|
}
|
||||||
switch g.Kind() {
|
switch g.Kind() {
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
@ -98,18 +149,29 @@ func checkNodeValidity(n, g node, r *Report) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// isCompatible determines if the type of kind n can be converted to the type
|
// checkWriteFiles checks to make sure that the target file can actually be
|
||||||
// of kind g in the context of YAML. This is not an exhaustive list, but its
|
// written. Note that this check is approximate (it only checks to see if the file
|
||||||
// enough for the purposes of cloud-config validation.
|
// is under /usr).
|
||||||
func isCompatible(n, g reflect.Kind) bool {
|
func checkWriteFiles(cfg node, report *Report) {
|
||||||
switch g {
|
for _, f := range cfg.Child("write_files").children {
|
||||||
case reflect.String:
|
c := f.Child("path")
|
||||||
return n == reflect.String || n == reflect.Int || n == reflect.Float64 || n == reflect.Bool
|
if !c.IsValid() {
|
||||||
case reflect.Struct:
|
continue
|
||||||
return n == reflect.Struct || n == reflect.Map
|
}
|
||||||
case reflect.Bool, reflect.Slice, reflect.Int, reflect.Float64:
|
|
||||||
return n == g
|
d := path.Dir(c.String())
|
||||||
default:
|
switch {
|
||||||
panic(fmt.Sprintf("isCompatible(): unhandled kind %s", g))
|
case strings.HasPrefix(d, "/usr"):
|
||||||
|
report.Error(c.line, "file cannot be written to a read-only filesystem")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkWriteFilesUnderCoreos checks to see if the 'write_files' node is a
|
||||||
|
// child of 'coreos' (it shouldn't be).
|
||||||
|
func checkWriteFilesUnderCoreos(cfg node, report *Report) {
|
||||||
|
c := cfg.Child("coreos").Child("write_files")
|
||||||
|
if c.IsValid() {
|
||||||
|
report.Info(c.line, "write_files doesn't belong under coreos")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
@ -21,6 +19,85 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestCheckDiscoveryUrl(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
config string
|
||||||
|
|
||||||
|
entries []Entry
|
||||||
|
}{
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
config: "coreos:\n etcd:\n discovery: https://discovery.etcd.io/00000000000000000000000000000000",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "coreos:\n etcd:\n discovery: http://custom.domain/mytoken",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "coreos:\n etcd:\n discovery: disco",
|
||||||
|
entries: []Entry{{entryWarning, "discovery URL is not valid", 3}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
r := Report{}
|
||||||
|
n, err := parseCloudConfig([]byte(tt.config), &r)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
checkDiscoveryUrl(n, &r)
|
||||||
|
|
||||||
|
if e := r.Entries(); !reflect.DeepEqual(tt.entries, e) {
|
||||||
|
t.Errorf("bad report (%d, %q): want %#v, got %#v", i, tt.config, tt.entries, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckEncoding(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
config string
|
||||||
|
|
||||||
|
entries []Entry
|
||||||
|
}{
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - encoding: base64\n content: aGVsbG8K",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - content: !!binary aGVsbG8K",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - encoding: base64\n content: !!binary aGVsbG8K",
|
||||||
|
entries: []Entry{{entryError, `content cannot be decoded as "base64"`, 3}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - encoding: base64\n content: !!binary YUdWc2JHOEsK",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - encoding: gzip\n content: !!binary H4sIAOC3tVQAA8tIzcnJ5wIAIDA6NgYAAAA=",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - encoding: gzip+base64\n content: H4sIAOC3tVQAA8tIzcnJ5wIAIDA6NgYAAAA=",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - encoding: custom\n content: hello",
|
||||||
|
entries: []Entry{{entryError, `content cannot be decoded as "custom"`, 3}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
r := Report{}
|
||||||
|
n, err := parseCloudConfig([]byte(tt.config), &r)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
checkEncoding(n, &r)
|
||||||
|
|
||||||
|
if e := r.Entries(); !reflect.DeepEqual(tt.entries, e) {
|
||||||
|
t.Errorf("bad report (%d, %q): want %#v, got %#v", i, tt.config, tt.entries, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckStructure(t *testing.T) {
|
func TestCheckStructure(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
config string
|
config string
|
||||||
@ -249,3 +326,74 @@ func TestCheckValidity(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCheckWriteFiles(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
config string
|
||||||
|
|
||||||
|
entries []Entry
|
||||||
|
}{
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - path: /valid",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - path: /tmp/usr/valid",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - path: /usr/invalid",
|
||||||
|
entries: []Entry{{entryError, "file cannot be written to a read-only filesystem", 2}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "write-files:\n - path: /tmp/../usr/invalid",
|
||||||
|
entries: []Entry{{entryError, "file cannot be written to a read-only filesystem", 2}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
r := Report{}
|
||||||
|
n, err := parseCloudConfig([]byte(tt.config), &r)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
checkWriteFiles(n, &r)
|
||||||
|
|
||||||
|
if e := r.Entries(); !reflect.DeepEqual(tt.entries, e) {
|
||||||
|
t.Errorf("bad report (%d, %q): want %#v, got %#v", i, tt.config, tt.entries, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCheckWriteFilesUnderCoreos(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
config string
|
||||||
|
|
||||||
|
entries []Entry
|
||||||
|
}{
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - path: /hi",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "coreos:\n write_files:\n - path: /hi",
|
||||||
|
entries: []Entry{{entryInfo, "write_files doesn't belong under coreos", 2}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "coreos:\n write-files:\n - path: /hyphen",
|
||||||
|
entries: []Entry{{entryInfo, "write_files doesn't belong under coreos", 2}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
r := Report{}
|
||||||
|
n, err := parseCloudConfig([]byte(tt.config), &r)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
checkWriteFilesUnderCoreos(n, &r)
|
||||||
|
|
||||||
|
if e := r.Entries(); !reflect.DeepEqual(tt.entries, e) {
|
||||||
|
t.Errorf("bad report (%d, %q): want %#v, got %#v", i, tt.config, tt.entries, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
@ -65,7 +63,6 @@ func validateCloudConfig(config []byte, rules []rule) (report Report, err error)
|
|||||||
return report, err
|
return report, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c = normalizeNodeNames(c, &report)
|
|
||||||
for _, r := range rules {
|
for _, r := range rules {
|
||||||
r(c, &report)
|
r(c, &report)
|
||||||
}
|
}
|
||||||
@ -75,30 +72,79 @@ func validateCloudConfig(config []byte, rules []rule) (report Report, err error)
|
|||||||
// parseCloudConfig parses the provided config into a node structure and logs
|
// parseCloudConfig parses the provided config into a node structure and logs
|
||||||
// any parsing issues into the provided report. Unrecoverable errors are
|
// any parsing issues into the provided report. Unrecoverable errors are
|
||||||
// returned as an error.
|
// returned as an error.
|
||||||
func parseCloudConfig(config []byte, report *Report) (n node, err error) {
|
func parseCloudConfig(cfg []byte, report *Report) (node, error) {
|
||||||
var raw map[interface{}]interface{}
|
yaml.UnmarshalMappingKeyTransform = func(nameIn string) (nameOut string) {
|
||||||
if err := yaml.Unmarshal(config, &raw); err != nil {
|
return nameIn
|
||||||
|
}
|
||||||
|
// unmarshal the config into an implicitly-typed form. The yaml library
|
||||||
|
// will implicitly convert types into their normalized form
|
||||||
|
// (e.g. 0744 -> 484, off -> false).
|
||||||
|
var weak map[interface{}]interface{}
|
||||||
|
if err := yaml.Unmarshal(cfg, &weak); err != nil {
|
||||||
matches := yamlLineError.FindStringSubmatch(err.Error())
|
matches := yamlLineError.FindStringSubmatch(err.Error())
|
||||||
if len(matches) == 3 {
|
if len(matches) == 3 {
|
||||||
line, err := strconv.Atoi(matches[1])
|
line, err := strconv.Atoi(matches[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return node{}, err
|
||||||
}
|
}
|
||||||
msg := matches[2]
|
msg := matches[2]
|
||||||
report.Error(line, msg)
|
report.Error(line, msg)
|
||||||
return n, nil
|
return node{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
matches = yamlError.FindStringSubmatch(err.Error())
|
matches = yamlError.FindStringSubmatch(err.Error())
|
||||||
if len(matches) == 2 {
|
if len(matches) == 2 {
|
||||||
report.Error(1, matches[1])
|
report.Error(1, matches[1])
|
||||||
return n, nil
|
return node{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return n, errors.New("couldn't parse yaml error")
|
return node{}, errors.New("couldn't parse yaml error")
|
||||||
|
}
|
||||||
|
w := NewNode(weak, NewContext(cfg))
|
||||||
|
w = normalizeNodeNames(w, report)
|
||||||
|
|
||||||
|
// unmarshal the config into the explicitly-typed form.
|
||||||
|
yaml.UnmarshalMappingKeyTransform = func(nameIn string) (nameOut string) {
|
||||||
|
return strings.Replace(nameIn, "-", "_", -1)
|
||||||
|
}
|
||||||
|
var strong config.CloudConfig
|
||||||
|
if err := yaml.Unmarshal([]byte(cfg), &strong); err != nil {
|
||||||
|
return node{}, err
|
||||||
|
}
|
||||||
|
s := NewNode(strong, NewContext(cfg))
|
||||||
|
|
||||||
|
// coerceNodes weak nodes and strong nodes. strong nodes replace weak nodes
|
||||||
|
// if they are compatible types (this happens when the yaml library
|
||||||
|
// converts the input).
|
||||||
|
// (e.g. weak 484 is replaced by strong 0744, weak 4 is not replaced by
|
||||||
|
// strong false)
|
||||||
|
return coerceNodes(w, s), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// coerceNodes recursively evaluates two nodes, returning a new node containing
|
||||||
|
// either the weak or strong node's value and its recursively processed
|
||||||
|
// children. The strong node's value is used if the two nodes are leafs, are
|
||||||
|
// both valid, and are compatible types (defined by isCompatible()). The weak
|
||||||
|
// node is returned in all other cases. coerceNodes is used to counteract the
|
||||||
|
// effects of yaml's automatic type conversion. The weak node is the one
|
||||||
|
// resulting from unmarshalling into an empty interface{} (the type is
|
||||||
|
// inferred). The strong node is the one resulting from unmarshalling into a
|
||||||
|
// struct. If the two nodes are of compatible types, the yaml library correctly
|
||||||
|
// parsed the value into the strongly typed unmarshalling. In this case, we
|
||||||
|
// prefer the strong node because its actually the type we are expecting.
|
||||||
|
func coerceNodes(w, s node) node {
|
||||||
|
n := w
|
||||||
|
n.children = nil
|
||||||
|
if len(w.children) == 0 && len(s.children) == 0 &&
|
||||||
|
w.IsValid() && s.IsValid() &&
|
||||||
|
isCompatible(w.Kind(), s.Kind()) {
|
||||||
|
n.Value = s.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewNode(raw, NewContext(config)), nil
|
for _, cw := range w.children {
|
||||||
|
n.children = append(n.children, coerceNodes(cw, s.Child(cw.name)))
|
||||||
|
}
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalizeNodeNames replaces all occurences of '-' with '_' within key names
|
// normalizeNodeNames replaces all occurences of '-' with '_' within key names
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package validate
|
package validate
|
||||||
|
|
||||||
@ -65,6 +63,31 @@ func TestValidateCloudConfig(t *testing.T) {
|
|||||||
rules: []rule{func(_ node, _ *Report) { panic("something happened") }},
|
rules: []rule{func(_ node, _ *Report) { panic("something happened") }},
|
||||||
err: errors.New("something happened"),
|
err: errors.New("something happened"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - permissions: 0744",
|
||||||
|
rules: Rules,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - permissions: '0744'",
|
||||||
|
rules: Rules,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - permissions: 744",
|
||||||
|
rules: Rules,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "write_files:\n - permissions: '744'",
|
||||||
|
rules: Rules,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "coreos:\n update:\n reboot-strategy: off",
|
||||||
|
rules: Rules,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: "coreos:\n update:\n reboot-strategy: false",
|
||||||
|
rules: Rules,
|
||||||
|
report: Report{entries: []Entry{{entryError, "invalid value false", 3}}},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@ -36,12 +34,13 @@ import (
|
|||||||
"github.com/coreos/coreos-cloudinit/datasource/url"
|
"github.com/coreos/coreos-cloudinit/datasource/url"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/waagent"
|
"github.com/coreos/coreos-cloudinit/datasource/waagent"
|
||||||
"github.com/coreos/coreos-cloudinit/initialize"
|
"github.com/coreos/coreos-cloudinit/initialize"
|
||||||
|
"github.com/coreos/coreos-cloudinit/network"
|
||||||
"github.com/coreos/coreos-cloudinit/pkg"
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
"github.com/coreos/coreos-cloudinit/system"
|
"github.com/coreos/coreos-cloudinit/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
version = "1.0.2+git"
|
version = "1.3.3+git"
|
||||||
datasourceInterval = 100 * time.Millisecond
|
datasourceInterval = 100 * time.Millisecond
|
||||||
datasourceMaxInterval = 30 * time.Second
|
datasourceMaxInterval = 30 * time.Second
|
||||||
datasourceTimeout = 5 * time.Minute
|
datasourceTimeout = 5 * time.Minute
|
||||||
@ -114,6 +113,9 @@ var (
|
|||||||
"azure": oemConfig{
|
"azure": oemConfig{
|
||||||
"from-waagent": "/var/lib/waagent",
|
"from-waagent": "/var/lib/waagent",
|
||||||
},
|
},
|
||||||
|
"cloudsigma": oemConfig{
|
||||||
|
"from-cloudsigma-metadata": "true",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -185,43 +187,18 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Fetching meta-data from datasource of type %q\n", ds.Type())
|
fmt.Printf("Fetching meta-data from datasource of type %q\n", ds.Type())
|
||||||
metadataBytes, err := ds.FetchMetadata()
|
metadata, err := ds.FetchMetadata()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed fetching meta-data from datasource: %v\n", err)
|
fmt.Printf("Failed fetching meta-data from datasource: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract IPv4 addresses from metadata if possible
|
|
||||||
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)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.sshKeyName, metadata)
|
||||||
userdata := env.Apply(string(userdataBytes))
|
userdata := env.Apply(string(userdataBytes))
|
||||||
|
|
||||||
var ccm, ccu *config.CloudConfig
|
var ccu *config.CloudConfig
|
||||||
var script *config.Script
|
var script *config.Script
|
||||||
if ccm, err = initialize.ParseMetaData(string(metadataBytes)); err != nil {
|
|
||||||
fmt.Printf("Failed to parse meta-data: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ccm != nil && flags.convertNetconf != "" {
|
|
||||||
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)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
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\nContinuing...\n", err)
|
fmt.Printf("Failed to parse user-data: %v\nContinuing...\n", err)
|
||||||
failure = true
|
failure = true
|
||||||
@ -229,33 +206,36 @@ func main() {
|
|||||||
switch t := ud.(type) {
|
switch t := ud.(type) {
|
||||||
case *config.CloudConfig:
|
case *config.CloudConfig:
|
||||||
ccu = t
|
ccu = t
|
||||||
case config.Script:
|
case *config.Script:
|
||||||
script = &t
|
script = t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var cc *config.CloudConfig
|
|
||||||
if ccm != nil && ccu != nil {
|
|
||||||
fmt.Println("Merging cloud-config from meta-data and user-data")
|
fmt.Println("Merging cloud-config from meta-data and user-data")
|
||||||
merged := mergeCloudConfig(*ccm, *ccu)
|
cc := mergeConfigs(ccu, metadata)
|
||||||
cc = &merged
|
|
||||||
} else if ccm != nil && ccu == nil {
|
|
||||||
fmt.Println("Processing cloud-config from meta-data")
|
|
||||||
cc = ccm
|
|
||||||
} else if ccm == nil && ccu != nil {
|
|
||||||
fmt.Println("Processing cloud-config from user-data")
|
|
||||||
cc = ccu
|
|
||||||
} else {
|
|
||||||
fmt.Println("No cloud-config data to handle.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if cc != nil {
|
var ifaces []network.InterfaceGenerator
|
||||||
if err = initialize.Apply(*cc, env); err != nil {
|
if flags.convertNetconf != "" {
|
||||||
fmt.Printf("Failed to apply cloud-config: %v\n", err)
|
var err error
|
||||||
|
switch flags.convertNetconf {
|
||||||
|
case "debian":
|
||||||
|
ifaces, err = network.ProcessDebianNetconf(metadata.NetworkConfig)
|
||||||
|
case "digitalocean":
|
||||||
|
ifaces, err = network.ProcessDigitalOceanNetconf(metadata.NetworkConfig)
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("Unsupported network config format %q", flags.convertNetconf)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to generate interfaces: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = initialize.Apply(cc, ifaces, env); err != nil {
|
||||||
|
fmt.Printf("Failed to apply cloud-config: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
if script != nil {
|
if script != nil {
|
||||||
if err = runScript(*script, env); err != nil {
|
if err = runScript(*script, env); err != nil {
|
||||||
fmt.Printf("Failed to run script: %v\n", err)
|
fmt.Printf("Failed to run script: %v\n", err)
|
||||||
@ -268,38 +248,25 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// mergeCloudConfig merges certain options from mdcc (a CloudConfig derived from
|
// mergeConfigs merges certain options from md (meta-data from the datasource)
|
||||||
// meta-data) onto udcc (a CloudConfig derived from user-data), if they are
|
// onto cc (a CloudConfig derived from user-data), if they are not already set
|
||||||
// not already set on udcc (i.e. user-data always takes precedence)
|
// on cc (i.e. user-data always takes precedence)
|
||||||
// NB: This needs to be kept in sync with ParseMetadata so that it tracks all
|
func mergeConfigs(cc *config.CloudConfig, md datasource.Metadata) (out config.CloudConfig) {
|
||||||
// elements of a CloudConfig which that function can populate.
|
if cc != nil {
|
||||||
func mergeCloudConfig(mdcc, udcc config.CloudConfig) (cc config.CloudConfig) {
|
out = *cc
|
||||||
if mdcc.Hostname != "" {
|
|
||||||
if udcc.Hostname != "" {
|
|
||||||
fmt.Printf("Warning: user-data hostname (%s) overrides metadata hostname (%s)\n", udcc.Hostname, mdcc.Hostname)
|
|
||||||
} else {
|
|
||||||
udcc.Hostname = mdcc.Hostname
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
if md.Hostname != "" {
|
||||||
for _, key := range mdcc.SSHAuthorizedKeys {
|
if out.Hostname != "" {
|
||||||
udcc.SSHAuthorizedKeys = append(udcc.SSHAuthorizedKeys, key)
|
fmt.Printf("Warning: user-data hostname (%s) overrides metadata hostname (%s)\n", out.Hostname, md.Hostname)
|
||||||
}
|
|
||||||
if mdcc.NetworkConfigPath != "" {
|
|
||||||
if udcc.NetworkConfigPath != "" {
|
|
||||||
fmt.Printf("Warning: user-data NetworkConfigPath %s overrides metadata NetworkConfigPath %s\n", udcc.NetworkConfigPath, mdcc.NetworkConfigPath)
|
|
||||||
} else {
|
} else {
|
||||||
udcc.NetworkConfigPath = mdcc.NetworkConfigPath
|
out.Hostname = md.Hostname
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if mdcc.NetworkConfig != "" {
|
for _, key := range md.SSHPublicKeys {
|
||||||
if udcc.NetworkConfig != "" {
|
out.SSHAuthorizedKeys = append(out.SSHAuthorizedKeys, key)
|
||||||
fmt.Printf("Warning: user-data NetworkConfig %s overrides metadata NetworkConfig %s\n", udcc.NetworkConfig, mdcc.NetworkConfig)
|
|
||||||
} else {
|
|
||||||
udcc.NetworkConfig = mdcc.NetworkConfig
|
|
||||||
}
|
}
|
||||||
}
|
return
|
||||||
return udcc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDatasources creates a slice of possible Datasources for cloudinit based
|
// getDatasources creates a slice of possible Datasources for cloudinit based
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
@ -21,116 +19,71 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
"github.com/coreos/coreos-cloudinit/config"
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMergeCloudConfig(t *testing.T) {
|
func TestMergeConfigs(t *testing.T) {
|
||||||
simplecc := config.CloudConfig{
|
tests := []struct {
|
||||||
SSHAuthorizedKeys: []string{"abc", "def"},
|
cc *config.CloudConfig
|
||||||
Hostname: "foobar",
|
md datasource.Metadata
|
||||||
NetworkConfigPath: "/path/somewhere",
|
|
||||||
NetworkConfig: `{}`,
|
out config.CloudConfig
|
||||||
}
|
|
||||||
for i, tt := range []struct {
|
|
||||||
udcc config.CloudConfig
|
|
||||||
mdcc config.CloudConfig
|
|
||||||
want config.CloudConfig
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
// If mdcc is empty, udcc should be returned unchanged
|
// If md is empty and cc is nil, result should be empty
|
||||||
simplecc,
|
out: config.CloudConfig{},
|
||||||
config.CloudConfig{},
|
|
||||||
simplecc,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// If udcc is empty, mdcc should be returned unchanged(overridden)
|
// If md and cc are empty, result should be empty
|
||||||
config.CloudConfig{},
|
cc: &config.CloudConfig{},
|
||||||
simplecc,
|
out: config.CloudConfig{},
|
||||||
simplecc,
|
},
|
||||||
|
{
|
||||||
|
// If cc is empty, cc should be returned unchanged
|
||||||
|
cc: &config.CloudConfig{SSHAuthorizedKeys: []string{"abc", "def"}, Hostname: "cc-host"},
|
||||||
|
out: config.CloudConfig{SSHAuthorizedKeys: []string{"abc", "def"}, Hostname: "cc-host"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// If cc is empty, cc should be returned unchanged(overridden)
|
||||||
|
cc: &config.CloudConfig{},
|
||||||
|
md: datasource.Metadata{Hostname: "md-host", SSHPublicKeys: map[string]string{"key": "ghi"}},
|
||||||
|
out: config.CloudConfig{SSHAuthorizedKeys: []string{"ghi"}, Hostname: "md-host"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// If cc is nil, cc should be returned unchanged(overridden)
|
||||||
|
md: datasource.Metadata{Hostname: "md-host", SSHPublicKeys: map[string]string{"key": "ghi"}},
|
||||||
|
out: config.CloudConfig{SSHAuthorizedKeys: []string{"ghi"}, Hostname: "md-host"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// user-data should override completely in the case of conflicts
|
// user-data should override completely in the case of conflicts
|
||||||
simplecc,
|
cc: &config.CloudConfig{SSHAuthorizedKeys: []string{"abc", "def"}, Hostname: "cc-host"},
|
||||||
config.CloudConfig{
|
md: datasource.Metadata{Hostname: "md-host"},
|
||||||
Hostname: "meta-hostname",
|
out: config.CloudConfig{SSHAuthorizedKeys: []string{"abc", "def"}, Hostname: "cc-host"},
|
||||||
NetworkConfigPath: "/path/meta",
|
|
||||||
NetworkConfig: `{"hostname":"test"}`,
|
|
||||||
},
|
|
||||||
simplecc,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Mixed merge should succeed
|
// Mixed merge should succeed
|
||||||
config.CloudConfig{
|
cc: &config.CloudConfig{SSHAuthorizedKeys: []string{"abc", "def"}, Hostname: "cc-host"},
|
||||||
SSHAuthorizedKeys: []string{"abc", "def"},
|
md: datasource.Metadata{Hostname: "md-host", SSHPublicKeys: map[string]string{"key": "ghi"}},
|
||||||
Hostname: "user-hostname",
|
out: config.CloudConfig{SSHAuthorizedKeys: []string{"abc", "def", "ghi"}, Hostname: "cc-host"},
|
||||||
NetworkConfigPath: "/path/somewhere",
|
|
||||||
NetworkConfig: `{"hostname":"test"}`,
|
|
||||||
},
|
|
||||||
config.CloudConfig{
|
|
||||||
SSHAuthorizedKeys: []string{"woof", "qux"},
|
|
||||||
Hostname: "meta-hostname",
|
|
||||||
},
|
|
||||||
config.CloudConfig{
|
|
||||||
SSHAuthorizedKeys: []string{"abc", "def", "woof", "qux"},
|
|
||||||
Hostname: "user-hostname",
|
|
||||||
NetworkConfigPath: "/path/somewhere",
|
|
||||||
NetworkConfig: `{"hostname":"test"}`,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Completely non-conflicting merge should be fine
|
// Completely non-conflicting merge should be fine
|
||||||
config.CloudConfig{
|
cc: &config.CloudConfig{Hostname: "cc-host"},
|
||||||
Hostname: "supercool",
|
md: datasource.Metadata{SSHPublicKeys: map[string]string{"zaphod": "beeblebrox"}},
|
||||||
},
|
out: config.CloudConfig{Hostname: "cc-host", SSHAuthorizedKeys: []string{"beeblebrox"}},
|
||||||
config.CloudConfig{
|
|
||||||
SSHAuthorizedKeys: []string{"zaphod", "beeblebrox"},
|
|
||||||
NetworkConfigPath: "/dev/fun",
|
|
||||||
NetworkConfig: `{"hostname":"test"}`,
|
|
||||||
},
|
|
||||||
config.CloudConfig{
|
|
||||||
Hostname: "supercool",
|
|
||||||
SSHAuthorizedKeys: []string{"zaphod", "beeblebrox"},
|
|
||||||
NetworkConfigPath: "/dev/fun",
|
|
||||||
NetworkConfig: `{"hostname":"test"}`,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Non-mergeable settings in user-data should not be affected
|
// Non-mergeable settings in user-data should not be affected
|
||||||
config.CloudConfig{
|
cc: &config.CloudConfig{Hostname: "cc-host", ManageEtcHosts: config.EtcHosts("lolz")},
|
||||||
Hostname: "mememe",
|
md: datasource.Metadata{Hostname: "md-host"},
|
||||||
ManageEtcHosts: config.EtcHosts("lolz"),
|
out: config.CloudConfig{Hostname: "cc-host", ManageEtcHosts: config.EtcHosts("lolz")},
|
||||||
},
|
},
|
||||||
config.CloudConfig{
|
}
|
||||||
Hostname: "youyouyou",
|
|
||||||
NetworkConfigPath: "meta-meta-yo",
|
for i, tt := range tests {
|
||||||
NetworkConfig: `{"hostname":"test"}`,
|
out := mergeConfigs(tt.cc, tt.md)
|
||||||
},
|
if !reflect.DeepEqual(tt.out, out) {
|
||||||
config.CloudConfig{
|
t.Errorf("bad config (%d): want %#v, got %#v", i, tt.out, out)
|
||||||
Hostname: "mememe",
|
|
||||||
ManageEtcHosts: config.EtcHosts("lolz"),
|
|
||||||
NetworkConfigPath: "meta-meta-yo",
|
|
||||||
NetworkConfig: `{"hostname":"test"}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Non-mergeable (unexpected) settings in meta-data are ignored
|
|
||||||
config.CloudConfig{
|
|
||||||
Hostname: "mememe",
|
|
||||||
},
|
|
||||||
config.CloudConfig{
|
|
||||||
ManageEtcHosts: config.EtcHosts("lolz"),
|
|
||||||
NetworkConfigPath: "meta-meta-yo",
|
|
||||||
NetworkConfig: `{"hostname":"test"}`,
|
|
||||||
},
|
|
||||||
config.CloudConfig{
|
|
||||||
Hostname: "mememe",
|
|
||||||
NetworkConfigPath: "meta-meta-yo",
|
|
||||||
NetworkConfig: `{"hostname":"test"}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
got := mergeCloudConfig(tt.mdcc, tt.udcc)
|
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
|
||||||
t.Errorf("case #%d: mergeCloudConfig mutated CloudConfig unexpectedly:\ngot:\n%s\nwant:\n%s", i, got, tt.want)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,27 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package configdrive
|
package configdrive
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -49,21 +50,36 @@ func (cd *configDrive) ConfigRoot() string {
|
|||||||
return cd.openstackRoot()
|
return cd.openstackRoot()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cd *configDrive) FetchMetadata() ([]byte, error) {
|
func (cd *configDrive) FetchMetadata() (metadata datasource.Metadata, err error) {
|
||||||
return cd.tryReadFile(path.Join(cd.openstackVersionRoot(), "meta_data.json"))
|
var data []byte
|
||||||
|
var m struct {
|
||||||
|
SSHAuthorizedKeyMap map[string]string `json:"public_keys"`
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
NetworkConfig struct {
|
||||||
|
ContentPath string `json:"content_path"`
|
||||||
|
} `json:"network_config"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if data, err = cd.tryReadFile(path.Join(cd.openstackVersionRoot(), "meta_data.json")); err != nil || len(data) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = json.Unmarshal([]byte(data), &m); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cd *configDrive) FetchUserdata() ([]byte, error) {
|
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) {
|
|
||||||
if filename == "" {
|
|
||||||
return []byte{}, nil
|
|
||||||
}
|
|
||||||
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,66 +1,69 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package configdrive
|
package configdrive
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockFilesystem []string
|
|
||||||
|
|
||||||
func (m mockFilesystem) readFile(filename string) ([]byte, error) {
|
|
||||||
for _, file := range m {
|
|
||||||
if file == filename {
|
|
||||||
return []byte(filename), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, os.ErrNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFetchMetadata(t *testing.T) {
|
func TestFetchMetadata(t *testing.T) {
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
root string
|
root string
|
||||||
filename string
|
files test.MockFilesystem
|
||||||
files mockFilesystem
|
|
||||||
|
metadata datasource.Metadata
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"/",
|
root: "/",
|
||||||
"",
|
files: test.NewMockFilesystem(test.File{Path: "/openstack/latest/meta_data.json", Contents: ""}),
|
||||||
mockFilesystem{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/",
|
root: "/",
|
||||||
"/openstack/latest/meta_data.json",
|
files: test.NewMockFilesystem(test.File{Path: "/openstack/latest/meta_data.json", Contents: `{"ignore": "me"}`}),
|
||||||
mockFilesystem([]string{"/openstack/latest/meta_data.json"}),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/media/configdrive",
|
root: "/",
|
||||||
"/media/configdrive/openstack/latest/meta_data.json",
|
files: test.NewMockFilesystem(test.File{Path: "/openstack/latest/meta_data.json", Contents: `{"hostname": "host"}`}),
|
||||||
mockFilesystem([]string{"/media/configdrive/openstack/latest/meta_data.json"}),
|
metadata: datasource.Metadata{Hostname: "host"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: "/media/configdrive",
|
||||||
|
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"),
|
||||||
|
SSHPublicKeys: map[string]string{
|
||||||
|
"1": "key1",
|
||||||
|
"2": "key2",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
cd := configDrive{tt.root, tt.files.readFile}
|
cd := configDrive{tt.root, tt.files.ReadFile}
|
||||||
filename, err := cd.FetchMetadata()
|
metadata, err := cd.FetchMetadata()
|
||||||
if err != nil {
|
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(filename) != tt.filename {
|
if !reflect.DeepEqual(tt.metadata, metadata) {
|
||||||
t.Fatalf("bad path for %q: want %q, got %q", tt, tt.filename, filename)
|
t.Fatalf("bad metadata for %+v: want %#v, got %#v", tt, tt.metadata, metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,32 +71,33 @@ func TestFetchMetadata(t *testing.T) {
|
|||||||
func TestFetchUserdata(t *testing.T) {
|
func TestFetchUserdata(t *testing.T) {
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
root string
|
root string
|
||||||
filename string
|
files test.MockFilesystem
|
||||||
files mockFilesystem
|
|
||||||
|
userdata string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"/",
|
"/",
|
||||||
|
test.NewMockFilesystem(),
|
||||||
"",
|
"",
|
||||||
mockFilesystem{},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/",
|
"/",
|
||||||
"/openstack/latest/user_data",
|
test.NewMockFilesystem(test.File{Path: "/openstack/latest/user_data", Contents: "userdata"}),
|
||||||
mockFilesystem([]string{"/openstack/latest/user_data"}),
|
"userdata",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/media/configdrive",
|
"/media/configdrive",
|
||||||
"/media/configdrive/openstack/latest/user_data",
|
test.NewMockFilesystem(test.File{Path: "/media/configdrive/openstack/latest/user_data", Contents: "userdata"}),
|
||||||
mockFilesystem([]string{"/media/configdrive/openstack/latest/user_data"}),
|
"userdata",
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
cd := configDrive{tt.root, tt.files.readFile}
|
cd := configDrive{tt.root, tt.files.ReadFile}
|
||||||
filename, err := cd.FetchUserdata()
|
userdata, err := cd.FetchUserdata()
|
||||||
if err != nil {
|
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(filename) != tt.filename {
|
if string(userdata) != tt.userdata {
|
||||||
t.Fatalf("bad path for %q: want %q, got %q", tt, tt.filename, filename)
|
t.Fatalf("bad userdata for %+v: want %q, got %q", tt, tt.userdata, userdata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,38 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package datasource
|
package datasource
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
type Datasource interface {
|
type Datasource interface {
|
||||||
IsAvailable() bool
|
IsAvailable() bool
|
||||||
AvailabilityChanges() bool
|
AvailabilityChanges() bool
|
||||||
ConfigRoot() string
|
ConfigRoot() string
|
||||||
FetchMetadata() ([]byte, error)
|
FetchMetadata() (Metadata, error)
|
||||||
FetchUserdata() ([]byte, error)
|
FetchUserdata() ([]byte, error)
|
||||||
FetchNetworkConfig(string) ([]byte, error)
|
|
||||||
Type() string
|
Type() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Metadata struct {
|
||||||
|
PublicIPv4 net.IP
|
||||||
|
PublicIPv6 net.IP
|
||||||
|
PrivateIPv4 net.IP
|
||||||
|
PrivateIPv6 net.IP
|
||||||
|
Hostname string
|
||||||
|
SSHPublicKeys map[string]string
|
||||||
|
NetworkConfig []byte
|
||||||
|
}
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package file
|
package file
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
)
|
)
|
||||||
|
|
||||||
type localFile struct {
|
type localFile struct {
|
||||||
@ -42,18 +42,14 @@ func (f *localFile) ConfigRoot() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *localFile) FetchMetadata() ([]byte, error) {
|
func (f *localFile) FetchMetadata() (datasource.Metadata, error) {
|
||||||
return []byte{}, nil
|
return datasource.Metadata{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *localFile) FetchUserdata() ([]byte, error) {
|
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"
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package cloudsigma
|
package cloudsigma
|
||||||
|
|
||||||
@ -26,6 +24,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/Godeps/_workspace/src/github.com/cloudsigma/cepgo"
|
"github.com/coreos/coreos-cloudinit/Godeps/_workspace/src/github.com/cloudsigma/cepgo"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ func (_ *serverContextService) Type() string {
|
|||||||
return "server-context"
|
return "server-context"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scs *serverContextService) FetchMetadata() ([]byte, error) {
|
func (scs *serverContextService) FetchMetadata() (metadata datasource.Metadata, err error) {
|
||||||
var (
|
var (
|
||||||
inputMetadata struct {
|
inputMetadata struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@ -90,48 +90,43 @@ func (scs *serverContextService) FetchMetadata() ([]byte, error) {
|
|||||||
} `json:"vlan"`
|
} `json:"vlan"`
|
||||||
} `json:"nics"`
|
} `json:"nics"`
|
||||||
}
|
}
|
||||||
outputMetadata struct {
|
rawMetadata []byte
|
||||||
Hostname string `json:"name"`
|
|
||||||
PublicKeys map[string]string `json:"public_keys"`
|
|
||||||
LocalIPv4 string `json:"local-ipv4"`
|
|
||||||
PublicIPv4 string `json:"public-ipv4"`
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
rawMetadata, err := scs.client.FetchRaw("")
|
if rawMetadata, err = scs.client.FetchRaw(""); err != nil {
|
||||||
if err != nil {
|
return
|
||||||
return []byte{}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(rawMetadata, &inputMetadata)
|
if err = json.Unmarshal(rawMetadata, &inputMetadata); err != nil {
|
||||||
if err != nil {
|
return
|
||||||
return []byte{}, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if inputMetadata.Name != "" {
|
if inputMetadata.Name != "" {
|
||||||
outputMetadata.Hostname = inputMetadata.Name
|
metadata.Hostname = inputMetadata.Name
|
||||||
} else {
|
} else {
|
||||||
outputMetadata.Hostname = inputMetadata.UUID
|
metadata.Hostname = inputMetadata.UUID
|
||||||
}
|
}
|
||||||
|
|
||||||
if key, ok := inputMetadata.Meta["ssh_public_key"]; ok {
|
metadata.SSHPublicKeys = map[string]string{}
|
||||||
|
// CloudSigma uses an empty string, rather than no string,
|
||||||
|
// to represent the lack of a SSH key
|
||||||
|
if key, _ := inputMetadata.Meta["ssh_public_key"]; len(key) > 0 {
|
||||||
splitted := strings.Split(key, " ")
|
splitted := strings.Split(key, " ")
|
||||||
outputMetadata.PublicKeys = make(map[string]string)
|
metadata.SSHPublicKeys[splitted[len(splitted)-1]] = key
|
||||||
outputMetadata.PublicKeys[splitted[len(splitted)-1]] = key
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, nic := range inputMetadata.Nics {
|
for _, nic := range inputMetadata.Nics {
|
||||||
if nic.IPv4Conf.IP.UUID != "" {
|
if nic.IPv4Conf.IP.UUID != "" {
|
||||||
outputMetadata.PublicIPv4 = nic.IPv4Conf.IP.UUID
|
metadata.PublicIPv4 = net.ParseIP(nic.IPv4Conf.IP.UUID)
|
||||||
}
|
}
|
||||||
if nic.VLAN.UUID != "" {
|
if nic.VLAN.UUID != "" {
|
||||||
if localIP, err := scs.findLocalIP(nic.Mac); err == nil {
|
if localIP, err := scs.findLocalIP(nic.Mac); err == nil {
|
||||||
outputMetadata.LocalIPv4 = localIP
|
metadata.PrivateIPv4 = localIP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return json.Marshal(outputMetadata)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scs *serverContextService) FetchUserdata() ([]byte, error) {
|
func (scs *serverContextService) FetchUserdata() ([]byte, error) {
|
||||||
@ -152,18 +147,14 @@ func (scs *serverContextService) FetchUserdata() ([]byte, error) {
|
|||||||
return []byte(userData), nil
|
return []byte(userData), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scs *serverContextService) FetchNetworkConfig(a string) ([]byte, error) {
|
func (scs *serverContextService) findLocalIP(mac string) (net.IP, error) {
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (scs *serverContextService) findLocalIP(mac string) (string, error) {
|
|
||||||
ifaces, err := net.Interfaces()
|
ifaces, err := net.Interfaces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
ifaceMac, err := net.ParseMAC(mac)
|
ifaceMac, err := net.ParseMAC(mac)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, iface := range ifaces {
|
for _, iface := range ifaces {
|
||||||
if !bytes.Equal(iface.HardwareAddr, ifaceMac) {
|
if !bytes.Equal(iface.HardwareAddr, ifaceMac) {
|
||||||
@ -178,12 +169,12 @@ func (scs *serverContextService) findLocalIP(mac string) (string, error) {
|
|||||||
switch ip := addr.(type) {
|
switch ip := addr.(type) {
|
||||||
case *net.IPNet:
|
case *net.IPNet:
|
||||||
if ip.IP.To4() != nil {
|
if ip.IP.To4() != nil {
|
||||||
return ip.IP.To4().String(), nil
|
return ip.IP.To4(), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", errors.New("Local IP not found")
|
return nil, errors.New("Local IP not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func isBase64Encoded(field string, userdata map[string]string) bool {
|
func isBase64Encoded(field string, userdata map[string]string) bool {
|
||||||
|
@ -1,23 +1,21 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package cloudsigma
|
package cloudsigma
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@ -45,13 +43,28 @@ func (f *fakeCepgoClient) FetchRaw(key string) ([]byte, error) {
|
|||||||
return f.raw, f.err
|
return f.raw, f.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServerContextFetchMetadata(t *testing.T) {
|
func TestServerContextWithEmptyPublicSSHKey(t *testing.T) {
|
||||||
var metadata struct {
|
client := new(fakeCepgoClient)
|
||||||
Hostname string `json:"name"`
|
scs := NewServerContextService()
|
||||||
PublicKeys map[string]string `json:"public_keys"`
|
scs.client = client
|
||||||
LocalIPv4 string `json:"local-ipv4"`
|
client.raw = []byte(`{
|
||||||
PublicIPv4 string `json:"public-ipv4"`
|
"meta": {
|
||||||
|
"base64_fields": "cloudinit-user-data",
|
||||||
|
"cloudinit-user-data": "I2Nsb3VkLWNvbmZpZwoKaG9zdG5hbWU6IGNvcmVvczE=",
|
||||||
|
"ssh_public_key": ""
|
||||||
}
|
}
|
||||||
|
}`)
|
||||||
|
metadata, err := scs.FetchMetadata()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(metadata.SSHPublicKeys) != 0 {
|
||||||
|
t.Error("There should be no Public SSH Keys provided")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerContextFetchMetadata(t *testing.T) {
|
||||||
client := new(fakeCepgoClient)
|
client := new(fakeCepgoClient)
|
||||||
scs := NewServerContextService()
|
scs := NewServerContextService()
|
||||||
scs.client = client
|
scs.client = client
|
||||||
@ -116,24 +129,20 @@ func TestServerContextFetchMetadata(t *testing.T) {
|
|||||||
"uuid": "20a0059b-041e-4d0c-bcc6-9b2852de48b3"
|
"uuid": "20a0059b-041e-4d0c-bcc6-9b2852de48b3"
|
||||||
}`)
|
}`)
|
||||||
|
|
||||||
metadataBytes, err := scs.FetchMetadata()
|
metadata, err := scs.FetchMetadata()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err.Error())
|
t.Error(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(metadataBytes, &metadata); err != nil {
|
|
||||||
t.Error(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if metadata.Hostname != "coreos" {
|
if metadata.Hostname != "coreos" {
|
||||||
t.Errorf("Hostname is not 'coreos' but %s instead", metadata.Hostname)
|
t.Errorf("Hostname is not 'coreos' but %s instead", metadata.Hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
if metadata.PublicKeys["john@doe"] != "ssh-rsa AAAAB3NzaC1yc2E.../hQ5D5 john@doe" {
|
if metadata.SSHPublicKeys["john@doe"] != "ssh-rsa AAAAB3NzaC1yc2E.../hQ5D5 john@doe" {
|
||||||
t.Error("Public SSH Keys are not being read properly")
|
t.Error("Public SSH Keys are not being read properly")
|
||||||
}
|
}
|
||||||
|
|
||||||
if metadata.PublicIPv4 != "31.171.251.74" {
|
if !metadata.PublicIPv4.Equal(net.ParseIP("31.171.251.74")) {
|
||||||
t.Errorf("Public IP is not 31.171.251.74 but %s instead", metadata.PublicIPv4)
|
t.Errorf("Public IP is not 31.171.251.74 but %s instead", metadata.PublicIPv4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package digitalocean
|
package digitalocean
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -61,8 +61,6 @@ type Metadata struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type metadataService struct {
|
type metadataService struct {
|
||||||
interfaces Interfaces
|
|
||||||
dns DNS
|
|
||||||
metadata.MetadataService
|
metadata.MetadataService
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,52 +68,41 @@ func NewDatasource(root string) *metadataService {
|
|||||||
return &metadataService{MetadataService: metadata.NewDatasource(root, apiVersion, userdataUrl, metadataPath)}
|
return &metadataService{MetadataService: metadata.NewDatasource(root, apiVersion, userdataUrl, metadataPath)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *metadataService) FetchMetadata() ([]byte, error) {
|
func (ms *metadataService) FetchMetadata() (metadata datasource.Metadata, err error) {
|
||||||
data, err := ms.FetchData(ms.MetadataUrl())
|
var data []byte
|
||||||
if err != nil || len(data) == 0 {
|
var m Metadata
|
||||||
return []byte{}, err
|
|
||||||
|
if data, err = ms.FetchData(ms.MetadataUrl()); err != nil || len(data) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = json.Unmarshal(data, &m); err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var metadata Metadata
|
if len(m.Interfaces.Public) > 0 {
|
||||||
if err := json.Unmarshal(data, &metadata); err != nil {
|
if m.Interfaces.Public[0].IPv4 != nil {
|
||||||
return []byte{}, err
|
metadata.PublicIPv4 = net.ParseIP(m.Interfaces.Public[0].IPv4.IPAddress)
|
||||||
}
|
}
|
||||||
|
if m.Interfaces.Public[0].IPv6 != nil {
|
||||||
|
metadata.PublicIPv6 = net.ParseIP(m.Interfaces.Public[0].IPv6.IPAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(m.Interfaces.Private) > 0 {
|
||||||
|
if m.Interfaces.Private[0].IPv4 != nil {
|
||||||
|
metadata.PrivateIPv4 = net.ParseIP(m.Interfaces.Private[0].IPv4.IPAddress)
|
||||||
|
}
|
||||||
|
if m.Interfaces.Private[0].IPv6 != nil {
|
||||||
|
metadata.PrivateIPv6 = net.ParseIP(m.Interfaces.Private[0].IPv6.IPAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
metadata.Hostname = m.Hostname
|
||||||
|
metadata.SSHPublicKeys = map[string]string{}
|
||||||
|
for i, key := range m.PublicKeys {
|
||||||
|
metadata.SSHPublicKeys[strconv.Itoa(i)] = key
|
||||||
|
}
|
||||||
|
metadata.NetworkConfig = data
|
||||||
|
|
||||||
ms.interfaces = metadata.Interfaces
|
return
|
||||||
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 {
|
func (ms metadataService) Type() string {
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package digitalocean
|
package digitalocean
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/metadata/test"
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/test"
|
||||||
"github.com/coreos/coreos-cloudinit/pkg"
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
@ -38,7 +38,7 @@ func TestFetchMetadata(t *testing.T) {
|
|||||||
root string
|
root string
|
||||||
metadataPath string
|
metadataPath string
|
||||||
resources map[string]string
|
resources map[string]string
|
||||||
expect []byte
|
expect datasource.Metadata
|
||||||
clientErr error
|
clientErr error
|
||||||
expectErr error
|
expectErr error
|
||||||
}{
|
}{
|
||||||
@ -83,7 +83,42 @@ func TestFetchMetadata(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
},
|
},
|
||||||
expect: []byte(`{"hostname":"","public-ipv4":"192.168.1.2","public-ipv6":"fe00::","public_keys":{"0":"publickey1","1":"publickey2"}}`),
|
expect: datasource.Metadata{
|
||||||
|
PublicIPv4: net.ParseIP("192.168.1.2"),
|
||||||
|
PublicIPv6: net.ParseIP("fe00::"),
|
||||||
|
SSHPublicKeys: map[string]string{
|
||||||
|
"0": "publickey1",
|
||||||
|
"1": "publickey2",
|
||||||
|
},
|
||||||
|
NetworkConfig: []byte(`{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
clientErr: pkg.ErrTimeout{Err: fmt.Errorf("test error")},
|
clientErr: pkg.ErrTimeout{Err: fmt.Errorf("test error")},
|
||||||
@ -101,8 +136,8 @@ func TestFetchMetadata(t *testing.T) {
|
|||||||
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)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(metadata, tt.expect) {
|
if !reflect.DeepEqual(tt.expect, metadata) {
|
||||||
t.Fatalf("bad fetch (%q): want %q, got %q", tt.resources, tt.expect, metadata)
|
t.Fatalf("bad fetch (%q): want %#q, got %#q", tt.resources, tt.expect, metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,27 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ec2
|
package ec2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
||||||
"github.com/coreos/coreos-cloudinit/pkg"
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
)
|
)
|
||||||
@ -42,59 +41,51 @@ func NewDatasource(root string) *metadataService {
|
|||||||
return &metadataService{metadata.NewDatasource(root, apiVersion, userdataPath, metadataPath)}
|
return &metadataService{metadata.NewDatasource(root, apiVersion, userdataPath, metadataPath)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms metadataService) FetchMetadata() ([]byte, error) {
|
func (ms metadataService) FetchMetadata() (datasource.Metadata, error) {
|
||||||
attrs := make(map[string]interface{})
|
metadata := datasource.Metadata{}
|
||||||
|
|
||||||
if keynames, err := ms.fetchAttributes(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)
|
||||||
if len(tokens) != 2 {
|
if len(tokens) != 2 {
|
||||||
return nil, fmt.Errorf("malformed public key: %q", keyname)
|
return metadata, fmt.Errorf("malformed public key: %q", keyname)
|
||||||
}
|
}
|
||||||
keyIDs[tokens[1]] = tokens[0]
|
keyIDs[tokens[1]] = tokens[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
keys := make(map[string]string)
|
metadata.SSHPublicKeys = map[string]string{}
|
||||||
for name, id := range keyIDs {
|
for name, id := range keyIDs {
|
||||||
sshkey, err := ms.fetchAttribute(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 metadata, err
|
||||||
}
|
}
|
||||||
keys[name] = sshkey
|
metadata.SSHPublicKeys[name] = sshkey
|
||||||
fmt.Printf("Found SSH key for %q\n", name)
|
fmt.Printf("Found SSH key for %q\n", name)
|
||||||
}
|
}
|
||||||
attrs["public_keys"] = keys
|
|
||||||
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
||||||
return nil, err
|
return metadata, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if hostname, err := ms.fetchAttribute(fmt.Sprintf("%s/hostname", ms.MetadataUrl())); err == nil {
|
if hostname, err := ms.fetchAttribute(fmt.Sprintf("%s/hostname", ms.MetadataUrl())); err == nil {
|
||||||
attrs["hostname"] = hostname
|
metadata.Hostname = strings.Split(hostname, " ")[0]
|
||||||
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
||||||
return nil, err
|
return metadata, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if localAddr, err := ms.fetchAttribute(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
|
metadata.PrivateIPv4 = net.ParseIP(localAddr)
|
||||||
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
||||||
return nil, err
|
return metadata, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if publicAddr, err := ms.fetchAttribute(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
|
metadata.PublicIPv4 = net.ParseIP(publicAddr)
|
||||||
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
||||||
return nil, err
|
return metadata, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if content_path, err := ms.fetchAttribute(fmt.Sprintf("%s/network_config/content_path", ms.MetadataUrl())); err == nil {
|
return metadata, nil
|
||||||
attrs["network_config"] = map[string]string{
|
|
||||||
"content_path": content_path,
|
|
||||||
}
|
|
||||||
} else if _, ok := err.(pkg.ErrNotFound); !ok {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.Marshal(attrs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms metadataService) Type() string {
|
func (ms metadataService) Type() string {
|
||||||
|
@ -1,27 +1,26 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ec2
|
package ec2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
"github.com/coreos/coreos-cloudinit/datasource/metadata"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/metadata/test"
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/test"
|
||||||
"github.com/coreos/coreos-cloudinit/pkg"
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
@ -147,7 +146,7 @@ func TestFetchMetadata(t *testing.T) {
|
|||||||
root string
|
root string
|
||||||
metadataPath string
|
metadataPath string
|
||||||
resources map[string]string
|
resources map[string]string
|
||||||
expect []byte
|
expect datasource.Metadata
|
||||||
clientErr error
|
clientErr error
|
||||||
expectErr error
|
expectErr error
|
||||||
}{
|
}{
|
||||||
@ -169,9 +168,31 @@ func TestFetchMetadata(t *testing.T) {
|
|||||||
"/2009-04-04/meta-data/public-keys": "0=test1\n",
|
"/2009-04-04/meta-data/public-keys": "0=test1\n",
|
||||||
"/2009-04-04/meta-data/public-keys/0": "openssh-key",
|
"/2009-04-04/meta-data/public-keys/0": "openssh-key",
|
||||||
"/2009-04-04/meta-data/public-keys/0/openssh-key": "key",
|
"/2009-04-04/meta-data/public-keys/0/openssh-key": "key",
|
||||||
"/2009-04-04/meta-data/network_config/content_path": "path",
|
|
||||||
},
|
},
|
||||||
expect: []byte(`{"hostname":"host","local-ipv4":"1.2.3.4","network_config":{"content_path":"path"},"public-ipv4":"5.6.7.8","public_keys":{"test1":"key"}}`),
|
expect: datasource.Metadata{
|
||||||
|
Hostname: "host",
|
||||||
|
PrivateIPv4: net.ParseIP("1.2.3.4"),
|
||||||
|
PublicIPv4: net.ParseIP("5.6.7.8"),
|
||||||
|
SSHPublicKeys: map[string]string{"test1": "key"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: "/",
|
||||||
|
metadataPath: "2009-04-04/meta-data",
|
||||||
|
resources: map[string]string{
|
||||||
|
"/2009-04-04/meta-data/hostname": "host domain another_domain",
|
||||||
|
"/2009-04-04/meta-data/local-ipv4": "1.2.3.4",
|
||||||
|
"/2009-04-04/meta-data/public-ipv4": "5.6.7.8",
|
||||||
|
"/2009-04-04/meta-data/public-keys": "0=test1\n",
|
||||||
|
"/2009-04-04/meta-data/public-keys/0": "openssh-key",
|
||||||
|
"/2009-04-04/meta-data/public-keys/0/openssh-key": "key",
|
||||||
|
},
|
||||||
|
expect: datasource.Metadata{
|
||||||
|
Hostname: "host",
|
||||||
|
PrivateIPv4: net.ParseIP("1.2.3.4"),
|
||||||
|
PublicIPv4: net.ParseIP("5.6.7.8"),
|
||||||
|
SSHPublicKeys: map[string]string{"test1": "key"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
clientErr: pkg.ErrTimeout{Err: fmt.Errorf("test error")},
|
clientErr: pkg.ErrTimeout{Err: fmt.Errorf("test error")},
|
||||||
@ -187,8 +208,8 @@ func TestFetchMetadata(t *testing.T) {
|
|||||||
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)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(metadata, tt.expect) {
|
if !reflect.DeepEqual(tt.expect, metadata) {
|
||||||
t.Fatalf("bad fetch (%q): want %q, got %q", tt.resources, tt.expect, metadata)
|
t.Fatalf("bad fetch (%q): want %#v, got %#v", tt.resources, tt.expect, metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package metadata
|
package metadata
|
||||||
|
|
||||||
@ -54,10 +52,6 @@ func (ms MetadataService) FetchUserdata() ([]byte, error) {
|
|||||||
return ms.FetchData(ms.UserdataUrl())
|
return ms.FetchData(ms.UserdataUrl())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms MetadataService) FetchNetworkConfig(filename string) ([]byte, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms MetadataService) FetchData(url string) ([]byte, error) {
|
func (ms MetadataService) FetchData(url string) ([]byte, error) {
|
||||||
if data, err := ms.Client.GetRetry(url); err == nil {
|
if data, err := ms.Client.GetRetry(url); err == nil {
|
||||||
return data, err
|
return data, err
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package metadata
|
package metadata
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package proc_cmdline
|
package proc_cmdline
|
||||||
|
|
||||||
@ -22,6 +20,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
"github.com/coreos/coreos-cloudinit/pkg"
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,8 +56,8 @@ func (c *procCmdline) ConfigRoot() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *procCmdline) FetchMetadata() ([]byte, error) {
|
func (c *procCmdline) FetchMetadata() (datasource.Metadata, error) {
|
||||||
return []byte{}, nil
|
return datasource.Metadata{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *procCmdline) FetchUserdata() ([]byte, error) {
|
func (c *procCmdline) FetchUserdata() ([]byte, error) {
|
||||||
@ -82,10 +81,6 @@ 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,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package proc_cmdline
|
package proc_cmdline
|
||||||
|
|
||||||
|
57
datasource/test/filesystem.go
Normal file
57
datasource/test/filesystem.go
Normal 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
|
||||||
|
}
|
115
datasource/test/filesystem_test.go
Normal file
115
datasource/test/filesystem_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,21 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package url
|
package url
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
"github.com/coreos/coreos-cloudinit/pkg"
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,8 +41,8 @@ func (f *remoteFile) ConfigRoot() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *remoteFile) FetchMetadata() ([]byte, error) {
|
func (f *remoteFile) FetchMetadata() (datasource.Metadata, error) {
|
||||||
return []byte{}, nil
|
return datasource.Metadata{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *remoteFile) FetchUserdata() ([]byte, error) {
|
func (f *remoteFile) FetchUserdata() ([]byte, error) {
|
||||||
@ -51,10 +50,6 @@ 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"
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,28 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package waagent
|
package waagent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
)
|
)
|
||||||
|
|
||||||
type waagent struct {
|
type waagent struct {
|
||||||
@ -48,13 +47,13 @@ func (a *waagent) ConfigRoot() string {
|
|||||||
return a.root
|
return a.root
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *waagent) FetchMetadata() ([]byte, error) {
|
func (a *waagent) FetchMetadata() (metadata datasource.Metadata, err error) {
|
||||||
metadataBytes, err := a.tryReadFile(path.Join(a.root, "SharedConfig.xml"))
|
var metadataBytes []byte
|
||||||
if err != nil {
|
if metadataBytes, err = a.tryReadFile(path.Join(a.root, "SharedConfig.xml")); err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
if len(metadataBytes) == 0 {
|
if len(metadataBytes) == 0 {
|
||||||
return metadataBytes, nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type Instance struct {
|
type Instance struct {
|
||||||
@ -76,40 +75,34 @@ func (a *waagent) FetchMetadata() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var metadata SharedConfig
|
var m SharedConfig
|
||||||
if err := xml.Unmarshal(metadataBytes, &metadata); err != nil {
|
if err = xml.Unmarshal(metadataBytes, &m); err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var instance Instance
|
var instance Instance
|
||||||
for _, i := range metadata.Instances.Instances {
|
for _, i := range m.Instances.Instances {
|
||||||
if i.Id == metadata.Incarnation.Instance {
|
if i.Id == m.Incarnation.Instance {
|
||||||
instance = i
|
instance = i
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attrs := map[string]string{
|
metadata.PrivateIPv4 = net.ParseIP(instance.Address)
|
||||||
"local-ipv4": instance.Address,
|
|
||||||
}
|
|
||||||
for _, e := range instance.InputEndpoints.Endpoints {
|
for _, e := range instance.InputEndpoints.Endpoints {
|
||||||
host, _, err := net.SplitHostPort(e.LoadBalancedPublicAddress)
|
host, _, err := net.SplitHostPort(e.LoadBalancedPublicAddress)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
attrs["public-ipv4"] = host
|
metadata.PublicIPv4 = net.ParseIP(host)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return json.Marshal(attrs)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *waagent) FetchUserdata() ([]byte, error) {
|
func (a *waagent) FetchUserdata() ([]byte, error) {
|
||||||
return a.tryReadFile(path.Join(a.root, "CustomData"))
|
return a.tryReadFile(path.Join(a.root, "CustomData"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *waagent) FetchNetworkConfig(filename string) ([]byte, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *waagent) Type() string {
|
func (a *waagent) Type() string {
|
||||||
return "waagent"
|
return "waagent"
|
||||||
}
|
}
|
||||||
|
@ -1,61 +1,49 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package waagent
|
package waagent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"net"
|
||||||
"os"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource"
|
||||||
|
"github.com/coreos/coreos-cloudinit/datasource/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockFilesystem map[string][]byte
|
|
||||||
|
|
||||||
func (m mockFilesystem) readFile(filename string) ([]byte, error) {
|
|
||||||
if contents := m[filename]; contents != nil {
|
|
||||||
return contents, nil
|
|
||||||
}
|
|
||||||
return nil, os.ErrNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFetchMetadata(t *testing.T) {
|
func TestFetchMetadata(t *testing.T) {
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
root string
|
root string
|
||||||
files mockFilesystem
|
files test.MockFilesystem
|
||||||
metadata map[string]string
|
metadata datasource.Metadata
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"/",
|
root: "/",
|
||||||
mockFilesystem{},
|
files: test.NewMockFilesystem(),
|
||||||
nil,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/",
|
root: "/",
|
||||||
mockFilesystem{"/SharedConfig.xml": []byte("")},
|
files: test.NewMockFilesystem(test.File{Path: "/SharedConfig.xml", Contents: ""}),
|
||||||
nil,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/var/lib/waagent",
|
root: "/var/lib/waagent",
|
||||||
mockFilesystem{"/var/lib/waagent/SharedConfig.xml": []byte("")},
|
files: test.NewMockFilesystem(test.File{Path: "/var/lib/waagent/SharedConfig.xml", Contents: ""}),
|
||||||
nil,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/var/lib/waagent",
|
root: "/var/lib/waagent",
|
||||||
mockFilesystem{"/var/lib/waagent/SharedConfig.xml": []byte(`<?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">
|
<SharedConfig version="1.0.0.0" goalStateIncarnation="1">
|
||||||
<Deployment name="c8f9e4c9c18948e1bebf57c5685da756" guid="{1d10394f-c741-4a1a-a6bb-278f213c5a5e}" incarnation="0" isNonCancellableTopologyChangeEnabled="false">
|
<Deployment name="c8f9e4c9c18948e1bebf57c5685da756" guid="{1d10394f-c741-4a1a-a6bb-278f213c5a5e}" incarnation="0" isNonCancellableTopologyChangeEnabled="false">
|
||||||
<Service name="core-test-1" guid="{00000000-0000-0000-0000-000000000000}" />
|
<Service name="core-test-1" guid="{00000000-0000-0000-0000-000000000000}" />
|
||||||
@ -91,26 +79,20 @@ func TestFetchMetadata(t *testing.T) {
|
|||||||
</InputEndpoints>
|
</InputEndpoints>
|
||||||
</Instance>
|
</Instance>
|
||||||
</Instances>
|
</Instances>
|
||||||
</SharedConfig>`)},
|
</SharedConfig>`}),
|
||||||
map[string]string{
|
metadata: datasource.Metadata{
|
||||||
"local-ipv4": "100.73.202.64",
|
PrivateIPv4: net.ParseIP("100.73.202.64"),
|
||||||
"public-ipv4": "191.239.39.77",
|
PublicIPv4: net.ParseIP("191.239.39.77"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
a := waagent{tt.root, tt.files.readFile}
|
a := waagent{tt.root, tt.files.ReadFile}
|
||||||
metadataBytes, err := a.FetchMetadata()
|
metadata, err := a.FetchMetadata()
|
||||||
if err != nil {
|
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)
|
||||||
}
|
|
||||||
var metadata map[string]string
|
|
||||||
if len(metadataBytes) > 0 {
|
|
||||||
if err := json.Unmarshal(metadataBytes, &metadata); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(tt.metadata, metadata) {
|
if !reflect.DeepEqual(tt.metadata, metadata) {
|
||||||
t.Fatalf("bad metadata for %q: want %q, got %q", tt, tt.metadata, metadata)
|
t.Fatalf("bad metadata for %+v: want %#v, got %#v", tt, tt.metadata, metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,25 +100,25 @@ func TestFetchMetadata(t *testing.T) {
|
|||||||
func TestFetchUserdata(t *testing.T) {
|
func TestFetchUserdata(t *testing.T) {
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
root string
|
root string
|
||||||
files mockFilesystem
|
files test.MockFilesystem
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"/",
|
"/",
|
||||||
mockFilesystem{},
|
test.NewMockFilesystem(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/",
|
"/",
|
||||||
mockFilesystem{"/CustomData": []byte{}},
|
test.NewMockFilesystem(test.File{Path: "/CustomData", Contents: ""}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"/var/lib/waagent/",
|
"/var/lib/waagent/",
|
||||||
mockFilesystem{"/var/lib/waagent/CustomData": []byte{}},
|
test.NewMockFilesystem(test.File{Path: "/var/lib/waagent/CustomData", Contents: ""}),
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
a := waagent{tt.root, tt.files.readFile}
|
a := waagent{tt.root, tt.files.ReadFile}
|
||||||
_, err := a.FetchUserdata()
|
_, err := a.FetchUserdata()
|
||||||
if err != nil {
|
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,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
@ -44,7 +42,7 @@ type CloudConfigUnit interface {
|
|||||||
// Apply renders a CloudConfig to an Environment. This can involve things like
|
// Apply renders a CloudConfig to an Environment. This can involve things like
|
||||||
// configuring the hostname, adding new users, writing various configuration
|
// configuring the hostname, adding new users, writing various configuration
|
||||||
// files to disk, and manipulating systemd services.
|
// files to disk, and manipulating systemd services.
|
||||||
func Apply(cfg config.CloudConfig, env *Environment) error {
|
func Apply(cfg config.CloudConfig, ifaces []network.InterfaceGenerator, env *Environment) error {
|
||||||
if cfg.Hostname != "" {
|
if cfg.Hostname != "" {
|
||||||
if err := system.SetHostname(cfg.Hostname); err != nil {
|
if err := system.SetHostname(cfg.Hostname); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -87,6 +85,12 @@ func Apply(cfg config.CloudConfig, env *Environment) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for _, u := range user.SSHImportGithubUsers {
|
||||||
|
log.Printf("Authorizing github user %s SSH keys for CoreOS user '%s'", u, user.Name)
|
||||||
|
if err := SSHImportGithubUser(user.Name, u); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if user.SSHImportURL != "" {
|
if user.SSHImportURL != "" {
|
||||||
log.Printf("Authorizing SSH keys for CoreOS user '%s' from '%s'", user.Name, user.SSHImportURL)
|
log.Printf("Authorizing SSH keys for CoreOS user '%s' from '%s'", user.Name, user.SSHImportURL)
|
||||||
if err := SSHImportKeysFromURL(user.Name, user.SSHImportURL); err != nil {
|
if err := SSHImportKeysFromURL(user.Name, user.SSHImportURL); err != nil {
|
||||||
@ -110,9 +114,10 @@ func Apply(cfg config.CloudConfig, env *Environment) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, ccf := range []CloudConfigFile{
|
for _, ccf := range []CloudConfigFile{
|
||||||
system.OEM{OEM: cfg.Coreos.OEM},
|
system.OEM{OEM: cfg.CoreOS.OEM},
|
||||||
system.Update{Update: cfg.Coreos.Update, ReadConfig: system.DefaultReadConfig},
|
system.Update{Update: cfg.CoreOS.Update, ReadConfig: system.DefaultReadConfig},
|
||||||
system.EtcHosts{EtcHosts: cfg.ManageEtcHosts},
|
system.EtcHosts{EtcHosts: cfg.ManageEtcHosts},
|
||||||
|
system.Flannel{Flannel: cfg.CoreOS.Flannel},
|
||||||
} {
|
} {
|
||||||
f, err := ccf.File()
|
f, err := ccf.File()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -124,16 +129,15 @@ func Apply(cfg config.CloudConfig, env *Environment) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var units []system.Unit
|
var units []system.Unit
|
||||||
for _, u := range cfg.Coreos.Units {
|
for _, u := range cfg.CoreOS.Units {
|
||||||
units = append(units, system.Unit{Unit: u})
|
units = append(units, system.Unit{Unit: u})
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ccu := range []CloudConfigUnit{
|
for _, ccu := range []CloudConfigUnit{
|
||||||
system.Etcd{Etcd: cfg.Coreos.Etcd},
|
system.Etcd{Etcd: cfg.CoreOS.Etcd},
|
||||||
system.Fleet{Fleet: cfg.Coreos.Fleet},
|
system.Fleet{Fleet: cfg.CoreOS.Fleet},
|
||||||
system.Locksmith{Locksmith: cfg.Coreos.Locksmith},
|
system.Locksmith{Locksmith: cfg.CoreOS.Locksmith},
|
||||||
system.Flannel{Flannel: cfg.Coreos.Flannel},
|
system.Update{Update: cfg.CoreOS.Update, ReadConfig: system.DefaultReadConfig},
|
||||||
system.Update{Update: cfg.Coreos.Update, ReadConfig: system.DefaultReadConfig},
|
|
||||||
} {
|
} {
|
||||||
units = append(units, ccu.Units()...)
|
units = append(units, ccu.Units()...)
|
||||||
}
|
}
|
||||||
@ -161,23 +165,9 @@ func Apply(cfg config.CloudConfig, env *Environment) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if env.NetconfType() != "" {
|
if len(ifaces) > 0 {
|
||||||
var interfaces []network.InterfaceGenerator
|
units = append(units, createNetworkingUnits(ifaces)...)
|
||||||
var err error
|
if err := system.RestartNetwork(ifaces); err != nil {
|
||||||
switch env.NetconfType() {
|
|
||||||
case "debian":
|
|
||||||
interfaces, err = network.ProcessDebianNetconf(cfg.NetworkConfig)
|
|
||||||
case "digitalocean":
|
|
||||||
interfaces, err = network.ProcessDigitalOceanNetconf(cfg.NetworkConfig)
|
|
||||||
default:
|
|
||||||
err = fmt.Errorf("Unsupported network config format %q", env.NetconfType())
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
units = append(units, createNetworkingUnits(interfaces)...)
|
|
||||||
if err := system.RestartNetwork(interfaces); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,28 +32,25 @@ type Environment struct {
|
|||||||
root string
|
root string
|
||||||
configRoot string
|
configRoot string
|
||||||
workspace string
|
workspace string
|
||||||
netconfType string
|
|
||||||
sshKeyName string
|
sshKeyName string
|
||||||
substitutions map[string]string
|
substitutions map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, 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, sshKeyName, substitutions}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Environment) Workspace() string {
|
func (e *Environment) Workspace() string {
|
||||||
@ -68,10 +65,6 @@ func (e *Environment) ConfigRoot() string {
|
|||||||
return e.configRoot
|
return e.configRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Environment) NetconfType() string {
|
|
||||||
return e.netconfType
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Environment) SSHKeyName() string {
|
func (e *Environment) SSHKeyName() string {
|
||||||
return e.sshKeyName
|
return e.sshKeyName
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package initialize
|
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -31,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"
|
||||||
@ -55,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
|
||||||
@ -85,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)
|
||||||
@ -100,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"
|
||||||
|
|
||||||
@ -114,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 {
|
||||||
@ -133,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)
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
|
@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 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 (
|
|
||||||
"encoding/json"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ParseMetaData parses a JSON blob in the OpenStack metadata service format,
|
|
||||||
// and converts it to a partially hydrated CloudConfig.
|
|
||||||
func ParseMetaData(contents string) (*config.CloudConfig, error) {
|
|
||||||
if len(contents) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
var metadata struct {
|
|
||||||
SSHAuthorizedKeyMap map[string]string `json:"public_keys"`
|
|
||||||
Hostname string `json:"hostname"`
|
|
||||||
NetworkConfig struct {
|
|
||||||
ContentPath string `json:"content_path"`
|
|
||||||
} `json:"network_config"`
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal([]byte(contents), &metadata); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var cfg config.CloudConfig
|
|
||||||
if len(metadata.SSHAuthorizedKeyMap) > 0 {
|
|
||||||
cfg.SSHAuthorizedKeys = make([]string, 0, len(metadata.SSHAuthorizedKeyMap))
|
|
||||||
for _, name := range sortedKeys(metadata.SSHAuthorizedKeyMap) {
|
|
||||||
cfg.SSHAuthorizedKeys = append(cfg.SSHAuthorizedKeys, metadata.SSHAuthorizedKeyMap[name])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cfg.Hostname = metadata.Hostname
|
|
||||||
cfg.NetworkConfigPath = metadata.NetworkConfig.ContentPath
|
|
||||||
return &cfg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(contents []byte) (map[string]string, error) {
|
|
||||||
var ips struct {
|
|
||||||
PublicIPv4 string `json:"public-ipv4"`
|
|
||||||
PrivateIPv4 string `json:"local-ipv4"`
|
|
||||||
PublicIPv6 string `json:"public-ipv6"`
|
|
||||||
PrivateIPv6 string `json:"local-ipv6"`
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(contents, &ips); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
m := make(map[string]string)
|
|
||||||
if ips.PrivateIPv4 != "" {
|
|
||||||
m["$private_ipv4"] = ips.PrivateIPv4
|
|
||||||
}
|
|
||||||
if ips.PublicIPv4 != "" {
|
|
||||||
m["$public_ipv4"] = ips.PublicIPv4
|
|
||||||
}
|
|
||||||
if ips.PrivateIPv6 != "" {
|
|
||||||
m["$private_ipv6"] = ips.PrivateIPv6
|
|
||||||
}
|
|
||||||
if ips.PublicIPv6 != "" {
|
|
||||||
m["$public_ipv6"] = ips.PublicIPv6
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortedKeys(m map[string]string) (keys []string) {
|
|
||||||
for key := range m {
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
return
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2014 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 (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParseMetadata(t *testing.T) {
|
|
||||||
for i, tt := range []struct {
|
|
||||||
in string
|
|
||||||
want *config.CloudConfig
|
|
||||||
err bool
|
|
||||||
}{
|
|
||||||
{"", nil, false},
|
|
||||||
{`garbage, invalid json`, nil, true},
|
|
||||||
{`{"foo": "bar"}`, &config.CloudConfig{}, false},
|
|
||||||
{`{"network_config": {"content_path": "asdf"}}`, &config.CloudConfig{NetworkConfigPath: "asdf"}, false},
|
|
||||||
{`{"hostname": "turkleton"}`, &config.CloudConfig{Hostname: "turkleton"}, false},
|
|
||||||
{`{"public_keys": {"jack": "jill", "bob": "alice"}}`, &config.CloudConfig{SSHAuthorizedKeys: []string{"alice", "jill"}}, false},
|
|
||||||
{`{"unknown": "thing", "hostname": "my_host", "public_keys": {"do": "re", "mi": "fa"}, "network_config": {"content_path": "/root", "blah": "zzz"}}`, &config.CloudConfig{SSHAuthorizedKeys: []string{"re", "fa"}, Hostname: "my_host", NetworkConfigPath: "/root"}, false},
|
|
||||||
} {
|
|
||||||
got, err := ParseMetaData(tt.in)
|
|
||||||
if tt.err != (err != nil) {
|
|
||||||
t.Errorf("case #%d: bad error state: got %t, want %t (err=%v)", i, (err != nil), tt.err, err)
|
|
||||||
}
|
|
||||||
if got == nil {
|
|
||||||
if tt.want != nil {
|
|
||||||
t.Errorf("case #%d: unexpected nil output", i)
|
|
||||||
}
|
|
||||||
} else if tt.want == nil {
|
|
||||||
t.Errorf("case #%d: unexpected non-nil output", i)
|
|
||||||
} else {
|
|
||||||
if !reflect.DeepEqual(*got, *tt.want) {
|
|
||||||
t.Errorf("case #%d: bad output:\ngot\n%v\nwant\n%v", i, *got, *tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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", "public-ipv6": "1234::", "local-ipv6": "5678::"}`),
|
|
||||||
false,
|
|
||||||
map[string]string{"$public_ipv4": "12.34.56.78", "$private_ipv4": "1.2.3.4", "$public_ipv6": "1234::", "$private_ipv6": "5678::"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package network
|
package network
|
||||||
|
|
||||||
@ -21,9 +19,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProcessDebianNetconf(config string) ([]InterfaceGenerator, error) {
|
func ProcessDebianNetconf(config []byte) ([]InterfaceGenerator, error) {
|
||||||
log.Println("Processing Debian network config")
|
log.Println("Processing Debian network config")
|
||||||
lines := formatConfig(config)
|
lines := formatConfig(string(config))
|
||||||
stanzas, err := parseStanzas(lines)
|
stanzas, err := parseStanzas(lines)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package network
|
package network
|
||||||
|
|
||||||
@ -46,7 +44,7 @@ func TestProcessDebianNetconf(t *testing.T) {
|
|||||||
{"auto eth1\nauto eth2", false, 0},
|
{"auto eth1\nauto eth2", false, 0},
|
||||||
{"iface eth1 inet manual", false, 1},
|
{"iface eth1 inet manual", false, 1},
|
||||||
} {
|
} {
|
||||||
interfaces, err := ProcessDebianNetconf(tt.in)
|
interfaces, err := ProcessDebianNetconf([]byte(tt.in))
|
||||||
failed := err != nil
|
failed := err != nil
|
||||||
if tt.fail != failed {
|
if tt.fail != failed {
|
||||||
t.Fatalf("bad failure state for %q: got %t, want %t", tt.in, failed, tt.fail)
|
t.Fatalf("bad failure state for %q: got %t, want %t", tt.in, failed, tt.fail)
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package network
|
package network
|
||||||
|
|
||||||
@ -25,14 +23,14 @@ import (
|
|||||||
"github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean"
|
"github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProcessDigitalOceanNetconf(config string) ([]InterfaceGenerator, error) {
|
func ProcessDigitalOceanNetconf(config []byte) ([]InterfaceGenerator, error) {
|
||||||
log.Println("Processing DigitalOcean network config")
|
log.Println("Processing DigitalOcean network config")
|
||||||
if config == "" {
|
if len(config) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var cfg digitalocean.Metadata
|
var cfg digitalocean.Metadata
|
||||||
if err := json.Unmarshal([]byte(config), &cfg); err != nil {
|
if err := json.Unmarshal(config, &cfg); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package network
|
package network
|
||||||
|
|
||||||
@ -380,7 +378,7 @@ func TestProcessDigitalOceanNetconf(t *testing.T) {
|
|||||||
ifaces: []InterfaceGenerator{},
|
ifaces: []InterfaceGenerator{},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
ifaces, err := ProcessDigitalOceanNetconf(tt.cfg)
|
ifaces, err := ProcessDigitalOceanNetconf([]byte(tt.cfg))
|
||||||
if !errorsEqual(tt.err, err) {
|
if !errorsEqual(tt.err, err) {
|
||||||
t.Fatalf("bad error (%q): want %q, got %q", tt.cfg, tt.err, err)
|
t.Fatalf("bad error (%q): want %q, got %q", tt.cfg, tt.err, err)
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package network
|
package network
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package network
|
package network
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package network
|
package network
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package network
|
package network
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pkg
|
package pkg
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
@ -23,22 +21,32 @@ import (
|
|||||||
"github.com/coreos/coreos-cloudinit/config"
|
"github.com/coreos/coreos-cloudinit/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// dropinContents generates the contents for a drop-in unit given the config.
|
// serviceContents generates the contents for a drop-in unit given the config.
|
||||||
// The argument must be a struct from the 'config' package.
|
// The argument must be a struct from the 'config' package.
|
||||||
func serviceContents(e interface{}) string {
|
func serviceContents(e interface{}) string {
|
||||||
|
vars := getEnvVars(e)
|
||||||
|
if len(vars) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
out := "[Service]\n"
|
||||||
|
for _, v := range vars {
|
||||||
|
out += fmt.Sprintf("Environment=\"%s\"\n", v)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEnvVars(e interface{}) []string {
|
||||||
et := reflect.TypeOf(e)
|
et := reflect.TypeOf(e)
|
||||||
ev := reflect.ValueOf(e)
|
ev := reflect.ValueOf(e)
|
||||||
|
|
||||||
var out string
|
vars := []string{}
|
||||||
for i := 0; i < et.NumField(); i++ {
|
for i := 0; i < et.NumField(); i++ {
|
||||||
if val := ev.Field(i).Interface(); !config.IsZero(val) {
|
if val := ev.Field(i).Interface(); !config.IsZero(val) {
|
||||||
key := et.Field(i).Tag.Get("env")
|
key := et.Field(i).Tag.Get("env")
|
||||||
out += fmt.Sprintf("Environment=\"%s=%v\"\n", key, val)
|
vars = append(vars, fmt.Sprintf("%s=%v", key, val))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if out == "" {
|
return vars
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return "[Service]\n" + out
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,3 +1,17 @@
|
|||||||
|
// 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 system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,25 +1,20 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
@ -43,68 +38,19 @@ func (f *File) Permissions() (os.FileMode, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse string representation of file mode as integer
|
// Parse string representation of file mode as integer
|
||||||
perm, err := strconv.ParseInt(f.RawFilePermissions, 0, 32)
|
perm, err := strconv.ParseInt(f.RawFilePermissions, 8, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("Unable to parse file permissions %q as integer", f.RawFilePermissions)
|
return 0, fmt.Errorf("Unable to parse file permissions %q as integer", f.RawFilePermissions)
|
||||||
}
|
}
|
||||||
return os.FileMode(perm), nil
|
return os.FileMode(perm), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecodeBase64Content(content string) ([]byte, error) {
|
|
||||||
output, err := base64.StdEncoding.DecodeString(content)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Unable to decode base64: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return output, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecodeGzipContent(content string) ([]byte, error) {
|
|
||||||
gzr, err := gzip.NewReader(bytes.NewReader([]byte(content)))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("Unable to decode gzip: %v", err)
|
|
||||||
}
|
|
||||||
defer gzr.Close()
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
buf.ReadFrom(gzr)
|
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecodeContent(content string, encoding string) ([]byte, error) {
|
|
||||||
switch encoding {
|
|
||||||
case "":
|
|
||||||
return []byte(content), nil
|
|
||||||
|
|
||||||
case "b64", "base64":
|
|
||||||
return DecodeBase64Content(content)
|
|
||||||
|
|
||||||
case "gz", "gzip":
|
|
||||||
return DecodeGzipContent(content)
|
|
||||||
|
|
||||||
case "gz+base64", "gzip+base64", "gz+b64", "gzip+b64":
|
|
||||||
gz, err := DecodeBase64Content(content)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return DecodeGzipContent(string(gz))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("Unsupported encoding %s", encoding)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func WriteFile(f *File, root string) (string, error) {
|
func WriteFile(f *File, root string) (string, error) {
|
||||||
fullpath := path.Join(root, f.Path)
|
fullpath := path.Join(root, f.Path)
|
||||||
dir := path.Dir(fullpath)
|
dir := path.Dir(fullpath)
|
||||||
log.Printf("Writing file to %q", fullpath)
|
log.Printf("Writing file to %q", fullpath)
|
||||||
|
|
||||||
content, err := DecodeContent(f.Content, f.Encoding)
|
content, err := config.DecodeContent(f.Content, f.Encoding)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Unable to decode %s (%v)", f.Path, err)
|
return "", fmt.Errorf("Unable to decode %s (%v)", f.Path, err)
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
@ -97,7 +95,7 @@ func TestDecimalFilePermissions(t *testing.T) {
|
|||||||
|
|
||||||
wf := File{config.File{
|
wf := File{config.File{
|
||||||
Path: fn,
|
Path: fn,
|
||||||
RawFilePermissions: "484", // Decimal representation of 0744
|
RawFilePermissions: "744",
|
||||||
}}
|
}}
|
||||||
|
|
||||||
path, err := WriteFile(&wf, dir)
|
path, err := WriteFile(&wf, dir)
|
||||||
|
@ -1,6 +1,23 @@
|
|||||||
|
// 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 system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
"github.com/coreos/coreos-cloudinit/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -10,15 +27,18 @@ type Flannel struct {
|
|||||||
config.Flannel
|
config.Flannel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Units generates a Unit file drop-in for flannel, if any flannel options were
|
func (fl Flannel) envVars() string {
|
||||||
// configured in cloud-config
|
return strings.Join(getEnvVars(fl.Flannel), "\n")
|
||||||
func (fl Flannel) Units() []Unit {
|
}
|
||||||
return []Unit{{config.Unit{
|
|
||||||
Name: "flanneld.service",
|
func (fl Flannel) File() (*File, error) {
|
||||||
Runtime: true,
|
vars := fl.envVars()
|
||||||
DropIns: []config.UnitDropIn{{
|
if vars == "" {
|
||||||
Name: "20-cloudinit.conf",
|
return nil, nil
|
||||||
Content: serviceContents(fl.Flannel),
|
}
|
||||||
}},
|
return &File{config.File{
|
||||||
}}}
|
Path: path.Join("run", "flannel", "options.env"),
|
||||||
|
RawFilePermissions: "0644",
|
||||||
|
Content: vars,
|
||||||
|
}}, nil
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,17 @@
|
|||||||
|
// 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 system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -7,40 +21,56 @@ import (
|
|||||||
"github.com/coreos/coreos-cloudinit/config"
|
"github.com/coreos/coreos-cloudinit/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFlannelUnits(t *testing.T) {
|
func TestFlannelEnvVars(t *testing.T) {
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
config config.Flannel
|
config config.Flannel
|
||||||
units []Unit
|
contents string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
config.Flannel{},
|
config.Flannel{},
|
||||||
[]Unit{{config.Unit{
|
"",
|
||||||
Name: "flanneld.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{{Name: "20-cloudinit.conf"}},
|
|
||||||
}}},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
config.Flannel{
|
config.Flannel{
|
||||||
EtcdEndpoint: "http://12.34.56.78:4001",
|
EtcdEndpoints: "http://12.34.56.78:4001",
|
||||||
EtcdPrefix: "/coreos.com/network/tenant1",
|
EtcdPrefix: "/coreos.com/network/tenant1",
|
||||||
},
|
},
|
||||||
[]Unit{{config.Unit{
|
`FLANNELD_ETCD_ENDPOINTS=http://12.34.56.78:4001
|
||||||
Name: "flanneld.service",
|
FLANNELD_ETCD_PREFIX=/coreos.com/network/tenant1`,
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{{
|
|
||||||
Name: "20-cloudinit.conf",
|
|
||||||
Content: `[Service]
|
|
||||||
Environment="FLANNELD_ETCD_ENDPOINT=http://12.34.56.78:4001"
|
|
||||||
Environment="FLANNELD_ETCD_PREFIX=/coreos.com/network/tenant1"
|
|
||||||
`,
|
|
||||||
}},
|
|
||||||
}}},
|
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
units := Flannel{tt.config}.Units()
|
out := Flannel{tt.config}.envVars()
|
||||||
if !reflect.DeepEqual(units, tt.units) {
|
if out != tt.contents {
|
||||||
t.Errorf("bad units (%q): want %v, got %v", tt.config, tt.units, units)
|
t.Errorf("bad contents (%+v): want %q, got %q", tt, tt.contents, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFlannelFile(t *testing.T) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
config config.Flannel
|
||||||
|
file *File
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
config.Flannel{},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config.Flannel{
|
||||||
|
EtcdEndpoints: "http://12.34.56.78:4001",
|
||||||
|
EtcdPrefix: "/coreos.com/network/tenant1",
|
||||||
|
},
|
||||||
|
&File{config.File{
|
||||||
|
Path: "run/flannel/options.env",
|
||||||
|
RawFilePermissions: "0644",
|
||||||
|
Content: `FLANNELD_ETCD_ENDPOINTS=http://12.34.56.78:4001
|
||||||
|
FLANNELD_ETCD_PREFIX=/coreos.com/network/tenant1`,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
file, _ := Flannel{tt.config}.File()
|
||||||
|
if !reflect.DeepEqual(tt.file, file) {
|
||||||
|
t.Errorf("bad units (%q): want %#v, got %#v", tt.config, tt.file, file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/*
|
// Copyright 2015 CoreOS, Inc.
|
||||||
Copyright 2014 CoreOS, Inc.
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
// you may not use this file except in compliance with the License.
|
||||||
you may not use this file except in compliance with the License.
|
// You may obtain a copy of the License at
|
||||||
You may obtain a copy of the License at
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
Unless required by applicable law or agreed to in writing, software
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// See the License for the specific language governing permissions and
|
||||||
See the License for the specific language governing permissions and
|
// limitations under the License.
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user