Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

devicestate: keep log from install-mode on installed system #9545

Merged
merged 8 commits into from
Feb 2, 2021
3 changes: 3 additions & 0 deletions overlord/devicestate/devicestate_install_mode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ func (s *deviceMgrInstallModeSuite) SetUpTest(c *C) {
s.state.Lock()
defer s.state.Unlock()
s.state.Set("seeded", true)

fakeJournalctl := testutil.MockCommand(c, "journalctl", "")
s.AddCleanup(fakeJournalctl.Restore)
}

const (
Expand Down
38 changes: 38 additions & 0 deletions overlord/devicestate/handlers_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
package devicestate

import (
"compress/gzip"
"fmt"
"os"
"os/exec"
"path/filepath"

"gopkg.in/tomb.v2"
Expand Down Expand Up @@ -90,6 +92,37 @@ func writeModel(model *asserts.Model, where string) error {
return asserts.NewEncoder(f).Encode(model)
}

func writeLogs(rootdir string) error {
// XXX: would be great to use native journal format but it's tied
// to machine-id, we could journal -o export but there
// is no systemd-journal-remote on core{,18,20}
//
// XXX: or only log if persistent journal is enabled?
logPath := filepath.Join(rootdir, "var/log/install-mode.log.gz")
if err := os.MkdirAll(filepath.Dir(logPath), 0755); err != nil {
return err
}

f, err := os.Create(logPath)
if err != nil {
return err
}
defer f.Close()

gz := gzip.NewWriter(f)
defer gz.Close()

cmd := exec.Command("journalctl", "-b", "0")
cmd.Stdout = gz
if err := cmd.Run(); err != nil {
return fmt.Errorf("cannot collect journal output: %v", err)
}
if err := gz.Flush(); err != nil {
return fmt.Errorf("cannot flush compressed log output: %v", err)
}
return nil
}

func (m *DeviceManager) doSetupRunSystem(t *state.Task, _ *tomb.Tomb) error {
st := t.State()
st.Lock()
Expand Down Expand Up @@ -237,6 +270,11 @@ func (m *DeviceManager) doSetupRunSystem(t *state.Task, _ *tomb.Tomb) error {
return fmt.Errorf("cannot make run system bootable: %v", err)
}

// store install-mode log into ubuntu-data partition
if err := writeLogs(boot.InstallHostWritableDir); err != nil {
logger.Noticef("cannot write installation log: %v", err)
}

// request a restart as the last action after a successful install
logger.Noticef("request system restart")
st.RequestRestart(state.RestartSystemNow)
Expand Down
5 changes: 5 additions & 0 deletions tests/nested/core20/basic/task.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,8 @@ execute: |
nested_exec 'cat /var/lib/snapd/save/device/asserts-v0/serial/'"$(nested_model_authority)"'/pc/*/active' >serial.saved
nested_exec snap model --serial --assertion >serial
cmp serial serial.saved

# check that we go the install log after the transition to run mode
nested_exec "test -e /var/log/install-mode.log.gz"
# transparently verify that the format is gzip
nested_exec "zcat /var/log/install-mode.log.gz" | MATCH 'installing a new system'