github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/overlord/devicestate/devicestate_install_mode_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package devicestate_test 21 22 import ( 23 "bytes" 24 "fmt" 25 "io/ioutil" 26 "os" 27 "path/filepath" 28 29 . "gopkg.in/check.v1" 30 31 "github.com/snapcore/snapd/asserts" 32 "github.com/snapcore/snapd/boot" 33 "github.com/snapcore/snapd/dirs" 34 "github.com/snapcore/snapd/gadget" 35 "github.com/snapcore/snapd/gadget/install" 36 "github.com/snapcore/snapd/overlord/auth" 37 "github.com/snapcore/snapd/overlord/devicestate" 38 "github.com/snapcore/snapd/overlord/devicestate/devicestatetest" 39 "github.com/snapcore/snapd/overlord/snapstate" 40 "github.com/snapcore/snapd/overlord/state" 41 "github.com/snapcore/snapd/release" 42 "github.com/snapcore/snapd/snap" 43 "github.com/snapcore/snapd/snap/snaptest" 44 "github.com/snapcore/snapd/sysconfig" 45 "github.com/snapcore/snapd/testutil" 46 ) 47 48 type deviceMgrInstallModeSuite struct { 49 deviceMgrBaseSuite 50 51 configureRunSystemOptsPassed []*sysconfig.Options 52 configureRunSystemErr error 53 } 54 55 var _ = Suite(&deviceMgrInstallModeSuite{}) 56 57 func (s *deviceMgrInstallModeSuite) findInstallSystem() *state.Change { 58 for _, chg := range s.state.Changes() { 59 if chg.Kind() == "install-system" { 60 return chg 61 } 62 } 63 return nil 64 } 65 66 func (s *deviceMgrInstallModeSuite) SetUpTest(c *C) { 67 s.deviceMgrBaseSuite.SetUpTest(c) 68 69 s.configureRunSystemOptsPassed = nil 70 s.configureRunSystemErr = nil 71 restore := devicestate.MockSysconfigConfigureRunSystem(func(opts *sysconfig.Options) error { 72 s.configureRunSystemOptsPassed = append(s.configureRunSystemOptsPassed, opts) 73 return s.configureRunSystemErr 74 }) 75 s.AddCleanup(restore) 76 77 restore = devicestate.MockSecbootCheckKeySealingSupported(func() error { 78 return fmt.Errorf("TPM not available") 79 }) 80 s.AddCleanup(restore) 81 82 s.state.Lock() 83 defer s.state.Unlock() 84 s.state.Set("seeded", true) 85 } 86 87 func (s *deviceMgrInstallModeSuite) makeMockInstalledPcGadget(c *C, grade, gadgetDefaultsYaml string) *asserts.Model { 88 const ( 89 pcSnapID = "pcididididididididididididididid" 90 pcKernelSnapID = "pckernelidididididididididididid" 91 core20SnapID = "core20ididididididididididididid" 92 ) 93 si := &snap.SideInfo{ 94 RealName: "pc-kernel", 95 Revision: snap.R(1), 96 SnapID: pcKernelSnapID, 97 } 98 snapstate.Set(s.state, "pc-kernel", &snapstate.SnapState{ 99 SnapType: "kernel", 100 Sequence: []*snap.SideInfo{si}, 101 Current: si.Revision, 102 Active: true, 103 }) 104 kernelInfo := snaptest.MockSnapWithFiles(c, "name: pc-kernel\ntype: kernel", si, nil) 105 kernelFn := snaptest.MakeTestSnapWithFiles(c, "name: pc-kernel\ntype: kernel\nversion: 1.0", nil) 106 err := os.Rename(kernelFn, kernelInfo.MountFile()) 107 c.Assert(err, IsNil) 108 109 si = &snap.SideInfo{ 110 RealName: "pc", 111 Revision: snap.R(1), 112 SnapID: pcSnapID, 113 } 114 snapstate.Set(s.state, "pc", &snapstate.SnapState{ 115 SnapType: "gadget", 116 Sequence: []*snap.SideInfo{si}, 117 Current: si.Revision, 118 Active: true, 119 }) 120 snaptest.MockSnapWithFiles(c, "name: pc\ntype: gadget", si, [][]string{ 121 {"meta/gadget.yaml", gadgetYaml + gadgetDefaultsYaml}, 122 }) 123 124 si = &snap.SideInfo{ 125 RealName: "core20", 126 Revision: snap.R(2), 127 SnapID: core20SnapID, 128 } 129 snapstate.Set(s.state, "core20", &snapstate.SnapState{ 130 SnapType: "base", 131 Sequence: []*snap.SideInfo{si}, 132 Current: si.Revision, 133 Active: true, 134 }) 135 snaptest.MockSnapWithFiles(c, "name: core20\ntype: base", si, nil) 136 137 mockModel := s.makeModelAssertionInState(c, "my-brand", "my-model", map[string]interface{}{ 138 "display-name": "my model", 139 "architecture": "amd64", 140 "base": "core20", 141 "grade": grade, 142 "snaps": []interface{}{ 143 map[string]interface{}{ 144 "name": "pc-kernel", 145 "id": pcKernelSnapID, 146 "type": "kernel", 147 "default-channel": "20", 148 }, 149 map[string]interface{}{ 150 "name": "pc", 151 "id": pcSnapID, 152 "type": "gadget", 153 "default-channel": "20", 154 }}, 155 }) 156 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 157 Brand: "my-brand", 158 Model: "my-model", 159 // no serial in install mode 160 }) 161 162 return mockModel 163 } 164 165 type encTestCase struct { 166 tpm bool 167 bypass bool 168 encrypt bool 169 } 170 171 func (s *deviceMgrInstallModeSuite) doRunChangeTestWithEncryption(c *C, grade string, tc encTestCase) error { 172 restore := release.MockOnClassic(false) 173 defer restore() 174 175 var brGadgetRoot, brDevice string 176 var brOpts install.Options 177 var installRunCalled int 178 var sealingObserver gadget.ContentObserver 179 restore = devicestate.MockInstallRun(func(gadgetRoot, device string, options install.Options, obs install.SystemInstallObserver) error { 180 // ensure we can grab the lock here, i.e. that it's not taken 181 s.state.Lock() 182 s.state.Unlock() 183 184 brGadgetRoot = gadgetRoot 185 brDevice = device 186 brOpts = options 187 sealingObserver = obs 188 installRunCalled++ 189 return nil 190 }) 191 defer restore() 192 193 restore = devicestate.MockSecbootCheckKeySealingSupported(func() error { 194 if tc.tpm { 195 return nil 196 } else { 197 return fmt.Errorf("TPM not available") 198 } 199 }) 200 defer restore() 201 202 s.state.Lock() 203 mockModel := s.makeMockInstalledPcGadget(c, grade, "") 204 s.state.Unlock() 205 206 bypassEncryptionPath := filepath.Join(boot.InitramfsUbuntuSeedDir, ".force-unencrypted") 207 if tc.bypass { 208 err := os.MkdirAll(filepath.Dir(bypassEncryptionPath), 0755) 209 c.Assert(err, IsNil) 210 f, err := os.Create(bypassEncryptionPath) 211 c.Assert(err, IsNil) 212 f.Close() 213 } else { 214 os.RemoveAll(bypassEncryptionPath) 215 } 216 217 bootMakeBootableCalled := 0 218 restore = devicestate.MockBootMakeBootable(func(model *asserts.Model, rootdir string, bootWith *boot.BootableSet, seal *boot.TrustedAssetsInstallObserver) error { 219 c.Check(model, DeepEquals, mockModel) 220 c.Check(rootdir, Equals, dirs.GlobalRootDir) 221 c.Check(bootWith.KernelPath, Matches, ".*/var/lib/snapd/snaps/pc-kernel_1.snap") 222 c.Check(bootWith.BasePath, Matches, ".*/var/lib/snapd/snaps/core20_2.snap") 223 c.Check(bootWith.RecoverySystemDir, Matches, "/systems/20191218") 224 c.Check(bootWith.UnpackedGadgetDir, Equals, filepath.Join(dirs.SnapMountDir, "pc/1")) 225 if tc.encrypt { 226 c.Check(seal, NotNil) 227 } 228 bootMakeBootableCalled++ 229 return nil 230 }) 231 defer restore() 232 233 modeenv := boot.Modeenv{ 234 Mode: "install", 235 RecoverySystem: "20191218", 236 } 237 c.Assert(modeenv.WriteTo(""), IsNil) 238 devicestate.SetSystemMode(s.mgr, "install") 239 240 // normally done by snap-bootstrap 241 err := os.MkdirAll(boot.InitramfsUbuntuBootDir, 0755) 242 c.Assert(err, IsNil) 243 244 s.settle(c) 245 246 // the install-system change is created 247 s.state.Lock() 248 defer s.state.Unlock() 249 installSystem := s.findInstallSystem() 250 c.Assert(installSystem, NotNil) 251 252 // and was run successfully 253 if err := installSystem.Err(); err != nil { 254 // we failed, no further checks needed 255 return err 256 } 257 258 c.Assert(installSystem.Status(), Equals, state.DoneStatus) 259 260 // in the right way 261 if tc.encrypt { 262 c.Assert(brGadgetRoot, Equals, filepath.Join(dirs.SnapMountDir, "/pc/1")) 263 c.Assert(brDevice, Equals, "") 264 c.Assert(brOpts, DeepEquals, install.Options{ 265 Mount: true, 266 Encrypt: true, 267 }) 268 269 // inteface is not nil 270 c.Assert(sealingObserver, NotNil) 271 // we expect a very specific type 272 trustedInstallObserver, ok := sealingObserver.(*boot.TrustedAssetsInstallObserver) 273 c.Assert(ok, Equals, true, Commentf("unexpected type: %T", sealingObserver)) 274 c.Assert(trustedInstallObserver, NotNil) 275 } else { 276 c.Assert(brGadgetRoot, Equals, filepath.Join(dirs.SnapMountDir, "/pc/1")) 277 c.Assert(brDevice, Equals, "") 278 c.Assert(brOpts, DeepEquals, install.Options{ 279 Mount: true, 280 }) 281 } 282 c.Assert(installRunCalled, Equals, 1) 283 c.Assert(bootMakeBootableCalled, Equals, 1) 284 c.Assert(s.restartRequests, DeepEquals, []state.RestartType{state.RestartSystemNow}) 285 286 return nil 287 } 288 289 func (s *deviceMgrInstallModeSuite) TestInstallTaskErrors(c *C) { 290 restore := release.MockOnClassic(false) 291 defer restore() 292 293 restore = devicestate.MockInstallRun(func(gadgetRoot, device string, options install.Options, _ install.SystemInstallObserver) error { 294 return fmt.Errorf("The horror, The horror") 295 }) 296 defer restore() 297 298 err := ioutil.WriteFile(filepath.Join(dirs.GlobalRootDir, "/var/lib/snapd/modeenv"), 299 []byte("mode=install\n"), 0644) 300 c.Assert(err, IsNil) 301 302 s.state.Lock() 303 s.makeMockInstalledPcGadget(c, "dangerous", "") 304 devicestate.SetSystemMode(s.mgr, "install") 305 s.state.Unlock() 306 307 s.settle(c) 308 309 s.state.Lock() 310 defer s.state.Unlock() 311 312 installSystem := s.findInstallSystem() 313 c.Check(installSystem.Err(), ErrorMatches, `(?ms)cannot perform the following tasks: 314 - Setup system for run mode \(cannot create partitions: The horror, The horror\)`) 315 // no restart request on failure 316 c.Check(s.restartRequests, HasLen, 0) 317 } 318 319 func (s *deviceMgrInstallModeSuite) TestInstallModeNotInstallmodeNoChg(c *C) { 320 restore := release.MockOnClassic(false) 321 defer restore() 322 323 s.state.Lock() 324 devicestate.SetSystemMode(s.mgr, "") 325 s.state.Unlock() 326 327 s.settle(c) 328 329 s.state.Lock() 330 defer s.state.Unlock() 331 332 // the install-system change is *not* created (not in install mode) 333 installSystem := s.findInstallSystem() 334 c.Assert(installSystem, IsNil) 335 } 336 337 func (s *deviceMgrInstallModeSuite) TestInstallModeNotClassic(c *C) { 338 restore := release.MockOnClassic(true) 339 defer restore() 340 341 s.state.Lock() 342 devicestate.SetSystemMode(s.mgr, "install") 343 s.state.Unlock() 344 345 s.settle(c) 346 347 s.state.Lock() 348 defer s.state.Unlock() 349 350 // the install-system change is *not* created (we're on classic) 351 installSystem := s.findInstallSystem() 352 c.Assert(installSystem, IsNil) 353 } 354 355 func (s *deviceMgrInstallModeSuite) TestInstallDangerous(c *C) { 356 err := s.doRunChangeTestWithEncryption(c, "dangerous", encTestCase{tpm: false, bypass: false, encrypt: false}) 357 c.Assert(err, IsNil) 358 } 359 360 func (s *deviceMgrInstallModeSuite) TestInstallDangerousWithTPM(c *C) { 361 err := s.doRunChangeTestWithEncryption(c, "dangerous", encTestCase{tpm: true, bypass: false, encrypt: true}) 362 c.Assert(err, IsNil) 363 } 364 365 func (s *deviceMgrInstallModeSuite) TestInstallDangerousBypassEncryption(c *C) { 366 err := s.doRunChangeTestWithEncryption(c, "dangerous", encTestCase{tpm: false, bypass: true, encrypt: false}) 367 c.Assert(err, IsNil) 368 } 369 370 func (s *deviceMgrInstallModeSuite) TestInstallDangerousWithTPMBypassEncryption(c *C) { 371 err := s.doRunChangeTestWithEncryption(c, "dangerous", encTestCase{tpm: true, bypass: true, encrypt: false}) 372 c.Assert(err, IsNil) 373 } 374 375 func (s *deviceMgrInstallModeSuite) TestInstallSigned(c *C) { 376 err := s.doRunChangeTestWithEncryption(c, "signed", encTestCase{tpm: false, bypass: false, encrypt: false}) 377 c.Assert(err, IsNil) 378 } 379 380 func (s *deviceMgrInstallModeSuite) TestInstallSignedWithTPM(c *C) { 381 err := s.doRunChangeTestWithEncryption(c, "signed", encTestCase{tpm: true, bypass: false, encrypt: true}) 382 c.Assert(err, IsNil) 383 } 384 385 func (s *deviceMgrInstallModeSuite) TestInstallSignedBypassEncryption(c *C) { 386 err := s.doRunChangeTestWithEncryption(c, "signed", encTestCase{tpm: false, bypass: true, encrypt: false}) 387 c.Assert(err, IsNil) 388 } 389 390 func (s *deviceMgrInstallModeSuite) TestInstallSecured(c *C) { 391 err := s.doRunChangeTestWithEncryption(c, "secured", encTestCase{tpm: false, bypass: false, encrypt: false}) 392 c.Assert(err, ErrorMatches, "(?s).*cannot encrypt secured device: TPM not available.*") 393 } 394 395 func (s *deviceMgrInstallModeSuite) TestInstallSecuredWithTPM(c *C) { 396 err := s.doRunChangeTestWithEncryption(c, "secured", encTestCase{tpm: true, bypass: false, encrypt: true}) 397 c.Assert(err, IsNil) 398 } 399 400 func (s *deviceMgrInstallModeSuite) TestInstallSecuredBypassEncryption(c *C) { 401 err := s.doRunChangeTestWithEncryption(c, "secured", encTestCase{tpm: false, bypass: true, encrypt: false}) 402 c.Assert(err, ErrorMatches, "(?s).*cannot encrypt secured device: TPM not available.*") 403 } 404 405 func (s *deviceMgrInstallModeSuite) mockInstallModeChange(c *C, modelGrade, gadgetDefaultsYaml string) *asserts.Model { 406 restore := release.MockOnClassic(false) 407 defer restore() 408 409 restore = devicestate.MockInstallRun(func(gadgetRoot, device string, options install.Options, _ install.SystemInstallObserver) error { 410 return nil 411 }) 412 defer restore() 413 414 s.state.Lock() 415 mockModel := s.makeMockInstalledPcGadget(c, modelGrade, gadgetDefaultsYaml) 416 s.state.Unlock() 417 c.Check(mockModel.Grade(), Equals, asserts.ModelGrade(modelGrade)) 418 419 restore = devicestate.MockBootMakeBootable(func(model *asserts.Model, rootdir string, bootWith *boot.BootableSet, seal *boot.TrustedAssetsInstallObserver) error { 420 return nil 421 }) 422 defer restore() 423 424 modeenv := boot.Modeenv{ 425 Mode: "install", 426 RecoverySystem: "20191218", 427 } 428 c.Assert(modeenv.WriteTo(""), IsNil) 429 devicestate.SetSystemMode(s.mgr, "install") 430 431 // normally done by snap-bootstrap 432 err := os.MkdirAll(boot.InitramfsUbuntuBootDir, 0755) 433 c.Assert(err, IsNil) 434 435 s.settle(c) 436 437 return mockModel 438 } 439 440 func (s *deviceMgrInstallModeSuite) TestInstallModeRunSysconfig(c *C) { 441 s.mockInstallModeChange(c, "dangerous", "") 442 443 s.state.Lock() 444 defer s.state.Unlock() 445 446 // the install-system change is created 447 installSystem := s.findInstallSystem() 448 c.Assert(installSystem, NotNil) 449 450 // and was run successfully 451 c.Check(installSystem.Err(), IsNil) 452 c.Check(installSystem.Status(), Equals, state.DoneStatus) 453 454 // and sysconfig.ConfigureRunSystem was run exactly once 455 c.Assert(s.configureRunSystemOptsPassed, DeepEquals, []*sysconfig.Options{ 456 { 457 AllowCloudInit: true, 458 TargetRootDir: boot.InstallHostWritableDir, 459 GadgetDir: filepath.Join(dirs.SnapMountDir, "pc/1/"), 460 }, 461 }) 462 } 463 464 func (s *deviceMgrInstallModeSuite) TestInstallModeRunSysconfigErr(c *C) { 465 s.configureRunSystemErr = fmt.Errorf("error from sysconfig.ConfigureRunSystem") 466 s.mockInstallModeChange(c, "dangerous", "") 467 468 s.state.Lock() 469 defer s.state.Unlock() 470 471 // the install-system was run but errorred as specified in the above mock 472 installSystem := s.findInstallSystem() 473 c.Check(installSystem.Err(), ErrorMatches, `(?ms)cannot perform the following tasks: 474 - Setup system for run mode \(error from sysconfig.ConfigureRunSystem\)`) 475 // and sysconfig.ConfigureRunSystem was run exactly once 476 c.Assert(s.configureRunSystemOptsPassed, DeepEquals, []*sysconfig.Options{ 477 { 478 AllowCloudInit: true, 479 TargetRootDir: boot.InstallHostWritableDir, 480 GadgetDir: filepath.Join(dirs.SnapMountDir, "pc/1/"), 481 }, 482 }) 483 } 484 485 func (s *deviceMgrInstallModeSuite) TestInstallModeSupportsCloudInitInDangerous(c *C) { 486 // pretend we have a cloud-init config on the seed partition 487 cloudCfg := filepath.Join(boot.InitramfsUbuntuSeedDir, "data/etc/cloud/cloud.cfg.d") 488 err := os.MkdirAll(cloudCfg, 0755) 489 c.Assert(err, IsNil) 490 for _, mockCfg := range []string{"foo.cfg", "bar.cfg"} { 491 err = ioutil.WriteFile(filepath.Join(cloudCfg, mockCfg), []byte(fmt.Sprintf("%s config", mockCfg)), 0644) 492 c.Assert(err, IsNil) 493 } 494 495 s.mockInstallModeChange(c, "dangerous", "") 496 497 // and did tell sysconfig about the cloud-init files 498 c.Assert(s.configureRunSystemOptsPassed, DeepEquals, []*sysconfig.Options{ 499 { 500 AllowCloudInit: true, 501 CloudInitSrcDir: filepath.Join(boot.InitramfsUbuntuSeedDir, "data/etc/cloud/cloud.cfg.d"), 502 TargetRootDir: boot.InstallHostWritableDir, 503 GadgetDir: filepath.Join(dirs.SnapMountDir, "pc/1/"), 504 }, 505 }) 506 } 507 508 func (s *deviceMgrInstallModeSuite) TestInstallModeSignedNoUbuntuSeedCloudInit(c *C) { 509 // pretend we have a cloud-init config on the seed partition 510 cloudCfg := filepath.Join(boot.InitramfsUbuntuSeedDir, "data/etc/cloud/cloud.cfg.d") 511 err := os.MkdirAll(cloudCfg, 0755) 512 c.Assert(err, IsNil) 513 for _, mockCfg := range []string{"foo.cfg", "bar.cfg"} { 514 err = ioutil.WriteFile(filepath.Join(cloudCfg, mockCfg), []byte(fmt.Sprintf("%s config", mockCfg)), 0644) 515 c.Assert(err, IsNil) 516 } 517 518 s.mockInstallModeChange(c, "signed", "") 519 520 // and did NOT tell sysconfig about the cloud-init file, but also did not 521 // explicitly disable cloud init 522 c.Assert(s.configureRunSystemOptsPassed, DeepEquals, []*sysconfig.Options{ 523 { 524 AllowCloudInit: true, 525 TargetRootDir: boot.InstallHostWritableDir, 526 GadgetDir: filepath.Join(dirs.SnapMountDir, "pc/1/"), 527 }, 528 }) 529 } 530 531 func (s *deviceMgrInstallModeSuite) TestInstallModeSecuredGadgetCloudConfCloudInit(c *C) { 532 // pretend we have a cloud.conf from the gadget 533 gadgetDir := filepath.Join(dirs.SnapMountDir, "pc/1/") 534 err := os.MkdirAll(gadgetDir, 0755) 535 c.Assert(err, IsNil) 536 err = ioutil.WriteFile(filepath.Join(gadgetDir, "cloud.conf"), nil, 0644) 537 c.Assert(err, IsNil) 538 539 err = s.doRunChangeTestWithEncryption(c, "secured", encTestCase{tpm: true, bypass: false, encrypt: true}) 540 c.Assert(err, IsNil) 541 542 c.Assert(s.configureRunSystemOptsPassed, DeepEquals, []*sysconfig.Options{ 543 { 544 AllowCloudInit: true, 545 TargetRootDir: boot.InstallHostWritableDir, 546 GadgetDir: filepath.Join(dirs.SnapMountDir, "pc/1/"), 547 }, 548 }) 549 } 550 551 func (s *deviceMgrInstallModeSuite) TestInstallModeSecuredNoUbuntuSeedCloudInit(c *C) { 552 // pretend we have a cloud-init config on the seed partition 553 cloudCfg := filepath.Join(boot.InitramfsUbuntuSeedDir, "data/etc/cloud/cloud.cfg.d") 554 err := os.MkdirAll(cloudCfg, 0755) 555 c.Assert(err, IsNil) 556 for _, mockCfg := range []string{"foo.cfg", "bar.cfg"} { 557 err = ioutil.WriteFile(filepath.Join(cloudCfg, mockCfg), []byte(fmt.Sprintf("%s config", mockCfg)), 0644) 558 c.Assert(err, IsNil) 559 } 560 561 err = s.doRunChangeTestWithEncryption(c, "secured", encTestCase{tpm: true, bypass: false, encrypt: true}) 562 c.Assert(err, IsNil) 563 564 // and did NOT tell sysconfig about the cloud-init files, instead it was 565 // disabled because only gadget cloud-init is allowed 566 c.Assert(s.configureRunSystemOptsPassed, DeepEquals, []*sysconfig.Options{ 567 { 568 AllowCloudInit: false, 569 TargetRootDir: boot.InstallHostWritableDir, 570 GadgetDir: filepath.Join(dirs.SnapMountDir, "pc/1/"), 571 }, 572 }) 573 } 574 575 func (s *deviceMgrInstallModeSuite) TestInstallModeWritesModel(c *C) { 576 // pretend we have a cloud-init config on the seed partition 577 model := s.mockInstallModeChange(c, "dangerous", "") 578 579 var buf bytes.Buffer 580 err := asserts.NewEncoder(&buf).Encode(model) 581 c.Assert(err, IsNil) 582 583 s.state.Lock() 584 defer s.state.Unlock() 585 586 installSystem := s.findInstallSystem() 587 c.Assert(installSystem, NotNil) 588 589 // and was run successfully 590 c.Check(installSystem.Err(), IsNil) 591 c.Check(installSystem.Status(), Equals, state.DoneStatus) 592 593 c.Check(filepath.Join(boot.InitramfsUbuntuBootDir, "model"), testutil.FileEquals, buf.String()) 594 }