system: clean up UnitManager interface
This commit is contained in:
parent
92c57423ba
commit
dcaabe4d4a
@ -195,66 +195,66 @@ func Apply(cfg config.CloudConfig, env *Environment) error {
|
|||||||
// commands against units. It returns any error encountered.
|
// commands against units. It returns any error encountered.
|
||||||
func processUnits(units []system.Unit, root string, um system.UnitManager) error {
|
func processUnits(units []system.Unit, root string, um system.UnitManager) error {
|
||||||
type action struct {
|
type action struct {
|
||||||
unit string
|
unit system.Unit
|
||||||
command string
|
command string
|
||||||
}
|
}
|
||||||
actions := make([]action, 0, len(units))
|
actions := make([]action, 0, len(units))
|
||||||
reload := false
|
reload := false
|
||||||
for _, unit := range units {
|
for _, unit := range units {
|
||||||
dst := unit.Destination(root)
|
|
||||||
if unit.Content != "" {
|
if unit.Content != "" {
|
||||||
log.Printf("Writing unit %s to filesystem at path %s", unit.Name, dst)
|
log.Printf("Writing unit %q to filesystem", unit.Name)
|
||||||
if err := um.PlaceUnit(&unit, dst); err != nil {
|
if err := um.PlaceUnit(unit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Printf("Placed unit %s at %s", unit.Name, dst)
|
log.Printf("Wrote unit %q", unit.Name)
|
||||||
reload = true
|
reload = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if unit.Mask {
|
if unit.Mask {
|
||||||
log.Printf("Masking unit file %s", unit.Name)
|
log.Printf("Masking unit file %q", unit.Name)
|
||||||
if err := um.MaskUnit(&unit); err != nil {
|
if err := um.MaskUnit(unit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if unit.Runtime {
|
} else if unit.Runtime {
|
||||||
log.Printf("Ensuring runtime unit file %s is unmasked", unit.Name)
|
log.Printf("Ensuring runtime unit file %q is unmasked", unit.Name)
|
||||||
if err := um.UnmaskUnit(&unit); err != nil {
|
if err := um.UnmaskUnit(unit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if unit.Enable {
|
if unit.Enable {
|
||||||
if unit.Group() != "network" {
|
if unit.Group() != "network" {
|
||||||
log.Printf("Enabling unit file %s", unit.Name)
|
log.Printf("Enabling unit file %q", unit.Name)
|
||||||
if err := um.EnableUnitFile(unit.Name, unit.Runtime); err != nil {
|
if err := um.EnableUnitFile(unit); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Printf("Enabled unit %s", unit.Name)
|
log.Printf("Enabled unit %q", unit.Name)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Skipping enable for network-like unit %s", unit.Name)
|
log.Printf("Skipping enable for network-like unit %q", unit.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if unit.Group() == "network" {
|
if unit.Group() == "network" {
|
||||||
actions = append(actions, action{"systemd-networkd.service", "restart"})
|
networkd := system.Unit{Unit: config.Unit{Name: "systemd-networkd.service"}}
|
||||||
|
actions = append(actions, action{networkd, "restart"})
|
||||||
} else if unit.Command != "" {
|
} else if unit.Command != "" {
|
||||||
actions = append(actions, action{unit.Name, unit.Command})
|
actions = append(actions, action{unit, unit.Command})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if reload {
|
if reload {
|
||||||
if err := um.DaemonReload(); err != nil {
|
if err := um.DaemonReload(); err != nil {
|
||||||
return errors.New(fmt.Sprintf("failed systemd daemon-reload: %v", err))
|
return errors.New(fmt.Sprintf("failed systemd daemon-reload: %s", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, action := range actions {
|
for _, action := range actions {
|
||||||
log.Printf("Calling unit command '%s %s'", action.command, action.unit)
|
log.Printf("Calling unit command %q on %q'", action.command, action.unit.Name)
|
||||||
res, err := um.RunUnitCommand(action.command, action.unit)
|
res, err := um.RunUnitCommand(action.unit, action.command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Printf("Result of '%s %s': %s", action.command, action.unit, res)
|
log.Printf("Result of %q on %q': %s", action.command, action.unit.Name, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -32,29 +32,29 @@ type TestUnitManager struct {
|
|||||||
reload bool
|
reload bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tum *TestUnitManager) PlaceUnit(unit *system.Unit, dst string) error {
|
func (tum *TestUnitManager) PlaceUnit(u system.Unit) error {
|
||||||
tum.placed = append(tum.placed, unit.Name)
|
tum.placed = append(tum.placed, u.Name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (tum *TestUnitManager) EnableUnitFile(unit string, runtime bool) error {
|
func (tum *TestUnitManager) EnableUnitFile(u system.Unit) error {
|
||||||
tum.enabled = append(tum.enabled, unit)
|
tum.enabled = append(tum.enabled, u.Name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (tum *TestUnitManager) RunUnitCommand(command, unit string) (string, error) {
|
func (tum *TestUnitManager) RunUnitCommand(u system.Unit, c string) (string, error) {
|
||||||
tum.commands = make(map[string]string)
|
tum.commands = make(map[string]string)
|
||||||
tum.commands[unit] = command
|
tum.commands[u.Name] = c
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
func (tum *TestUnitManager) DaemonReload() error {
|
func (tum *TestUnitManager) DaemonReload() error {
|
||||||
tum.reload = true
|
tum.reload = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (tum *TestUnitManager) MaskUnit(unit *system.Unit) error {
|
func (tum *TestUnitManager) MaskUnit(u system.Unit) error {
|
||||||
tum.masked = append(tum.masked, unit.Name)
|
tum.masked = append(tum.masked, u.Name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (tum *TestUnitManager) UnmaskUnit(unit *system.Unit) error {
|
func (tum *TestUnitManager) UnmaskUnit(u system.Unit) error {
|
||||||
tum.unmasked = append(tum.unmasked, unit.Name)
|
tum.unmasked = append(tum.unmasked, u.Name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ package system
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
@ -47,13 +48,14 @@ func (f *File) Permissions() (os.FileMode, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func WriteFile(f *File, root string) (string, error) {
|
func WriteFile(f *File, root string) (string, error) {
|
||||||
|
fullpath := path.Join(root, f.Path)
|
||||||
|
dir := path.Dir(fullpath)
|
||||||
|
log.Printf("Writing file to %q", fullpath)
|
||||||
|
|
||||||
if f.Encoding != "" {
|
if f.Encoding != "" {
|
||||||
return "", fmt.Errorf("Unable to write file with encoding %s", f.Encoding)
|
return "", fmt.Errorf("Unable to write file with encoding %s", f.Encoding)
|
||||||
}
|
}
|
||||||
|
|
||||||
fullpath := path.Join(root, f.Path)
|
|
||||||
dir := path.Dir(fullpath)
|
|
||||||
|
|
||||||
if err := EnsureDirectoryExists(dir); err != nil {
|
if err := EnsureDirectoryExists(dir); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -94,6 +96,7 @@ func WriteFile(f *File, root string) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("Wrote file to %q", fullpath)
|
||||||
return fullpath, nil
|
return fullpath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +96,8 @@ func maybeProbeBonding(interfaces []network.InterfaceGenerator) error {
|
|||||||
|
|
||||||
func restartNetworkd() error {
|
func restartNetworkd() error {
|
||||||
log.Printf("Restarting networkd.service\n")
|
log.Printf("Restarting networkd.service\n")
|
||||||
_, err := NewUnitManager("").RunUnitCommand("restart", "systemd-networkd.service")
|
networkd := Unit{config.Unit{Name: "systemd-networkd.service"}}
|
||||||
|
_, err := NewUnitManager("").RunUnitCommand(networkd, "restart")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/coreos/coreos-cloudinit/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus"
|
"github.com/coreos/coreos-cloudinit/Godeps/_workspace/src/github.com/coreos/go-systemd/dbus"
|
||||||
@ -42,49 +41,38 @@ type systemd struct {
|
|||||||
// never be used as a true MachineID
|
// never be used as a true MachineID
|
||||||
const fakeMachineID = "42000000000000000000000000000042"
|
const fakeMachineID = "42000000000000000000000000000042"
|
||||||
|
|
||||||
// PlaceUnit writes a unit file at the provided destination, creating
|
// PlaceUnit writes a unit file at its desired destination, creating parent
|
||||||
// parent directories as necessary.
|
// directories as necessary.
|
||||||
func (s *systemd) PlaceUnit(u *Unit, dst string) error {
|
func (s *systemd) PlaceUnit(u Unit) error {
|
||||||
dir := filepath.Dir(dst)
|
|
||||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
|
||||||
if err := os.MkdirAll(dir, os.FileMode(0755)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file := File{config.File{
|
file := File{config.File{
|
||||||
Path: filepath.Base(dst),
|
Path: u.Destination(s.root),
|
||||||
Content: u.Content,
|
Content: u.Content,
|
||||||
RawFilePermissions: "0644",
|
RawFilePermissions: "0644",
|
||||||
}}
|
}}
|
||||||
|
|
||||||
_, err := WriteFile(&file, dir)
|
_, err := WriteFile(&file, "/")
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *systemd) EnableUnitFile(unit string, runtime bool) error {
|
func (s *systemd) EnableUnitFile(u Unit) error {
|
||||||
conn, err := dbus.New()
|
conn, err := dbus.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
units := []string{unit}
|
units := []string{u.Name}
|
||||||
_, _, err = conn.EnableUnitFiles(units, runtime, true)
|
_, _, err = conn.EnableUnitFiles(units, u.Runtime, true)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *systemd) RunUnitCommand(command, unit string) (string, error) {
|
func (s *systemd) RunUnitCommand(u Unit, c string) (string, error) {
|
||||||
conn, err := dbus.New()
|
conn, err := dbus.New()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var fn func(string, string) (string, error)
|
var fn func(string, string) (string, error)
|
||||||
switch command {
|
switch c {
|
||||||
case "start":
|
case "start":
|
||||||
fn = conn.StartUnit
|
fn = conn.StartUnit
|
||||||
case "stop":
|
case "stop":
|
||||||
@ -100,10 +88,10 @@ func (s *systemd) RunUnitCommand(command, unit string) (string, error) {
|
|||||||
case "reload-or-try-restart":
|
case "reload-or-try-restart":
|
||||||
fn = conn.ReloadOrTryRestartUnit
|
fn = conn.ReloadOrTryRestartUnit
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("Unsupported systemd command %q", command)
|
return "", fmt.Errorf("Unsupported systemd command %q", c)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fn(unit, "replace")
|
return fn(u.Name, "replace")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *systemd) DaemonReload() error {
|
func (s *systemd) DaemonReload() error {
|
||||||
@ -119,8 +107,8 @@ func (s *systemd) DaemonReload() error {
|
|||||||
// /dev/null, analogous to `systemctl mask`.
|
// /dev/null, analogous to `systemctl mask`.
|
||||||
// N.B.: Unlike `systemctl mask`, this function will *remove any existing unit
|
// N.B.: Unlike `systemctl mask`, this function will *remove any existing unit
|
||||||
// file at the location*, to ensure that the mask will succeed.
|
// file at the location*, to ensure that the mask will succeed.
|
||||||
func (s *systemd) MaskUnit(unit *Unit) error {
|
func (s *systemd) MaskUnit(u Unit) error {
|
||||||
masked := unit.Destination(s.root)
|
masked := u.Destination(s.root)
|
||||||
if _, err := os.Stat(masked); os.IsNotExist(err) {
|
if _, err := os.Stat(masked); os.IsNotExist(err) {
|
||||||
if err := os.MkdirAll(path.Dir(masked), os.FileMode(0755)); err != nil {
|
if err := os.MkdirAll(path.Dir(masked), os.FileMode(0755)); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -134,8 +122,8 @@ func (s *systemd) MaskUnit(unit *Unit) error {
|
|||||||
// UnmaskUnit is analogous to systemd's unit_file_unmask. If the file
|
// 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
|
// associated with the given Unit is empty or appears to be a symlink to
|
||||||
// /dev/null, it is removed.
|
// /dev/null, it is removed.
|
||||||
func (s *systemd) UnmaskUnit(unit *Unit) error {
|
func (s *systemd) UnmaskUnit(u Unit) error {
|
||||||
masked := unit.Destination(s.root)
|
masked := u.Destination(s.root)
|
||||||
ne, err := nullOrEmpty(masked)
|
ne, err := nullOrEmpty(masked)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -51,7 +51,7 @@ Address=10.209.171.177/19
|
|||||||
t.Fatalf("unit.Destination returned %s, expected %s", dst, expectDst)
|
t.Fatalf("unit.Destination returned %s, expected %s", dst, expectDst)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sd.PlaceUnit(&u, dst); err != nil {
|
if err := sd.PlaceUnit(u); err != nil {
|
||||||
t.Fatalf("PlaceUnit failed: %v", err)
|
t.Fatalf("PlaceUnit failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ Where=/media/state
|
|||||||
t.Fatalf("unit.Destination returned %s, expected %s", dst, expectDst)
|
t.Fatalf("unit.Destination returned %s, expected %s", dst, expectDst)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sd.PlaceUnit(&u, dst); err != nil {
|
if err := sd.PlaceUnit(u); err != nil {
|
||||||
t.Fatalf("PlaceUnit failed: %v", err)
|
t.Fatalf("PlaceUnit failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ func TestMaskUnit(t *testing.T) {
|
|||||||
sd := &systemd{dir}
|
sd := &systemd{dir}
|
||||||
|
|
||||||
// Ensure mask works with units that do not currently exist
|
// Ensure mask works with units that do not currently exist
|
||||||
uf := &Unit{config.Unit{Name: "foo.service"}}
|
uf := Unit{config.Unit{Name: "foo.service"}}
|
||||||
if err := sd.MaskUnit(uf); err != nil {
|
if err := sd.MaskUnit(uf); err != nil {
|
||||||
t.Fatalf("Unable to mask new unit: %v", err)
|
t.Fatalf("Unable to mask new unit: %v", err)
|
||||||
}
|
}
|
||||||
@ -194,7 +194,7 @@ func TestMaskUnit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure mask works with unit files that already exist
|
// Ensure mask works with unit files that already exist
|
||||||
ub := &Unit{config.Unit{Name: "bar.service"}}
|
ub := Unit{config.Unit{Name: "bar.service"}}
|
||||||
barPath := path.Join(dir, "etc", "systemd", "system", "bar.service")
|
barPath := path.Join(dir, "etc", "systemd", "system", "bar.service")
|
||||||
if _, err := os.Create(barPath); err != nil {
|
if _, err := os.Create(barPath); err != nil {
|
||||||
t.Fatalf("Error creating new unit file: %v", err)
|
t.Fatalf("Error creating new unit file: %v", err)
|
||||||
@ -220,12 +220,12 @@ func TestUnmaskUnit(t *testing.T) {
|
|||||||
|
|
||||||
sd := &systemd{dir}
|
sd := &systemd{dir}
|
||||||
|
|
||||||
nilUnit := &Unit{config.Unit{Name: "null.service"}}
|
nilUnit := Unit{config.Unit{Name: "null.service"}}
|
||||||
if err := sd.UnmaskUnit(nilUnit); err != nil {
|
if err := sd.UnmaskUnit(nilUnit); err != nil {
|
||||||
t.Errorf("unexpected error from unmasking nonexistent unit: %v", err)
|
t.Errorf("unexpected error from unmasking nonexistent unit: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
uf := &Unit{config.Unit{Name: "foo.service", Content: "[Service]\nExecStart=/bin/true"}}
|
uf := Unit{config.Unit{Name: "foo.service", Content: "[Service]\nExecStart=/bin/true"}}
|
||||||
dst := uf.Destination(dir)
|
dst := uf.Destination(dir)
|
||||||
if err := os.MkdirAll(path.Dir(dst), os.FileMode(0755)); err != nil {
|
if err := os.MkdirAll(path.Dir(dst), os.FileMode(0755)); err != nil {
|
||||||
t.Fatalf("Unable to create unit directory: %v", err)
|
t.Fatalf("Unable to create unit directory: %v", err)
|
||||||
@ -245,7 +245,7 @@ func TestUnmaskUnit(t *testing.T) {
|
|||||||
t.Errorf("unmask of non-empty unit mutated unit contents unexpectedly")
|
t.Errorf("unmask of non-empty unit mutated unit contents unexpectedly")
|
||||||
}
|
}
|
||||||
|
|
||||||
ub := &Unit{config.Unit{Name: "bar.service"}}
|
ub := Unit{config.Unit{Name: "bar.service"}}
|
||||||
dst = ub.Destination(dir)
|
dst = ub.Destination(dir)
|
||||||
if err := os.Symlink("/dev/null", dst); err != nil {
|
if err := os.Symlink("/dev/null", dst); err != nil {
|
||||||
t.Fatalf("Unable to create masked unit: %v", err)
|
t.Fatalf("Unable to create masked unit: %v", err)
|
||||||
|
@ -27,12 +27,12 @@ import (
|
|||||||
const cloudConfigDropIn = "20-cloudinit.conf"
|
const cloudConfigDropIn = "20-cloudinit.conf"
|
||||||
|
|
||||||
type UnitManager interface {
|
type UnitManager interface {
|
||||||
PlaceUnit(unit *Unit, dst string) error
|
PlaceUnit(unit Unit) error
|
||||||
EnableUnitFile(unit string, runtime bool) error
|
EnableUnitFile(unit Unit) error
|
||||||
RunUnitCommand(command, unit string) (string, error)
|
RunUnitCommand(unit Unit, command string) (string, error)
|
||||||
|
MaskUnit(unit Unit) error
|
||||||
|
UnmaskUnit(unit Unit) error
|
||||||
DaemonReload() error
|
DaemonReload() error
|
||||||
MaskUnit(unit *Unit) error
|
|
||||||
UnmaskUnit(unit *Unit) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unit is a top-level structure which embeds its underlying configuration,
|
// Unit is a top-level structure which embeds its underlying configuration,
|
||||||
@ -41,10 +41,10 @@ type Unit struct {
|
|||||||
config.Unit
|
config.Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destination builds the appropriate absolute file path for
|
// Destination builds the appropriate absolute file path for the Unit. The root
|
||||||
// the Unit. The root argument indicates the effective base
|
// argument indicates the effective base directory of the system (similar to a
|
||||||
// directory of the system (similar to a chroot).
|
// chroot).
|
||||||
func (u *Unit) Destination(root string) string {
|
func (u Unit) Destination(root string) string {
|
||||||
dir := "etc"
|
dir := "etc"
|
||||||
if u.Runtime {
|
if u.Runtime {
|
||||||
dir = "run"
|
dir = "run"
|
||||||
|
Loading…
Reference in New Issue
Block a user