mirror of
https://github.com/token2/snapd.git
synced 2026-03-13 11:15:47 -07:00
merged lp:snappy
This commit is contained in:
+87
-2
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user