Revert "Merge pull request #234 from crawford/validate"
This reverts commitcdfc94f4e9
, reversing changes made to2051cd3e1c
. Conflicts: initialize/config.go system/etcd.go system/etcd_test.go system/fleet.go system/fleet_test.go system/update.go system/update_test.go test
This commit is contained in:
@@ -1,26 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// dropinContents generates the contents for a drop-in unit given the config.
|
||||
// The argument must be a struct from the 'config' package.
|
||||
func dropinContents(e interface{}) string {
|
||||
et := reflect.TypeOf(e)
|
||||
ev := reflect.ValueOf(e)
|
||||
|
||||
var out string
|
||||
for i := 0; i < et.NumField(); i++ {
|
||||
if val := ev.Field(i).String(); val != "" {
|
||||
key := et.Field(i).Tag.Get("env")
|
||||
out += fmt.Sprintf("Environment=\"%s=%s\"\n", key, val)
|
||||
}
|
||||
}
|
||||
|
||||
if out == "" {
|
||||
return ""
|
||||
}
|
||||
return "[Service]\n" + out
|
||||
}
|
@@ -7,8 +7,6 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/coreos-cloudinit/config"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -50,9 +48,9 @@ func TestWriteEnvFileUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
ef := EnvFile{
|
||||
File: &File{config.File{
|
||||
File: &File{
|
||||
Path: name,
|
||||
}},
|
||||
},
|
||||
Vars: valueUpdate,
|
||||
}
|
||||
|
||||
@@ -97,9 +95,9 @@ func TestWriteEnvFileUpdateNoNewline(t *testing.T) {
|
||||
}
|
||||
|
||||
ef := EnvFile{
|
||||
File: &File{config.File{
|
||||
File: &File{
|
||||
Path: name,
|
||||
}},
|
||||
},
|
||||
Vars: valueUpdate,
|
||||
}
|
||||
|
||||
@@ -138,9 +136,9 @@ func TestWriteEnvFileCreate(t *testing.T) {
|
||||
fullPath := path.Join(dir, name)
|
||||
|
||||
ef := EnvFile{
|
||||
File: &File{config.File{
|
||||
File: &File{
|
||||
Path: name,
|
||||
}},
|
||||
},
|
||||
Vars: valueUpdate,
|
||||
}
|
||||
|
||||
@@ -176,9 +174,9 @@ func TestWriteEnvFileNoop(t *testing.T) {
|
||||
}
|
||||
|
||||
ef := EnvFile{
|
||||
File: &File{config.File{
|
||||
File: &File{
|
||||
Path: name,
|
||||
}},
|
||||
},
|
||||
Vars: valueNoop,
|
||||
}
|
||||
|
||||
@@ -223,9 +221,9 @@ func TestWriteEnvFileUpdateDos(t *testing.T) {
|
||||
}
|
||||
|
||||
ef := EnvFile{
|
||||
File: &File{config.File{
|
||||
File: &File{
|
||||
Path: name,
|
||||
}},
|
||||
},
|
||||
Vars: valueUpdate,
|
||||
}
|
||||
|
||||
@@ -272,9 +270,9 @@ func TestWriteEnvFileDos2Unix(t *testing.T) {
|
||||
}
|
||||
|
||||
ef := EnvFile{
|
||||
File: &File{config.File{
|
||||
File: &File{
|
||||
Path: name,
|
||||
}},
|
||||
},
|
||||
Vars: valueNoop,
|
||||
}
|
||||
|
||||
@@ -320,9 +318,9 @@ func TestWriteEnvFileEmpty(t *testing.T) {
|
||||
}
|
||||
|
||||
ef := EnvFile{
|
||||
File: &File{config.File{
|
||||
File: &File{
|
||||
Path: name,
|
||||
}},
|
||||
},
|
||||
Vars: valueEmpty,
|
||||
}
|
||||
|
||||
@@ -362,9 +360,9 @@ func TestWriteEnvFileEmptyNoCreate(t *testing.T) {
|
||||
fullPath := path.Join(dir, name)
|
||||
|
||||
ef := EnvFile{
|
||||
File: &File{config.File{
|
||||
File: &File{
|
||||
Path: name,
|
||||
}},
|
||||
},
|
||||
Vars: valueEmpty,
|
||||
}
|
||||
|
||||
@@ -393,9 +391,9 @@ func TestWriteEnvFilePermFailure(t *testing.T) {
|
||||
ioutil.WriteFile(fullPath, []byte(base), 0000)
|
||||
|
||||
ef := EnvFile{
|
||||
File: &File{config.File{
|
||||
File: &File{
|
||||
Path: name,
|
||||
}},
|
||||
},
|
||||
Vars: valueUpdate,
|
||||
}
|
||||
|
||||
@@ -415,9 +413,9 @@ func TestWriteEnvFileNameFailure(t *testing.T) {
|
||||
name := "foo.conf"
|
||||
|
||||
ef := EnvFile{
|
||||
File: &File{config.File{
|
||||
File: &File{
|
||||
Path: name,
|
||||
}},
|
||||
},
|
||||
Vars: valueInvalid,
|
||||
}
|
||||
|
||||
|
@@ -1,48 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/coreos/coreos-cloudinit/config"
|
||||
)
|
||||
|
||||
const DefaultIpv4Address = "127.0.0.1"
|
||||
|
||||
type EtcHosts struct {
|
||||
Config config.EtcHosts
|
||||
}
|
||||
|
||||
func (eh EtcHosts) generateEtcHosts() (out string, err error) {
|
||||
if eh.Config != "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.Config == "" {
|
||||
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
|
||||
}
|
@@ -1,46 +0,0 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
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 {
|
||||
content := dropinContents(ee.Etcd)
|
||||
if content == "" {
|
||||
return nil
|
||||
}
|
||||
return []Unit{{config.Unit{
|
||||
Name: "etcd.service",
|
||||
Runtime: true,
|
||||
DropIn: true,
|
||||
Content: content,
|
||||
}}}
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
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{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
config.Etcd{
|
||||
Discovery: "http://disco.example.com/foobar",
|
||||
PeerBindAddr: "127.0.0.1:7002",
|
||||
},
|
||||
[]Unit{{config.Unit{
|
||||
Name: "etcd.service",
|
||||
Runtime: true,
|
||||
DropIn: true,
|
||||
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,
|
||||
DropIn: true,
|
||||
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 (%q): want %#v, got %#v", tt.config, tt.units, units)
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,14 +8,14 @@ import (
|
||||
"os/exec"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/coreos/coreos-cloudinit/config"
|
||||
)
|
||||
|
||||
// File is a top-level structure which embeds its underlying configuration,
|
||||
// config.File, and provides the system-specific Permissions().
|
||||
type File struct {
|
||||
config.File
|
||||
Encoding string
|
||||
Content string
|
||||
Owner string
|
||||
Path string
|
||||
RawFilePermissions string `yaml:"permissions"`
|
||||
}
|
||||
|
||||
func (f *File) Permissions() (os.FileMode, error) {
|
||||
|
@@ -5,8 +5,6 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/coreos-cloudinit/config"
|
||||
)
|
||||
|
||||
func TestWriteFileUnencodedContent(t *testing.T) {
|
||||
@@ -19,11 +17,11 @@ func TestWriteFileUnencodedContent(t *testing.T) {
|
||||
fn := "foo"
|
||||
fullPath := path.Join(dir, fn)
|
||||
|
||||
wf := File{config.File{
|
||||
wf := File{
|
||||
Path: fn,
|
||||
Content: "bar",
|
||||
RawFilePermissions: "0644",
|
||||
}}
|
||||
}
|
||||
|
||||
path, err := WriteFile(&wf, dir)
|
||||
if err != nil {
|
||||
@@ -58,11 +56,11 @@ func TestWriteFileInvalidPermission(t *testing.T) {
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
wf := File{config.File{
|
||||
wf := File{
|
||||
Path: path.Join(dir, "tmp", "foo"),
|
||||
Content: "bar",
|
||||
RawFilePermissions: "pants",
|
||||
}}
|
||||
}
|
||||
|
||||
if _, err := WriteFile(&wf, dir); err == nil {
|
||||
t.Fatalf("Expected error to be raised when writing file with invalid permission")
|
||||
@@ -79,10 +77,10 @@ func TestWriteFilePermissions(t *testing.T) {
|
||||
fn := "foo"
|
||||
fullPath := path.Join(dir, fn)
|
||||
|
||||
wf := File{config.File{
|
||||
wf := File{
|
||||
Path: fn,
|
||||
RawFilePermissions: "0755",
|
||||
}}
|
||||
}
|
||||
|
||||
path, err := WriteFile(&wf, dir)
|
||||
if err != nil {
|
||||
@@ -108,11 +106,11 @@ func TestWriteFileEncodedContent(t *testing.T) {
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
wf := File{config.File{
|
||||
wf := File{
|
||||
Path: path.Join(dir, "tmp", "foo"),
|
||||
Content: "",
|
||||
Encoding: "base64",
|
||||
}}
|
||||
}
|
||||
|
||||
if _, err := WriteFile(&wf, dir); err == nil {
|
||||
t.Fatalf("Expected error to be raised when writing file with encoding")
|
||||
|
@@ -1,26 +0,0 @@
|
||||
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 {
|
||||
content := dropinContents(fe.Fleet)
|
||||
if content == "" {
|
||||
return nil
|
||||
}
|
||||
return []Unit{{config.Unit{
|
||||
Name: "fleet.service",
|
||||
Runtime: true,
|
||||
DropIn: true,
|
||||
Content: content,
|
||||
}}}
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
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{},
|
||||
nil,
|
||||
},
|
||||
{
|
||||
config.Fleet{
|
||||
PublicIP: "12.34.56.78",
|
||||
},
|
||||
[]Unit{{config.Unit{
|
||||
Name: "fleet.service",
|
||||
Content: `[Service]
|
||||
Environment="FLEET_PUBLIC_IP=12.34.56.78"
|
||||
`,
|
||||
Runtime: true,
|
||||
DropIn: true,
|
||||
}}},
|
||||
},
|
||||
} {
|
||||
units := Fleet{tt.config}.Units()
|
||||
if !reflect.DeepEqual(units, tt.units) {
|
||||
t.Errorf("bad units (%q): want %q, got %q", tt.config, tt.units, units)
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,7 +8,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/coreos-cloudinit/config"
|
||||
"github.com/coreos/coreos-cloudinit/network"
|
||||
"github.com/coreos/coreos-cloudinit/third_party/github.com/dotcloud/docker/pkg/netlink"
|
||||
)
|
||||
@@ -109,11 +108,11 @@ func WriteNetworkdConfigs(interfaces []network.InterfaceGenerator) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeConfig(filename string, content string) error {
|
||||
if content == "" {
|
||||
func writeConfig(filename string, config string) error {
|
||||
if config == "" {
|
||||
return nil
|
||||
}
|
||||
log.Printf("Writing networkd unit %q\n", filename)
|
||||
_, err := WriteFile(&File{config.File{Content: content, Path: filename}}, runtimeNetworkPath)
|
||||
_, err := WriteFile(&File{Content: config, Path: filename}, runtimeNetworkPath)
|
||||
return err
|
||||
}
|
||||
|
@@ -1,32 +0,0 @@
|
||||
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
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
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 %q, 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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,7 +10,6 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/coreos-cloudinit/config"
|
||||
"github.com/coreos/coreos-cloudinit/third_party/github.com/coreos/go-systemd/dbus"
|
||||
)
|
||||
|
||||
@@ -36,11 +35,11 @@ func (s *systemd) PlaceUnit(u *Unit, dst string) error {
|
||||
}
|
||||
}
|
||||
|
||||
file := File{config.File{
|
||||
file := File{
|
||||
Path: filepath.Base(dst),
|
||||
Content: u.Content,
|
||||
RawFilePermissions: "0644",
|
||||
}}
|
||||
}
|
||||
|
||||
_, err := WriteFile(&file, dir)
|
||||
if err != nil {
|
||||
|
@@ -5,12 +5,10 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/coreos-cloudinit/config"
|
||||
)
|
||||
|
||||
func TestPlaceNetworkUnit(t *testing.T) {
|
||||
u := Unit{config.Unit{
|
||||
u := Unit{
|
||||
Name: "50-eth0.network",
|
||||
Runtime: true,
|
||||
Content: `[Match]
|
||||
@@ -19,7 +17,7 @@ Name=eth47
|
||||
[Network]
|
||||
Address=10.209.171.177/19
|
||||
`,
|
||||
}}
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
||||
if err != nil {
|
||||
@@ -68,10 +66,10 @@ func TestUnitDestination(t *testing.T) {
|
||||
dir := "/some/dir"
|
||||
name := "foobar.service"
|
||||
|
||||
u := Unit{config.Unit{
|
||||
u := Unit{
|
||||
Name: name,
|
||||
DropIn: false,
|
||||
}}
|
||||
}
|
||||
|
||||
dst := u.Destination(dir)
|
||||
expectDst := path.Join(dir, "etc", "systemd", "system", "foobar.service")
|
||||
@@ -89,14 +87,14 @@ func TestUnitDestination(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPlaceMountUnit(t *testing.T) {
|
||||
u := Unit{config.Unit{
|
||||
u := Unit{
|
||||
Name: "media-state.mount",
|
||||
Runtime: false,
|
||||
Content: `[Mount]
|
||||
What=/dev/sdb1
|
||||
Where=/media/state
|
||||
`,
|
||||
}}
|
||||
}
|
||||
|
||||
dir, err := ioutil.TempDir(os.TempDir(), "coreos-cloudinit-")
|
||||
if err != nil {
|
||||
@@ -164,7 +162,7 @@ func TestMaskUnit(t *testing.T) {
|
||||
sd := &systemd{dir}
|
||||
|
||||
// Ensure mask works with units that do not currently exist
|
||||
uf := &Unit{config.Unit{Name: "foo.service"}}
|
||||
uf := &Unit{Name: "foo.service"}
|
||||
if err := sd.MaskUnit(uf); err != nil {
|
||||
t.Fatalf("Unable to mask new unit: %v", err)
|
||||
}
|
||||
@@ -178,7 +176,7 @@ func TestMaskUnit(t *testing.T) {
|
||||
}
|
||||
|
||||
// Ensure mask works with unit files that already exist
|
||||
ub := &Unit{config.Unit{Name: "bar.service"}}
|
||||
ub := &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)
|
||||
@@ -204,12 +202,12 @@ func TestUnmaskUnit(t *testing.T) {
|
||||
|
||||
sd := &systemd{dir}
|
||||
|
||||
nilUnit := &Unit{config.Unit{Name: "null.service"}}
|
||||
nilUnit := &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"}}
|
||||
uf := &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)
|
||||
@@ -229,7 +227,7 @@ func TestUnmaskUnit(t *testing.T) {
|
||||
t.Errorf("unmask of non-empty unit mutated unit contents unexpectedly")
|
||||
}
|
||||
|
||||
ub := &Unit{config.Unit{Name: "bar.service"}}
|
||||
ub := &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)
|
||||
|
@@ -3,8 +3,8 @@ package system
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/coreos/coreos-cloudinit/config"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Name for drop-in service configuration files created by cloudconfig
|
||||
@@ -19,10 +19,33 @@ type UnitManager interface {
|
||||
UnmaskUnit(unit *Unit) error
|
||||
}
|
||||
|
||||
// Unit is a top-level structure which embeds its underlying configuration,
|
||||
// config.Unit, and provides the system-specific Destination().
|
||||
type Unit struct {
|
||||
config.Unit
|
||||
Name string
|
||||
Mask bool
|
||||
Enable bool
|
||||
Runtime bool
|
||||
Content string
|
||||
Command string
|
||||
|
||||
// For drop-in units, a cloudinit.conf is generated.
|
||||
// This is currently unbound in YAML (and hence unsettable in cloud-config files)
|
||||
// until the correct behaviour for multiple drop-in units is determined.
|
||||
DropIn bool `yaml:"-"`
|
||||
}
|
||||
|
||||
func (u *Unit) Type() string {
|
||||
ext := filepath.Ext(u.Name)
|
||||
return strings.TrimLeft(ext, ".")
|
||||
}
|
||||
|
||||
func (u *Unit) Group() (group string) {
|
||||
t := u.Type()
|
||||
if t == "network" || t == "netdev" || t == "link" {
|
||||
group = "network"
|
||||
} else {
|
||||
group = "system"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Script []byte
|
||||
|
137
system/update.go
137
system/update.go
@@ -1,137 +0,0 @@
|
||||
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 {
|
||||
Config config.Update
|
||||
ReadConfig func() (io.Reader, error)
|
||||
}
|
||||
|
||||
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.Config) {
|
||||
return nil, nil
|
||||
}
|
||||
if err := config.AssertValid(uc.Config); 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.Config)
|
||||
ucv := reflect.ValueOf(uc.Config)
|
||||
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.Config.RebootStrategy != "" {
|
||||
ls := &Unit{config.Unit{
|
||||
Name: locksmithUnit,
|
||||
Command: "restart",
|
||||
Mask: false,
|
||||
Runtime: true,
|
||||
}}
|
||||
|
||||
if uc.Config.RebootStrategy == "off" {
|
||||
ls.Command = "stop"
|
||||
ls.Mask = true
|
||||
}
|
||||
units = append(units, *ls)
|
||||
}
|
||||
|
||||
if uc.Config.Group != "" || uc.Config.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
|
||||
}
|
@@ -1,148 +0,0 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"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{tt.config, 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: errors.New("invalid value \"wizzlewazzle\" for option \"RebootStrategy\" (valid options: \"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{tt.config, 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)
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,16 +6,30 @@ import (
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"strings"
|
||||
|
||||
"github.com/coreos/coreos-cloudinit/config"
|
||||
)
|
||||
|
||||
func UserExists(u *config.User) bool {
|
||||
type User struct {
|
||||
Name string `yaml:"name"`
|
||||
PasswordHash string `yaml:"passwd"`
|
||||
SSHAuthorizedKeys []string `yaml:"ssh-authorized-keys"`
|
||||
SSHImportGithubUser string `yaml:"coreos-ssh-import-github"`
|
||||
SSHImportURL string `yaml:"coreos-ssh-import-url"`
|
||||
GECOS string `yaml:"gecos"`
|
||||
Homedir string `yaml:"homedir"`
|
||||
NoCreateHome bool `yaml:"no-create-home"`
|
||||
PrimaryGroup string `yaml:"primary-group"`
|
||||
Groups []string `yaml:"groups"`
|
||||
NoUserGroup bool `yaml:"no-user-group"`
|
||||
System bool `yaml:"system"`
|
||||
NoLogInit bool `yaml:"no-log-init"`
|
||||
}
|
||||
|
||||
func UserExists(u *User) bool {
|
||||
_, err := user.Lookup(u.Name)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func CreateUser(u *config.User) error {
|
||||
func CreateUser(u *User) error {
|
||||
args := []string{}
|
||||
|
||||
if u.PasswordHash != "" {
|
||||
|
Reference in New Issue
Block a user