merged lp:snappy

This commit is contained in:
Michael Vogt
2015-02-26 17:23:41 +01:00
2 changed files with 225 additions and 6 deletions
+87 -2
View File
@@ -1,10 +1,13 @@
package coreconfig
import (
"errors"
"io/ioutil"
"os"
"os/exec"
"reflect"
"strings"
"syscall"
"gopkg.in/yaml.v2"
)
@@ -14,8 +17,19 @@ const (
tzPathDefault string = "/etc/timezone"
)
const (
autopilotTimer string = "snappy-autopilot.timer"
autopilotTimerEnabled string = "enabled"
autopilotTimerDisabled string = "disabled"
)
// ErrInvalidUnitStatus signals that a unit is not returning a status
// of "enabled" or "disabled".
var ErrInvalidUnitStatus = errors.New("invalid unit status")
type systemConfig struct {
Timezone string `yaml:"timezone"`
Autopilot bool `yaml:"autopilot"`
Timezone string `yaml:"timezone"`
}
type coreConfig struct {
@@ -33,8 +47,13 @@ func newSystemConfig() (*systemConfig, error) {
return nil, err
}
autopilot, err := getAutopilot()
if err != nil {
return nil, err
}
config := &systemConfig{
Timezone: tz,
Autopilot: autopilot,
Timezone: tz,
}
return config, nil
@@ -89,6 +108,14 @@ func Set(rawConfig string) (newRawConfig string, err error) {
if err := setTimezone(newConfig.Timezone); err != nil {
return "", err
}
case "Autopilot":
if oldConfig.Autopilot == newConfig.Autopilot {
continue
}
if err := setAutopilot(newConfig.Autopilot); err != nil {
return "", err
}
}
}
@@ -121,3 +148,61 @@ var getTimezone = func() (timezone string, err error) {
var setTimezone = func(timezone string) error {
return ioutil.WriteFile(tzFile(), []byte(timezone), 0644)
}
// for testing purposes
var (
cmdAutopilotEnabled = []string{"is-enabled", autopilotTimer}
cmdSystemctl = "systemctl"
)
// getAutopilot returns the autopilot state
var getAutopilot = func() (state bool, err error) {
out, err := exec.Command(cmdSystemctl, cmdAutopilotEnabled...).Output()
if exitErr, ok := err.(*exec.ExitError); ok {
waitStatus := exitErr.Sys().(syscall.WaitStatus)
// when a service is disabled the exit status is 1
if e := waitStatus.ExitStatus(); e != 1 {
return false, err
}
}
status := strings.TrimSpace(string(out))
if status == autopilotTimerEnabled {
return true, nil
} else if status == autopilotTimerDisabled {
return false, nil
} else {
return false, ErrInvalidUnitStatus
}
}
// for testing purposes
var (
cmdEnableAutopilot = []string{"enable", autopilotTimer}
cmdStartAutopilot = []string{"start", autopilotTimer}
cmdDisableAutopilot = []string{"disable", autopilotTimer}
cmdStopAutopilot = []string{"stop", autopilotTimer}
)
// setAutopilot enables and starts, or stops and disables autopilot
var setAutopilot = func(stateEnabled bool) error {
if stateEnabled {
if err := exec.Command(cmdSystemctl, cmdEnableAutopilot...).Run(); err != nil {
return err
}
if err := exec.Command(cmdSystemctl, cmdStartAutopilot...).Run(); err != nil {
return err
}
} else {
if err := exec.Command(cmdSystemctl, cmdStopAutopilot...).Run(); err != nil {
return err
}
if err := exec.Command(cmdSystemctl, cmdDisableAutopilot...).Run(); err != nil {
return err
}
}
return nil
}
+138 -4
View File
@@ -13,9 +13,19 @@ import (
// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) { TestingT(t) }
var originalGetTimezone = getTimezone
var originalSetTimezone = setTimezone
var originalYamlMarshal = yamlMarshal
var (
originalGetTimezone = getTimezone
originalSetTimezone = setTimezone
originalGetAutopilot = getAutopilot
originalSetAutopilot = setAutopilot
originalYamlMarshal = yamlMarshal
originalCmdEnableAutopilot = cmdEnableAutopilot
originalCmdDisableAutopilot = cmdDisableAutopilot
originalCmdStartAutopilot = cmdStartAutopilot
originalCmdStopAutopilot = cmdStopAutopilot
originalCmdAutopilotEnabled = cmdAutopilotEnabled
originalCmdSystemctl = cmdSystemctl
)
type ConfigTestSuite struct {
tempdir string
@@ -29,19 +39,34 @@ func (cts *ConfigTestSuite) SetUpTest(c *C) {
err := ioutil.WriteFile(tzPath, []byte("America/Argentina/Cordoba"), 0644)
c.Assert(err, IsNil)
os.Setenv(tzPathEnvironment, tzPath)
cmdSystemctl = "/bin/sh"
cmdAutopilotEnabled = []string{"-c", "echo disabled"}
cmdEnableAutopilot = []string{"-c", "/bin/true"}
cmdStartAutopilot = []string{"-c", "/bin/true"}
}
func (cts *ConfigTestSuite) TearDownTest(c *C) {
getTimezone = originalGetTimezone
setTimezone = originalSetTimezone
getAutopilot = originalGetAutopilot
setAutopilot = originalSetAutopilot
yamlMarshal = originalYamlMarshal
cmdEnableAutopilot = originalCmdEnableAutopilot
cmdDisableAutopilot = originalCmdDisableAutopilot
cmdStartAutopilot = originalCmdStartAutopilot
cmdStopAutopilot = originalCmdStopAutopilot
cmdAutopilotEnabled = originalCmdAutopilotEnabled
cmdSystemctl = originalCmdSystemctl
}
// TestGet is a broad test, close enough to be an integration test.
// TestGet is a broad test, close enough to be an integration test for
// the defaults
func (cts *ConfigTestSuite) TestGet(c *C) {
// TODO figure out if we care about exact output or just want valid yaml.
expectedOutput := `config:
ubuntu-core:
autopilot: false
timezone: America/Argentina/Cordoba
`
@@ -55,9 +80,43 @@ func (cts *ConfigTestSuite) TestSet(c *C) {
// TODO figure out if we care about exact output or just want valid yaml.
expected := `config:
ubuntu-core:
autopilot: true
timezone: America/Argentina/Mendoza
`
cmdAutopilotEnabled = []string{"-c", "echo enabled"}
rawConfig, err := Set(expected)
c.Assert(err, IsNil)
c.Assert(rawConfig, Equals, expected)
}
// TestSetTimezone is a broad test, close enough to be an integration test.
func (cts *ConfigTestSuite) TestSetTimezone(c *C) {
// TODO figure out if we care about exact output or just want valid yaml.
expected := `config:
ubuntu-core:
autopilot: false
timezone: America/Argentina/Mendoza
`
rawConfig, err := Set(expected)
c.Assert(err, IsNil)
c.Assert(rawConfig, Equals, expected)
}
// TestSetAutopilot is a broad test, close enough to be an integration test.
func (cts *ConfigTestSuite) TestSetAutopilot(c *C) {
// TODO figure out if we care about exact output or just want valid yaml.
expected := `config:
ubuntu-core:
autopilot: true
timezone: America/Argentina/Cordoba
`
enabled := false
getAutopilot = func() (bool, error) { return enabled, nil }
setAutopilot = func(state bool) error { enabled = state; return nil }
rawConfig, err := Set(expected)
c.Assert(err, IsNil)
c.Assert(rawConfig, Equals, expected)
@@ -66,6 +125,7 @@ func (cts *ConfigTestSuite) TestSet(c *C) {
func (cts *ConfigTestSuite) TestSetInvalid(c *C) {
input := `config:
ubuntu-core:
autopilot: false
timezone America/Argentina/Mendoza
`
@@ -77,6 +137,7 @@ func (cts *ConfigTestSuite) TestSetInvalid(c *C) {
func (cts *ConfigTestSuite) TestNoChangeSet(c *C) {
input := `config:
ubuntu-core:
autopilot: false
timezone: America/Argentina/Cordoba
`
@@ -112,6 +173,7 @@ func (cts *ConfigTestSuite) TestErrorOnTzSet(c *C) {
input := `config:
ubuntu-core:
autopilot: false
timezone: America/Argentina/Mendoza
`
@@ -120,6 +182,30 @@ func (cts *ConfigTestSuite) TestErrorOnTzSet(c *C) {
c.Assert(rawConfig, Equals, "")
}
func (cts *ConfigTestSuite) TestBadAutopilotOnGet(c *C) {
getAutopilot = func() (bool, error) { return false, errors.New("Bad mock autopilot") }
rawConfig, err := Get()
c.Assert(err, NotNil)
c.Assert(rawConfig, Equals, "")
}
func (cts *ConfigTestSuite) TestErrorOnAutopilotSet(c *C) {
input := `config:
ubuntu-core:
autopilot: true
timezone: America/Argentina/Mendoza
`
enabled := false
getAutopilot = func() (bool, error) { return enabled, nil }
setAutopilot = func(state bool) error { enabled = state; return errors.New("setAutopilot error") }
rawConfig, err := Set(input)
c.Assert(err, NotNil)
c.Assert(rawConfig, Equals, "")
}
func (cts *ConfigTestSuite) TestErrorOnUnmarshal(c *C) {
yamlMarshal = func(interface{}) ([]byte, error) { return []byte{}, errors.New("Mock unmarhal error") }
@@ -137,3 +223,51 @@ func (cts *ConfigTestSuite) TestInvalidTzFile(c *C) {
c.Assert(err, NotNil)
c.Assert(tz, Equals, "")
}
func (cts *ConfigTestSuite) TestInvalidAutopilotUnitStatus(c *C) {
cmdAutopilotEnabled = []string{"-c", "echo unkown"}
autopilot, err := getAutopilot()
c.Assert(err, NotNil)
c.Assert(autopilot, Equals, false)
}
func (cts *ConfigTestSuite) TestInvalidAutopilotExitStatus(c *C) {
cmdAutopilotEnabled = []string{"-c", "exit 2"}
autopilot, err := getAutopilot()
c.Assert(err, NotNil)
c.Assert(autopilot, Equals, false)
}
func (cts *ConfigTestSuite) TestInvalidGetAutopilotCommand(c *C) {
cmdSystemctl = "/bin/sh"
cmdAutopilotEnabled = []string{"-c", "/bin/false"}
autopilot, err := getAutopilot()
c.Assert(err, NotNil)
c.Assert(autopilot, Equals, false)
}
func (cts *ConfigTestSuite) TestSetAutopilots(c *C) {
cmdSystemctl = "/bin/sh"
// no errors
c.Assert(setAutopilot(true), IsNil)
// enable cases
cmdEnableAutopilot = []string{"-c", "/bin/true"}
cmdStartAutopilot = []string{"-c", "/bin/false"}
c.Assert(setAutopilot(true), NotNil)
cmdEnableAutopilot = []string{"-c", "/bin/false"}
c.Assert(setAutopilot(true), NotNil)
// disable cases
cmdStopAutopilot = []string{"-c", "/bin/true"}
cmdDisableAutopilot = []string{"-c", "/bin/false"}
c.Assert(setAutopilot(false), NotNil)
cmdStopAutopilot = []string{"-c", "/bin/false"}
c.Assert(setAutopilot(false), NotNil)
}