Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
eca51031c8 | ||
|
19522bcb82 | ||
|
62248ea33d | ||
|
d2a19cc86d | ||
|
08131ffab1 | ||
|
4a0019c669 | ||
|
3275ead1ec | ||
|
32b6a55724 | ||
|
6c43644369 | ||
|
e6593d49e6 | ||
|
ab752b239f | ||
|
0742e4d357 | ||
|
78f586ec9e | ||
|
6f91b76d79 | ||
|
5c80ccacc4 | ||
|
97758b343b | ||
|
fb6f52b360 | ||
|
786cd2a539 | ||
|
45793f1254 | ||
|
b621756d92 | ||
|
a5b5c700a6 | ||
|
d7602f3c08 | ||
|
a20addd05e | ||
|
d9d89a6fa0 |
@@ -97,6 +97,29 @@ For more information on fleet configuration, see the [fleet documentation][fleet
|
|||||||
|
|
||||||
[fleet-config]: https://github.com/coreos/fleet/blob/master/Documentation/deployment-and-configuration.md#configuration
|
[fleet-config]: https://github.com/coreos/fleet/blob/master/Documentation/deployment-and-configuration.md#configuration
|
||||||
|
|
||||||
|
#### flannel
|
||||||
|
|
||||||
|
The `coreos.flannel.*` parameters also work very similarly to `coreos.etcd.*` and `coreos.fleet.*`. They can be used to set enviornment variables for flanneld. Given the following cloud-config...
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
#cloud-config
|
||||||
|
|
||||||
|
coreos:
|
||||||
|
flannel:
|
||||||
|
etcd-prefix: /coreos.com/network2
|
||||||
|
```
|
||||||
|
|
||||||
|
...will generate systemd unit drop-in like so:
|
||||||
|
|
||||||
|
```
|
||||||
|
[Service]
|
||||||
|
Environment="FLANNELD_ETCD_PREFIX=/coreos.com/network2"
|
||||||
|
```
|
||||||
|
|
||||||
|
For complete list of flannel configuraion parameters, see the [flannel documentation][flannel-readme].
|
||||||
|
|
||||||
|
[flannel-readme]: https://github.com/coreos/flannel/blob/master/README.md
|
||||||
|
|
||||||
#### update
|
#### update
|
||||||
|
|
||||||
The `coreos.update.*` parameters manipulate settings related to how CoreOS instances are updated.
|
The `coreos.update.*` parameters manipulate settings related to how CoreOS instances are updated.
|
||||||
@@ -303,7 +326,7 @@ Each item in the list may have the following keys:
|
|||||||
|
|
||||||
- **path**: Absolute location on disk where contents should be written
|
- **path**: Absolute location on disk where contents should be written
|
||||||
- **content**: Data to write at the provided `path`
|
- **content**: Data to write at the provided `path`
|
||||||
- **permissions**: String representing file permissions in octal notation (i.e. '0644')
|
- **permissions**: Integer representing file permissions, typically in octal notation (i.e. 0644)
|
||||||
- **owner**: User and group that should own the file written to disk. This is equivalent to the `<user>:<group>` argument to `chown <user>:<group> <path>`.
|
- **owner**: User and group that should own the file written to disk. This is equivalent to the `<user>:<group>` argument to `chown <user>:<group> <path>`.
|
||||||
|
|
||||||
Explicitly not implemented is the **encoding** attribute.
|
Explicitly not implemented is the **encoding** attribute.
|
||||||
|
@@ -31,6 +31,7 @@ type CloudConfig struct {
|
|||||||
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"`
|
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"`
|
||||||
Coreos struct {
|
Coreos struct {
|
||||||
Etcd Etcd `yaml:"etcd"`
|
Etcd Etcd `yaml:"etcd"`
|
||||||
|
Flannel Flannel `yaml:"flannel"`
|
||||||
Fleet Fleet `yaml:"fleet"`
|
Fleet Fleet `yaml:"fleet"`
|
||||||
OEM OEM `yaml:"oem"`
|
OEM OEM `yaml:"oem"`
|
||||||
Update Update `yaml:"update"`
|
Update Update `yaml:"update"`
|
||||||
|
@@ -276,6 +276,40 @@ Address=10.209.171.177/19
|
|||||||
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
|
||||||
@@ -479,6 +513,7 @@ func TestNormalizeKeys(t *testing.T) {
|
|||||||
{"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: false\n"},
|
||||||
|
{"coreos:\n update:\n reboot-strategy: 'off'\n", "coreos:\n update:\n reboot_strategy: \"off\"\n"},
|
||||||
} {
|
} {
|
||||||
out, err := normalizeConfig(tt.in)
|
out, err := normalizeConfig(tt.in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -21,28 +21,33 @@ type Etcd struct {
|
|||||||
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"`
|
||||||
ClusterActiveSize string `yaml:"cluster_active_size" env:"ETCD_CLUSTER_ACTIVE_SIZE"`
|
ClusterActiveSize int `yaml:"cluster_active_size" env:"ETCD_CLUSTER_ACTIVE_SIZE"`
|
||||||
ClusterRemoveDelay string `yaml:"cluster_remove_delay" env:"ETCD_CLUSTER_REMOVE_DELAY"`
|
ClusterRemoveDelay float64 `yaml:"cluster_remove_delay" env:"ETCD_CLUSTER_REMOVE_DELAY"`
|
||||||
ClusterSyncInterval string `yaml:"cluster_sync_interval" env:"ETCD_CLUSTER_SYNC_INTERVAL"`
|
ClusterSyncInterval float64 `yaml:"cluster_sync_interval" env:"ETCD_CLUSTER_SYNC_INTERVAL"`
|
||||||
Cors string `yaml:"cors" env:"ETCD_CORS"`
|
CorsOrigins string `yaml:"cors" env:"ETCD_CORS"`
|
||||||
CPUProfileFile string `yaml:"cpu_profile_file" env:"ETCD_CPU_PROFILE_FILE"`
|
|
||||||
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"`
|
||||||
HTTPReadTimeout string `yaml:"http_read_timeout" env:"ETCD_HTTP_READ_TIMEOUT"`
|
GraphiteHost string `yaml:"graphite_host" env:"ETCD_GRAPHITE_HOST"`
|
||||||
HTTPWriteTimeout string `yaml:"http_write_timeout" env:"ETCD_HTTP_WRITE_TIMEOUT"`
|
HTTPReadTimeout float64 `yaml:"http_read_timeout" env:"ETCD_HTTP_READ_TIMEOUT"`
|
||||||
|
HTTPWriteTimeout float64 `yaml:"http_write_timeout" env:"ETCD_HTTP_WRITE_TIMEOUT"`
|
||||||
KeyFile string `yaml:"key_file" env:"ETCD_KEY_FILE"`
|
KeyFile string `yaml:"key_file" env:"ETCD_KEY_FILE"`
|
||||||
MaxClusterSize string `yaml:"max_cluster_size" env:"ETCD_MAX_CLUSTER_SIZE"`
|
MaxResultBuffer int `yaml:"max_result_buffer" env:"ETCD_MAX_RESULT_BUFFER"`
|
||||||
MaxResultBuffer string `yaml:"max_result_buffer" env:"ETCD_MAX_RESULT_BUFFER"`
|
MaxRetryAttempts int `yaml:"max_retry_attempts" env:"ETCD_MAX_RETRY_ATTEMPTS"`
|
||||||
MaxRetryAttempts string `yaml:"max_retry_attempts" env:"ETCD_MAX_RETRY_ATTEMPTS"`
|
|
||||||
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"`
|
||||||
PeerCAFile string `yaml:"peer_ca_file" env:"ETCD_PEER_CA_FILE"`
|
PeerCAFile string `yaml:"peer_ca_file" env:"ETCD_PEER_CA_FILE"`
|
||||||
PeerCertFile string `yaml:"peer_cert_file" env:"ETCD_PEER_CERT_FILE"`
|
PeerCertFile string `yaml:"peer_cert_file" env:"ETCD_PEER_CERT_FILE"`
|
||||||
|
PeerElectionTimeout int `yaml:"peer_election_timeout" env:"ETCD_PEER_ELECTION_TIMEOUT"`
|
||||||
|
PeerHeartbeatInterval int `yaml:"peer_heartbeat_interval" env:"ETCD_PEER_HEARTBEAT_INTERVAL"`
|
||||||
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"`
|
||||||
Snapshot string `yaml:"snapshot" env:"ETCD_SNAPSHOT"`
|
RetryInterval float64 `yaml:"retry_interval" env:"ETCD_RETRY_INTERVAL"`
|
||||||
Verbose string `yaml:"verbose" env:"ETCD_VERBOSE"`
|
Snapshot bool `yaml:"snapshot" env:"ETCD_SNAPSHOT"`
|
||||||
VeryVerbose string `yaml:"very_verbose" env:"ETCD_VERY_VERBOSE"`
|
SnapshotCount int `yaml:"snapshot_count" env:"ETCD_SNAPSHOTCOUNT"`
|
||||||
|
StrTrace string `yaml:"trace" env:"ETCD_TRACE"`
|
||||||
|
Verbose bool `yaml:"verbose" env:"ETCD_VERBOSE"`
|
||||||
|
VeryVerbose bool `yaml:"very_verbose" env:"ETCD_VERY_VERBOSE"`
|
||||||
|
VeryVeryVerbose bool `yaml:"very_very_verbose" env:"ETCD_VERY_VERY_VERBOSE"`
|
||||||
}
|
}
|
||||||
|
9
config/flannel.go
Normal file
9
config/flannel.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
type Flannel struct {
|
||||||
|
EtcdEndpoint string `yaml:"etcd_endpoint" env:"FLANNELD_ETCD_ENDPOINT"`
|
||||||
|
EtcdPrefix string `yaml:"etcd_prefix" env:"FLANNELD_ETCD_PREFIX"`
|
||||||
|
IPMasq string `yaml:"ip_masq" env:"FLANNELD_IP_MASQ"`
|
||||||
|
SubnetFile string `yaml:"subnet_file" env:"FLANNELD_SUBNET_FILE"`
|
||||||
|
Iface string `yaml:"interface" env:"FLANNELD_IFACE"`
|
||||||
|
}
|
@@ -18,13 +18,14 @@ package config
|
|||||||
|
|
||||||
type Fleet struct {
|
type Fleet struct {
|
||||||
AgentTTL string `yaml:"agent_ttl" env:"FLEET_AGENT_TTL"`
|
AgentTTL string `yaml:"agent_ttl" env:"FLEET_AGENT_TTL"`
|
||||||
EngineReconcileInterval string `yaml:"engine_reconcile_interval" env:"FLEET_ENGINE_RECONCILE_INTERVAL"`
|
EngineReconcileInterval float64 `yaml:"engine_reconcile_interval" env:"FLEET_ENGINE_RECONCILE_INTERVAL"`
|
||||||
EtcdCAFile string `yaml:"etcd_cafile" env:"FLEET_ETCD_CAFILE"`
|
EtcdCAFile string `yaml:"etcd_cafile" env:"FLEET_ETCD_CAFILE"`
|
||||||
EtcdCertFile string `yaml:"etcd_certfile" env:"FLEET_ETCD_CERTFILE"`
|
EtcdCertFile string `yaml:"etcd_certfile" env:"FLEET_ETCD_CERTFILE"`
|
||||||
EtcdKeyFile string `yaml:"etcd_keyfile" env:"FLEET_ETCD_KEYFILE"`
|
EtcdKeyFile string `yaml:"etcd_keyfile" env:"FLEET_ETCD_KEYFILE"`
|
||||||
EtcdRequestTimeout string `yaml:"etcd_request_timeout" env:"FLEET_ETCD_REQUEST_TIMEOUT"`
|
EtcdKeyPrefix string `yaml:"etcd_key_prefix" env:"FLEET_ETCD_KEY_PREFIX"`
|
||||||
|
EtcdRequestTimeout float64 `yaml:"etcd_request_timeout" env:"FLEET_ETCD_REQUEST_TIMEOUT"`
|
||||||
EtcdServers string `yaml:"etcd_servers" env:"FLEET_ETCD_SERVERS"`
|
EtcdServers string `yaml:"etcd_servers" env:"FLEET_ETCD_SERVERS"`
|
||||||
Metadata string `yaml:"metadata" env:"FLEET_METADATA"`
|
Metadata string `yaml:"metadata" env:"FLEET_METADATA"`
|
||||||
PublicIP string `yaml:"public_ip" env:"FLEET_PUBLIC_IP"`
|
PublicIP string `yaml:"public_ip" env:"FLEET_PUBLIC_IP"`
|
||||||
Verbosity string `yaml:"verbosity" env:"FLEET_VERBOSITY"`
|
Verbosity int `yaml:"verbosity" env:"FLEET_VERBOSITY"`
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
type Update struct {
|
type Update struct {
|
||||||
RebootStrategy string `yaml:"reboot_strategy" env:"REBOOT_STRATEGY" valid:"best-effort,etcd-lock,reboot,false"`
|
RebootStrategy string `yaml:"reboot_strategy" env:"REBOOT_STRATEGY" valid:"best-effort,etcd-lock,reboot,off,false"`
|
||||||
Group string `yaml:"group" env:"GROUP"`
|
Group string `yaml:"group" env:"GROUP"`
|
||||||
Server string `yaml:"server" env:"SERVER"`
|
Server string `yaml:"server" env:"SERVER"`
|
||||||
}
|
}
|
||||||
|
@@ -125,7 +125,7 @@ func toNode(v interface{}, c context, n *node) {
|
|||||||
n.children = append(n.children, cn)
|
n.children = append(n.children, cn)
|
||||||
c.Increment()
|
c.Increment()
|
||||||
}
|
}
|
||||||
case reflect.String, reflect.Int, reflect.Bool:
|
case reflect.String, reflect.Int, reflect.Bool, reflect.Float64:
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("toNode(): unhandled kind %s", vv.Kind()))
|
panic(fmt.Sprintf("toNode(): unhandled kind %s", vv.Kind()))
|
||||||
}
|
}
|
||||||
|
@@ -61,7 +61,7 @@ func checkNodeStructure(n, g node, r *Report) {
|
|||||||
toNode(reflect.New(c).Elem().Interface(), context{}, &cg)
|
toNode(reflect.New(c).Elem().Interface(), context{}, &cg)
|
||||||
checkNodeStructure(cn, cg, r)
|
checkNodeStructure(cn, cg, r)
|
||||||
}
|
}
|
||||||
case reflect.String, reflect.Int, reflect.Bool:
|
case reflect.String, reflect.Int, reflect.Float64, reflect.Bool:
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("checkNodeStructure(): unhandled kind %s", g.Kind()))
|
panic(fmt.Sprintf("checkNodeStructure(): unhandled kind %s", g.Kind()))
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ func checkNodeValidity(n, g node, r *Report) {
|
|||||||
toNode(reflect.New(c).Elem().Interface(), context{}, &cg)
|
toNode(reflect.New(c).Elem().Interface(), context{}, &cg)
|
||||||
checkNodeValidity(cn, cg, r)
|
checkNodeValidity(cn, cg, r)
|
||||||
}
|
}
|
||||||
case reflect.String, reflect.Int, reflect.Bool:
|
case reflect.String, reflect.Int, reflect.Float64, reflect.Bool:
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("checkNodeValidity(): unhandled kind %s", g.Kind()))
|
panic(fmt.Sprintf("checkNodeValidity(): unhandled kind %s", g.Kind()))
|
||||||
}
|
}
|
||||||
@@ -104,10 +104,10 @@ func checkNodeValidity(n, g node, r *Report) {
|
|||||||
func isCompatible(n, g reflect.Kind) bool {
|
func isCompatible(n, g reflect.Kind) bool {
|
||||||
switch g {
|
switch g {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return n == reflect.String || n == reflect.Int || n == reflect.Bool
|
return n == reflect.String || n == reflect.Int || n == reflect.Float64 || n == reflect.Bool
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
return n == reflect.Struct || n == reflect.Map
|
return n == reflect.Struct || n == reflect.Map
|
||||||
case reflect.Bool, reflect.Slice:
|
case reflect.Bool, reflect.Slice, reflect.Int, reflect.Float64:
|
||||||
return n == g
|
return n == g
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("isCompatible(): unhandled kind %s", g))
|
panic(fmt.Sprintf("isCompatible(): unhandled kind %s", g))
|
||||||
|
@@ -44,7 +44,7 @@ func Validate(userdataBytes []byte) (Report, error) {
|
|||||||
return validateCloudConfig(userdataBytes, Rules)
|
return validateCloudConfig(userdataBytes, Rules)
|
||||||
default:
|
default:
|
||||||
return Report{entries: []Entry{
|
return Report{entries: []Entry{
|
||||||
Entry{kind: entryError, message: `must be "#cloud-config" or begin with "#!"`},
|
Entry{kind: entryError, message: `must be "#cloud-config" or begin with "#!"`, line: 1},
|
||||||
}}, nil
|
}}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +103,8 @@ func parseCloudConfig(config []byte, report *Report) (n node, err error) {
|
|||||||
// and makes a note of each replacement in the report.
|
// and makes a note of each replacement in the report.
|
||||||
func normalizeNodeNames(node node, report *Report) node {
|
func normalizeNodeNames(node node, report *Report) node {
|
||||||
if strings.Contains(node.name, "-") {
|
if strings.Contains(node.name, "-") {
|
||||||
report.Info(node.line, fmt.Sprintf("%q uses '-' instead of '_'", node.name))
|
// TODO(crawford): Enable this message once the new validator hits stable.
|
||||||
|
//report.Info(node.line, fmt.Sprintf("%q uses '-' instead of '_'", node.name))
|
||||||
node.name = strings.Replace(node.name, "-", "_", -1)
|
node.name = strings.Replace(node.name, "-", "_", -1)
|
||||||
}
|
}
|
||||||
for i := range node.children {
|
for i := range node.children {
|
||||||
|
@@ -40,7 +40,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
version = "0.11.0"
|
version = "0.11.4"
|
||||||
datasourceInterval = 100 * time.Millisecond
|
datasourceInterval = 100 * time.Millisecond
|
||||||
datasourceMaxInterval = 30 * time.Second
|
datasourceMaxInterval = 30 * time.Second
|
||||||
datasourceTimeout = 5 * time.Minute
|
datasourceTimeout = 5 * time.Minute
|
||||||
|
@@ -131,6 +131,7 @@ func Apply(cfg config.CloudConfig, env *Environment) error {
|
|||||||
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.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()...)
|
||||||
|
@@ -19,6 +19,8 @@ package system
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// dropinContents generates the contents for a drop-in unit given the config.
|
// dropinContents generates the contents for a drop-in unit given the config.
|
||||||
@@ -29,9 +31,9 @@ func dropinContents(e interface{}) string {
|
|||||||
|
|
||||||
var out string
|
var out string
|
||||||
for i := 0; i < et.NumField(); i++ {
|
for i := 0; i < et.NumField(); i++ {
|
||||||
if val := ev.Field(i).String(); 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=%s\"\n", key, val)
|
out += fmt.Sprintf("Environment=\"%s=%v\"\n", key, val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,3 +42,16 @@ func dropinContents(e interface{}) string {
|
|||||||
}
|
}
|
||||||
return "[Service]\n" + out
|
return "[Service]\n" + out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dropinFromConfig(cfg interface{}, name string) []Unit {
|
||||||
|
content := dropinContents(cfg)
|
||||||
|
if content == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []Unit{{config.Unit{
|
||||||
|
Name: name,
|
||||||
|
Runtime: true,
|
||||||
|
DropIn: true,
|
||||||
|
Content: content,
|
||||||
|
}}}
|
||||||
|
}
|
||||||
|
55
system/env_test.go
Normal file
55
system/env_test.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDropinContents(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
Config interface{}
|
||||||
|
Contents string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
struct{}{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
A string `env:"A"`
|
||||||
|
B int `env:"B"`
|
||||||
|
C bool `env:"C"`
|
||||||
|
D float64 `env:"D"`
|
||||||
|
}{
|
||||||
|
"hi", 1, true, 0.12345,
|
||||||
|
},
|
||||||
|
`[Service]
|
||||||
|
Environment="A=hi"
|
||||||
|
Environment="B=1"
|
||||||
|
Environment="C=true"
|
||||||
|
Environment="D=0.12345"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
A float64 `env:"A"`
|
||||||
|
B float64 `env:"B"`
|
||||||
|
C float64 `env:"C"`
|
||||||
|
D float64 `env:"D"`
|
||||||
|
}{
|
||||||
|
0.000001, 1, 0.9999999, 0.1,
|
||||||
|
},
|
||||||
|
`[Service]
|
||||||
|
Environment="A=1e-06"
|
||||||
|
Environment="B=1"
|
||||||
|
Environment="C=0.9999999"
|
||||||
|
Environment="D=0.1"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
if c := dropinContents(tt.Config); c != tt.Contents {
|
||||||
|
t.Errorf("bad contents (%+v): want %q, got %q", tt, tt.Contents, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -28,14 +28,5 @@ type Etcd struct {
|
|||||||
|
|
||||||
// Units creates a Unit file drop-in for etcd, using any configured options.
|
// Units creates a Unit file drop-in for etcd, using any configured options.
|
||||||
func (ee Etcd) Units() []Unit {
|
func (ee Etcd) Units() []Unit {
|
||||||
content := dropinContents(ee.Etcd)
|
return dropinFromConfig(ee.Etcd, "etcd.service")
|
||||||
if content == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return []Unit{{config.Unit{
|
|
||||||
Name: "etcd.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIn: true,
|
|
||||||
Content: content,
|
|
||||||
}}}
|
|
||||||
}
|
}
|
||||||
|
@@ -67,7 +67,7 @@ Environment="ETCD_PEER_BIND_ADDR=127.0.0.1:7002"
|
|||||||
} {
|
} {
|
||||||
units := Etcd{tt.config}.Units()
|
units := Etcd{tt.config}.Units()
|
||||||
if !reflect.DeepEqual(tt.units, units) {
|
if !reflect.DeepEqual(tt.units, units) {
|
||||||
t.Errorf("bad units (%q): want %#v, got %#v", tt.config, tt.units, units)
|
t.Errorf("bad units (%+v): want %#v, got %#v", tt.config, tt.units, units)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@@ -39,10 +38,10 @@ func (f *File) Permissions() (os.FileMode, error) {
|
|||||||
return os.FileMode(0644), nil
|
return os.FileMode(0644), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse string representation of file mode as octal
|
// Parse string representation of file mode as integer
|
||||||
perm, err := strconv.ParseInt(f.RawFilePermissions, 8, 32)
|
perm, err := strconv.ParseInt(f.RawFilePermissions, 0, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.New("Unable to parse file permissions as octal integer")
|
return 0, fmt.Errorf("Unable to parse file permissions %q as integer", f.RawFilePermissions)
|
||||||
}
|
}
|
||||||
return os.FileMode(perm), nil
|
return os.FileMode(perm), nil
|
||||||
}
|
}
|
||||||
|
@@ -85,6 +85,38 @@ func TestWriteFileInvalidPermission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDecimalFilePermissions(t *testing.T) {
|
||||||
|
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unable to create tempdir: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
fn := "foo"
|
||||||
|
fullPath := path.Join(dir, fn)
|
||||||
|
|
||||||
|
wf := File{config.File{
|
||||||
|
Path: fn,
|
||||||
|
RawFilePermissions: "484", // Decimal representation of 0744
|
||||||
|
}}
|
||||||
|
|
||||||
|
path, err := WriteFile(&wf, dir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Processing of WriteFile failed: %v", err)
|
||||||
|
} else if path != fullPath {
|
||||||
|
t.Fatalf("WriteFile returned bad path: want %s, got %s", fullPath, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := os.Stat(fullPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unable to stat file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.Mode() != os.FileMode(0744) {
|
||||||
|
t.Errorf("File has incorrect mode: %v", fi.Mode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestWriteFilePermissions(t *testing.T) {
|
func TestWriteFilePermissions(t *testing.T) {
|
||||||
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
17
system/flannel.go
Normal file
17
system/flannel.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/coreos/coreos-cloudinit/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// flannel is a top-level structure which embeds its underlying configuration,
|
||||||
|
// config.Flannel, and provides the system-specific Unit().
|
||||||
|
type Flannel struct {
|
||||||
|
config.Flannel
|
||||||
|
}
|
||||||
|
|
||||||
|
// Units generates a Unit file drop-in for flannel, if any flannel options were
|
||||||
|
// configured in cloud-config
|
||||||
|
func (fl Flannel) Units() []Unit {
|
||||||
|
return dropinFromConfig(fl.Flannel, "flannel.service")
|
||||||
|
}
|
40
system/flannel_test.go
Normal file
40
system/flannel_test.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/coreos/coreos-cloudinit/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFlannelUnits(t *testing.T) {
|
||||||
|
for _, tt := range []struct {
|
||||||
|
config config.Flannel
|
||||||
|
units []Unit
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
config.Flannel{},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config.Flannel{
|
||||||
|
EtcdEndpoint: "http://12.34.56.78:4001",
|
||||||
|
EtcdPrefix: "/coreos.com/network/tenant1",
|
||||||
|
},
|
||||||
|
[]Unit{{config.Unit{
|
||||||
|
Name: "flannel.service",
|
||||||
|
Content: `[Service]
|
||||||
|
Environment="FLANNELD_ETCD_ENDPOINT=http://12.34.56.78:4001"
|
||||||
|
Environment="FLANNELD_ETCD_PREFIX=/coreos.com/network/tenant1"
|
||||||
|
`,
|
||||||
|
Runtime: true,
|
||||||
|
DropIn: true,
|
||||||
|
}}},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
units := Flannel{tt.config}.Units()
|
||||||
|
if !reflect.DeepEqual(units, tt.units) {
|
||||||
|
t.Errorf("bad units (%q): want %v, got %v", tt.config, tt.units, units)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -29,14 +29,5 @@ type Fleet struct {
|
|||||||
// Units generates a Unit file drop-in for fleet, if any fleet options were
|
// Units generates a Unit file drop-in for fleet, if any fleet options were
|
||||||
// configured in cloud-config
|
// configured in cloud-config
|
||||||
func (fe Fleet) Units() []Unit {
|
func (fe Fleet) Units() []Unit {
|
||||||
content := dropinContents(fe.Fleet)
|
return dropinFromConfig(fe.Fleet, "fleet.service")
|
||||||
if content == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return []Unit{{config.Unit{
|
|
||||||
Name: "fleet.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIn: true,
|
|
||||||
Content: content,
|
|
||||||
}}}
|
|
||||||
}
|
}
|
||||||
|
@@ -48,7 +48,7 @@ Environment="FLEET_PUBLIC_IP=12.34.56.78"
|
|||||||
} {
|
} {
|
||||||
units := Fleet{tt.config}.Units()
|
units := Fleet{tt.config}.Units()
|
||||||
if !reflect.DeepEqual(units, tt.units) {
|
if !reflect.DeepEqual(units, tt.units) {
|
||||||
t.Errorf("bad units (%q): want %#v, got %#v", tt.config, tt.units, units)
|
t.Errorf("bad units (%+v): want %#v, got %#v", tt.config, tt.units, units)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -126,7 +126,7 @@ func (uc Update) Units() []Unit {
|
|||||||
Runtime: true,
|
Runtime: true,
|
||||||
}}
|
}}
|
||||||
|
|
||||||
if uc.Update.RebootStrategy == "false" {
|
if uc.Update.RebootStrategy == "false" || uc.Update.RebootStrategy == "off" {
|
||||||
ls.Command = "stop"
|
ls.Command = "stop"
|
||||||
ls.Mask = true
|
ls.Mask = true
|
||||||
}
|
}
|
||||||
|
@@ -80,6 +80,15 @@ func TestUpdateUnits(t *testing.T) {
|
|||||||
Mask: true,
|
Mask: true,
|
||||||
}}},
|
}}},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
config: config.Update{RebootStrategy: "off"},
|
||||||
|
units: []Unit{{config.Unit{
|
||||||
|
Name: "locksmithd.service",
|
||||||
|
Command: "stop",
|
||||||
|
Runtime: true,
|
||||||
|
Mask: true,
|
||||||
|
}}},
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
units := Update{Update: tt.config, ReadConfig: testReadConfig("")}.Units()
|
units := Update{Update: tt.config, ReadConfig: testReadConfig("")}.Units()
|
||||||
if !reflect.DeepEqual(tt.units, units) {
|
if !reflect.DeepEqual(tt.units, units) {
|
||||||
@@ -100,7 +109,7 @@ func TestUpdateFile(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
config: config.Update{RebootStrategy: "wizzlewazzle"},
|
config: config.Update{RebootStrategy: "wizzlewazzle"},
|
||||||
err: &config.ErrorValid{Value: "wizzlewazzle", Field: "RebootStrategy", Valid: []string{"best-effort", "etcd-lock", "reboot", "false"}},
|
err: &config.ErrorValid{Value: "wizzlewazzle", Field: "RebootStrategy", Valid: []string{"best-effort", "etcd-lock", "reboot", "off", "false"}},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
config: config.Update{Group: "master", Server: "http://foo.com"},
|
config: config.Update{Group: "master", Server: "http://foo.com"},
|
||||||
@@ -142,6 +151,14 @@ func TestUpdateFile(t *testing.T) {
|
|||||||
RawFilePermissions: "0644",
|
RawFilePermissions: "0644",
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
config: config.Update{RebootStrategy: "off"},
|
||||||
|
file: &File{config.File{
|
||||||
|
Content: "REBOOT_STRATEGY=off\n",
|
||||||
|
Path: "etc/coreos/update.conf",
|
||||||
|
RawFilePermissions: "0644",
|
||||||
|
}},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
config: config.Update{RebootStrategy: "etcd-lock"},
|
config: config.Update{RebootStrategy: "etcd-lock"},
|
||||||
orig: "SERVER=https://example.com\nGROUP=thegroupc\nREBOOT_STRATEGY=awesome",
|
orig: "SERVER=https://example.com\nGROUP=thegroupc\nREBOOT_STRATEGY=awesome",
|
||||||
|
Reference in New Issue
Block a user