diff options
| author | Michael Vogt <mvo@ubuntu.com> | 2016-11-16 18:02:13 +0100 |
|---|---|---|
| committer | Michael Vogt <mvo@ubuntu.com> | 2016-11-16 18:18:03 +0100 |
| commit | 92f99f59d3c60f2c41c2d3729f2b5f99aa0bf6bf (patch) | |
| tree | fccb8fc231b19e7651ecbb3f61fe8431c62e9ddf | |
| parent | c42d61c4132145ae08ea23fc91f8926c2aece4cc (diff) | |
initial health checks draftfeature/simple-health-checks
| -rw-r--r-- | overlord/snapstate/backend.go | 3 | ||||
| -rw-r--r-- | overlord/snapstate/backend/health.go | 43 | ||||
| -rw-r--r-- | overlord/snapstate/backend_test.go | 11 | ||||
| -rw-r--r-- | overlord/snapstate/snapmgr.go | 16 | ||||
| -rw-r--r-- | overlord/snapstate/snapmgr_test.go | 11 | ||||
| -rw-r--r-- | overlord/snapstate/snapstate.go | 6 | ||||
| -rwxr-xr-x | tests/lib/snaps/test-snapd-service-v3-bad-health/bin/good | 3 | ||||
| -rwxr-xr-x | tests/lib/snaps/test-snapd-service-v3-bad-health/meta/checks/static-check | 4 | ||||
| -rw-r--r-- | tests/lib/snaps/test-snapd-service-v3-bad-health/meta/snap.yaml | 7 | ||||
| -rw-r--r-- | tests/main/health-check-static/task.yaml | 45 |
10 files changed, 145 insertions, 4 deletions
diff --git a/overlord/snapstate/backend.go b/overlord/snapstate/backend.go index c67b2e04ef..4916806d61 100644 --- a/overlord/snapstate/backend.go +++ b/overlord/snapstate/backend.go @@ -63,6 +63,9 @@ type managerBackend interface { RemoveSnapCommonData(info *snap.Info) error DiscardSnapNamespace(snapName string) error + // health check + HealthCheckStatic(name string, rev snap.Revision) error + // testing helpers CurrentInfo(cur *snap.Info) Candidate(sideInfo *snap.SideInfo) diff --git a/overlord/snapstate/backend/health.go b/overlord/snapstate/backend/health.go new file mode 100644 index 0000000000..490ad97449 --- /dev/null +++ b/overlord/snapstate/backend/health.go @@ -0,0 +1,43 @@ +// -*- Mode: Go; indent-tabs-mode: t -*- + +/* + * Copyright (C) 2016 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +package backend + +import ( + "fmt" + "os/exec" + "path/filepath" + + "github.com/snapcore/snapd/osutil" + "github.com/snapcore/snapd/snap" +) + +func (b Backend) HealthCheckStatic(snapName string, rev snap.Revision) error { + checker := filepath.Join(snap.MountDir(snapName, rev), "meta/checks/static-check") + if osutil.FileExists(checker) { + // FIXME: this is curently unconfined, we need + // `snap run --health-check=static snap-name` + output, err := exec.Command(checker).CombinedOutput() + if err != nil { + return fmt.Errorf("static health check for %q failed: %s", snapName, osutil.OutputErr(output, err)) + } + } + + return nil +} diff --git a/overlord/snapstate/backend_test.go b/overlord/snapstate/backend_test.go index 86849338ed..2b2d8223c4 100644 --- a/overlord/snapstate/backend_test.go +++ b/overlord/snapstate/backend_test.go @@ -418,6 +418,17 @@ func (f *fakeSnappyBackend) DiscardSnapNamespace(snapName string) error { return nil } +func (f *fakeSnappyBackend) HealthCheckStatic(snapName string, rev snap.Revision) error { + // FIXME: update all tests + /* + f.ops = append(f.ops, fakeOp{ + op: "health-check-static", + name: snapName, + }) + */ + return nil +} + func (f *fakeSnappyBackend) Candidate(sideInfo *snap.SideInfo) { var sinfo snap.SideInfo if sideInfo != nil { diff --git a/overlord/snapstate/snapmgr.go b/overlord/snapstate/snapmgr.go index 434655ccf6..6efc568078 100644 --- a/overlord/snapstate/snapmgr.go +++ b/overlord/snapstate/snapmgr.go @@ -315,6 +315,9 @@ func Manager(s *state.State) (*SnapManager, error) { runner.AddHandler("clear-snap", m.doClearSnapData, nil) runner.AddHandler("discard-snap", m.doDiscardSnap, nil) + // health check + runner.AddHandler("health-check-static", m.doHealthCheckStatic, nil) + // test handlers runner.AddHandler("fake-install-snap", func(t *state.Task, _ *tomb.Tomb) error { return nil @@ -562,6 +565,19 @@ func (m *SnapManager) doDiscardSnap(t *state.Task, _ *tomb.Tomb) error { return nil } +func (m *SnapManager) doHealthCheckStatic(t *state.Task, _ *tomb.Tomb) error { + st := t.State() + + st.Lock() + ss, err := TaskSnapSetup(t) + st.Unlock() + if err != nil { + return err + } + + return m.backend.HealthCheckStatic(ss.Name(), ss.Revision()) +} + // Ensure implements StateManager.Ensure. func (m *SnapManager) Ensure() error { m.runner.Ensure() diff --git a/overlord/snapstate/snapmgr_test.go b/overlord/snapstate/snapmgr_test.go index ed514a8ab2..1470fe364f 100644 --- a/overlord/snapstate/snapmgr_test.go +++ b/overlord/snapstate/snapmgr_test.go @@ -163,6 +163,7 @@ func verifyInstallUpdateTasks(c *C, opts, discards int, ts *state.TaskSet, st *s } expected = append(expected, "run-hook", + "health-check-static", ) c.Assert(kinds, DeepEquals, expected) @@ -214,6 +215,7 @@ func (s *snapmgrTestSuite) TestRevertTasks(c *C) { "link-snap", "start-snap-services", "run-hook", + "health-check-static", }) } @@ -424,6 +426,7 @@ func (s *snapmgrTestSuite) TestRevertCreatesNoGCTasks(c *C) { "link-snap", "start-snap-services", "run-hook", + "health-check-static", }) } @@ -881,9 +884,9 @@ func (s *snapmgrTestSuite) TestInstallRunThrough(c *C) { c.Check(task.Summary(), Equals, `Download snap "some-snap" (42) from channel "some-channel"`) // check link/start snap summary - linkTask := ta[len(ta)-3] + linkTask := ta[len(ta)-4] c.Check(linkTask.Summary(), Equals, `Make snap "some-snap" (42) available to the system`) - startTask := ta[len(ta)-2] + startTask := ta[len(ta)-3] c.Check(startTask.Summary(), Equals, `Start snap "some-snap" (42) services`) // verify snap-setup in the task state @@ -3898,13 +3901,13 @@ func (s *snapmgrTestSuite) TestUpdateTasksWithOldCurrent(c *C) { var ss snapstate.SnapSetup tasks := ts.Tasks() - i := len(tasks) - 6 + i := len(tasks) - 7 c.Check(tasks[i].Kind(), Equals, "clear-snap") err = tasks[i].Get("snap-setup", &ss) c.Assert(err, IsNil) c.Check(ss.Revision(), Equals, si3.Revision) - i = len(tasks) - 4 + i = len(tasks) - 5 c.Check(tasks[i].Kind(), Equals, "clear-snap") err = tasks[i].Get("snap-setup", &ss) c.Assert(err, IsNil) diff --git a/overlord/snapstate/snapstate.go b/overlord/snapstate/snapstate.go index 2a23f348b4..4af6ea3a1d 100644 --- a/overlord/snapstate/snapstate.go +++ b/overlord/snapstate/snapstate.go @@ -179,6 +179,12 @@ func doInstall(s *state.State, snapst *SnapState, ss *SnapSetup) (*state.TaskSet configSet.WaitAll(installSet) installSet.AddAll(configSet) + // FIXME: move to a separate pkg? + healthCheck := s.NewTask("health-check-static", fmt.Sprintf("Static health check for %q", ss.Name())) + healthCheck.Set("snap-setup-task", prepare.ID()) + healthCheck.WaitAll(configSet) + installSet.AddAll(state.NewTaskSet(healthCheck)) + return installSet, nil } diff --git a/tests/lib/snaps/test-snapd-service-v3-bad-health/bin/good b/tests/lib/snaps/test-snapd-service-v3-bad-health/bin/good new file mode 100755 index 0000000000..d07a9f9584 --- /dev/null +++ b/tests/lib/snaps/test-snapd-service-v3-bad-health/bin/good @@ -0,0 +1,3 @@ +#!/bin/sh + +echo "service v1" diff --git a/tests/lib/snaps/test-snapd-service-v3-bad-health/meta/checks/static-check b/tests/lib/snaps/test-snapd-service-v3-bad-health/meta/checks/static-check new file mode 100755 index 0000000000..759dbfd2d3 --- /dev/null +++ b/tests/lib/snaps/test-snapd-service-v3-bad-health/meta/checks/static-check @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "I don't feel well" +exit 1 diff --git a/tests/lib/snaps/test-snapd-service-v3-bad-health/meta/snap.yaml b/tests/lib/snaps/test-snapd-service-v3-bad-health/meta/snap.yaml new file mode 100644 index 0000000000..3a93f5574d --- /dev/null +++ b/tests/lib/snaps/test-snapd-service-v3-bad-health/meta/snap.yaml @@ -0,0 +1,7 @@ +name: test-snapd-service +version: 3.0 +apps: + service: + command: bin/good + daemon: oneshot + restart-condition: never diff --git a/tests/main/health-check-static/task.yaml b/tests/main/health-check-static/task.yaml new file mode 100644 index 0000000000..89bdedf52f --- /dev/null +++ b/tests/main/health-check-static/task.yaml @@ -0,0 +1,45 @@ +summary: Run static health check +details: | + When a snap is refreshed and the health check fails, the snap in reverted + +environment: + SNAP_NAME: test-snapd-service + SNAP_NAME_GOOD: ${SNAP_NAME}-v1-good + SNAP_NAME_BAD: ${SNAP_NAME}-v3-bad-health + SNAP_FILE_GOOD: ${SNAP_NAME}_1.0_all.snap + SNAP_FILE_BAD: ${SNAP_NAME}_3.0_all.snap + +prepare: | + echo "Given a good (v1) and a bad health check (v3) snap" + snapbuild $TESTSLIB/snaps/$SNAP_NAME_GOOD . + snapbuild $TESTSLIB/snaps/$SNAP_NAME_BAD . + +debug: | + journalctl -u snap.test-snapd-service.service.service + +execute: | + wait_for_service_status() { + retries=0 + while ! systemctl status snap.test-snapd-service.service.service|grep "$1"; do + # retry + retries=$((retries+1)) + if [ $retries -gt 20 ]; then + echo 'expected "service v1" output did not appear in systemctl status snap.test-snapd-service.service.service' + exit 1 + fi + sleep 1 + done + } + echo "When we install v1" + snap install --dangerous ${SNAP_FILE_GOOD} + echo "The v1 service started correctly" + wait_for_service_status "Started Service for snap application test-snapd-service.service" + + echo "When we refresh to v3 with a broken health check" + if snap install --dangerous ${SNAP_FILE_BAD}; then + echo "The ${SNAP_FILE_BAD} snap should not install cleanly, test broken" + exit 1 + fi + echo "Then v3 is rolled back and v1 is started again" + wait_for_service_status "Started Service for snap application test-snapd-service.service" + wait_for_service_status "service v1" |
