diff --git a/glide.yaml b/glide.yaml index 38983d92..833da17c 100644 --- a/glide.yaml +++ b/glide.yaml @@ -11,7 +11,7 @@ import: version: 0302d3914d2a6ad61404584cdae6e6dbc9c03599 - package: github.com/coreos/coreos-cloudinit - version: 405c2600b19ae77516c967f8ee8ebde5624d3663 + version: 65031e1ab2d3574544d26f5b5d7ddddd0032fd00 repo: https://github.com/rancher/coreos-cloudinit.git - package: github.com/coreos/go-systemd diff --git a/vendor/github.com/coreos/coreos-cloudinit/.travis.yml b/vendor/github.com/coreos/coreos-cloudinit/.travis.yml index 5bd6fddc..07494db3 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/.travis.yml +++ b/vendor/github.com/coreos/coreos-cloudinit/.travis.yml @@ -3,15 +3,10 @@ sudo: false matrix: include: - go: 1.4 - env: TOOLS_CMD=golang.org/x/tools/cmd - - go: 1.3 - env: TOOLS_CMD=code.google.com/p/go.tools/cmd - - go: 1.2 - env: TOOLS_CMD=code.google.com/p/go.tools/cmd - -install: - - go get ${TOOLS_CMD}/cover - - go get ${TOOLS_CMD}/vet + install: + - go get golang.org/x/tools/cmd/cover + - go get golang.org/x/tools/cmd/vet + - go: 1.5 script: - ./test diff --git a/vendor/github.com/coreos/coreos-cloudinit/README.md b/vendor/github.com/coreos/coreos-cloudinit/README.md index 64969a49..9c4f3141 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/README.md +++ b/vendor/github.com/coreos/coreos-cloudinit/README.md @@ -76,4 +76,11 @@ coreos: etcd: addr: 203.0.113.29:4001 peer-addr: 192.0.2.13:7001 -``` \ No newline at end of file +``` + +## Bugs + +Please use the [CoreOS issue tracker][bugs] to report all bugs, issues, and feature requests. + +[bugs]: https://github.com/coreos/bugs/issues/new?labels=component/cloud-init + diff --git a/vendor/github.com/coreos/coreos-cloudinit/build b/vendor/github.com/coreos/coreos-cloudinit/build index e6ed9bc8..36865afc 100755 --- a/vendor/github.com/coreos/coreos-cloudinit/build +++ b/vendor/github.com/coreos/coreos-cloudinit/build @@ -1,7 +1,10 @@ #!/bin/bash -e +NAME="coreos-cloudinit" ORG_PATH="github.com/coreos" -REPO_PATH="${ORG_PATH}/coreos-cloudinit" +REPO_PATH="${ORG_PATH}/${NAME}" +VERSION=$(git describe --dirty --tags) +GLDFLAGS="-X main.version \"${VERSION}\"" if [ ! -h gopath/src/${REPO_PATH} ]; then mkdir -p gopath/src/${ORG_PATH} @@ -11,4 +14,4 @@ fi export GOBIN=${PWD}/bin export GOPATH=${PWD}/gopath -go build -o bin/coreos-cloudinit ${REPO_PATH} +go build -ldflags "${GLDFLAGS}" -o ${GOBIN}/${NAME} ${REPO_PATH} diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/config.go b/vendor/github.com/coreos/coreos-cloudinit/config/config.go index 594597ec..ede380b4 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/config.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/config.go @@ -19,6 +19,7 @@ import ( "reflect" "regexp" "strings" + "unicode" "github.com/coreos/yaml" ) @@ -37,6 +38,7 @@ type CloudConfig struct { type CoreOS struct { Etcd Etcd `yaml:"etcd"` + Etcd2 Etcd2 `yaml:"etcd2"` Flannel Flannel `yaml:"flannel"` Fleet Fleet `yaml:"fleet"` Locksmith Locksmith `yaml:"locksmith"` @@ -48,10 +50,8 @@ type CoreOS struct { func IsCloudConfig(userdata string) bool { header := strings.SplitN(userdata, "\n", 2)[0] - // Explicitly trim the header so we can handle user-data from - // non-unix operating systems. The rest of the file is parsed - // by yaml, which correctly handles CRLF. - header = strings.TrimSuffix(header, "\r") + // Trim trailing whitespaces + header = strings.TrimRightFunc(header, unicode.IsSpace) return (header == "#cloud-config") } diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/config_test.go b/vendor/github.com/coreos/coreos-cloudinit/config/config_test.go index 71033b75..efcdd18b 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/config_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/config_test.go @@ -374,6 +374,7 @@ users: no_user_group: true system: y no_log_init: True + shell: /bin/sh ` cfg, err := NewCloudConfig(contents) if err != nil { @@ -441,6 +442,10 @@ users: if !user.NoLogInit { t.Errorf("Failed to parse no_log_init field") } + + if user.Shell != "/bin/sh" { + t.Errorf("Failed to parse shell field, got %q", user.Shell) + } } func TestCloudConfigUsersGithubUser(t *testing.T) { diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/etcd.go b/vendor/github.com/coreos/coreos-cloudinit/config/etcd.go index d52bdb6e..4315f49e 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/etcd.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/etcd.go @@ -16,7 +16,7 @@ package config type Etcd struct { Addr string `yaml:"addr" env:"ETCD_ADDR"` - AdvertiseClientURLs string `yaml:"advertise_client_urls" env:"ETCD_ADVERTISE_CLIENT_URLS"` + AdvertiseClientURLs string `yaml:"advertise_client_urls" env:"ETCD_ADVERTISE_CLIENT_URLS" deprecated:"etcd2 options no longer work for etcd"` BindAddr string `yaml:"bind_addr" env:"ETCD_BIND_ADDR"` CAFile string `yaml:"ca_file" env:"ETCD_CA_FILE"` CertFile string `yaml:"cert_file" env:"ETCD_CERT_FILE"` @@ -26,26 +26,26 @@ type Etcd struct { CorsOrigins string `yaml:"cors" env:"ETCD_CORS"` DataDir string `yaml:"data_dir" env:"ETCD_DATA_DIR"` 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"` + DiscoveryFallback string `yaml:"discovery_fallback" env:"ETCD_DISCOVERY_FALLBACK" deprecated:"etcd2 options no longer work for etcd"` + DiscoverySRV string `yaml:"discovery_srv" env:"ETCD_DISCOVERY_SRV" deprecated:"etcd2 options no longer work for etcd"` + DiscoveryProxy string `yaml:"discovery_proxy" env:"ETCD_DISCOVERY_PROXY" deprecated:"etcd2 options no longer work for etcd"` + ElectionTimeout int `yaml:"election_timeout" env:"ETCD_ELECTION_TIMEOUT" deprecated:"etcd2 options no longer work for etcd"` + ForceNewCluster bool `yaml:"force_new_cluster" env:"ETCD_FORCE_NEW_CLUSTER" deprecated:"etcd2 options no longer work for etcd"` GraphiteHost string `yaml:"graphite_host" env:"ETCD_GRAPHITE_HOST"` - HeartbeatInterval int `yaml:"heartbeat_interval" env:"ETCD_HEARTBEAT_INTERVAL"` + HeartbeatInterval int `yaml:"heartbeat_interval" env:"ETCD_HEARTBEAT_INTERVAL" deprecated:"etcd2 options no longer work for etcd"` HTTPReadTimeout float64 `yaml:"http_read_timeout" env:"ETCD_HTTP_READ_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"` + InitialAdvertisePeerURLs string `yaml:"initial_advertise_peer_urls" env:"ETCD_INITIAL_ADVERTISE_PEER_URLS" deprecated:"etcd2 options no longer work for etcd"` + InitialCluster string `yaml:"initial_cluster" env:"ETCD_INITIAL_CLUSTER" deprecated:"etcd2 options no longer work for etcd"` + InitialClusterState string `yaml:"initial_cluster_state" env:"ETCD_INITIAL_CLUSTER_STATE" deprecated:"etcd2 options no longer work for etcd"` + InitialClusterToken string `yaml:"initial_cluster_token" env:"ETCD_INITIAL_CLUSTER_TOKEN" deprecated:"etcd2 options no longer work for etcd"` 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"` + ListenClientURLs string `yaml:"listen_client_urls" env:"ETCD_LISTEN_CLIENT_URLS" deprecated:"etcd2 options no longer work for etcd"` + ListenPeerURLs string `yaml:"listen_peer_urls" env:"ETCD_LISTEN_PEER_URLS" deprecated:"etcd2 options no longer work for etcd"` MaxResultBuffer int `yaml:"max_result_buffer" env:"ETCD_MAX_RESULT_BUFFER"` 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"` + MaxSnapshots int `yaml:"max_snapshots" env:"ETCD_MAX_SNAPSHOTS" deprecated:"etcd2 options no longer work for etcd"` + MaxWALs int `yaml:"max_wals" env:"ETCD_MAX_WALS" deprecated:"etcd2 options no longer work for etcd"` Name string `yaml:"name" env:"ETCD_NAME"` PeerAddr string `yaml:"peer_addr" env:"ETCD_PEER_ADDR"` PeerBindAddr string `yaml:"peer_bind_addr" env:"ETCD_PEER_BIND_ADDR"` @@ -56,7 +56,7 @@ type Etcd struct { PeerKeyFile string `yaml:"peer_key_file" env:"ETCD_PEER_KEY_FILE"` Peers string `yaml:"peers" env:"ETCD_PEERS"` PeersFile string `yaml:"peers_file" env:"ETCD_PEERS_FILE"` - Proxy string `yaml:"proxy" env:"ETCD_PROXY"` + Proxy string `yaml:"proxy" env:"ETCD_PROXY" deprecated:"etcd2 options no longer work for etcd"` RetryInterval float64 `yaml:"retry_interval" env:"ETCD_RETRY_INTERVAL"` Snapshot bool `yaml:"snapshot" env:"ETCD_SNAPSHOT"` SnapshotCount int `yaml:"snapshot_count" env:"ETCD_SNAPSHOTCOUNT"` diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/etcd2.go b/vendor/github.com/coreos/coreos-cloudinit/config/etcd2.go new file mode 100644 index 00000000..4070800e --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/config/etcd2.go @@ -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 config + +type Etcd2 struct { + AdvertiseClientURLs string `yaml:"advertise_client_urls" env:"ETCD_ADVERTISE_CLIENT_URLS"` + CAFile string `yaml:"ca_file" env:"ETCD_CA_FILE" deprecated:"ca_file obsoleted by trusted_ca_file and client_cert_auth"` + CertFile string `yaml:"cert_file" env:"ETCD_CERT_FILE"` + ClientCertAuth bool `yaml:"client_cert_auth" env:"ETCD_CLIENT_CERT_AUTH"` + CorsOrigins string `yaml:"cors" env:"ETCD_CORS"` + DataDir string `yaml:"data_dir" env:"ETCD_DATA_DIR"` + Debug bool `yaml:"debug" env:"ETCD_DEBUG"` + 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"` + HeartbeatInterval int `yaml:"heartbeat_interval" env:"ETCD_HEARTBEAT_INTERVAL"` + 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"` + ListenClientURLs string `yaml:"listen_client_urls" env:"ETCD_LISTEN_CLIENT_URLS"` + ListenPeerURLs string `yaml:"listen_peer_urls" env:"ETCD_LISTEN_PEER_URLS"` + LogPackageLevels string `yaml:"log_package_levels" env:"ETCD_LOG_PACKAGE_LEVELS"` + 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"` + PeerCAFile string `yaml:"peer_ca_file" env:"ETCD_PEER_CA_FILE" deprecated:"peer_ca_file obsoleted peer_trusted_ca_file and peer_client_cert_auth"` + PeerCertFile string `yaml:"peer_cert_file" env:"ETCD_PEER_CERT_FILE"` + PeerKeyFile string `yaml:"peer_key_file" env:"ETCD_PEER_KEY_FILE"` + PeerClientCertAuth bool `yaml:"peer_client_cert_auth" env:"ETCD_PEER_CLIENT_CERT_AUTH"` + PeerTrustedCAFile string `yaml:"peer_trusted_ca_file" env:"ETCD_PEER_TRUSTED_CA_FILE"` + Proxy string `yaml:"proxy" env:"ETCD_PROXY" valid:"^(on|off|readonly)$"` + ProxyDialTimeout int `yaml:"proxy_dial_timeout" env:"ETCD_PROXY_DIAL_TIMEOUT"` + ProxyFailureWait int `yaml:"proxy_failure_wait" env:"ETCD_PROXY_FAILURE_WAIT"` + ProxyReadTimeout int `yaml:"proxy_read_timeout" env:"ETCD_PROXY_READ_TIMEOUT"` + ProxyRefreshInterval int `yaml:"proxy_refresh_interval" env:"ETCD_PROXY_REFRESH_INTERVAL"` + ProxyWriteTimeout int `yaml:"proxy_write_timeout" env:"ETCD_PROXY_WRITE_TIMEOUT"` + SnapshotCount int `yaml:"snapshot_count" env:"ETCD_SNAPSHOT_COUNT"` + TrustedCAFile string `yaml:"trusted_ca_file" env:"ETCD_TRUSTED_CA_FILE"` + WalDir string `yaml:"wal_dir" env:"ETCD_WAL_DIR"` +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/file_test.go b/vendor/github.com/coreos/coreos-cloudinit/config/file_test.go index e3f08716..60a8efe2 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/file_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/file_test.go @@ -1,18 +1,16 @@ -/* - 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. -*/ +// 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 diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/flannel.go b/vendor/github.com/coreos/coreos-cloudinit/config/flannel.go index 043afc9a..7a953f8c 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/flannel.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/flannel.go @@ -23,4 +23,5 @@ type Flannel struct { 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"` + PublicIP string `yaml:"public_ip" env:"FLANNELD_PUBLIC_IP"` } diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/fleet.go b/vendor/github.com/coreos/coreos-cloudinit/config/fleet.go index 534ccb48..970905cc 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/fleet.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/fleet.go @@ -16,6 +16,8 @@ package config type Fleet struct { AgentTTL string `yaml:"agent_ttl" env:"FLEET_AGENT_TTL"` + AuthorizedKeysFile string `yaml:"authorized_keys_file" env:"FLEET_AUTHORIZED_KEYS_FILE"` + DisableEngine bool `yaml:"disable_engine" env:"FLEET_DISABLE_ENGINE"` EngineReconcileInterval float64 `yaml:"engine_reconcile_interval" env:"FLEET_ENGINE_RECONCILE_INTERVAL"` EtcdCAFile string `yaml:"etcd_cafile" env:"FLEET_ETCD_CAFILE"` EtcdCertFile string `yaml:"etcd_certfile" env:"FLEET_ETCD_CERTFILE"` @@ -25,5 +27,7 @@ type Fleet struct { EtcdServers string `yaml:"etcd_servers" env:"FLEET_ETCD_SERVERS"` Metadata string `yaml:"metadata" env:"FLEET_METADATA"` PublicIP string `yaml:"public_ip" env:"FLEET_PUBLIC_IP"` + TokenLimit int `yaml:"token_limit" env:"FLEET_TOKEN_LIMIT"` Verbosity int `yaml:"verbosity" env:"FLEET_VERBOSITY"` + VerifyUnits bool `yaml:"verify_units" env:"FLEET_VERIFY_UNITS"` } diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/ignition.go b/vendor/github.com/coreos/coreos-cloudinit/config/ignition.go new file mode 100644 index 00000000..413a636c --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/config/ignition.go @@ -0,0 +1,26 @@ +// 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 + +import ( + "encoding/json" +) + +func IsIgnitionConfig(userdata string) bool { + var cfg struct { + Version *int `json:"ignitionVersion" yaml:"ignition_version"` + } + return (json.Unmarshal([]byte(userdata), &cfg) == nil && cfg.Version != nil) +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/locksmith.go b/vendor/github.com/coreos/coreos-cloudinit/config/locksmith.go index 6bf8f857..aa1232d9 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/locksmith.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/locksmith.go @@ -15,8 +15,11 @@ package config type Locksmith struct { - Endpoint string `yaml:"endpoint" env:"LOCKSMITHD_ENDPOINT"` - EtcdCAFile string `yaml:"etcd_cafile" env:"LOCKSMITHD_ETCD_CAFILE"` - EtcdCertFile string `yaml:"etcd_certfile" env:"LOCKSMITHD_ETCD_CERTFILE"` - EtcdKeyFile string `yaml:"etcd_keyfile" env:"LOCKSMITHD_ETCD_KEYFILE"` + Endpoint string `yaml:"endpoint" env:"LOCKSMITHD_ENDPOINT"` + EtcdCAFile string `yaml:"etcd_cafile" env:"LOCKSMITHD_ETCD_CAFILE"` + EtcdCertFile string `yaml:"etcd_certfile" env:"LOCKSMITHD_ETCD_CERTFILE"` + EtcdKeyFile string `yaml:"etcd_keyfile" env:"LOCKSMITHD_ETCD_KEYFILE"` + Group string `yaml:"group" env:"LOCKSMITHD_GROUP"` + RebootWindowStart string `yaml:"window_start" env:"REBOOT_WINDOW_START" valid:"^((?i:sun|mon|tue|wed|thu|fri|sat|sun) )?0*([0-9]|1[0-9]|2[0-3]):0*([0-9]|[1-5][0-9])$"` + RebootWindowLength string `yaml:"window_length" env:"REBOOT_WINDOW_LENGTH" valid:"^[-+]?([0-9]*(\\.[0-9]*)?[a-z]+)+$"` } diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/locksmith_test.go b/vendor/github.com/coreos/coreos-cloudinit/config/locksmith_test.go new file mode 100644 index 00000000..a8c4eb57 --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/config/locksmith_test.go @@ -0,0 +1,76 @@ +// 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 + +import ( + "testing" +) + +func TestRebootWindowStart(t *testing.T) { + tests := []struct { + value string + + isValid bool + }{ + {value: "Sun 0:0", isValid: true}, + {value: "Sun 00:00", isValid: true}, + {value: "sUn 23:59", isValid: true}, + {value: "mon 0:0", isValid: true}, + {value: "tue 0:0", isValid: true}, + {value: "tues 0:0", isValid: false}, + {value: "wed 0:0", isValid: true}, + {value: "thu 0:0", isValid: true}, + {value: "thur 0:0", isValid: false}, + {value: "fri 0:0", isValid: true}, + {value: "sat 0:0", isValid: true}, + {value: "sat00:00", isValid: false}, + {value: "00:00", isValid: true}, + {value: "10:10", isValid: true}, + {value: "20:20", isValid: true}, + {value: "20:30", isValid: true}, + {value: "20:40", isValid: true}, + {value: "20:50", isValid: true}, + {value: "20:60", isValid: false}, + {value: "24:00", isValid: false}, + } + + for _, tt := range tests { + isValid := (nil == AssertStructValid(Locksmith{RebootWindowStart: tt.value})) + if tt.isValid != isValid { + t.Errorf("bad assert (%s): want %t, got %t", tt.value, tt.isValid, isValid) + } + } +} + +func TestRebootWindowLength(t *testing.T) { + tests := []struct { + value string + + isValid bool + }{ + {value: "1h", isValid: true}, + {value: "1d", isValid: true}, + {value: "0d", isValid: true}, + {value: "0.5h", isValid: true}, + {value: "0.5.0h", isValid: false}, + } + + for _, tt := range tests { + isValid := (nil == AssertStructValid(Locksmith{RebootWindowLength: tt.value})) + if tt.isValid != isValid { + t.Errorf("bad assert (%s): want %t, got %t", tt.value, tt.isValid, isValid) + } + } +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/config/user.go b/vendor/github.com/coreos/coreos-cloudinit/config/user.go index 024b6fa1..eb04bc18 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/config/user.go +++ b/vendor/github.com/coreos/coreos-cloudinit/config/user.go @@ -18,9 +18,9 @@ type User struct { Name string `yaml:"name"` PasswordHash string `yaml:"passwd"` SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"` - SSHImportGithubUser string `yaml:"coreos_ssh_import_github"` - SSHImportGithubUsers []string `yaml:"coreos_ssh_import_github_users"` - SSHImportURL string `yaml:"coreos_ssh_import_url"` + SSHImportGithubUser string `yaml:"coreos_ssh_import_github" deprecated:"trying to fetch from a remote endpoint introduces too many intermittent errors"` + SSHImportGithubUsers []string `yaml:"coreos_ssh_import_github_users" deprecated:"trying to fetch from a remote endpoint introduces too many intermittent errors"` + SSHImportURL string `yaml:"coreos_ssh_import_url" deprecated:"trying to fetch from a remote endpoint introduces too many intermittent errors"` GECOS string `yaml:"gecos"` Homedir string `yaml:"homedir"` NoCreateHome bool `yaml:"no_create_home"` @@ -29,4 +29,5 @@ type User struct { NoUserGroup bool `yaml:"no_user_group"` System bool `yaml:"system"` NoLogInit bool `yaml:"no_log_init"` + Shell string `yaml:"shell"` } diff --git a/vendor/github.com/coreos/coreos-cloudinit/coreos-cloudinit.go b/vendor/github.com/coreos/coreos-cloudinit/coreos-cloudinit.go index 91992cb1..d82a72dd 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/coreos-cloudinit.go +++ b/vendor/github.com/coreos/coreos-cloudinit/coreos-cloudinit.go @@ -15,9 +15,14 @@ package main import ( + "bytes" + "compress/gzip" "flag" "fmt" + "io/ioutil" + "log" "os" + "runtime" "sync" "time" @@ -29,8 +34,10 @@ import ( "github.com/coreos/coreos-cloudinit/datasource/metadata/cloudsigma" "github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean" "github.com/coreos/coreos-cloudinit/datasource/metadata/ec2" + "github.com/coreos/coreos-cloudinit/datasource/metadata/packet" "github.com/coreos/coreos-cloudinit/datasource/proc_cmdline" "github.com/coreos/coreos-cloudinit/datasource/url" + "github.com/coreos/coreos-cloudinit/datasource/vmware" "github.com/coreos/coreos-cloudinit/datasource/waagent" "github.com/coreos/coreos-cloudinit/initialize" "github.com/coreos/coreos-cloudinit/network" @@ -39,7 +46,6 @@ import ( ) const ( - version = "1.3.2+git" datasourceInterval = 100 * time.Millisecond datasourceMaxInterval = 30 * time.Second datasourceTimeout = 5 * time.Minute @@ -57,8 +63,10 @@ var ( ec2MetadataService string cloudSigmaMetadataService bool digitalOceanMetadataService string + packetMetadataService string url string procCmdLine bool + vmware bool } convertNetconf string workspace string @@ -66,6 +74,7 @@ var ( oem string validate bool }{} + version = "was not built properly" ) func init() { @@ -78,8 +87,10 @@ func init() { flag.StringVar(&flags.sources.ec2MetadataService, "from-ec2-metadata", "", "Download EC2 data from the provided url") flag.BoolVar(&flags.sources.cloudSigmaMetadataService, "from-cloudsigma-metadata", false, "Download data from CloudSigma server context") flag.StringVar(&flags.sources.digitalOceanMetadataService, "from-digitalocean-metadata", "", "Download DigitalOcean data from the provided url") + flag.StringVar(&flags.sources.packetMetadataService, "from-packet-metadata", "", "Download Packet data from metadata service") flag.StringVar(&flags.sources.url, "from-url", "", "Download user-data from provided url") flag.BoolVar(&flags.sources.procCmdLine, "from-proc-cmdline", false, fmt.Sprintf("Parse %s for '%s=', using the cloud-config served by an HTTP GET to ", proc_cmdline.ProcCmdlineLocation, proc_cmdline.ProcCmdlineCloudConfigFlag)) + flag.BoolVar(&flags.sources.vmware, "from-vmware-guestinfo", false, "Read data from VMware guestinfo") flag.StringVar(&flags.oem, "oem", "", "Use the settings specific to the provided OEM") flag.StringVar(&flags.convertNetconf, "convert-netconf", "", "Read the network config provided in cloud-drive and translate it from the specified format into networkd unit files") flag.StringVar(&flags.workspace, "workspace", "/var/lib/coreos-cloudinit", "Base directory coreos-cloudinit should use to store data") @@ -109,12 +120,25 @@ var ( "cloudsigma": oemConfig{ "from-cloudsigma-metadata": "true", }, + "packet": oemConfig{ + "from-packet-metadata": "https://metadata.packet.net/", + }, + "vmware": oemConfig{ + "from-vmware-guestinfo": "true", + "convert-netconf": "vmware", + }, } ) func main() { failure := false + // Conservative Go 1.5 upgrade strategy: + // keep GOMAXPROCS' default at 1 for now. + if os.Getenv("GOMAXPROCS") == "" { + runtime.GOMAXPROCS(1) + } + flag.Parse() if c, ok := oemConfigs[flags.oem]; ok { @@ -126,12 +150,12 @@ func main() { for k := range oemConfigs { oems = append(oems, k) } - fmt.Printf("Invalid option to --oem: %q. Supported options: %q\n", flags.oem, oems) + fmt.Printf("Invalid option to -oem: %q. Supported options: %q\n", flags.oem, oems) os.Exit(2) } if flags.printVersion == true { - fmt.Printf("coreos-cloudinit version %s\n", version) + fmt.Printf("coreos-cloudinit %s\n", version) os.Exit(0) } @@ -139,50 +163,57 @@ func main() { case "": case "debian": case "digitalocean": + case "packet": + case "vmware": default: - fmt.Printf("Invalid option to -convert-netconf: '%s'. Supported options: 'debian, digitalocean'\n", flags.convertNetconf) + fmt.Printf("Invalid option to -convert-netconf: '%s'. Supported options: 'debian, digitalocean, packet, vmware'\n", flags.convertNetconf) os.Exit(2) } dss := getDatasources() if len(dss) == 0 { - fmt.Println("Provide at least one of --from-file, --from-configdrive, --from-ec2-metadata, --from-cloudsigma-metadata, --from-url or --from-proc-cmdline") + fmt.Println("Provide at least one of --from-file, --from-configdrive, --from-ec2-metadata, --from-cloudsigma-metadata, --from-packet-metadata, --from-digitalocean-metadata, --from-vmware-guestinfo, --from-waagent, --from-url or --from-proc-cmdline") os.Exit(2) } ds := selectDatasource(dss) if ds == nil { - fmt.Println("No datasources available in time") + log.Println("No datasources available in time") os.Exit(1) } - fmt.Printf("Fetching user-data from datasource of type %q\n", ds.Type()) + log.Printf("Fetching user-data from datasource of type %q\n", ds.Type()) userdataBytes, err := ds.FetchUserdata() if err != nil { - fmt.Printf("Failed fetching user-data from datasource: %v\nContinuing...\n", err) + log.Printf("Failed fetching user-data from datasource: %v. Continuing...\n", err) + failure = true + } + userdataBytes, err = decompressIfGzip(userdataBytes) + if err != nil { + log.Printf("Failed decompressing user-data from datasource: %v. Continuing...\n", err) failure = true } if report, err := validate.Validate(userdataBytes); err == nil { ret := 0 for _, e := range report.Entries() { - fmt.Println(e) + log.Println(e) ret = 1 } if flags.validate { os.Exit(ret) } } else { - fmt.Printf("Failed while validating user_data (%q)\n", err) + log.Printf("Failed while validating user_data (%q)\n", err) if flags.validate { os.Exit(1) } } - fmt.Printf("Fetching meta-data from datasource of type %q\n", ds.Type()) + log.Printf("Fetching meta-data from datasource of type %q\n", ds.Type()) metadata, err := ds.FetchMetadata() if err != nil { - fmt.Printf("Failed fetching meta-data from datasource: %v\n", err) + log.Printf("Failed fetching meta-data from datasource: %v\n", err) os.Exit(1) } @@ -192,19 +223,23 @@ func main() { var ccu *config.CloudConfig var script *config.Script - if ud, err := initialize.ParseUserData(userdata); err != nil { - fmt.Printf("Failed to parse user-data: %v\nContinuing...\n", err) - failure = true - } else { + switch ud, err := initialize.ParseUserData(userdata); err { + case initialize.ErrIgnitionConfig: + fmt.Printf("Detected an Ignition config. Exiting...") + os.Exit(0) + case nil: switch t := ud.(type) { case *config.CloudConfig: ccu = t case *config.Script: script = t } + default: + fmt.Printf("Failed to parse user-data: %v\nContinuing...\n", err) + failure = true } - fmt.Println("Merging cloud-config from meta-data and user-data") + log.Println("Merging cloud-config from meta-data and user-data") cc := mergeConfigs(ccu, metadata) var ifaces []network.InterfaceGenerator @@ -212,26 +247,30 @@ func main() { var err error switch flags.convertNetconf { case "debian": - ifaces, err = network.ProcessDebianNetconf(metadata.NetworkConfig) + ifaces, err = network.ProcessDebianNetconf(metadata.NetworkConfig.([]byte)) case "digitalocean": - ifaces, err = network.ProcessDigitalOceanNetconf(metadata.NetworkConfig) + ifaces, err = network.ProcessDigitalOceanNetconf(metadata.NetworkConfig.(digitalocean.Metadata)) + case "packet": + ifaces, err = network.ProcessPacketNetconf(metadata.NetworkConfig.(packet.NetworkData)) + case "vmware": + ifaces, err = network.ProcessVMwareNetconf(metadata.NetworkConfig.(map[string]string)) default: err = fmt.Errorf("Unsupported network config format %q", flags.convertNetconf) } if err != nil { - fmt.Printf("Failed to generate interfaces: %v\n", err) + log.Printf("Failed to generate interfaces: %v\n", err) os.Exit(1) } } if err = initialize.Apply(cc, ifaces, env); err != nil { - fmt.Printf("Failed to apply cloud-config: %v\n", err) + log.Printf("Failed to apply cloud-config: %v\n", err) os.Exit(1) } if script != nil { if err = runScript(*script, env); err != nil { - fmt.Printf("Failed to run script: %v\n", err) + log.Printf("Failed to run script: %v\n", err) os.Exit(1) } } @@ -251,7 +290,7 @@ func mergeConfigs(cc *config.CloudConfig, md datasource.Metadata) (out config.Cl if md.Hostname != "" { if out.Hostname != "" { - fmt.Printf("Warning: user-data hostname (%s) overrides metadata hostname (%s)\n", out.Hostname, md.Hostname) + log.Printf("Warning: user-data hostname (%s) overrides metadata hostname (%s)\n", out.Hostname, md.Hostname) } else { out.Hostname = md.Hostname } @@ -290,9 +329,15 @@ func getDatasources() []datasource.Datasource { if flags.sources.waagent != "" { dss = append(dss, waagent.NewDatasource(flags.sources.waagent)) } + if flags.sources.packetMetadataService != "" { + dss = append(dss, packet.NewDatasource(flags.sources.packetMetadataService)) + } if flags.sources.procCmdLine { dss = append(dss, proc_cmdline.NewDatasource()) } + if flags.sources.vmware { + dss = append(dss, vmware.NewDatasource()) + } return dss } @@ -313,7 +358,7 @@ func selectDatasource(sources []datasource.Datasource) datasource.Datasource { duration := datasourceInterval for { - fmt.Printf("Checking availability of %q\n", s.Type()) + log.Printf("Checking availability of %q\n", s.Type()) if s.IsAvailable() { ds <- s return @@ -351,7 +396,7 @@ func selectDatasource(sources []datasource.Datasource) datasource.Datasource { func runScript(script config.Script, env *initialize.Environment) error { err := initialize.PrepWorkspace(env.Workspace()) if err != nil { - fmt.Printf("Failed preparing workspace: %v\n", err) + log.Printf("Failed preparing workspace: %v\n", err) return err } path, err := initialize.PersistScriptInWorkspace(script, env.Workspace()) @@ -362,3 +407,17 @@ func runScript(script config.Script, env *initialize.Environment) error { } return err } + +const gzipMagicBytes = "\x1f\x8b" + +func decompressIfGzip(userdataBytes []byte) ([]byte, error) { + if !bytes.HasPrefix(userdataBytes, []byte(gzipMagicBytes)) { + return userdataBytes, nil + } + gzr, err := gzip.NewReader(bytes.NewReader(userdataBytes)) + if err != nil { + return nil, err + } + defer gzr.Close() + return ioutil.ReadAll(gzr) +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/coreos-cloudinit_test.go b/vendor/github.com/coreos/coreos-cloudinit/coreos-cloudinit_test.go index cd87d5f4..cd5c6da4 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/coreos-cloudinit_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/coreos-cloudinit_test.go @@ -15,6 +15,9 @@ package main import ( + "bytes" + "encoding/base64" + "errors" "reflect" "testing" @@ -87,3 +90,58 @@ func TestMergeConfigs(t *testing.T) { } } } + +func mustDecode(in string) []byte { + out, err := base64.StdEncoding.DecodeString(in) + if err != nil { + panic(err) + } + return out +} + +func TestDecompressIfGzip(t *testing.T) { + tests := []struct { + in []byte + + out []byte + err error + }{ + { + in: nil, + + out: nil, + err: nil, + }, + { + in: []byte{}, + + out: []byte{}, + err: nil, + }, + { + in: mustDecode("H4sIAJWV/VUAA1NOzskvTdFNzs9Ly0wHABt6mQENAAAA"), + + out: []byte("#cloud-config"), + err: nil, + }, + { + in: []byte("#cloud-config"), + + out: []byte("#cloud-config"), + err: nil, + }, + { + in: mustDecode("H4sCORRUPT=="), + + out: nil, + err: errors.New("any error"), + }, + } + for i, tt := range tests { + out, err := decompressIfGzip(tt.in) + if !bytes.Equal(out, tt.out) || (tt.err != nil && err == nil) { + t.Errorf("bad gzip (%d): want (%s, %#v), got (%s, %#v)", i, string(tt.out), tt.err, string(out), err) + } + } + +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/configdrive/configdrive.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/configdrive/configdrive.go index ed4c7c73..6c65bfcc 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/configdrive/configdrive.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/configdrive/configdrive.go @@ -16,8 +16,8 @@ package configdrive import ( "encoding/json" - "fmt" "io/ioutil" + "log" "os" "path" @@ -93,7 +93,7 @@ func (cd *configDrive) openstackVersionRoot() string { } func (cd *configDrive) tryReadFile(filename string) ([]byte, error) { - fmt.Printf("Attempting to read from %q\n", filename) + log.Printf("Attempting to read from %q\n", filename) data, err := cd.readFile(filename) if os.IsNotExist(err) { err = nil diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/datasource.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/datasource.go index 766f9a7a..e459303c 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/datasource.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/datasource.go @@ -34,5 +34,5 @@ type Metadata struct { PrivateIPv6 net.IP Hostname string SSHPublicKeys map[string]string - NetworkConfig []byte + NetworkConfig interface{} } diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata.go index a42796e7..fa6c605c 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata.go @@ -38,10 +38,11 @@ type Address struct { } type Interface struct { - IPv4 *Address `json:"ipv4"` - IPv6 *Address `json:"ipv6"` - MAC string `json:"mac"` - Type string `json:"type"` + IPv4 *Address `json:"ipv4"` + IPv6 *Address `json:"ipv6"` + AnchorIPv4 *Address `json:"anchor_ipv4"` + MAC string `json:"mac"` + Type string `json:"type"` } type Interfaces struct { @@ -100,7 +101,7 @@ func (ms *metadataService) FetchMetadata() (metadata datasource.Metadata, err er for i, key := range m.PublicKeys { metadata.SSHPublicKeys[strconv.Itoa(i)] = key } - metadata.NetworkConfig = data + metadata.NetworkConfig = m return } diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata_test.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata_test.go index 881a3520..fd8a0a0c 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean/metadata_test.go @@ -90,34 +90,27 @@ func TestFetchMetadata(t *testing.T) { "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" - } - ] - } -}`), + NetworkConfig: Metadata{ + Interfaces: Interfaces{ + Public: []Interface{ + Interface{ + IPv4: &Address{ + IPAddress: "192.168.1.2", + Netmask: "255.255.255.0", + Gateway: "192.168.1.1", + }, + IPv6: &Address{ + IPAddress: "fe00::", + Cidr: 126, + Gateway: "fe00::", + }, + MAC: "ab:cd:ef:gh:ij", + Type: "public", + }, + }, + }, + PublicKeys: []string{"publickey1", "publickey2"}, + }, }, }, { diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/ec2/metadata.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/ec2/metadata.go index 35baa095..141fdc94 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/ec2/metadata.go +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/ec2/metadata.go @@ -18,6 +18,7 @@ import ( "bufio" "bytes" "fmt" + "log" "net" "strings" @@ -61,7 +62,7 @@ func (ms metadataService) FetchMetadata() (datasource.Metadata, error) { return metadata, err } metadata.SSHPublicKeys[name] = sshkey - fmt.Printf("Found SSH key for %q\n", name) + log.Printf("Found SSH key for %q\n", name) } } else if _, ok := err.(pkg.ErrNotFound); !ok { return metadata, err diff --git a/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/packet/metadata.go b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/packet/metadata.go new file mode 100644 index 00000000..3c7d499d --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/datasource/metadata/packet/metadata.go @@ -0,0 +1,106 @@ +// 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 packet + +import ( + "encoding/json" + "net" + "strconv" + + "github.com/coreos/coreos-cloudinit/datasource" + "github.com/coreos/coreos-cloudinit/datasource/metadata" +) + +const ( + DefaultAddress = "https://metadata.packet.net/" + apiVersion = "" + userdataUrl = "userdata" + metadataPath = "metadata" +) + +type Netblock struct { + Address net.IP `json:"address"` + Cidr int `json:"cidr"` + Netmask net.IP `json:"netmask"` + Gateway net.IP `json:"gateway"` + AddressFamily int `json:"address_family"` + Public bool `json:"public"` +} + +type Nic struct { + Name string `json:"name"` + Mac string `json:"mac"` +} + +type NetworkData struct { + Interfaces []Nic `json:"interfaces"` + Netblocks []Netblock `json:"addresses"` + DNS []net.IP `json:"dns"` +} + +// Metadata that will be pulled from the https://metadata.packet.net/metadata only. We have the opportunity to add more later. +type Metadata struct { + Hostname string `json:"hostname"` + SSHKeys []string `json:"ssh_keys"` + NetworkData NetworkData `json:"network"` +} + +type metadataService struct { + metadata.MetadataService +} + +func NewDatasource(root string) *metadataService { + return &metadataService{MetadataService: metadata.NewDatasource(root, apiVersion, userdataUrl, metadataPath)} +} + +func (ms *metadataService) FetchMetadata() (metadata datasource.Metadata, err error) { + var data []byte + var m Metadata + + if data, err = ms.FetchData(ms.MetadataUrl()); err != nil || len(data) == 0 { + return + } + + if err = json.Unmarshal(data, &m); err != nil { + return + } + + if len(m.NetworkData.Netblocks) > 0 { + for _, Netblock := range m.NetworkData.Netblocks { + if Netblock.AddressFamily == 4 { + if Netblock.Public == true { + metadata.PublicIPv4 = Netblock.Address + } else { + metadata.PrivateIPv4 = Netblock.Address + } + } else { + metadata.PublicIPv6 = Netblock.Address + } + } + } + metadata.Hostname = m.Hostname + metadata.SSHPublicKeys = map[string]string{} + for i, key := range m.SSHKeys { + metadata.SSHPublicKeys[strconv.Itoa(i)] = key + } + + metadata.NetworkConfig = m.NetworkData + + return +} + +func (ms metadataService) Type() string { + return "packet-metadata-service" +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/initialize/config.go b/vendor/github.com/coreos/coreos-cloudinit/initialize/config.go index 3bf7f541..94a47fa3 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/initialize/config.go +++ b/vendor/github.com/coreos/coreos-cloudinit/initialize/config.go @@ -135,6 +135,7 @@ func Apply(cfg config.CloudConfig, ifaces []network.InterfaceGenerator, env *Env for _, ccu := range []CloudConfigUnit{ system.Etcd{Etcd: cfg.CoreOS.Etcd}, + system.Etcd2{Etcd2: cfg.CoreOS.Etcd2}, system.Fleet{Fleet: cfg.CoreOS.Fleet}, system.Locksmith{Locksmith: cfg.CoreOS.Locksmith}, system.Update{Update: cfg.CoreOS.Update, ReadConfig: system.DefaultReadConfig}, diff --git a/vendor/github.com/coreos/coreos-cloudinit/initialize/user_data.go b/vendor/github.com/coreos/coreos-cloudinit/initialize/user_data.go index 170efaaa..c728d64e 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/initialize/user_data.go +++ b/vendor/github.com/coreos/coreos-cloudinit/initialize/user_data.go @@ -21,6 +21,10 @@ import ( "github.com/coreos/coreos-cloudinit/config" ) +var ( + ErrIgnitionConfig = errors.New("not a config (found Ignition)") +) + func ParseUserData(contents string) (interface{}, error) { if len(contents) == 0 { return nil, nil @@ -33,6 +37,8 @@ func ParseUserData(contents string) (interface{}, error) { case config.IsCloudConfig(contents): log.Printf("Parsing user-data as cloud-config") return config.NewCloudConfig(contents) + case config.IsIgnitionConfig(contents): + return nil, ErrIgnitionConfig default: return nil, errors.New("Unrecognized user-data format") } diff --git a/vendor/github.com/coreos/coreos-cloudinit/initialize/user_data_test.go b/vendor/github.com/coreos/coreos-cloudinit/initialize/user_data_test.go index 1d883694..7a5acc98 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/initialize/user_data_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/initialize/user_data_test.go @@ -47,7 +47,7 @@ func TestParseHeaderCRLF(t *testing.T) { } func TestParseConfigCRLF(t *testing.T) { - contents := "#cloud-config\r\nhostname: foo\r\nssh_authorized_keys:\r\n - foobar\r\n" + contents := "#cloud-config \r\nhostname: foo\r\nssh_authorized_keys:\r\n - foobar\r\n" ud, err := ParseUserData(contents) if err != nil { t.Fatalf("Failed parsing config: %v", err) diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/digitalocean.go b/vendor/github.com/coreos/coreos-cloudinit/network/digitalocean.go index d55681aa..78759a10 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/network/digitalocean.go +++ b/vendor/github.com/coreos/coreos-cloudinit/network/digitalocean.go @@ -15,7 +15,6 @@ package network import ( - "encoding/json" "fmt" "log" "net" @@ -23,26 +22,18 @@ import ( "github.com/coreos/coreos-cloudinit/datasource/metadata/digitalocean" ) -func ProcessDigitalOceanNetconf(config []byte) ([]InterfaceGenerator, error) { +func ProcessDigitalOceanNetconf(config digitalocean.Metadata) ([]InterfaceGenerator, error) { log.Println("Processing DigitalOcean network config") - if len(config) == 0 { - return nil, nil - } - - var cfg digitalocean.Metadata - if err := json.Unmarshal(config, &cfg); err != nil { - return nil, err - } log.Println("Parsing nameservers") - nameservers, err := parseNameservers(cfg.DNS) + nameservers, err := parseNameservers(config.DNS) if err != nil { return nil, err } log.Printf("Parsed %d nameservers\n", len(nameservers)) log.Println("Parsing interfaces") - generators, err := parseInterfaces(cfg.Interfaces, nameservers) + generators, err := parseInterfaces(config.Interfaces, nameservers) if err != nil { return nil, err } @@ -52,9 +43,9 @@ func ProcessDigitalOceanNetconf(config []byte) ([]InterfaceGenerator, error) { return generators, nil } -func parseNameservers(cfg digitalocean.DNS) ([]net.IP, error) { - nameservers := make([]net.IP, 0, len(cfg.Nameservers)) - for _, ns := range cfg.Nameservers { +func parseNameservers(config digitalocean.DNS) ([]net.IP, error) { + nameservers := make([]net.IP, 0, len(config.Nameservers)) + for _, ns := range config.Nameservers { if ip := net.ParseIP(ns); ip == nil { return nil, fmt.Errorf("could not parse %q as nameserver IP address", ns) } else { @@ -64,16 +55,16 @@ func parseNameservers(cfg digitalocean.DNS) ([]net.IP, error) { return nameservers, nil } -func parseInterfaces(cfg digitalocean.Interfaces, nameservers []net.IP) ([]InterfaceGenerator, error) { - generators := make([]InterfaceGenerator, 0, len(cfg.Public)+len(cfg.Private)) - for _, iface := range cfg.Public { +func parseInterfaces(config digitalocean.Interfaces, nameservers []net.IP) ([]InterfaceGenerator, error) { + generators := make([]InterfaceGenerator, 0, len(config.Public)+len(config.Private)) + for _, iface := range config.Public { if generator, err := parseInterface(iface, nameservers, true); err == nil { generators = append(generators, &physicalInterface{*generator}) } else { return nil, err } } - for _, iface := range cfg.Private { + for _, iface := range config.Private { if generator, err := parseInterface(iface, []net.IP{}, false); err == nil { generators = append(generators, &physicalInterface{*generator}) } else { @@ -135,6 +126,28 @@ func parseInterface(iface digitalocean.Interface, nameservers []net.IP, useRoute }) } } + if iface.AnchorIPv4 != nil { + var ip, mask net.IP + if ip = net.ParseIP(iface.AnchorIPv4.IPAddress); ip == nil { + return nil, fmt.Errorf("could not parse %q as anchor IPv4 address", iface.AnchorIPv4.IPAddress) + } + if mask = net.ParseIP(iface.AnchorIPv4.Netmask); mask == nil { + return nil, fmt.Errorf("could not parse %q as anchor IPv4 mask", iface.AnchorIPv4.Netmask) + } + addresses = append(addresses, net.IPNet{ + IP: ip, + Mask: net.IPMask(mask), + }) + + if useRoute { + routes = append(routes, route{ + destination: net.IPNet{ + IP: net.IPv4zero, + Mask: net.IPMask(net.IPv4zero), + }, + }) + } + } hwaddr, err := net.ParseMAC(iface.MAC) if err != nil { diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/digitalocean_test.go b/vendor/github.com/coreos/coreos-cloudinit/network/digitalocean_test.go index 5cb72572..fc4fc6d5 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/network/digitalocean_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/network/digitalocean_test.go @@ -52,6 +52,14 @@ func TestParseNameservers(t *testing.T) { } } +func mkInvalidMAC() error { + if isGo15 { + return &net.AddrError{Err: "invalid MAC address", Addr: "bad"} + } else { + return errors.New("invalid MAC address: bad") + } +} + func TestParseInterface(t *testing.T) { for _, tt := range []struct { cfg digitalocean.Interface @@ -64,7 +72,7 @@ func TestParseInterface(t *testing.T) { cfg: digitalocean.Interface{ MAC: "bad", }, - err: errors.New("invalid MAC address: bad"), + err: mkInvalidMAC(), }, { cfg: digitalocean.Interface{ @@ -250,6 +258,70 @@ func TestParseInterface(t *testing.T) { }, }, }, + + { + cfg: digitalocean.Interface{ + MAC: "01:23:45:67:89:AB", + AnchorIPv4: &digitalocean.Address{ + IPAddress: "bad", + Netmask: "255.255.0.0", + }, + }, + nss: []net.IP{}, + err: errors.New("could not parse \"bad\" as anchor IPv4 address"), + }, + { + cfg: digitalocean.Interface{ + MAC: "01:23:45:67:89:AB", + AnchorIPv4: &digitalocean.Address{ + IPAddress: "1.2.3.4", + Netmask: "bad", + }, + }, + nss: []net.IP{}, + err: errors.New("could not parse \"bad\" as anchor IPv4 mask"), + }, + { + cfg: digitalocean.Interface{ + MAC: "01:23:45:67:89:AB", + IPv4: &digitalocean.Address{ + IPAddress: "1.2.3.4", + Netmask: "255.255.0.0", + Gateway: "5.6.7.8", + }, + AnchorIPv4: &digitalocean.Address{ + IPAddress: "7.8.9.10", + Netmask: "255.255.0.0", + }, + }, + useRoute: true, + nss: []net.IP{}, + iface: &logicalInterface{ + hwaddr: net.HardwareAddr([]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}), + config: configMethodStatic{ + addresses: []net.IPNet{ + { + IP: net.ParseIP("1.2.3.4"), + Mask: net.IPMask(net.ParseIP("255.255.0.0")), + }, + { + IP: net.ParseIP("7.8.9.10"), + Mask: net.IPMask(net.ParseIP("255.255.0.0")), + }, + }, + nameservers: []net.IP{}, + routes: []route{ + { + destination: net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)}, + gateway: net.ParseIP("5.6.7.8"), + }, + { + destination: net.IPNet{IP: net.IPv4zero, Mask: net.IPMask(net.IPv4zero)}, + }, + }, + }, + }, + }, } { iface, err := parseInterface(tt.cfg, tt.nss, tt.useRoute) if !errorsEqual(tt.err, err) { @@ -337,13 +409,13 @@ func TestParseInterfaces(t *testing.T) { cfg: digitalocean.Interfaces{ Public: []digitalocean.Interface{{MAC: "bad"}}, }, - err: errors.New("invalid MAC address: bad"), + err: mkInvalidMAC(), }, { cfg: digitalocean.Interfaces{ Private: []digitalocean.Interface{{MAC: "bad"}}, }, - err: errors.New("invalid MAC address: bad"), + err: mkInvalidMAC(), }, } { ifaces, err := parseInterfaces(tt.cfg, tt.nss) @@ -358,27 +430,37 @@ func TestParseInterfaces(t *testing.T) { func TestProcessDigitalOceanNetconf(t *testing.T) { for _, tt := range []struct { - cfg string + cfg digitalocean.Metadata ifaces []InterfaceGenerator err error }{ { - cfg: ``, - }, - { - cfg: `{"dns":{"nameservers":["bad"]}}`, + cfg: digitalocean.Metadata{ + DNS: digitalocean.DNS{ + Nameservers: []string{"bad"}, + }, + }, err: errors.New("could not parse \"bad\" as nameserver IP address"), }, { - cfg: `{"interfaces":{"public":[{"ipv4":{"ip_address":"bad"}}]}}`, + cfg: digitalocean.Metadata{ + Interfaces: digitalocean.Interfaces{ + Public: []digitalocean.Interface{ + digitalocean.Interface{ + IPv4: &digitalocean.Address{ + IPAddress: "bad", + }, + }, + }, + }, + }, err: errors.New("could not parse \"bad\" as IPv4 address"), }, { - cfg: `{}`, ifaces: []InterfaceGenerator{}, }, } { - ifaces, err := ProcessDigitalOceanNetconf([]byte(tt.cfg)) + ifaces, err := ProcessDigitalOceanNetconf(tt.cfg) if !errorsEqual(tt.err, err) { t.Fatalf("bad error (%q): want %q, got %q", tt.cfg, tt.err, err) } diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/interface.go b/vendor/github.com/coreos/coreos-cloudinit/network/interface.go index 877cb9ef..73a83cbc 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/network/interface.go +++ b/vendor/github.com/coreos/coreos-cloudinit/network/interface.go @@ -130,7 +130,17 @@ type bondInterface struct { } func (b *bondInterface) Netdev() string { - return fmt.Sprintf("[NetDev]\nKind=bond\nName=%s\n", b.name) + config := fmt.Sprintf("[NetDev]\nKind=bond\nName=%s\n", b.name) + if b.hwaddr != nil { + config += fmt.Sprintf("MACAddress=%s\n", b.hwaddr.String()) + } + + config += fmt.Sprintf("\n[Bond]\n") + for _, name := range sortedKeys(b.options) { + config += fmt.Sprintf("%s=%s\n", name, b.options[name]) + } + + return config } func (b *bondInterface) Type() string { diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/interface_test.go b/vendor/github.com/coreos/coreos-cloudinit/network/interface_test.go index df6eea32..5cafc939 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/network/interface_test.go +++ b/vendor/github.com/coreos/coreos-cloudinit/network/interface_test.go @@ -52,7 +52,7 @@ func TestInterfaceGenerators(t *testing.T) { }, { name: "testname", - netdev: "[NetDev]\nKind=bond\nName=testname\n", + netdev: "[NetDev]\nKind=bond\nName=testname\n\n[Bond]\n", network: "[Match]\nName=testname\n\n[Network]\nBond=testbond1\nVLAN=testvlan1\nVLAN=testvlan2\nDHCP=true\n", kind: "bond", iface: &bondInterface{logicalInterface: logicalInterface{ diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/is_go15_false_test.go b/vendor/github.com/coreos/coreos-cloudinit/network/is_go15_false_test.go new file mode 100644 index 00000000..85d5f0db --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/network/is_go15_false_test.go @@ -0,0 +1,5 @@ +// +build !go1.5 + +package network + +const isGo15 = false diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/is_go15_true_test.go b/vendor/github.com/coreos/coreos-cloudinit/network/is_go15_true_test.go new file mode 100644 index 00000000..953836de --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/network/is_go15_true_test.go @@ -0,0 +1,5 @@ +// +build go1.5 + +package network + +const isGo15 = true diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/packet.go b/vendor/github.com/coreos/coreos-cloudinit/network/packet.go new file mode 100644 index 00000000..a2834ff9 --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/network/packet.go @@ -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 network + +import ( + "net" + + "github.com/coreos/coreos-cloudinit/datasource/metadata/packet" +) + +func ProcessPacketNetconf(netdata packet.NetworkData) ([]InterfaceGenerator, error) { + var nameservers []net.IP + if netdata.DNS != nil { + nameservers = netdata.DNS + } else { + nameservers = append(nameservers, net.ParseIP("8.8.8.8"), net.ParseIP("8.8.4.4")) + } + + generators, err := parseNetwork(netdata, nameservers) + if err != nil { + return nil, err + } + + return generators, nil +} + +func parseNetwork(netdata packet.NetworkData, nameservers []net.IP) ([]InterfaceGenerator, error) { + var interfaces []InterfaceGenerator + var addresses []net.IPNet + var routes []route + for _, netblock := range netdata.Netblocks { + addresses = append(addresses, net.IPNet{ + IP: netblock.Address, + Mask: net.IPMask(netblock.Netmask), + }) + if netblock.Public == false { + routes = append(routes, route{ + destination: net.IPNet{ + IP: net.IPv4(10, 0, 0, 0), + Mask: net.IPv4Mask(255, 0, 0, 0), + }, + gateway: netblock.Gateway, + }) + } else { + if netblock.AddressFamily == 4 { + routes = append(routes, route{ + destination: net.IPNet{ + IP: net.IPv4zero, + Mask: net.IPMask(net.IPv4zero), + }, + gateway: netblock.Gateway, + }) + } else { + routes = append(routes, route{ + destination: net.IPNet{ + IP: net.IPv6zero, + Mask: net.IPMask(net.IPv6zero), + }, + gateway: netblock.Gateway, + }) + } + } + } + + bond := bondInterface{ + logicalInterface: logicalInterface{ + name: "bond0", + config: configMethodStatic{ + addresses: addresses, + nameservers: nameservers, + routes: routes, + }, + }, + options: map[string]string{ + "Mode": "802.3ad", + "LACPTransmitRate": "fast", + "MIIMonitorSec": ".2", + "UpDelaySec": ".2", + "DownDelaySec": ".2", + }, + } + + bond.hwaddr, _ = net.ParseMAC(netdata.Interfaces[0].Mac) + + for index, iface := range netdata.Interfaces { + bond.slaves = append(bond.slaves, iface.Name) + + interfaces = append(interfaces, &physicalInterface{ + logicalInterface: logicalInterface{ + name: iface.Name, + config: configMethodStatic{ + nameservers: nameservers, + }, + children: []networkInterface{&bond}, + configDepth: index, + }, + }) + } + + interfaces = append(interfaces, &bond) + + return interfaces, nil +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/vmware.go b/vendor/github.com/coreos/coreos-cloudinit/network/vmware.go new file mode 100644 index 00000000..230be42a --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/network/vmware.go @@ -0,0 +1,174 @@ +// 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 network + +import ( + "fmt" + "log" + "net" +) + +func ProcessVMwareNetconf(config map[string]string) ([]InterfaceGenerator, error) { + log.Println("Processing VMware network config") + + log.Println("Parsing nameservers") + var nameservers []net.IP + for i := 0; ; i++ { + if ipStr, ok := config[fmt.Sprintf("dns.server.%d", i)]; ok { + if ip := net.ParseIP(ipStr); ip != nil { + nameservers = append(nameservers, ip) + } else { + return nil, fmt.Errorf("invalid nameserver: %q", ipStr) + } + } else { + break + } + } + log.Printf("Parsed %d nameservers", len(nameservers)) + + var interfaces []InterfaceGenerator + for i := 0; ; i++ { + var addresses []net.IPNet + var routes []route + var err error + var dhcp bool + iface := &physicalInterface{} + + log.Printf("Proccessing interface %d", i) + + log.Println("Processing DHCP") + if dhcp, err = processDHCPConfig(config, fmt.Sprintf("interface.%d.", i)); err != nil { + return nil, err + } + + log.Println("Processing addresses") + if as, err := processAddressConfig(config, fmt.Sprintf("interface.%d.", i)); err == nil { + addresses = append(addresses, as...) + } else { + return nil, err + } + + log.Println("Processing routes") + if rs, err := processRouteConfig(config, fmt.Sprintf("interface.%d.", i)); err == nil { + routes = append(routes, rs...) + } else { + return nil, err + } + + if mac, ok := config[fmt.Sprintf("interface.%d.mac", i)]; ok { + log.Printf("Parsing interface %d MAC address: %q", i, mac) + if hwaddr, err := net.ParseMAC(mac); err == nil { + iface.hwaddr = hwaddr + } else { + return nil, fmt.Errorf("error while parsing MAC address: %v", err) + } + } + + if name, ok := config[fmt.Sprintf("interface.%d.name", i)]; ok { + log.Printf("Parsing interface %d name: %q", i, name) + iface.name = name + } + + if len(addresses) > 0 || len(routes) > 0 { + iface.config = configMethodStatic{ + hwaddress: iface.hwaddr, + addresses: addresses, + nameservers: nameservers, + routes: routes, + } + } else if dhcp { + iface.config = configMethodDHCP{ + hwaddress: iface.hwaddr, + } + } else { + break + } + + interfaces = append(interfaces, iface) + } + + return interfaces, nil +} + +func processAddressConfig(config map[string]string, prefix string) (addresses []net.IPNet, err error) { + for a := 0; ; a++ { + prefix := fmt.Sprintf("%sip.%d.", prefix, a) + + addressStr, ok := config[prefix+"address"] + if !ok { + break + } + + ip, network, err := net.ParseCIDR(addressStr) + if err != nil { + return nil, fmt.Errorf("invalid address: %q", addressStr) + } + addresses = append(addresses, net.IPNet{ + IP: ip, + Mask: network.Mask, + }) + } + + return +} + +func processRouteConfig(config map[string]string, prefix string) (routes []route, err error) { + for r := 0; ; r++ { + prefix := fmt.Sprintf("%sroute.%d.", prefix, r) + + gatewayStr, gok := config[prefix+"gateway"] + destinationStr, dok := config[prefix+"destination"] + if gok && !dok { + return nil, fmt.Errorf("missing destination key") + } else if !gok && dok { + return nil, fmt.Errorf("missing gateway key") + } else if !gok && !dok { + break + } + + gateway := net.ParseIP(gatewayStr) + if gateway == nil { + return nil, fmt.Errorf("invalid gateway: %q", gatewayStr) + } + + _, destination, err := net.ParseCIDR(destinationStr) + if err != nil { + return nil, err + } + + routes = append(routes, route{ + destination: *destination, + gateway: gateway, + }) + } + + return +} + +func processDHCPConfig(config map[string]string, prefix string) (dhcp bool, err error) { + dhcpStr, ok := config[prefix+"dhcp"] + if !ok { + return false, nil + } + + switch dhcpStr { + case "yes": + return true, nil + case "no": + return false, nil + default: + return false, fmt.Errorf("invalid DHCP option: %q", dhcpStr) + } +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/network/vmware_test.go b/vendor/github.com/coreos/coreos-cloudinit/network/vmware_test.go new file mode 100644 index 00000000..010568c9 --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/network/vmware_test.go @@ -0,0 +1,361 @@ +// 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 network + +import ( + "errors" + "net" + "reflect" + "testing" +) + +func mustParseMac(mac net.HardwareAddr, err error) net.HardwareAddr { + if err != nil { + panic(err) + } + return mac +} + +func TestProcessVMwareNetconf(t *testing.T) { + tests := []struct { + config map[string]string + + interfaces []InterfaceGenerator + err error + }{ + {}, + { + config: map[string]string{ + "interface.0.dhcp": "yes", + }, + interfaces: []InterfaceGenerator{ + &physicalInterface{logicalInterface{ + config: configMethodDHCP{}, + }}, + }, + }, + { + config: map[string]string{ + "interface.0.mac": "00:11:22:33:44:55", + "interface.0.dhcp": "yes", + }, + interfaces: []InterfaceGenerator{ + &physicalInterface{logicalInterface{ + hwaddr: mustParseMac(net.ParseMAC("00:11:22:33:44:55")), + config: configMethodDHCP{hwaddress: mustParseMac(net.ParseMAC("00:11:22:33:44:55"))}, + }}, + }, + }, + { + config: map[string]string{ + "interface.0.name": "eth0", + "interface.0.dhcp": "yes", + }, + interfaces: []InterfaceGenerator{ + &physicalInterface{logicalInterface{ + name: "eth0", + config: configMethodDHCP{}, + }}, + }, + }, + { + config: map[string]string{ + "interface.0.mac": "00:11:22:33:44:55", + "interface.0.ip.0.address": "10.0.0.100/24", + "interface.0.route.0.gateway": "10.0.0.1", + "interface.0.route.0.destination": "0.0.0.0/0", + }, + interfaces: []InterfaceGenerator{ + &physicalInterface{logicalInterface{ + hwaddr: mustParseMac(net.ParseMAC("00:11:22:33:44:55")), + config: configMethodStatic{ + hwaddress: mustParseMac(net.ParseMAC("00:11:22:33:44:55")), + addresses: []net.IPNet{net.IPNet{IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}}, + // I realize how upset you must be that I am shoving an IPMask into an IP. This is because net.IPv4zero is + // actually a magic IPv6 address which ruins our equality check. What's that? Just use IP::Equal()? I'd rather + // DeepEqual just handle that for me, but until Go gets operator overloading, we are stuck with this. + routes: []route{route{ + destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)}, + gateway: net.ParseIP("10.0.0.1")}, + }, + }, + }}, + }, + }, + { + config: map[string]string{ + "dns.server.0": "1.2.3.4", + "dns.server.1": "5.6.7.8", + "interface.0.mac": "00:11:22:33:44:55", + "interface.0.ip.0.address": "10.0.0.100/24", + "interface.0.ip.1.address": "10.0.0.101/24", + "interface.0.route.0.gateway": "10.0.0.1", + "interface.0.route.0.destination": "0.0.0.0/0", + "interface.1.name": "eth0", + "interface.1.ip.0.address": "10.0.1.100/24", + "interface.1.route.0.gateway": "10.0.1.1", + "interface.1.route.0.destination": "0.0.0.0/0", + "interface.2.dhcp": "yes", + "interface.2.mac": "00:11:22:33:44:77", + }, + interfaces: []InterfaceGenerator{ + &physicalInterface{logicalInterface{ + hwaddr: mustParseMac(net.ParseMAC("00:11:22:33:44:55")), + config: configMethodStatic{ + hwaddress: mustParseMac(net.ParseMAC("00:11:22:33:44:55")), + addresses: []net.IPNet{ + net.IPNet{IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}, + net.IPNet{IP: net.ParseIP("10.0.0.101"), Mask: net.CIDRMask(24, net.IPv4len*8)}, + }, + routes: []route{route{ + destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)}, + gateway: net.ParseIP("10.0.0.1")}, + }, + nameservers: []net.IP{net.ParseIP("1.2.3.4"), net.ParseIP("5.6.7.8")}, + }, + }}, + &physicalInterface{logicalInterface{ + name: "eth0", + config: configMethodStatic{ + addresses: []net.IPNet{net.IPNet{IP: net.ParseIP("10.0.1.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}}, + routes: []route{route{ + destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)}, + gateway: net.ParseIP("10.0.1.1")}, + }, + nameservers: []net.IP{net.ParseIP("1.2.3.4"), net.ParseIP("5.6.7.8")}, + }, + }}, + &physicalInterface{logicalInterface{ + hwaddr: mustParseMac(net.ParseMAC("00:11:22:33:44:77")), + config: configMethodDHCP{hwaddress: mustParseMac(net.ParseMAC("00:11:22:33:44:77"))}, + }}, + }, + }, + { + config: map[string]string{"dns.server.0": "test dns"}, + err: errors.New(`invalid nameserver: "test dns"`), + }, + } + + for i, tt := range tests { + interfaces, err := ProcessVMwareNetconf(tt.config) + if !reflect.DeepEqual(tt.err, err) { + t.Errorf("bad error (#%d): want %v, got %v", i, tt.err, err) + } + if !reflect.DeepEqual(tt.interfaces, interfaces) { + t.Errorf("bad interfaces (#%d): want %#v, got %#v", i, tt.interfaces, interfaces) + for _, iface := range tt.interfaces { + t.Logf(" want: %#v", iface) + } + for _, iface := range interfaces { + t.Logf(" got: %#v", iface) + } + } + } +} + +func TestProcessAddressConfig(t *testing.T) { + tests := []struct { + config map[string]string + prefix string + + addresses []net.IPNet + err error + }{ + {}, + + // static - ipv4 + { + config: map[string]string{ + "ip.0.address": "10.0.0.100/24", + }, + + addresses: []net.IPNet{{IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}}, + }, + { + config: map[string]string{ + "this.is.a.prefix.ip.0.address": "10.0.0.100/24", + }, + prefix: "this.is.a.prefix.", + + addresses: []net.IPNet{{IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}}, + }, + { + config: map[string]string{ + "ip.0.address": "10.0.0.100/24", + "ip.1.address": "10.0.0.101/24", + "ip.2.address": "10.0.0.102/24", + }, + + addresses: []net.IPNet{ + {IP: net.ParseIP("10.0.0.100"), Mask: net.CIDRMask(24, net.IPv4len*8)}, + {IP: net.ParseIP("10.0.0.101"), Mask: net.CIDRMask(24, net.IPv4len*8)}, + {IP: net.ParseIP("10.0.0.102"), Mask: net.CIDRMask(24, net.IPv4len*8)}, + }, + }, + + // static - ipv6 + { + config: map[string]string{ + "ip.0.address": "fe00::100/64", + }, + + addresses: []net.IPNet{{IP: net.ParseIP("fe00::100"), Mask: net.IPMask(net.CIDRMask(64, net.IPv6len*8))}}, + }, + { + config: map[string]string{ + "ip.0.address": "fe00::100/64", + "ip.1.address": "fe00::101/64", + "ip.2.address": "fe00::102/64", + }, + + addresses: []net.IPNet{ + {IP: net.ParseIP("fe00::100"), Mask: net.CIDRMask(64, net.IPv6len*8)}, + {IP: net.ParseIP("fe00::101"), Mask: net.CIDRMask(64, net.IPv6len*8)}, + {IP: net.ParseIP("fe00::102"), Mask: net.CIDRMask(64, net.IPv6len*8)}, + }, + }, + + // invalid + { + config: map[string]string{ + "ip.0.address": "test address", + }, + + err: errors.New(`invalid address: "test address"`), + }, + } + + for i, tt := range tests { + addresses, err := processAddressConfig(tt.config, tt.prefix) + if !reflect.DeepEqual(tt.err, err) { + t.Errorf("bad error (#%d): want %v, got %v", i, tt.err, err) + } + if err != nil { + continue + } + + if !reflect.DeepEqual(tt.addresses, addresses) { + t.Errorf("bad addresses (#%d): want %#v, got %#v", i, tt.addresses, addresses) + } + } +} + +func TestProcessRouteConfig(t *testing.T) { + tests := []struct { + config map[string]string + prefix string + + routes []route + err error + }{ + {}, + + { + config: map[string]string{ + "route.0.gateway": "10.0.0.1", + "route.0.destination": "0.0.0.0/0", + }, + + routes: []route{{destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)}, gateway: net.ParseIP("10.0.0.1")}}, + }, + { + config: map[string]string{ + "this.is.a.prefix.route.0.gateway": "10.0.0.1", + "this.is.a.prefix.route.0.destination": "0.0.0.0/0", + }, + prefix: "this.is.a.prefix.", + + routes: []route{{destination: net.IPNet{IP: net.IP(net.CIDRMask(0, net.IPv4len*8)), Mask: net.CIDRMask(0, net.IPv4len*8)}, gateway: net.ParseIP("10.0.0.1")}}, + }, + { + config: map[string]string{ + "route.0.gateway": "fe00::1", + "route.0.destination": "::/0", + }, + + routes: []route{{destination: net.IPNet{IP: net.IPv6zero, Mask: net.IPMask(net.IPv6zero)}, gateway: net.ParseIP("fe00::1")}}, + }, + + // invalid + { + config: map[string]string{ + "route.0.gateway": "test gateway", + "route.0.destination": "0.0.0.0/0", + }, + + err: errors.New(`invalid gateway: "test gateway"`), + }, + { + config: map[string]string{ + "route.0.gateway": "10.0.0.1", + "route.0.destination": "test destination", + }, + + err: &net.ParseError{Type: "CIDR address", Text: "test destination"}, + }, + } + + for i, tt := range tests { + routes, err := processRouteConfig(tt.config, tt.prefix) + if !reflect.DeepEqual(tt.err, err) { + t.Errorf("bad error (#%d): want %v, got %v", i, tt.err, err) + } + if err != nil { + continue + } + + if !reflect.DeepEqual(tt.routes, routes) { + t.Errorf("bad routes (#%d): want %#v, got %#v", i, tt.routes, routes) + } + } +} + +func TestProcessDHCPConfig(t *testing.T) { + tests := []struct { + config map[string]string + prefix string + + dhcp bool + err error + }{ + {}, + + // prefix + {config: map[string]string{"this.is.a.prefix.mac": ""}, prefix: "this.is.a.prefix.", dhcp: false}, + {config: map[string]string{"this.is.a.prefix.dhcp": "yes"}, prefix: "this.is.a.prefix.", dhcp: true}, + + // dhcp + {config: map[string]string{"dhcp": "yes"}, dhcp: true}, + {config: map[string]string{"dhcp": "no"}, dhcp: false}, + + // invalid + {config: map[string]string{"dhcp": "blah"}, err: errors.New(`invalid DHCP option: "blah"`)}, + } + + for i, tt := range tests { + dhcp, err := processDHCPConfig(tt.config, tt.prefix) + if !reflect.DeepEqual(tt.err, err) { + t.Errorf("bad error (#%d): want %v, got %v", i, tt.err, err) + } + if err != nil { + continue + } + + if tt.dhcp != dhcp { + t.Errorf("bad dhcp (#%d): want %v, got %v", i, tt.dhcp, dhcp) + } + } +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/pkg/http_client.go b/vendor/github.com/coreos/coreos-cloudinit/pkg/http_client.go index 5d275ec3..c4fb8032 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/pkg/http_client.go +++ b/vendor/github.com/coreos/coreos-cloudinit/pkg/http_client.go @@ -15,12 +15,10 @@ package pkg import ( - "crypto/tls" "errors" "fmt" "io/ioutil" "log" - "net" "net/http" neturl "net/url" "strings" @@ -55,16 +53,15 @@ type ErrNetwork struct { } type HttpClient struct { + // Initial backoff duration. Defaults to 50 milliseconds + InitialBackoff time.Duration + // Maximum exp backoff duration. Defaults to 5 seconds MaxBackoff time.Duration // Maximum number of connection retries. Defaults to 15 MaxRetries int - // HTTP client timeout, this is suggested to be low since exponential - // backoff will kick off too. Defaults to 2 seconds - Timeout time.Duration - // Whether or not to skip TLS verification. Defaults to false SkipTLS bool @@ -78,29 +75,12 @@ type Getter interface { func NewHttpClient() *HttpClient { hc := &HttpClient{ - MaxBackoff: time.Second * 5, - MaxRetries: 15, - Timeout: time.Duration(2) * time.Second, - SkipTLS: false, - } - - // We need to create our own client in order to add timeout support. - // TODO(c4milo) Replace it once Go 1.3 is officially used by CoreOS - // More info: https://code.google.com/p/go/source/detail?r=ada6f2d5f99f - hc.client = &http.Client{ - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: hc.SkipTLS, - }, - Dial: func(network, addr string) (net.Conn, error) { - deadline := time.Now().Add(hc.Timeout) - c, err := net.DialTimeout(network, addr, hc.Timeout) - if err != nil { - return nil, err - } - c.SetDeadline(deadline) - return c, nil - }, + InitialBackoff: 50 * time.Millisecond, + MaxBackoff: time.Second * 5, + MaxRetries: 15, + SkipTLS: false, + client: &http.Client{ + Timeout: 10 * time.Second, }, } @@ -134,7 +114,7 @@ func (h *HttpClient) GetRetry(rawurl string) ([]byte, error) { dataURL := url.String() - duration := 50 * time.Millisecond + duration := h.InitialBackoff for retry := 1; retry <= h.MaxRetries; retry++ { log.Printf("Fetching data from %s. Attempt #%d", dataURL, retry) diff --git a/vendor/github.com/coreos/coreos-cloudinit/system/etcd2.go b/vendor/github.com/coreos/coreos-cloudinit/system/etcd2.go new file mode 100644 index 00000000..9b243e0f --- /dev/null +++ b/vendor/github.com/coreos/coreos-cloudinit/system/etcd2.go @@ -0,0 +1,37 @@ +// 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 + +import ( + "github.com/coreos/coreos-cloudinit/config" +) + +// Etcd2 is a top-level structure which embeds its underlying configuration, +// config.Etcd2, and provides the system-specific Unit(). +type Etcd2 struct { + config.Etcd2 +} + +// Units creates a Unit file drop-in for etcd, using any configured options. +func (ee Etcd2) Units() []Unit { + return []Unit{{config.Unit{ + Name: "etcd2.service", + Runtime: true, + DropIns: []config.UnitDropIn{{ + Name: "20-cloudinit.conf", + Content: serviceContents(ee.Etcd2), + }}, + }}} +} diff --git a/vendor/github.com/coreos/coreos-cloudinit/system/networkd.go b/vendor/github.com/coreos/coreos-cloudinit/system/networkd.go index 1e075ea0..025b09cb 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/system/networkd.go +++ b/vendor/github.com/coreos/coreos-cloudinit/system/networkd.go @@ -15,7 +15,6 @@ package system import ( - "fmt" "log" "net" "os/exec" @@ -59,7 +58,7 @@ func downNetworkInterfaces(interfaces []network.InterfaceGenerator) error { if systemInterface, ok := sysInterfaceMap[iface.Name()]; ok { log.Printf("Taking down interface %q\n", systemInterface.Name) if err := netlink.NetworkLinkDown(systemInterface); err != nil { - fmt.Printf("Error while downing interface %q (%s). Continuing...\n", systemInterface.Name, err) + log.Printf("Error while downing interface %q (%s). Continuing...\n", systemInterface.Name, err) } } } diff --git a/vendor/github.com/coreos/coreos-cloudinit/system/user.go b/vendor/github.com/coreos/coreos-cloudinit/system/user.go index 2f5d85da..3f973c3d 100644 --- a/vendor/github.com/coreos/coreos-cloudinit/system/user.go +++ b/vendor/github.com/coreos/coreos-cloudinit/system/user.go @@ -72,6 +72,10 @@ func CreateUser(u *config.User) error { args = append(args, "--no-log-init") } + if u.Shell != "" { + args = append(args, "--shell", u.Shell) + } + args = append(args, u.Name) output, err := exec.Command("useradd", args...).CombinedOutput() diff --git a/vendor/github.com/coreos/coreos-cloudinit/test b/vendor/github.com/coreos/coreos-cloudinit/test index a24bb31e..645e967a 100755 --- a/vendor/github.com/coreos/coreos-cloudinit/test +++ b/vendor/github.com/coreos/coreos-cloudinit/test @@ -1,19 +1,8 @@ #!/bin/bash -e -# -# Run all coreos-cloudinit tests -# ./test -# ./test -v -# -# Run tests for one package -# PKG=initialize ./test -# - -# Invoke ./cover for HTML output -COVER=${COVER:-"-cover"} source ./build -declare -a TESTPKGS=( +SRC=" config config/validate datasource @@ -26,41 +15,29 @@ declare -a TESTPKGS=( datasource/proc_cmdline datasource/test datasource/url + datasource/vmware datasource/waagent initialize network pkg system -) + . +" -if [ -z "$PKG" ]; then - GOFMTPATH="${TESTPKGS[*]} *.go" - # prepend repo path to each package - TESTPKGS="${TESTPKGS[*]/#/${REPO_PATH}/} ./" -else - GOFMTPATH="$TESTPKGS" - # strip out slashes and dots from PKG=./foo/ - TESTPKGS=${PKG//\//} - TESTPKGS=${TESTPKGS//./} - TESTPKGS=${TESTPKGS/#/${REPO_PATH}/} -fi - -echo "Running tests..." -go test -i ${TESTPKGS} -go test ${COVER} $@ ${TESTPKGS} +echo "Checking gofix..." +go tool fix -diff $SRC echo "Checking gofmt..." -fmtRes=$(gofmt -l $GOFMTPATH) -if [ -n "$fmtRes" ]; then - echo "$fmtRes" - exit 1 -fi +gofmt -d -e $SRC + +# split SRC into an array and prepend REPO_PATH to each local package for go vet +split_vet=(${SRC// / }) +VET_TEST="${REPO_PATH} ${split_vet[@]/#/${REPO_PATH}/}" echo "Checking govet..." -vetRes=$(go vet $TESTPKGS) -if [ -n "${vetRes}" ]; then - echo -e "govet checking failed:\n${vetRes}" - exit 255 -fi +go vet $VET_TEST + +echo "Running tests..." +go test -timeout 60s -cover $@ ${VET_TEST} --race echo "Success"