mirror of
https://github.com/rancher/os.git
synced 2025-07-01 01:01:48 +00:00
Merge branch 'sidharthamani-cloudinit'
This commit is contained in:
commit
a24e1572f4
11
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/config/config.go
generated
vendored
11
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/config/config.go
generated
vendored
@ -28,23 +28,12 @@ import (
|
|||||||
// used for internal use) have the YAML tag '-' so that they aren't marshalled.
|
// used for internal use) have the YAML tag '-' so that they aren't marshalled.
|
||||||
type CloudConfig struct {
|
type CloudConfig struct {
|
||||||
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"`
|
SSHAuthorizedKeys []string `yaml:"ssh_authorized_keys"`
|
||||||
CoreOS CoreOS `yaml:"coreos"`
|
|
||||||
WriteFiles []File `yaml:"write_files"`
|
WriteFiles []File `yaml:"write_files"`
|
||||||
Hostname string `yaml:"hostname"`
|
Hostname string `yaml:"hostname"`
|
||||||
Users []User `yaml:"users"`
|
Users []User `yaml:"users"`
|
||||||
ManageEtcHosts EtcHosts `yaml:"manage_etc_hosts"`
|
ManageEtcHosts EtcHosts `yaml:"manage_etc_hosts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CoreOS struct {
|
|
||||||
Etcd Etcd `yaml:"etcd"`
|
|
||||||
Flannel Flannel `yaml:"flannel"`
|
|
||||||
Fleet Fleet `yaml:"fleet"`
|
|
||||||
Locksmith Locksmith `yaml:"locksmith"`
|
|
||||||
OEM OEM `yaml:"oem"`
|
|
||||||
Update Update `yaml:"update"`
|
|
||||||
Units []Unit `yaml:"units"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsCloudConfig(userdata string) bool {
|
func IsCloudConfig(userdata string) bool {
|
||||||
header := strings.SplitN(userdata, "\n", 2)[0]
|
header := strings.SplitN(userdata, "\n", 2)[0]
|
||||||
|
|
||||||
|
293
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/initialize/config.go
generated
vendored
293
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/initialize/config.go
generated
vendored
@ -1,293 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package initialize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"path"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
"github.com/coreos/coreos-cloudinit/network"
|
|
||||||
"github.com/coreos/coreos-cloudinit/system"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CloudConfigFile represents a CoreOS specific configuration option that can generate
|
|
||||||
// an associated system.File to be written to disk
|
|
||||||
type CloudConfigFile interface {
|
|
||||||
// File should either return (*system.File, error), or (nil, nil) if nothing
|
|
||||||
// needs to be done for this configuration option.
|
|
||||||
File() (*system.File, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CloudConfigUnit represents a CoreOS specific configuration option that can generate
|
|
||||||
// associated system.Units to be created/enabled appropriately
|
|
||||||
type CloudConfigUnit interface {
|
|
||||||
Units() []system.Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply renders a CloudConfig to an Environment. This can involve things like
|
|
||||||
// configuring the hostname, adding new users, writing various configuration
|
|
||||||
// files to disk, and manipulating systemd services.
|
|
||||||
func Apply(cfg config.CloudConfig, ifaces []network.InterfaceGenerator, env *Environment) error {
|
|
||||||
if cfg.Hostname != "" {
|
|
||||||
if err := system.SetHostname(cfg.Hostname); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("Set hostname to %s", cfg.Hostname)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, user := range cfg.Users {
|
|
||||||
if user.Name == "" {
|
|
||||||
log.Printf("User object has no 'name' field, skipping")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if system.UserExists(&user) {
|
|
||||||
log.Printf("User '%s' exists, ignoring creation-time fields", user.Name)
|
|
||||||
if user.PasswordHash != "" {
|
|
||||||
log.Printf("Setting '%s' user's password", user.Name)
|
|
||||||
if err := system.SetUserPassword(user.Name, user.PasswordHash); err != nil {
|
|
||||||
log.Printf("Failed setting '%s' user's password: %v", user.Name, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Printf("Creating user '%s'", user.Name)
|
|
||||||
if err := system.CreateUser(&user); err != nil {
|
|
||||||
log.Printf("Failed creating user '%s': %v", user.Name, err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(user.SSHAuthorizedKeys) > 0 {
|
|
||||||
log.Printf("Authorizing %d SSH keys for user '%s'", len(user.SSHAuthorizedKeys), user.Name)
|
|
||||||
if err := system.AuthorizeSSHKeys(user.Name, env.SSHKeyName(), user.SSHAuthorizedKeys); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if user.SSHImportGithubUser != "" {
|
|
||||||
log.Printf("Authorizing github user %s SSH keys for CoreOS user '%s'", user.SSHImportGithubUser, user.Name)
|
|
||||||
if err := SSHImportGithubUser(user.Name, user.SSHImportGithubUser); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, u := range user.SSHImportGithubUsers {
|
|
||||||
log.Printf("Authorizing github user %s SSH keys for CoreOS user '%s'", u, user.Name)
|
|
||||||
if err := SSHImportGithubUser(user.Name, u); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if user.SSHImportURL != "" {
|
|
||||||
log.Printf("Authorizing SSH keys for CoreOS user '%s' from '%s'", user.Name, user.SSHImportURL)
|
|
||||||
if err := SSHImportKeysFromURL(user.Name, user.SSHImportURL); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cfg.SSHAuthorizedKeys) > 0 {
|
|
||||||
err := system.AuthorizeSSHKeys("core", env.SSHKeyName(), cfg.SSHAuthorizedKeys)
|
|
||||||
if err == nil {
|
|
||||||
log.Printf("Authorized SSH keys for core user")
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var writeFiles []system.File
|
|
||||||
for _, file := range cfg.WriteFiles {
|
|
||||||
writeFiles = append(writeFiles, system.File{File: file})
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ccf := range []CloudConfigFile{
|
|
||||||
system.OEM{OEM: cfg.CoreOS.OEM},
|
|
||||||
system.Update{Update: cfg.CoreOS.Update, ReadConfig: system.DefaultReadConfig},
|
|
||||||
system.EtcHosts{EtcHosts: cfg.ManageEtcHosts},
|
|
||||||
system.Flannel{Flannel: cfg.CoreOS.Flannel},
|
|
||||||
} {
|
|
||||||
f, err := ccf.File()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if f != nil {
|
|
||||||
writeFiles = append(writeFiles, *f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var units []system.Unit
|
|
||||||
for _, u := range cfg.CoreOS.Units {
|
|
||||||
units = append(units, system.Unit{Unit: u})
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ccu := range []CloudConfigUnit{
|
|
||||||
system.Etcd{Etcd: cfg.CoreOS.Etcd},
|
|
||||||
system.Fleet{Fleet: cfg.CoreOS.Fleet},
|
|
||||||
system.Locksmith{Locksmith: cfg.CoreOS.Locksmith},
|
|
||||||
system.Update{Update: cfg.CoreOS.Update, ReadConfig: system.DefaultReadConfig},
|
|
||||||
} {
|
|
||||||
units = append(units, ccu.Units()...)
|
|
||||||
}
|
|
||||||
|
|
||||||
wroteEnvironment := false
|
|
||||||
for _, file := range writeFiles {
|
|
||||||
fullPath, err := system.WriteFile(&file, env.Root())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if path.Clean(file.Path) == "/etc/environment" {
|
|
||||||
wroteEnvironment = true
|
|
||||||
}
|
|
||||||
log.Printf("Wrote file %s to filesystem", fullPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !wroteEnvironment {
|
|
||||||
ef := env.DefaultEnvironmentFile()
|
|
||||||
if ef != nil {
|
|
||||||
err := system.WriteEnvFile(ef, env.Root())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("Updated /etc/environment")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ifaces) > 0 {
|
|
||||||
units = append(units, createNetworkingUnits(ifaces)...)
|
|
||||||
if err := system.RestartNetwork(ifaces); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
um := system.NewUnitManager(env.Root())
|
|
||||||
return processUnits(units, env.Root(), um)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createNetworkingUnits(interfaces []network.InterfaceGenerator) (units []system.Unit) {
|
|
||||||
appendNewUnit := func(units []system.Unit, name, content string) []system.Unit {
|
|
||||||
if content == "" {
|
|
||||||
return units
|
|
||||||
}
|
|
||||||
return append(units, system.Unit{Unit: config.Unit{
|
|
||||||
Name: name,
|
|
||||||
Runtime: true,
|
|
||||||
Content: content,
|
|
||||||
}})
|
|
||||||
}
|
|
||||||
for _, i := range interfaces {
|
|
||||||
units = appendNewUnit(units, fmt.Sprintf("%s.netdev", i.Filename()), i.Netdev())
|
|
||||||
units = appendNewUnit(units, fmt.Sprintf("%s.link", i.Filename()), i.Link())
|
|
||||||
units = appendNewUnit(units, fmt.Sprintf("%s.network", i.Filename()), i.Network())
|
|
||||||
}
|
|
||||||
return units
|
|
||||||
}
|
|
||||||
|
|
||||||
// processUnits takes a set of Units and applies them to the given root using
|
|
||||||
// the given UnitManager. This can involve things like writing unit files to
|
|
||||||
// disk, masking/unmasking units, or invoking systemd
|
|
||||||
// commands against units. It returns any error encountered.
|
|
||||||
func processUnits(units []system.Unit, root string, um system.UnitManager) error {
|
|
||||||
type action struct {
|
|
||||||
unit system.Unit
|
|
||||||
command string
|
|
||||||
}
|
|
||||||
actions := make([]action, 0, len(units))
|
|
||||||
reload := false
|
|
||||||
restartNetworkd := false
|
|
||||||
for _, unit := range units {
|
|
||||||
if unit.Name == "" {
|
|
||||||
log.Printf("Skipping unit without name")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if unit.Content != "" {
|
|
||||||
log.Printf("Writing unit %q to filesystem", unit.Name)
|
|
||||||
if err := um.PlaceUnit(unit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("Wrote unit %q", unit.Name)
|
|
||||||
reload = true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, dropin := range unit.DropIns {
|
|
||||||
if dropin.Name != "" && dropin.Content != "" {
|
|
||||||
log.Printf("Writing drop-in unit %q to filesystem", dropin.Name)
|
|
||||||
if err := um.PlaceUnitDropIn(unit, dropin); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("Wrote drop-in unit %q", dropin.Name)
|
|
||||||
reload = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if unit.Mask {
|
|
||||||
log.Printf("Masking unit file %q", unit.Name)
|
|
||||||
if err := um.MaskUnit(unit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if unit.Runtime {
|
|
||||||
log.Printf("Ensuring runtime unit file %q is unmasked", unit.Name)
|
|
||||||
if err := um.UnmaskUnit(unit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if unit.Enable {
|
|
||||||
if unit.Group() != "network" {
|
|
||||||
log.Printf("Enabling unit file %q", unit.Name)
|
|
||||||
if err := um.EnableUnitFile(unit); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("Enabled unit %q", unit.Name)
|
|
||||||
} else {
|
|
||||||
log.Printf("Skipping enable for network-like unit %q", unit.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if unit.Group() == "network" {
|
|
||||||
restartNetworkd = true
|
|
||||||
} else if unit.Command != "" {
|
|
||||||
actions = append(actions, action{unit, unit.Command})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if reload {
|
|
||||||
if err := um.DaemonReload(); err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("failed systemd daemon-reload: %s", err))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if restartNetworkd {
|
|
||||||
log.Printf("Restarting systemd-networkd")
|
|
||||||
networkd := system.Unit{Unit: config.Unit{Name: "systemd-networkd.service"}}
|
|
||||||
res, err := um.RunUnitCommand(networkd, "restart")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("Restarted systemd-networkd (%s)", res)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, action := range actions {
|
|
||||||
log.Printf("Calling unit command %q on %q'", action.command, action.unit.Name)
|
|
||||||
res, err := um.RunUnitCommand(action.unit, action.command)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("Result of %q on %q: %s", action.command, action.unit.Name, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
299
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/initialize/config_test.go
generated
vendored
299
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/initialize/config_test.go
generated
vendored
@ -1,299 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package initialize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
"github.com/coreos/coreos-cloudinit/network"
|
|
||||||
"github.com/coreos/coreos-cloudinit/system"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TestUnitManager struct {
|
|
||||||
placed []string
|
|
||||||
enabled []string
|
|
||||||
masked []string
|
|
||||||
unmasked []string
|
|
||||||
commands []UnitAction
|
|
||||||
reload bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type UnitAction struct {
|
|
||||||
unit string
|
|
||||||
command string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tum *TestUnitManager) PlaceUnit(u system.Unit) error {
|
|
||||||
tum.placed = append(tum.placed, u.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (tum *TestUnitManager) PlaceUnitDropIn(u system.Unit, d config.UnitDropIn) error {
|
|
||||||
tum.placed = append(tum.placed, u.Name+".d/"+d.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (tum *TestUnitManager) EnableUnitFile(u system.Unit) error {
|
|
||||||
tum.enabled = append(tum.enabled, u.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (tum *TestUnitManager) RunUnitCommand(u system.Unit, c string) (string, error) {
|
|
||||||
tum.commands = append(tum.commands, UnitAction{u.Name, c})
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
func (tum *TestUnitManager) DaemonReload() error {
|
|
||||||
tum.reload = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (tum *TestUnitManager) MaskUnit(u system.Unit) error {
|
|
||||||
tum.masked = append(tum.masked, u.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (tum *TestUnitManager) UnmaskUnit(u system.Unit) error {
|
|
||||||
tum.unmasked = append(tum.unmasked, u.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type mockInterface struct {
|
|
||||||
name string
|
|
||||||
filename string
|
|
||||||
netdev string
|
|
||||||
link string
|
|
||||||
network string
|
|
||||||
kind string
|
|
||||||
modprobeParams string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i mockInterface) Name() string {
|
|
||||||
return i.name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i mockInterface) Filename() string {
|
|
||||||
return i.filename
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i mockInterface) Netdev() string {
|
|
||||||
return i.netdev
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i mockInterface) Link() string {
|
|
||||||
return i.link
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i mockInterface) Network() string {
|
|
||||||
return i.network
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i mockInterface) Type() string {
|
|
||||||
return i.kind
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i mockInterface) ModprobeParams() string {
|
|
||||||
return i.modprobeParams
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateNetworkingUnits(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
interfaces []network.InterfaceGenerator
|
|
||||||
expect []system.Unit
|
|
||||||
}{
|
|
||||||
{nil, nil},
|
|
||||||
{
|
|
||||||
[]network.InterfaceGenerator{
|
|
||||||
network.InterfaceGenerator(mockInterface{filename: "test"}),
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]network.InterfaceGenerator{
|
|
||||||
network.InterfaceGenerator(mockInterface{filename: "test1", netdev: "test netdev"}),
|
|
||||||
network.InterfaceGenerator(mockInterface{filename: "test2", link: "test link"}),
|
|
||||||
network.InterfaceGenerator(mockInterface{filename: "test3", network: "test network"}),
|
|
||||||
},
|
|
||||||
[]system.Unit{
|
|
||||||
system.Unit{Unit: config.Unit{Name: "test1.netdev", Runtime: true, Content: "test netdev"}},
|
|
||||||
system.Unit{Unit: config.Unit{Name: "test2.link", Runtime: true, Content: "test link"}},
|
|
||||||
system.Unit{Unit: config.Unit{Name: "test3.network", Runtime: true, Content: "test network"}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
[]network.InterfaceGenerator{
|
|
||||||
network.InterfaceGenerator(mockInterface{filename: "test", netdev: "test netdev", link: "test link", network: "test network"}),
|
|
||||||
},
|
|
||||||
[]system.Unit{
|
|
||||||
system.Unit{Unit: config.Unit{Name: "test.netdev", Runtime: true, Content: "test netdev"}},
|
|
||||||
system.Unit{Unit: config.Unit{Name: "test.link", Runtime: true, Content: "test link"}},
|
|
||||||
system.Unit{Unit: config.Unit{Name: "test.network", Runtime: true, Content: "test network"}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
units := createNetworkingUnits(tt.interfaces)
|
|
||||||
if !reflect.DeepEqual(tt.expect, units) {
|
|
||||||
t.Errorf("bad units (%+v): want %#v, got %#v", tt.interfaces, tt.expect, units)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestProcessUnits(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
units []system.Unit
|
|
||||||
|
|
||||||
result TestUnitManager
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
units: []system.Unit{
|
|
||||||
system.Unit{Unit: config.Unit{
|
|
||||||
Name: "foo",
|
|
||||||
Mask: true,
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
result: TestUnitManager{
|
|
||||||
masked: []string{"foo"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
units: []system.Unit{
|
|
||||||
system.Unit{Unit: config.Unit{
|
|
||||||
Name: "baz.service",
|
|
||||||
Content: "[Service]\nExecStart=/bin/baz",
|
|
||||||
Command: "start",
|
|
||||||
}},
|
|
||||||
system.Unit{Unit: config.Unit{
|
|
||||||
Name: "foo.network",
|
|
||||||
Content: "[Network]\nFoo=true",
|
|
||||||
}},
|
|
||||||
system.Unit{Unit: config.Unit{
|
|
||||||
Name: "bar.network",
|
|
||||||
Content: "[Network]\nBar=true",
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
result: TestUnitManager{
|
|
||||||
placed: []string{"baz.service", "foo.network", "bar.network"},
|
|
||||||
commands: []UnitAction{
|
|
||||||
UnitAction{"systemd-networkd.service", "restart"},
|
|
||||||
UnitAction{"baz.service", "start"},
|
|
||||||
},
|
|
||||||
reload: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
units: []system.Unit{
|
|
||||||
system.Unit{Unit: config.Unit{
|
|
||||||
Name: "baz.service",
|
|
||||||
Content: "[Service]\nExecStart=/bin/true",
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
result: TestUnitManager{
|
|
||||||
placed: []string{"baz.service"},
|
|
||||||
reload: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
units: []system.Unit{
|
|
||||||
system.Unit{Unit: config.Unit{
|
|
||||||
Name: "locksmithd.service",
|
|
||||||
Runtime: true,
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
result: TestUnitManager{
|
|
||||||
unmasked: []string{"locksmithd.service"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
units: []system.Unit{
|
|
||||||
system.Unit{Unit: config.Unit{
|
|
||||||
Name: "woof",
|
|
||||||
Enable: true,
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
result: TestUnitManager{
|
|
||||||
enabled: []string{"woof"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
units: []system.Unit{
|
|
||||||
system.Unit{Unit: config.Unit{
|
|
||||||
Name: "hi.service",
|
|
||||||
Runtime: true,
|
|
||||||
Content: "[Service]\nExecStart=/bin/echo hi",
|
|
||||||
DropIns: []config.UnitDropIn{
|
|
||||||
{
|
|
||||||
Name: "lo.conf",
|
|
||||||
Content: "[Service]\nExecStart=/bin/echo lo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "bye.conf",
|
|
||||||
Content: "[Service]\nExecStart=/bin/echo bye",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
result: TestUnitManager{
|
|
||||||
placed: []string{"hi.service", "hi.service.d/lo.conf", "hi.service.d/bye.conf"},
|
|
||||||
unmasked: []string{"hi.service"},
|
|
||||||
reload: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
units: []system.Unit{
|
|
||||||
system.Unit{Unit: config.Unit{
|
|
||||||
DropIns: []config.UnitDropIn{
|
|
||||||
{
|
|
||||||
Name: "lo.conf",
|
|
||||||
Content: "[Service]\nExecStart=/bin/echo lo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
result: TestUnitManager{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
units: []system.Unit{
|
|
||||||
system.Unit{Unit: config.Unit{
|
|
||||||
Name: "hi.service",
|
|
||||||
DropIns: []config.UnitDropIn{
|
|
||||||
{
|
|
||||||
Content: "[Service]\nExecStart=/bin/echo lo",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
result: TestUnitManager{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
units: []system.Unit{
|
|
||||||
system.Unit{Unit: config.Unit{
|
|
||||||
Name: "hi.service",
|
|
||||||
DropIns: []config.UnitDropIn{
|
|
||||||
{
|
|
||||||
Name: "lo.conf",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
result: TestUnitManager{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
tum := &TestUnitManager{}
|
|
||||||
if err := processUnits(tt.units, "", tum); err != nil {
|
|
||||||
t.Errorf("bad error (%+v): want nil, got %s", tt.units, err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(tt.result, *tum) {
|
|
||||||
t.Errorf("bad result (%+v): want %+v, got %+v", tt.units, tt.result, tum)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
32
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/initialize/github.go
generated
vendored
32
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/initialize/github.go
generated
vendored
@ -1,32 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package initialize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/system"
|
|
||||||
)
|
|
||||||
|
|
||||||
func SSHImportGithubUser(system_user string, github_user string) error {
|
|
||||||
url := fmt.Sprintf("https://api.github.com/users/%s/keys", github_user)
|
|
||||||
keys, err := fetchUserKeys(url)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
key_name := fmt.Sprintf("github-%s", github_user)
|
|
||||||
return system.AuthorizeSSHKeys(system_user, key_name, keys)
|
|
||||||
}
|
|
57
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/initialize/ssh_keys.go
generated
vendored
57
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/initialize/ssh_keys.go
generated
vendored
@ -1,57 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package initialize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/pkg"
|
|
||||||
"github.com/coreos/coreos-cloudinit/system"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UserKey struct {
|
|
||||||
ID int `json:"id,omitempty"`
|
|
||||||
Key string `json:"key"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func SSHImportKeysFromURL(system_user string, url string) error {
|
|
||||||
keys, err := fetchUserKeys(url)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
key_name := fmt.Sprintf("coreos-cloudinit-%s", system_user)
|
|
||||||
return system.AuthorizeSSHKeys(system_user, key_name, keys)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchUserKeys(url string) ([]string, error) {
|
|
||||||
client := pkg.NewHttpClient()
|
|
||||||
data, err := client.GetRetry(url)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var userKeys []UserKey
|
|
||||||
err = json.Unmarshal(data, &userKeys)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
keys := make([]string, 0)
|
|
||||||
for _, key := range userKeys {
|
|
||||||
keys = append(keys, key.Key)
|
|
||||||
}
|
|
||||||
return keys, err
|
|
||||||
}
|
|
56
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/initialize/ssh_keys_test.go
generated
vendored
56
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/initialize/ssh_keys_test.go
generated
vendored
@ -1,56 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package initialize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCloudConfigUsersUrlMarshal(t *testing.T) {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
gh_res := `
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"key": "ssh-dss AAAAB3NzaC1kc3MAAACBAIHAu822ggSkIHrJYvhmBceOSVjuflfQm8RbMMDNVe9relQfuPbN+nxGGTCKzPLebeOcX+Wwi77TPXWwK3BZMglfXxhABlFPsuMb63Tqp94pBYsJdx/iFj9iGo6pKoM1k8ubOcqsUnq+BR9895zRbE7MjdwkGo67+QhCEwvkwAnNAAAAFQCuddVqXLCubzqnWmeHLQE+2GFfHwAAAIBnlXW5h15ndVuwi0htF4oodVSB1KwnTWcuBK+aE1zRs76yvRb0Ws+oifumThDwB/Tec6FQuAfRKfy6piChZqsu5KvL98I+2t5yyi1td+kMvdTnVL2lW44etDKseOcozmknCOmh4Dqvhl/2MwrDAhlPaN08EEq9h3w3mXtNLWH64QAAAIBAzDOKr17llngaKIdDXh+LtXKh87+zfjlTA36/9r2uF2kYE5uApDtu9sPCkt7+YBQt7R8prADPckwAiXwVdk0xijIOpLDBmoydQJJRQ+zTMxvpQmUr/1kUOv0zb+lB657CgvN0vVTmP2swPeMvgntt3C4vw7Ab+O+MS9peOAJbbQ=="
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "ssh-dss AAAAB3NzaC1kc3MAAACBANxpzIbTzKTeBRaOIdUxwwGwvDasTfU/PonhbNIuhYjc+xFGvBRTumox2F+luVAKKs4WdvA4nJXaY1OFi6DZftk5Bp4E2JaSzp8ulAzHsMexDdv6LGHGEJj/qdHAL1vHk2K89PpwRFSRZI8XRBLjvkr4ZgBKLG5ZILXPJEPP2j3lAAAAFQCtxoTnV8wy0c4grcGrQ+1sCsD7WQAAAIAqZsW2GviMe1RQrbZT0xAZmI64XRPrnLsoLxycHWlS7r6uUln2c6Ae2MB/YF0d4Kd1XZii9GHj7rrypqEo7MW8uSabhu70nmu1J8m2O3Dsr+4oJLeat9vwPsJV92IKO0jQwjKnAOHOiB9JKGeCw+NfXfogbti9/q38Q6XcS+SI5wAAAIEA1803Y2h+tOOpZXAsNIwl9mRfExWzLQ3L7knwJdznQu/6SW1H/1oyoYLebuk187Qj2UFI5qQ6AZNc49DvohWx0Cg6ABcyubNyoaCjZKWIdxVnItHWNbLe//+tyTu0I2eQwJOORsEPK5gMpf599C7wXQ//DzZOWbTWiHEX52gCTmk="
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 5224438,
|
|
||||||
"key": "ssh-dss AAAAB3NzaC1kc3MAAACBAPKRWdKhzGZuLAJL6M1eM51hWViMqNBC2C6lm2OqGRYLuIf1GJ391widUuSf4wQqnkR22Q9PCmAZ19XCf11wBRMnuw9I/Z3Bt5bXfc+dzFBCmHYGJ6wNSv++H9jxyMb+usmsenWOFZGNO2jN0wrJ4ay8Yt0bwtRU+VCXpuRLszMzAAAAFQDZUIuPjcfK5HLgnwZ/J3lvtvlUjQAAAIEApIkAwLuCQV5j3U6DmI/Y6oELqSUR2purFm8jo8jePFfe1t+ghikgD254/JXlhDCVgY0NLXcak+coJfGCTT23quJ7I5xdpTn/OZO2Q6Woum/bijFC/UWwQbLz0R2nU3DoHv5v6XHQZxuIG4Fsxa91S+vWjZFtI7RuYlBCZA//ANMAAACBAJO0FojzkX6IeaWLqrgu9GTkFwGFazZ+LPH5JOWPoPn1hQKuR32Uf6qNcBZcIjY7SF0P7HF5rLQd6zKZzHqqQQ92MV555NEwjsnJglYU8CaaZsfYooaGPgA1YN7RhTSAuDmUW5Hyfj5BH4NTtrzrvJxIhDoQLf31Fasjw00r4R0O"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
`
|
|
||||||
fmt.Fprintln(w, gh_res)
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
|
|
||||||
keys, err := fetchUserKeys(ts.URL)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Encountered unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
expected := "ssh-dss AAAAB3NzaC1kc3MAAACBAIHAu822ggSkIHrJYvhmBceOSVjuflfQm8RbMMDNVe9relQfuPbN+nxGGTCKzPLebeOcX+Wwi77TPXWwK3BZMglfXxhABlFPsuMb63Tqp94pBYsJdx/iFj9iGo6pKoM1k8ubOcqsUnq+BR9895zRbE7MjdwkGo67+QhCEwvkwAnNAAAAFQCuddVqXLCubzqnWmeHLQE+2GFfHwAAAIBnlXW5h15ndVuwi0htF4oodVSB1KwnTWcuBK+aE1zRs76yvRb0Ws+oifumThDwB/Tec6FQuAfRKfy6piChZqsu5KvL98I+2t5yyi1td+kMvdTnVL2lW44etDKseOcozmknCOmh4Dqvhl/2MwrDAhlPaN08EEq9h3w3mXtNLWH64QAAAIBAzDOKr17llngaKIdDXh+LtXKh87+zfjlTA36/9r2uF2kYE5uApDtu9sPCkt7+YBQt7R8prADPckwAiXwVdk0xijIOpLDBmoydQJJRQ+zTMxvpQmUr/1kUOv0zb+lB657CgvN0vVTmP2swPeMvgntt3C4vw7Ab+O+MS9peOAJbbQ=="
|
|
||||||
if keys[0] != expected {
|
|
||||||
t.Fatalf("expected %s, got %s", expected, keys[0])
|
|
||||||
}
|
|
||||||
expected = "ssh-dss AAAAB3NzaC1kc3MAAACBAPKRWdKhzGZuLAJL6M1eM51hWViMqNBC2C6lm2OqGRYLuIf1GJ391widUuSf4wQqnkR22Q9PCmAZ19XCf11wBRMnuw9I/Z3Bt5bXfc+dzFBCmHYGJ6wNSv++H9jxyMb+usmsenWOFZGNO2jN0wrJ4ay8Yt0bwtRU+VCXpuRLszMzAAAAFQDZUIuPjcfK5HLgnwZ/J3lvtvlUjQAAAIEApIkAwLuCQV5j3U6DmI/Y6oELqSUR2purFm8jo8jePFfe1t+ghikgD254/JXlhDCVgY0NLXcak+coJfGCTT23quJ7I5xdpTn/OZO2Q6Woum/bijFC/UWwQbLz0R2nU3DoHv5v6XHQZxuIG4Fsxa91S+vWjZFtI7RuYlBCZA//ANMAAACBAJO0FojzkX6IeaWLqrgu9GTkFwGFazZ+LPH5JOWPoPn1hQKuR32Uf6qNcBZcIjY7SF0P7HF5rLQd6zKZzHqqQQ92MV555NEwjsnJglYU8CaaZsfYooaGPgA1YN7RhTSAuDmUW5Hyfj5BH4NTtrzrvJxIhDoQLf31Fasjw00r4R0O"
|
|
||||||
if keys[2] != expected {
|
|
||||||
t.Fatalf("expected %s, got %s", expected, keys[2])
|
|
||||||
}
|
|
||||||
}
|
|
62
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/etc_hosts.go
generated
vendored
62
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/etc_hosts.go
generated
vendored
@ -1,62 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
const DefaultIpv4Address = "127.0.0.1"
|
|
||||||
|
|
||||||
type EtcHosts struct {
|
|
||||||
config.EtcHosts
|
|
||||||
}
|
|
||||||
|
|
||||||
func (eh EtcHosts) generateEtcHosts() (out string, err error) {
|
|
||||||
if eh.EtcHosts != "localhost" {
|
|
||||||
return "", errors.New("Invalid option to manage_etc_hosts")
|
|
||||||
}
|
|
||||||
|
|
||||||
// use the operating system hostname
|
|
||||||
hostname, err := os.Hostname()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s %s\n", DefaultIpv4Address, hostname), nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (eh EtcHosts) File() (*File, error) {
|
|
||||||
if eh.EtcHosts == "" {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
etcHosts, err := eh.generateEtcHosts()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &File{config.File{
|
|
||||||
Path: path.Join("etc", "hosts"),
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
Content: etcHosts,
|
|
||||||
}}, nil
|
|
||||||
}
|
|
60
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/etc_hosts_test.go
generated
vendored
60
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/etc_hosts_test.go
generated
vendored
@ -1,60 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEtcdHostsFile(t *testing.T) {
|
|
||||||
hostname, err := os.Hostname()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range []struct {
|
|
||||||
config config.EtcHosts
|
|
||||||
file *File
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"invalid",
|
|
||||||
nil,
|
|
||||||
fmt.Errorf("Invalid option to manage_etc_hosts"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"localhost",
|
|
||||||
&File{config.File{
|
|
||||||
Content: fmt.Sprintf("127.0.0.1 %s\n", hostname),
|
|
||||||
Path: "etc/hosts",
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
}},
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
file, err := EtcHosts{tt.config}.File()
|
|
||||||
if !reflect.DeepEqual(tt.err, err) {
|
|
||||||
t.Errorf("bad error (%q): want %q, got %q", tt.config, tt.err, err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(tt.file, file) {
|
|
||||||
t.Errorf("bad units (%q): want %#v, got %#v", tt.config, tt.file, file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
37
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/etcd.go
generated
vendored
37
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/etcd.go
generated
vendored
@ -1,37 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Etcd is a top-level structure which embeds its underlying configuration,
|
|
||||||
// config.Etcd, and provides the system-specific Unit().
|
|
||||||
type Etcd struct {
|
|
||||||
config.Etcd
|
|
||||||
}
|
|
||||||
|
|
||||||
// Units creates a Unit file drop-in for etcd, using any configured options.
|
|
||||||
func (ee Etcd) Units() []Unit {
|
|
||||||
return []Unit{{config.Unit{
|
|
||||||
Name: "etcd.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{{
|
|
||||||
Name: "20-cloudinit.conf",
|
|
||||||
Content: serviceContents(ee.Etcd),
|
|
||||||
}},
|
|
||||||
}}}
|
|
||||||
}
|
|
79
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/etcd_test.go
generated
vendored
79
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/etcd_test.go
generated
vendored
@ -1,79 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEtcdUnits(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
config config.Etcd
|
|
||||||
units []Unit
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
config.Etcd{},
|
|
||||||
[]Unit{{config.Unit{
|
|
||||||
Name: "etcd.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{{Name: "20-cloudinit.conf"}},
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config.Etcd{
|
|
||||||
Discovery: "http://disco.example.com/foobar",
|
|
||||||
PeerBindAddr: "127.0.0.1:7002",
|
|
||||||
},
|
|
||||||
[]Unit{{config.Unit{
|
|
||||||
Name: "etcd.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{{
|
|
||||||
Name: "20-cloudinit.conf",
|
|
||||||
Content: `[Service]
|
|
||||||
Environment="ETCD_DISCOVERY=http://disco.example.com/foobar"
|
|
||||||
Environment="ETCD_PEER_BIND_ADDR=127.0.0.1:7002"
|
|
||||||
`,
|
|
||||||
}},
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config.Etcd{
|
|
||||||
Name: "node001",
|
|
||||||
Discovery: "http://disco.example.com/foobar",
|
|
||||||
PeerBindAddr: "127.0.0.1:7002",
|
|
||||||
},
|
|
||||||
[]Unit{{config.Unit{
|
|
||||||
Name: "etcd.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{{
|
|
||||||
Name: "20-cloudinit.conf",
|
|
||||||
Content: `[Service]
|
|
||||||
Environment="ETCD_DISCOVERY=http://disco.example.com/foobar"
|
|
||||||
Environment="ETCD_NAME=node001"
|
|
||||||
Environment="ETCD_PEER_BIND_ADDR=127.0.0.1:7002"
|
|
||||||
`,
|
|
||||||
}},
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
units := Etcd{tt.config}.Units()
|
|
||||||
if !reflect.DeepEqual(tt.units, units) {
|
|
||||||
t.Errorf("bad units (%+v): want %#v, got %#v", tt.config, tt.units, units)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
44
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/flannel.go
generated
vendored
44
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/flannel.go
generated
vendored
@ -1,44 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fl Flannel) envVars() string {
|
|
||||||
return strings.Join(getEnvVars(fl.Flannel), "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fl Flannel) File() (*File, error) {
|
|
||||||
vars := fl.envVars()
|
|
||||||
if vars == "" {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return &File{config.File{
|
|
||||||
Path: path.Join("run", "flannel", "options.env"),
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
Content: vars,
|
|
||||||
}}, nil
|
|
||||||
}
|
|
76
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/flannel_test.go
generated
vendored
76
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/flannel_test.go
generated
vendored
@ -1,76 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFlannelEnvVars(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
config config.Flannel
|
|
||||||
contents string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
config.Flannel{},
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config.Flannel{
|
|
||||||
EtcdEndpoints: "http://12.34.56.78:4001",
|
|
||||||
EtcdPrefix: "/coreos.com/network/tenant1",
|
|
||||||
},
|
|
||||||
`FLANNELD_ETCD_ENDPOINTS=http://12.34.56.78:4001
|
|
||||||
FLANNELD_ETCD_PREFIX=/coreos.com/network/tenant1`,
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
out := Flannel{tt.config}.envVars()
|
|
||||||
if out != tt.contents {
|
|
||||||
t.Errorf("bad contents (%+v): want %q, got %q", tt, tt.contents, out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFlannelFile(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
config config.Flannel
|
|
||||||
file *File
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
config.Flannel{},
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config.Flannel{
|
|
||||||
EtcdEndpoints: "http://12.34.56.78:4001",
|
|
||||||
EtcdPrefix: "/coreos.com/network/tenant1",
|
|
||||||
},
|
|
||||||
&File{config.File{
|
|
||||||
Path: "run/flannel/options.env",
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
Content: `FLANNELD_ETCD_ENDPOINTS=http://12.34.56.78:4001
|
|
||||||
FLANNELD_ETCD_PREFIX=/coreos.com/network/tenant1`,
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
file, _ := Flannel{tt.config}.File()
|
|
||||||
if !reflect.DeepEqual(tt.file, file) {
|
|
||||||
t.Errorf("bad units (%q): want %#v, got %#v", tt.config, tt.file, file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
38
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/fleet.go
generated
vendored
38
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/fleet.go
generated
vendored
@ -1,38 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Fleet is a top-level structure which embeds its underlying configuration,
|
|
||||||
// config.Fleet, and provides the system-specific Unit().
|
|
||||||
type Fleet struct {
|
|
||||||
config.Fleet
|
|
||||||
}
|
|
||||||
|
|
||||||
// Units generates a Unit file drop-in for fleet, if any fleet options were
|
|
||||||
// configured in cloud-config
|
|
||||||
func (fe Fleet) Units() []Unit {
|
|
||||||
return []Unit{{config.Unit{
|
|
||||||
Name: "fleet.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{{
|
|
||||||
Name: "20-cloudinit.conf",
|
|
||||||
Content: serviceContents(fe.Fleet),
|
|
||||||
}},
|
|
||||||
}}}
|
|
||||||
}
|
|
58
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/fleet_test.go
generated
vendored
58
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/fleet_test.go
generated
vendored
@ -1,58 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFleetUnits(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
config config.Fleet
|
|
||||||
units []Unit
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
config.Fleet{},
|
|
||||||
[]Unit{{config.Unit{
|
|
||||||
Name: "fleet.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{{Name: "20-cloudinit.conf"}},
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config.Fleet{
|
|
||||||
PublicIP: "12.34.56.78",
|
|
||||||
},
|
|
||||||
[]Unit{{config.Unit{
|
|
||||||
Name: "fleet.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{{
|
|
||||||
Name: "20-cloudinit.conf",
|
|
||||||
Content: `[Service]
|
|
||||||
Environment="FLEET_PUBLIC_IP=12.34.56.78"
|
|
||||||
`,
|
|
||||||
}},
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
units := Fleet{tt.config}.Units()
|
|
||||||
if !reflect.DeepEqual(units, tt.units) {
|
|
||||||
t.Errorf("bad units (%+v): want %#v, got %#v", tt.config, tt.units, units)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
37
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/locksmith.go
generated
vendored
37
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/locksmith.go
generated
vendored
@ -1,37 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Locksmith is a top-level structure which embeds its underlying configuration,
|
|
||||||
// config.Locksmith, and provides the system-specific Unit().
|
|
||||||
type Locksmith struct {
|
|
||||||
config.Locksmith
|
|
||||||
}
|
|
||||||
|
|
||||||
// Units creates a Unit file drop-in for etcd, using any configured options.
|
|
||||||
func (ee Locksmith) Units() []Unit {
|
|
||||||
return []Unit{{config.Unit{
|
|
||||||
Name: "locksmithd.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{{
|
|
||||||
Name: "20-cloudinit.conf",
|
|
||||||
Content: serviceContents(ee.Locksmith),
|
|
||||||
}},
|
|
||||||
}}}
|
|
||||||
}
|
|
58
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/locksmith_test.go
generated
vendored
58
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/locksmith_test.go
generated
vendored
@ -1,58 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestLocksmithUnits(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
config config.Locksmith
|
|
||||||
units []Unit
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
config.Locksmith{},
|
|
||||||
[]Unit{{config.Unit{
|
|
||||||
Name: "locksmithd.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{{Name: "20-cloudinit.conf"}},
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config.Locksmith{
|
|
||||||
Endpoint: "12.34.56.78:4001",
|
|
||||||
},
|
|
||||||
[]Unit{{config.Unit{
|
|
||||||
Name: "locksmithd.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{{
|
|
||||||
Name: "20-cloudinit.conf",
|
|
||||||
Content: `[Service]
|
|
||||||
Environment="LOCKSMITHD_ENDPOINT=12.34.56.78:4001"
|
|
||||||
`,
|
|
||||||
}},
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
units := Locksmith{tt.config}.Units()
|
|
||||||
if !reflect.DeepEqual(units, tt.units) {
|
|
||||||
t.Errorf("bad units (%+v): want %#v, got %#v", tt.config, tt.units, units)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
96
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/networkd.go
generated
vendored
96
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/networkd.go
generated
vendored
@ -1,96 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
"github.com/coreos/coreos-cloudinit/network"
|
|
||||||
|
|
||||||
"github.com/docker/libcontainer/netlink"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RestartNetwork(interfaces []network.InterfaceGenerator) (err error) {
|
|
||||||
defer func() {
|
|
||||||
if e := restartNetworkd(); e != nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err = downNetworkInterfaces(interfaces); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = maybeProbe8012q(interfaces); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return maybeProbeBonding(interfaces)
|
|
||||||
}
|
|
||||||
|
|
||||||
func downNetworkInterfaces(interfaces []network.InterfaceGenerator) error {
|
|
||||||
sysInterfaceMap := make(map[string]*net.Interface)
|
|
||||||
if systemInterfaces, err := net.Interfaces(); err == nil {
|
|
||||||
for _, iface := range systemInterfaces {
|
|
||||||
iface := iface
|
|
||||||
sysInterfaceMap[iface.Name] = &iface
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, iface := range interfaces {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func maybeProbe8012q(interfaces []network.InterfaceGenerator) error {
|
|
||||||
for _, iface := range interfaces {
|
|
||||||
if iface.Type() == "vlan" {
|
|
||||||
log.Printf("Probing LKM %q (%q)\n", "8021q", "8021q")
|
|
||||||
return exec.Command("modprobe", "8021q").Run()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func maybeProbeBonding(interfaces []network.InterfaceGenerator) error {
|
|
||||||
for _, iface := range interfaces {
|
|
||||||
if iface.Type() == "bond" {
|
|
||||||
args := append([]string{"bonding"}, strings.Split(iface.ModprobeParams(), " ")...)
|
|
||||||
log.Printf("Probing LKM %q (%q)\n", "bonding", args)
|
|
||||||
return exec.Command("modprobe", args...).Run()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func restartNetworkd() error {
|
|
||||||
log.Printf("Restarting networkd.service\n")
|
|
||||||
networkd := Unit{config.Unit{Name: "systemd-networkd.service"}}
|
|
||||||
_, err := NewUnitManager("").RunUnitCommand(networkd, "restart")
|
|
||||||
return err
|
|
||||||
}
|
|
46
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/oem.go
generated
vendored
46
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/oem.go
generated
vendored
@ -1,46 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"path"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// OEM is a top-level structure which embeds its underlying configuration,
|
|
||||||
// config.OEM, and provides the system-specific File().
|
|
||||||
type OEM struct {
|
|
||||||
config.OEM
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oem OEM) File() (*File, error) {
|
|
||||||
if oem.ID == "" {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
content := fmt.Sprintf("ID=%s\n", oem.ID)
|
|
||||||
content += fmt.Sprintf("VERSION_ID=%s\n", oem.VersionID)
|
|
||||||
content += fmt.Sprintf("NAME=%q\n", oem.Name)
|
|
||||||
content += fmt.Sprintf("HOME_URL=%q\n", oem.HomeURL)
|
|
||||||
content += fmt.Sprintf("BUG_REPORT_URL=%q\n", oem.BugReportURL)
|
|
||||||
|
|
||||||
return &File{config.File{
|
|
||||||
Path: path.Join("etc", "oem-release"),
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
Content: content,
|
|
||||||
}}, nil
|
|
||||||
}
|
|
61
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/oem_test.go
generated
vendored
61
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/oem_test.go
generated
vendored
@ -1,61 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestOEMFile(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
config config.OEM
|
|
||||||
file *File
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
config.OEM{},
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config.OEM{
|
|
||||||
ID: "rackspace",
|
|
||||||
Name: "Rackspace Cloud Servers",
|
|
||||||
VersionID: "168.0.0",
|
|
||||||
HomeURL: "https://www.rackspace.com/cloud/servers/",
|
|
||||||
BugReportURL: "https://github.com/coreos/coreos-overlay",
|
|
||||||
},
|
|
||||||
&File{config.File{
|
|
||||||
Path: "etc/oem-release",
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
Content: `ID=rackspace
|
|
||||||
VERSION_ID=168.0.0
|
|
||||||
NAME="Rackspace Cloud Servers"
|
|
||||||
HOME_URL="https://www.rackspace.com/cloud/servers/"
|
|
||||||
BUG_REPORT_URL="https://github.com/coreos/coreos-overlay"
|
|
||||||
`,
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
file, err := OEM{tt.config}.File()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("bad error (%q): want %v, got %q", tt.config, nil, err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(tt.file, file) {
|
|
||||||
t.Errorf("bad file (%q): want %#v, got %#v", tt.config, tt.file, file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
43
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/ssh_key.go
generated
vendored
43
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/ssh_key.go
generated
vendored
@ -16,8 +16,6 @@ package system
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -25,48 +23,19 @@ import (
|
|||||||
// Add the provide SSH public key to the core user's list of
|
// Add the provide SSH public key to the core user's list of
|
||||||
// authorized keys
|
// authorized keys
|
||||||
func AuthorizeSSHKeys(user string, keysName string, keys []string) error {
|
func AuthorizeSSHKeys(user string, keysName string, keys []string) error {
|
||||||
for i, key := range keys {
|
for _, key := range keys {
|
||||||
keys[i] = strings.TrimSpace(key)
|
trimmedKey := strings.TrimSpace(key)
|
||||||
}
|
cmd := exec.Command("update-ssh-keys", user, trimmedKey)
|
||||||
|
|
||||||
// join all keys with newlines, ensuring the resulting string
|
err := cmd.Start()
|
||||||
// also ends with a newline
|
|
||||||
joined := fmt.Sprintf("%s\n", strings.Join(keys, "\n"))
|
|
||||||
|
|
||||||
cmd := exec.Command("update-ssh-keys", "-u", user, "-a", keysName)
|
|
||||||
stdin, err := cmd.StdinPipe()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, err := cmd.StdoutPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
stderr, err := cmd.StderrPipe()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cmd.Start()
|
|
||||||
if err != nil {
|
|
||||||
stdin.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = io.WriteString(stdin, joined)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
stdin.Close()
|
|
||||||
stdoutBytes, _ := ioutil.ReadAll(stdout)
|
|
||||||
stderrBytes, _ := ioutil.ReadAll(stderr)
|
|
||||||
|
|
||||||
err = cmd.Wait()
|
err = cmd.Wait()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Call to update-ssh-keys failed with %v: %s %s", err, string(stdoutBytes), string(stderrBytes))
|
return fmt.Errorf("Call to update-ssh-keys failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
205
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/systemd.go
generated
vendored
205
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/systemd.go
generated
vendored
@ -1,205 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/coreos/go-systemd/dbus"
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewUnitManager(root string) UnitManager {
|
|
||||||
return &systemd{root}
|
|
||||||
}
|
|
||||||
|
|
||||||
type systemd struct {
|
|
||||||
root string
|
|
||||||
}
|
|
||||||
|
|
||||||
// fakeMachineID is placed on non-usr CoreOS images and should
|
|
||||||
// never be used as a true MachineID
|
|
||||||
const fakeMachineID = "42000000000000000000000000000042"
|
|
||||||
|
|
||||||
// PlaceUnit writes a unit file at its desired destination, creating parent
|
|
||||||
// directories as necessary.
|
|
||||||
func (s *systemd) PlaceUnit(u Unit) error {
|
|
||||||
file := File{config.File{
|
|
||||||
Path: u.Destination(s.root),
|
|
||||||
Content: u.Content,
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
}}
|
|
||||||
|
|
||||||
_, err := WriteFile(&file, "/")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// PlaceUnitDropIn writes a unit drop-in file at its desired destination,
|
|
||||||
// creating parent directories as necessary.
|
|
||||||
func (s *systemd) PlaceUnitDropIn(u Unit, d config.UnitDropIn) error {
|
|
||||||
file := File{config.File{
|
|
||||||
Path: u.DropInDestination(s.root, d),
|
|
||||||
Content: d.Content,
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
}}
|
|
||||||
|
|
||||||
_, err := WriteFile(&file, "/")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *systemd) EnableUnitFile(u Unit) error {
|
|
||||||
conn, err := dbus.New()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
units := []string{u.Name}
|
|
||||||
_, _, err = conn.EnableUnitFiles(units, u.Runtime, true)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *systemd) RunUnitCommand(u Unit, c string) (string, error) {
|
|
||||||
conn, err := dbus.New()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var fn func(string, string) (string, error)
|
|
||||||
switch c {
|
|
||||||
case "start":
|
|
||||||
fn = conn.StartUnit
|
|
||||||
case "stop":
|
|
||||||
fn = conn.StopUnit
|
|
||||||
case "restart":
|
|
||||||
fn = conn.RestartUnit
|
|
||||||
case "reload":
|
|
||||||
fn = conn.ReloadUnit
|
|
||||||
case "try-restart":
|
|
||||||
fn = conn.TryRestartUnit
|
|
||||||
case "reload-or-restart":
|
|
||||||
fn = conn.ReloadOrRestartUnit
|
|
||||||
case "reload-or-try-restart":
|
|
||||||
fn = conn.ReloadOrTryRestartUnit
|
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("Unsupported systemd command %q", c)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fn(u.Name, "replace")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *systemd) DaemonReload() error {
|
|
||||||
conn, err := dbus.New()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return conn.Reload()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MaskUnit masks the given Unit by symlinking its unit file to
|
|
||||||
// /dev/null, analogous to `systemctl mask`.
|
|
||||||
// N.B.: Unlike `systemctl mask`, this function will *remove any existing unit
|
|
||||||
// file at the location*, to ensure that the mask will succeed.
|
|
||||||
func (s *systemd) MaskUnit(u Unit) error {
|
|
||||||
masked := u.Destination(s.root)
|
|
||||||
if _, err := os.Stat(masked); os.IsNotExist(err) {
|
|
||||||
if err := os.MkdirAll(path.Dir(masked), os.FileMode(0755)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if err := os.Remove(masked); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return os.Symlink("/dev/null", masked)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmaskUnit is analogous to systemd's unit_file_unmask. If the file
|
|
||||||
// associated with the given Unit is empty or appears to be a symlink to
|
|
||||||
// /dev/null, it is removed.
|
|
||||||
func (s *systemd) UnmaskUnit(u Unit) error {
|
|
||||||
masked := u.Destination(s.root)
|
|
||||||
ne, err := nullOrEmpty(masked)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
} else if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !ne {
|
|
||||||
log.Printf("%s is not null or empty, refusing to unmask", masked)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return os.Remove(masked)
|
|
||||||
}
|
|
||||||
|
|
||||||
// nullOrEmpty checks whether a given path appears to be an empty regular file
|
|
||||||
// or a symlink to /dev/null
|
|
||||||
func nullOrEmpty(path string) (bool, error) {
|
|
||||||
fi, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
m := fi.Mode()
|
|
||||||
if m.IsRegular() && fi.Size() <= 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
if m&os.ModeCharDevice > 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExecuteScript(scriptPath string) (string, error) {
|
|
||||||
props := []dbus.Property{
|
|
||||||
dbus.PropDescription("Unit generated and executed by coreos-cloudinit on behalf of user"),
|
|
||||||
dbus.PropExecStart([]string{"/bin/bash", scriptPath}, false),
|
|
||||||
}
|
|
||||||
|
|
||||||
base := path.Base(scriptPath)
|
|
||||||
name := fmt.Sprintf("coreos-cloudinit-%s.service", base)
|
|
||||||
|
|
||||||
log.Printf("Creating transient systemd unit '%s'", name)
|
|
||||||
|
|
||||||
conn, err := dbus.New()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = conn.StartTransientUnit(name, "replace", props...)
|
|
||||||
return name, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetHostname(hostname string) error {
|
|
||||||
return exec.Command("hostnamectl", "set-hostname", hostname).Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Hostname() (string, error) {
|
|
||||||
return os.Hostname()
|
|
||||||
}
|
|
||||||
|
|
||||||
func MachineID(root string) string {
|
|
||||||
contents, _ := ioutil.ReadFile(path.Join(root, "etc", "machine-id"))
|
|
||||||
id := strings.TrimSpace(string(contents))
|
|
||||||
|
|
||||||
if id == fakeMachineID {
|
|
||||||
id = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return id
|
|
||||||
}
|
|
280
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/systemd_test.go
generated
vendored
280
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/systemd_test.go
generated
vendored
@ -1,280 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPlaceUnit(t *testing.T) {
|
|
||||||
tests := []config.Unit{
|
|
||||||
{
|
|
||||||
Name: "50-eth0.network",
|
|
||||||
Runtime: true,
|
|
||||||
Content: "[Match]\nName=eth47\n\n[Network]\nAddress=10.209.171.177/19\n",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "media-state.mount",
|
|
||||||
Content: "[Mount]\nWhat=/dev/sdb1\nWhere=/media/state\n",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("Unable to create tempdir: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
u := Unit{tt}
|
|
||||||
sd := &systemd{dir}
|
|
||||||
|
|
||||||
if err := sd.PlaceUnit(u); err != nil {
|
|
||||||
t.Fatalf("PlaceUnit(): bad error (%+v): want nil, got %s", tt, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fi, err := os.Stat(u.Destination(dir))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Stat(): bad error (%+v): want nil, got %s", tt, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if mode := fi.Mode(); mode != os.FileMode(0644) {
|
|
||||||
t.Errorf("bad filemode (%+v): want %v, got %v", tt, os.FileMode(0644), mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := ioutil.ReadFile(u.Destination(dir))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("ReadFile(): bad error (%+v): want nil, got %s", tt, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if string(c) != tt.Content {
|
|
||||||
t.Errorf("bad contents (%+v): want %q, got %q", tt, tt.Content, string(c))
|
|
||||||
}
|
|
||||||
|
|
||||||
os.RemoveAll(dir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPlaceUnitDropIn(t *testing.T) {
|
|
||||||
tests := []config.Unit{
|
|
||||||
{
|
|
||||||
Name: "false.service",
|
|
||||||
Runtime: true,
|
|
||||||
DropIns: []config.UnitDropIn{
|
|
||||||
{
|
|
||||||
Name: "00-true.conf",
|
|
||||||
Content: "[Service]\nExecStart=\nExecStart=/usr/bin/true\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "true.service",
|
|
||||||
DropIns: []config.UnitDropIn{
|
|
||||||
{
|
|
||||||
Name: "00-false.conf",
|
|
||||||
Content: "[Service]\nExecStart=\nExecStart=/usr/bin/false\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("Unable to create tempdir: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
u := Unit{tt}
|
|
||||||
sd := &systemd{dir}
|
|
||||||
|
|
||||||
if err := sd.PlaceUnitDropIn(u, u.DropIns[0]); err != nil {
|
|
||||||
t.Fatalf("PlaceUnit(): bad error (%+v): want nil, got %s", tt, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fi, err := os.Stat(u.DropInDestination(dir, u.DropIns[0]))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Stat(): bad error (%+v): want nil, got %s", tt, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if mode := fi.Mode(); mode != os.FileMode(0644) {
|
|
||||||
t.Errorf("bad filemode (%+v): want %v, got %v", tt, os.FileMode(0644), mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
c, err := ioutil.ReadFile(u.DropInDestination(dir, u.DropIns[0]))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("ReadFile(): bad error (%+v): want nil, got %s", tt, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if string(c) != u.DropIns[0].Content {
|
|
||||||
t.Errorf("bad contents (%+v): want %q, got %q", tt, u.DropIns[0].Content, string(c))
|
|
||||||
}
|
|
||||||
|
|
||||||
os.RemoveAll(dir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMachineID(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)
|
|
||||||
|
|
||||||
os.Mkdir(path.Join(dir, "etc"), os.FileMode(0755))
|
|
||||||
ioutil.WriteFile(path.Join(dir, "etc", "machine-id"), []byte("node007\n"), os.FileMode(0444))
|
|
||||||
|
|
||||||
if MachineID(dir) != "node007" {
|
|
||||||
t.Fatalf("File has incorrect contents")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMaskUnit(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)
|
|
||||||
|
|
||||||
sd := &systemd{dir}
|
|
||||||
|
|
||||||
// Ensure mask works with units that do not currently exist
|
|
||||||
uf := Unit{config.Unit{Name: "foo.service"}}
|
|
||||||
if err := sd.MaskUnit(uf); err != nil {
|
|
||||||
t.Fatalf("Unable to mask new unit: %v", err)
|
|
||||||
}
|
|
||||||
fooPath := path.Join(dir, "etc", "systemd", "system", "foo.service")
|
|
||||||
fooTgt, err := os.Readlink(fooPath)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("Unable to read link", err)
|
|
||||||
}
|
|
||||||
if fooTgt != "/dev/null" {
|
|
||||||
t.Fatal("unit not masked, got unit target", fooTgt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure mask works with unit files that already exist
|
|
||||||
ub := Unit{config.Unit{Name: "bar.service"}}
|
|
||||||
barPath := path.Join(dir, "etc", "systemd", "system", "bar.service")
|
|
||||||
if _, err := os.Create(barPath); err != nil {
|
|
||||||
t.Fatalf("Error creating new unit file: %v", err)
|
|
||||||
}
|
|
||||||
if err := sd.MaskUnit(ub); err != nil {
|
|
||||||
t.Fatalf("Unable to mask existing unit: %v", err)
|
|
||||||
}
|
|
||||||
barTgt, err := os.Readlink(barPath)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("Unable to read link", err)
|
|
||||||
}
|
|
||||||
if barTgt != "/dev/null" {
|
|
||||||
t.Fatal("unit not masked, got unit target", barTgt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUnmaskUnit(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)
|
|
||||||
|
|
||||||
sd := &systemd{dir}
|
|
||||||
|
|
||||||
nilUnit := Unit{config.Unit{Name: "null.service"}}
|
|
||||||
if err := sd.UnmaskUnit(nilUnit); err != nil {
|
|
||||||
t.Errorf("unexpected error from unmasking nonexistent unit: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
uf := Unit{config.Unit{Name: "foo.service", Content: "[Service]\nExecStart=/bin/true"}}
|
|
||||||
dst := uf.Destination(dir)
|
|
||||||
if err := os.MkdirAll(path.Dir(dst), os.FileMode(0755)); err != nil {
|
|
||||||
t.Fatalf("Unable to create unit directory: %v", err)
|
|
||||||
}
|
|
||||||
if _, err := os.Create(dst); err != nil {
|
|
||||||
t.Fatalf("Unable to write unit file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ioutil.WriteFile(dst, []byte(uf.Content), 700); err != nil {
|
|
||||||
t.Fatalf("Unable to write unit file: %v", err)
|
|
||||||
}
|
|
||||||
if err := sd.UnmaskUnit(uf); err != nil {
|
|
||||||
t.Errorf("unmask of non-empty unit returned unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
got, _ := ioutil.ReadFile(dst)
|
|
||||||
if string(got) != uf.Content {
|
|
||||||
t.Errorf("unmask of non-empty unit mutated unit contents unexpectedly")
|
|
||||||
}
|
|
||||||
|
|
||||||
ub := Unit{config.Unit{Name: "bar.service"}}
|
|
||||||
dst = ub.Destination(dir)
|
|
||||||
if err := os.Symlink("/dev/null", dst); err != nil {
|
|
||||||
t.Fatalf("Unable to create masked unit: %v", err)
|
|
||||||
}
|
|
||||||
if err := sd.UnmaskUnit(ub); err != nil {
|
|
||||||
t.Errorf("unmask of unit returned unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if _, err := os.Stat(dst); !os.IsNotExist(err) {
|
|
||||||
t.Errorf("expected %s to not exist after unmask, but got err: %s", dst, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNullOrEmpty(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)
|
|
||||||
|
|
||||||
non := path.Join(dir, "does_not_exist")
|
|
||||||
ne, err := nullOrEmpty(non)
|
|
||||||
if !os.IsNotExist(err) {
|
|
||||||
t.Errorf("nullOrEmpty on nonexistent file returned bad error: %v", err)
|
|
||||||
}
|
|
||||||
if ne {
|
|
||||||
t.Errorf("nullOrEmpty returned true unxpectedly")
|
|
||||||
}
|
|
||||||
|
|
||||||
regEmpty := path.Join(dir, "regular_empty_file")
|
|
||||||
_, err = os.Create(regEmpty)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unable to create tempfile: %v", err)
|
|
||||||
}
|
|
||||||
gotNe, gotErr := nullOrEmpty(regEmpty)
|
|
||||||
if !gotNe || gotErr != nil {
|
|
||||||
t.Errorf("nullOrEmpty of regular empty file returned %t, %v - want true, nil", gotNe, gotErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
reg := path.Join(dir, "regular_file")
|
|
||||||
if err := ioutil.WriteFile(reg, []byte("asdf"), 700); err != nil {
|
|
||||||
t.Fatalf("Unable to create tempfile: %v", err)
|
|
||||||
}
|
|
||||||
gotNe, gotErr = nullOrEmpty(reg)
|
|
||||||
if gotNe || gotErr != nil {
|
|
||||||
t.Errorf("nullOrEmpty of regular file returned %t, %v - want false, nil", gotNe, gotErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
null := path.Join(dir, "null")
|
|
||||||
if err := os.Symlink(os.DevNull, null); err != nil {
|
|
||||||
t.Fatalf("Unable to create /dev/null link: %s", err)
|
|
||||||
}
|
|
||||||
gotNe, gotErr = nullOrEmpty(null)
|
|
||||||
if !gotNe || gotErr != nil {
|
|
||||||
t.Errorf("nullOrEmpty of null symlink returned %t, %v - want true, nil", gotNe, gotErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
82
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/unit.go
generated
vendored
82
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/unit.go
generated
vendored
@ -1,82 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
type UnitManager interface {
|
|
||||||
PlaceUnit(unit Unit) error
|
|
||||||
PlaceUnitDropIn(unit Unit, dropIn config.UnitDropIn) error
|
|
||||||
EnableUnitFile(unit Unit) error
|
|
||||||
RunUnitCommand(unit Unit, command string) (string, error)
|
|
||||||
MaskUnit(unit Unit) error
|
|
||||||
UnmaskUnit(unit Unit) error
|
|
||||||
DaemonReload() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unit is a top-level structure which embeds its underlying configuration,
|
|
||||||
// config.Unit, and provides the system-specific Destination(), Type(), and
|
|
||||||
// Group().
|
|
||||||
type Unit struct {
|
|
||||||
config.Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type returns the extension of the unit (everything that follows the final
|
|
||||||
// period).
|
|
||||||
func (u Unit) Type() string {
|
|
||||||
ext := filepath.Ext(u.Name)
|
|
||||||
return strings.TrimLeft(ext, ".")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Group returns "network" or "system" depending on whether or not the unit is
|
|
||||||
// a network unit or otherwise.
|
|
||||||
func (u Unit) Group() string {
|
|
||||||
switch u.Type() {
|
|
||||||
case "network", "netdev", "link":
|
|
||||||
return "network"
|
|
||||||
default:
|
|
||||||
return "system"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destination builds the appropriate absolute file path for the Unit. The root
|
|
||||||
// argument indicates the effective base directory of the system (similar to a
|
|
||||||
// chroot).
|
|
||||||
func (u Unit) Destination(root string) string {
|
|
||||||
return path.Join(u.prefix(root), u.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DropInDestination builds the appropriate absolute file path for the
|
|
||||||
// UnitDropIn. The root argument indicates the effective base directory of the
|
|
||||||
// system (similar to a chroot) and the dropIn argument is the UnitDropIn for
|
|
||||||
// which the destination is being calculated.
|
|
||||||
func (u Unit) DropInDestination(root string, dropIn config.UnitDropIn) string {
|
|
||||||
return path.Join(u.prefix(root), fmt.Sprintf("%s.d", u.Name), dropIn.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u Unit) prefix(root string) string {
|
|
||||||
dir := "etc"
|
|
||||||
if u.Runtime {
|
|
||||||
dir = "run"
|
|
||||||
}
|
|
||||||
return path.Join(root, dir, "systemd", u.Group())
|
|
||||||
}
|
|
136
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/unit_test.go
generated
vendored
136
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/unit_test.go
generated
vendored
@ -1,136 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestType(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
|
|
||||||
typ string
|
|
||||||
}{
|
|
||||||
{},
|
|
||||||
{"test.service", "service"},
|
|
||||||
{"hello", ""},
|
|
||||||
{"lots.of.dots", "dots"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
u := Unit{config.Unit{
|
|
||||||
Name: tt.name,
|
|
||||||
}}
|
|
||||||
if typ := u.Type(); tt.typ != typ {
|
|
||||||
t.Errorf("bad type (%+v): want %q, got %q", tt, tt.typ, typ)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGroup(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
|
|
||||||
group string
|
|
||||||
}{
|
|
||||||
{"test.service", "system"},
|
|
||||||
{"test.link", "network"},
|
|
||||||
{"test.network", "network"},
|
|
||||||
{"test.netdev", "network"},
|
|
||||||
{"test.conf", "system"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
u := Unit{config.Unit{
|
|
||||||
Name: tt.name,
|
|
||||||
}}
|
|
||||||
if group := u.Group(); tt.group != group {
|
|
||||||
t.Errorf("bad group (%+v): want %q, got %q", tt, tt.group, group)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDestination(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
root string
|
|
||||||
name string
|
|
||||||
runtime bool
|
|
||||||
|
|
||||||
destination string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
root: "/some/dir",
|
|
||||||
name: "foobar.service",
|
|
||||||
destination: "/some/dir/etc/systemd/system/foobar.service",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
root: "/some/dir",
|
|
||||||
name: "foobar.service",
|
|
||||||
runtime: true,
|
|
||||||
destination: "/some/dir/run/systemd/system/foobar.service",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
u := Unit{config.Unit{
|
|
||||||
Name: tt.name,
|
|
||||||
Runtime: tt.runtime,
|
|
||||||
}}
|
|
||||||
if d := u.Destination(tt.root); tt.destination != d {
|
|
||||||
t.Errorf("bad destination (%+v): want %q, got %q", tt, tt.destination, d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDropInDestination(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
root string
|
|
||||||
unitName string
|
|
||||||
dropInName string
|
|
||||||
runtime bool
|
|
||||||
|
|
||||||
destination string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
root: "/some/dir",
|
|
||||||
unitName: "foo.service",
|
|
||||||
dropInName: "bar.conf",
|
|
||||||
destination: "/some/dir/etc/systemd/system/foo.service.d/bar.conf",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
root: "/some/dir",
|
|
||||||
unitName: "foo.service",
|
|
||||||
dropInName: "bar.conf",
|
|
||||||
runtime: true,
|
|
||||||
destination: "/some/dir/run/systemd/system/foo.service.d/bar.conf",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
u := Unit{config.Unit{
|
|
||||||
Name: tt.unitName,
|
|
||||||
Runtime: tt.runtime,
|
|
||||||
DropIns: []config.UnitDropIn{{
|
|
||||||
Name: tt.dropInName,
|
|
||||||
}},
|
|
||||||
}}
|
|
||||||
if d := u.DropInDestination(tt.root, u.DropIns[0]); tt.destination != d {
|
|
||||||
t.Errorf("bad destination (%+v): want %q, got %q", tt, tt.destination, d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
151
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/update.go
generated
vendored
151
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/update.go
generated
vendored
@ -1,151 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"reflect"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
locksmithUnit = "locksmithd.service"
|
|
||||||
updateEngineUnit = "update-engine.service"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Update is a top-level structure which contains its underlying configuration,
|
|
||||||
// config.Update, a function for reading the configuration (the default
|
|
||||||
// implementation reading from the filesystem), and provides the system-specific
|
|
||||||
// File() and Unit().
|
|
||||||
type Update struct {
|
|
||||||
ReadConfig func() (io.Reader, error)
|
|
||||||
config.Update
|
|
||||||
}
|
|
||||||
|
|
||||||
func DefaultReadConfig() (io.Reader, error) {
|
|
||||||
etcUpdate := path.Join("/etc", "coreos", "update.conf")
|
|
||||||
usrUpdate := path.Join("/usr", "share", "coreos", "update.conf")
|
|
||||||
|
|
||||||
f, err := os.Open(etcUpdate)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
f, err = os.Open(usrUpdate)
|
|
||||||
}
|
|
||||||
return f, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// File generates an `/etc/coreos/update.conf` file (if any update
|
|
||||||
// configuration options are set in cloud-config) by either rewriting the
|
|
||||||
// existing file on disk, or starting from `/usr/share/coreos/update.conf`
|
|
||||||
func (uc Update) File() (*File, error) {
|
|
||||||
if config.IsZero(uc.Update) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
if err := config.AssertStructValid(uc.Update); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate the list of possible substitutions to be performed based on the options that are configured
|
|
||||||
subs := map[string]string{}
|
|
||||||
uct := reflect.TypeOf(uc.Update)
|
|
||||||
ucv := reflect.ValueOf(uc.Update)
|
|
||||||
for i := 0; i < uct.NumField(); i++ {
|
|
||||||
val := ucv.Field(i).String()
|
|
||||||
if val == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
env := uct.Field(i).Tag.Get("env")
|
|
||||||
subs[env] = fmt.Sprintf("%s=%s", env, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
conf, err := uc.ReadConfig()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
scanner := bufio.NewScanner(conf)
|
|
||||||
|
|
||||||
var out string
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
for env, value := range subs {
|
|
||||||
if strings.HasPrefix(line, env) {
|
|
||||||
line = value
|
|
||||||
delete(subs, env)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out += line
|
|
||||||
out += "\n"
|
|
||||||
if err := scanner.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, key := range sortedKeys(subs) {
|
|
||||||
out += subs[key]
|
|
||||||
out += "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
return &File{config.File{
|
|
||||||
Path: path.Join("etc", "coreos", "update.conf"),
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
Content: out,
|
|
||||||
}}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Units generates units for the cloud-init initializer to act on:
|
|
||||||
// - a locksmith Unit, if "reboot-strategy" was set in cloud-config
|
|
||||||
// - an update_engine Unit, if "group" or "server" was set in cloud-config
|
|
||||||
func (uc Update) Units() []Unit {
|
|
||||||
var units []Unit
|
|
||||||
if uc.Update.RebootStrategy != "" {
|
|
||||||
ls := &Unit{config.Unit{
|
|
||||||
Name: locksmithUnit,
|
|
||||||
Command: "restart",
|
|
||||||
Mask: false,
|
|
||||||
Runtime: true,
|
|
||||||
}}
|
|
||||||
|
|
||||||
if uc.Update.RebootStrategy == "off" {
|
|
||||||
ls.Command = "stop"
|
|
||||||
ls.Mask = true
|
|
||||||
}
|
|
||||||
units = append(units, *ls)
|
|
||||||
}
|
|
||||||
|
|
||||||
if uc.Update.Group != "" || uc.Update.Server != "" {
|
|
||||||
ue := Unit{config.Unit{
|
|
||||||
Name: updateEngineUnit,
|
|
||||||
Command: "restart",
|
|
||||||
}}
|
|
||||||
units = append(units, ue)
|
|
||||||
}
|
|
||||||
|
|
||||||
return units
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortedKeys(m map[string]string) (keys []string) {
|
|
||||||
for key := range m {
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
return
|
|
||||||
}
|
|
161
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/update_test.go
generated
vendored
161
Godeps/_workspace/src/github.com/coreos/coreos-cloudinit/system/update_test.go
generated
vendored
@ -1,161 +0,0 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package system
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func testReadConfig(config string) func() (io.Reader, error) {
|
|
||||||
return func() (io.Reader, error) {
|
|
||||||
return strings.NewReader(config), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateUnits(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
config config.Update
|
|
||||||
units []Unit
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
config: config.Update{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config: config.Update{Group: "master", Server: "http://foo.com"},
|
|
||||||
units: []Unit{{config.Unit{
|
|
||||||
Name: "update-engine.service",
|
|
||||||
Command: "restart",
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config: config.Update{RebootStrategy: "best-effort"},
|
|
||||||
units: []Unit{{config.Unit{
|
|
||||||
Name: "locksmithd.service",
|
|
||||||
Command: "restart",
|
|
||||||
Runtime: true,
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config: config.Update{RebootStrategy: "etcd-lock"},
|
|
||||||
units: []Unit{{config.Unit{
|
|
||||||
Name: "locksmithd.service",
|
|
||||||
Command: "restart",
|
|
||||||
Runtime: true,
|
|
||||||
}}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config: config.Update{RebootStrategy: "reboot"},
|
|
||||||
units: []Unit{{config.Unit{
|
|
||||||
Name: "locksmithd.service",
|
|
||||||
Command: "restart",
|
|
||||||
Runtime: 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()
|
|
||||||
if !reflect.DeepEqual(tt.units, units) {
|
|
||||||
t.Errorf("bad units (%q): want %#v, got %#v", tt.config, tt.units, units)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUpdateFile(t *testing.T) {
|
|
||||||
for _, tt := range []struct {
|
|
||||||
config config.Update
|
|
||||||
orig string
|
|
||||||
file *File
|
|
||||||
err error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
config: config.Update{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config: config.Update{RebootStrategy: "wizzlewazzle"},
|
|
||||||
err: &config.ErrorValid{Value: "wizzlewazzle", Field: "RebootStrategy", Valid: "^(best-effort|etcd-lock|reboot|off)$"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config: config.Update{Group: "master", Server: "http://foo.com"},
|
|
||||||
file: &File{config.File{
|
|
||||||
Content: "GROUP=master\nSERVER=http://foo.com\n",
|
|
||||||
Path: "etc/coreos/update.conf",
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config: config.Update{RebootStrategy: "best-effort"},
|
|
||||||
file: &File{config.File{
|
|
||||||
Content: "REBOOT_STRATEGY=best-effort\n",
|
|
||||||
Path: "etc/coreos/update.conf",
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config: config.Update{RebootStrategy: "etcd-lock"},
|
|
||||||
file: &File{config.File{
|
|
||||||
Content: "REBOOT_STRATEGY=etcd-lock\n",
|
|
||||||
Path: "etc/coreos/update.conf",
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config: config.Update{RebootStrategy: "reboot"},
|
|
||||||
file: &File{config.File{
|
|
||||||
Content: "REBOOT_STRATEGY=reboot\n",
|
|
||||||
Path: "etc/coreos/update.conf",
|
|
||||||
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"},
|
|
||||||
orig: "SERVER=https://example.com\nGROUP=thegroupc\nREBOOT_STRATEGY=awesome",
|
|
||||||
file: &File{config.File{
|
|
||||||
Content: "SERVER=https://example.com\nGROUP=thegroupc\nREBOOT_STRATEGY=etcd-lock\n",
|
|
||||||
Path: "etc/coreos/update.conf",
|
|
||||||
RawFilePermissions: "0644",
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
file, err := Update{Update: tt.config, ReadConfig: testReadConfig(tt.orig)}.File()
|
|
||||||
if !reflect.DeepEqual(tt.err, err) {
|
|
||||||
t.Errorf("bad error (%q): want %q, got %q", tt.config, tt.err, err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(tt.file, file) {
|
|
||||||
t.Errorf("bad units (%q): want %#v, got %#v", tt.config, tt.file, file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
17
cmd/cloudinit/authorizeSSHKeys.go
Normal file
17
cmd/cloudinit/authorizeSSHKeys.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package cloudinit
|
||||||
|
|
||||||
|
import(
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func authorizeSSHKeys(user string, authorizedKeys []string, name string) {
|
||||||
|
for _, authorizedKey := range authorizedKeys {
|
||||||
|
cmd := exec.Command("update-ssh-keys", user, authorizedKey)
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,3 @@
|
|||||||
// Copyright 2015 CoreOS, Inc.
|
|
||||||
// Copyright 2015 Rancher Labs, 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 cloudinit
|
package cloudinit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -20,7 +5,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -35,7 +22,6 @@ import (
|
|||||||
"github.com/coreos/coreos-cloudinit/datasource/proc_cmdline"
|
"github.com/coreos/coreos-cloudinit/datasource/proc_cmdline"
|
||||||
"github.com/coreos/coreos-cloudinit/datasource/url"
|
"github.com/coreos/coreos-cloudinit/datasource/url"
|
||||||
"github.com/coreos/coreos-cloudinit/initialize"
|
"github.com/coreos/coreos-cloudinit/initialize"
|
||||||
"github.com/coreos/coreos-cloudinit/network"
|
|
||||||
"github.com/coreos/coreos-cloudinit/pkg"
|
"github.com/coreos/coreos-cloudinit/pkg"
|
||||||
"github.com/coreos/coreos-cloudinit/system"
|
"github.com/coreos/coreos-cloudinit/system"
|
||||||
rancherConfig "github.com/rancherio/os/config"
|
rancherConfig "github.com/rancherio/os/config"
|
||||||
@ -97,6 +83,7 @@ func Main() {
|
|||||||
fail = true
|
fail = true
|
||||||
}
|
}
|
||||||
if fail {
|
if fail {
|
||||||
|
fmt.Println("failed validation")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -151,15 +138,41 @@ func Main() {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = initialize.Apply(cc, []network.InterfaceGenerator{}, env); err != nil {
|
if script != nil {
|
||||||
log.Fatalf("Failed to apply cloud-config: %v", err)
|
if ds.Type() != "local-file" {
|
||||||
|
fmt.Println("can only execute local files")
|
||||||
|
}
|
||||||
|
cmdPath := reflect.ValueOf(ds).Elem().Field(0).String()
|
||||||
|
cmd := exec.Command(cmdPath)
|
||||||
|
fmt.Println("running ", cmdPath)
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
fmt.Printf("Failed to run script: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if script != nil {
|
if &cc == nil {
|
||||||
if err = runScript(*script, env); err != nil {
|
log.Fatal("no config or script found")
|
||||||
log.Fatalf("Failed to run script: %v", err)
|
}
|
||||||
|
|
||||||
|
for _, user := range cc.Users {
|
||||||
|
if user.Name == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(user.SSHAuthorizedKeys) > 0 {
|
||||||
|
authorizeSSHKeys(user.Name, user.SSHAuthorizedKeys, env.SSHKeyName())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, file := range cc.WriteFiles {
|
||||||
|
f := system.File{File: file}
|
||||||
|
fullPath, err := system.WriteFile(&f, env.Root())
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
log.Printf("Wrote file %s to filesystem", fullPath)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mergeConfigs merges certain options from md (meta-data from the datasource)
|
// mergeConfigs merges certain options from md (meta-data from the datasource)
|
||||||
@ -271,18 +284,3 @@ func selectDatasource(sources []datasource.Datasource) datasource.Datasource {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jonboulle): this should probably be refactored and moved into a different module
|
|
||||||
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)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
path, err := initialize.PersistScriptInWorkspace(script, env.Workspace())
|
|
||||||
if err == nil {
|
|
||||||
var name string
|
|
||||||
name, err = system.ExecuteScript(path)
|
|
||||||
initialize.PersistUnitNameInWorkspace(name, env.Workspace())
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
@ -17,6 +17,9 @@ func NewConfig() *Config {
|
|||||||
Userdocker: UserDockerInfo{
|
Userdocker: UserDockerInfo{
|
||||||
UseTLS: true,
|
UseTLS: true,
|
||||||
},
|
},
|
||||||
|
CloudInit: CloudInit{
|
||||||
|
Datasources: []string{"file:/home/rancher/cloudconfig"},
|
||||||
|
},
|
||||||
SystemContainers: []ContainerConfig{
|
SystemContainers: []ContainerConfig{
|
||||||
{
|
{
|
||||||
Id: "system-volumes",
|
Id: "system-volumes",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
FROM base
|
FROM base
|
||||||
COPY scripts/dockerimages/scripts/console.sh /usr/sbin/
|
COPY scripts/dockerimages/scripts/console.sh /usr/sbin/
|
||||||
|
COPY scripts/dockerimages/scripts/update-ssh-keys /usr/bin/
|
||||||
RUN sed -i 's/rancher.*/rancher:rixbL64o6zGmY:16486:0:99999:7:::/g' /etc/shadow && \
|
RUN sed -i 's/rancher.*/rancher:rixbL64o6zGmY:16486:0:99999:7:::/g' /etc/shadow && \
|
||||||
echo '## allow password less for rancher user' >> /etc/sudoers && \
|
echo '## allow password less for rancher user' >> /etc/sudoers && \
|
||||||
echo 'rancher ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
|
echo 'rancher ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
|
||||||
|
@ -2,6 +2,4 @@
|
|||||||
|
|
||||||
set -x -e
|
set -x -e
|
||||||
|
|
||||||
CLOUD_CONFIG_FLAGS=$(rancherctl config get cloud_config)
|
cloud-init
|
||||||
|
|
||||||
cloud-init --preinit "$CLOUD_CONFIG_FLAGS"
|
|
||||||
|
13
scripts/dockerimages/scripts/update-ssh-keys
Executable file
13
scripts/dockerimages/scripts/update-ssh-keys
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
USERNAME=$1
|
||||||
|
HOME_DIR=$(grep ^$USERNAME /etc/passwd | cut -f6 -d:)
|
||||||
|
|
||||||
|
if [ ! -d $HOME_DIR/.ssh ]; then
|
||||||
|
mkdir -p $HOME_DIR/.ssh
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ ! grep -q $HOME_DIR/.ssh/authorized_keys ]; then
|
||||||
|
echo "$2" >> $HOME_DIR/.ssh/authorized_keys
|
||||||
|
fi
|
Loading…
Reference in New Issue
Block a user