github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/overlord/devicestate/devicestate_serial_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016-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 "fmt" 24 "net" 25 "net/http" 26 "net/http/httptest" 27 "net/url" 28 "os" 29 "path/filepath" 30 "syscall" 31 "time" 32 33 . "gopkg.in/check.v1" 34 "gopkg.in/yaml.v2" 35 36 "github.com/snapcore/snapd/asserts" 37 "github.com/snapcore/snapd/asserts/assertstest" 38 "github.com/snapcore/snapd/asserts/sysdb" 39 "github.com/snapcore/snapd/dirs" 40 "github.com/snapcore/snapd/httputil" 41 "github.com/snapcore/snapd/logger" 42 "github.com/snapcore/snapd/osutil" 43 "github.com/snapcore/snapd/overlord/assertstate" 44 "github.com/snapcore/snapd/overlord/assertstate/assertstatetest" 45 "github.com/snapcore/snapd/overlord/auth" 46 "github.com/snapcore/snapd/overlord/configstate/config" 47 "github.com/snapcore/snapd/overlord/devicestate" 48 "github.com/snapcore/snapd/overlord/devicestate/devicestatetest" 49 "github.com/snapcore/snapd/overlord/snapstate" 50 "github.com/snapcore/snapd/overlord/state" 51 "github.com/snapcore/snapd/overlord/storecontext" 52 "github.com/snapcore/snapd/release" 53 "github.com/snapcore/snapd/snap" 54 "github.com/snapcore/snapd/snap/snaptest" 55 "github.com/snapcore/snapd/snapdenv" 56 "github.com/snapcore/snapd/strutil" 57 "github.com/snapcore/snapd/testutil" 58 ) 59 60 var testKeyLength = 1024 61 62 type deviceMgrSerialSuite struct { 63 deviceMgrBaseSuite 64 } 65 66 var _ = Suite(&deviceMgrSerialSuite{}) 67 68 func (s *deviceMgrSerialSuite) signSerial(c *C, bhv *devicestatetest.DeviceServiceBehavior, headers map[string]interface{}, body []byte) (serial asserts.Assertion, ancillary []asserts.Assertion, err error) { 69 brandID := headers["brand-id"].(string) 70 model := headers["model"].(string) 71 keyID := "" 72 73 var signing assertstest.SignerDB = s.storeSigning 74 75 switch model { 76 case "pc", "pc2", "pc-20": 77 fallthrough 78 case "classic-alt-store": 79 c.Check(brandID, Equals, "canonical") 80 case "my-model-accept-generic": 81 c.Check(brandID, Equals, "my-brand") 82 headers["authority-id"] = "generic" 83 keyID = s.storeSigning.GenericKey.PublicKeyID() 84 case "generic-classic": 85 c.Check(brandID, Equals, "generic") 86 headers["authority-id"] = "generic" 87 keyID = s.storeSigning.GenericKey.PublicKeyID() 88 case "rereg-model": 89 headers["authority-id"] = "rereg-brand" 90 signing = s.brands.Signing("rereg-brand") 91 default: 92 return nil, nil, fmt.Errorf("unknown model: %s", model) 93 } 94 a, err := signing.Sign(asserts.SerialType, headers, body, keyID) 95 return a, s.ancillary, err 96 } 97 98 func (s *deviceMgrSerialSuite) mockServer(c *C, reqID string, bhv *devicestatetest.DeviceServiceBehavior) *httptest.Server { 99 if bhv == nil { 100 bhv = &devicestatetest.DeviceServiceBehavior{} 101 } 102 103 bhv.ReqID = reqID 104 bhv.SignSerial = s.signSerial 105 bhv.ExpectedCapabilities = "serial-stream" 106 107 return devicestatetest.MockDeviceService(c, bhv) 108 } 109 110 func (s *deviceMgrSerialSuite) findBecomeOperationalChange(skipIDs ...string) *state.Change { 111 for _, chg := range s.state.Changes() { 112 if chg.Kind() == "become-operational" && !strutil.ListContains(skipIDs, chg.ID()) { 113 return chg 114 } 115 } 116 return nil 117 } 118 119 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappy(c *C) { 120 r1 := devicestate.MockKeyLength(testKeyLength) 121 defer r1() 122 123 mockServer := s.mockServer(c, "REQID-1", nil) 124 defer mockServer.Close() 125 126 r2 := devicestate.MockBaseStoreURL(mockServer.URL) 127 defer r2() 128 129 // setup state as will be done by first-boot 130 s.state.Lock() 131 defer s.state.Unlock() 132 133 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 134 "architecture": "amd64", 135 "kernel": "pc-kernel", 136 "gadget": "pc", 137 }) 138 139 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 140 Brand: "canonical", 141 Model: "pc", 142 }) 143 144 // avoid full seeding 145 s.seeding() 146 147 // not started if not seeded 148 s.state.Unlock() 149 s.se.Ensure() 150 s.state.Lock() 151 152 becomeOperational := s.findBecomeOperationalChange() 153 c.Check(becomeOperational, IsNil) 154 155 devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil) 156 // mark it as seeded 157 s.state.Set("seeded", true) 158 159 // runs the whole device registration process 160 s.state.Unlock() 161 s.settle(c) 162 s.state.Lock() 163 164 becomeOperational = s.findBecomeOperationalChange() 165 c.Assert(becomeOperational, NotNil) 166 167 c.Check(becomeOperational.Status().Ready(), Equals, true) 168 c.Check(becomeOperational.Err(), IsNil) 169 170 device, err := devicestatetest.Device(s.state) 171 c.Assert(err, IsNil) 172 c.Check(device.Brand, Equals, "canonical") 173 c.Check(device.Model, Equals, "pc") 174 c.Check(device.Serial, Equals, "9999") 175 176 ok := false 177 select { 178 case <-s.mgr.Registered(): 179 ok = true 180 case <-time.After(5 * time.Second): 181 c.Fatal("should have been marked registered") 182 } 183 c.Check(ok, Equals, true) 184 185 a, err := s.db.Find(asserts.SerialType, map[string]string{ 186 "brand-id": "canonical", 187 "model": "pc", 188 "serial": "9999", 189 }) 190 c.Assert(err, IsNil) 191 serial := a.(*asserts.Serial) 192 193 privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID()) 194 c.Assert(err, IsNil) 195 c.Check(privKey, NotNil) 196 197 c.Check(device.KeyID, Equals, privKey.PublicKey().ID()) 198 199 // check that keypair manager is under device 200 c.Check(osutil.IsDirectory(filepath.Join(dirs.SnapDeviceDir, "private-keys-v1")), Equals, true) 201 } 202 203 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappyWithProxy(c *C) { 204 r1 := devicestate.MockKeyLength(testKeyLength) 205 defer r1() 206 207 mockServer := s.mockServer(c, "REQID-1", nil) 208 defer mockServer.Close() 209 210 // as core.proxy.store is set, should not need to do this but just in case 211 r2 := devicestate.MockBaseStoreURL(mockServer.URL + "/direct/baaad/") 212 defer r2() 213 214 // setup state as will be done by first-boot 215 s.state.Lock() 216 defer s.state.Unlock() 217 218 tr := config.NewTransaction(s.state) 219 c.Assert(tr.Set("core", "proxy.store", "foo"), IsNil) 220 tr.Commit() 221 operatorAcct := assertstest.NewAccount(s.storeSigning, "foo-operator", nil, "") 222 223 // have a store assertion. 224 stoAs, err := s.storeSigning.Sign(asserts.StoreType, map[string]interface{}{ 225 "store": "foo", 226 "url": mockServer.URL, 227 "operator-id": operatorAcct.AccountID(), 228 "timestamp": time.Now().Format(time.RFC3339), 229 }, nil, "") 230 c.Assert(err, IsNil) 231 232 assertstatetest.AddMany(s.state, operatorAcct, stoAs) 233 234 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 235 "architecture": "amd64", 236 "kernel": "pc-kernel", 237 "gadget": "pc", 238 }) 239 240 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 241 Brand: "canonical", 242 Model: "pc", 243 }) 244 245 devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil) 246 // mark as seeded 247 s.state.Set("seeded", true) 248 249 // runs the whole device registration process 250 s.state.Unlock() 251 s.settle(c) 252 s.state.Lock() 253 254 becomeOperational := s.findBecomeOperationalChange() 255 c.Assert(becomeOperational, NotNil) 256 257 c.Check(becomeOperational.Status().Ready(), Equals, true) 258 c.Check(becomeOperational.Err(), IsNil) 259 260 device, err := devicestatetest.Device(s.state) 261 c.Assert(err, IsNil) 262 c.Check(device.Brand, Equals, "canonical") 263 c.Check(device.Model, Equals, "pc") 264 c.Check(device.Serial, Equals, "9999") 265 266 ok := false 267 select { 268 case <-s.mgr.Registered(): 269 ok = true 270 case <-time.After(5 * time.Second): 271 c.Fatal("should have been marked registered") 272 } 273 c.Check(ok, Equals, true) 274 275 a, err := s.db.Find(asserts.SerialType, map[string]string{ 276 "brand-id": "canonical", 277 "model": "pc", 278 "serial": "9999", 279 }) 280 c.Assert(err, IsNil) 281 serial := a.(*asserts.Serial) 282 283 privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID()) 284 c.Assert(err, IsNil) 285 c.Check(privKey, NotNil) 286 287 c.Check(device.KeyID, Equals, privKey.PublicKey().ID()) 288 } 289 290 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappyClassicNoGadget(c *C) { 291 restore := release.MockOnClassic(true) 292 defer restore() 293 294 r1 := devicestate.MockKeyLength(testKeyLength) 295 defer r1() 296 297 mockServer := s.mockServer(c, "REQID-1", nil) 298 defer mockServer.Close() 299 300 r2 := devicestate.MockBaseStoreURL(mockServer.URL) 301 defer r2() 302 303 // setup state as will be done by first-boot 304 s.state.Lock() 305 defer s.state.Unlock() 306 307 s.makeModelAssertionInState(c, "canonical", "classic-alt-store", map[string]interface{}{ 308 "classic": "true", 309 "store": "alt-store", 310 }) 311 312 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 313 Brand: "canonical", 314 Model: "classic-alt-store", 315 }) 316 317 // avoid full seeding 318 s.seeding() 319 320 // runs the whole device registration process 321 s.state.Unlock() 322 s.settle(c) 323 s.state.Lock() 324 325 becomeOperational := s.findBecomeOperationalChange() 326 c.Assert(becomeOperational, NotNil) 327 328 c.Check(becomeOperational.Status().Ready(), Equals, true) 329 c.Check(becomeOperational.Err(), IsNil) 330 331 device, err := devicestatetest.Device(s.state) 332 c.Assert(err, IsNil) 333 c.Check(device.Brand, Equals, "canonical") 334 c.Check(device.Model, Equals, "classic-alt-store") 335 c.Check(device.Serial, Equals, "9999") 336 337 a, err := s.db.Find(asserts.SerialType, map[string]string{ 338 "brand-id": "canonical", 339 "model": "classic-alt-store", 340 "serial": "9999", 341 }) 342 c.Assert(err, IsNil) 343 serial := a.(*asserts.Serial) 344 345 privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID()) 346 c.Assert(err, IsNil) 347 c.Check(privKey, NotNil) 348 349 c.Check(device.KeyID, Equals, privKey.PublicKey().ID()) 350 } 351 352 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappyClassicFallback(c *C) { 353 restore := release.MockOnClassic(true) 354 defer restore() 355 356 r1 := devicestate.MockKeyLength(testKeyLength) 357 defer r1() 358 359 mockServer := s.mockServer(c, "REQID-1", nil) 360 defer mockServer.Close() 361 362 r2 := devicestate.MockBaseStoreURL(mockServer.URL) 363 defer r2() 364 365 // setup state as will be done by first-boot 366 s.state.Lock() 367 defer s.state.Unlock() 368 369 // in this case is just marked seeded without snaps 370 s.state.Set("seeded", true) 371 372 // not started without some installation happening or happened 373 s.state.Unlock() 374 s.se.Ensure() 375 s.state.Lock() 376 377 becomeOperational := s.findBecomeOperationalChange() 378 c.Check(becomeOperational, IsNil) 379 380 // have a in-progress installation 381 inst := s.state.NewChange("install", "...") 382 task := s.state.NewTask("mount-snap", "...") 383 inst.AddTask(task) 384 385 // runs the whole device registration process 386 s.state.Unlock() 387 s.settle(c) 388 s.state.Lock() 389 390 becomeOperational = s.findBecomeOperationalChange() 391 c.Assert(becomeOperational, NotNil) 392 393 c.Check(becomeOperational.Status().Ready(), Equals, true) 394 c.Check(becomeOperational.Err(), IsNil) 395 396 device, err := devicestatetest.Device(s.state) 397 c.Assert(err, IsNil) 398 c.Check(device.Brand, Equals, "generic") 399 c.Check(device.Model, Equals, "generic-classic") 400 c.Check(device.Serial, Equals, "9999") 401 402 // model was installed 403 _, err = s.db.Find(asserts.ModelType, map[string]string{ 404 "series": "16", 405 "brand-id": "generic", 406 "model": "generic-classic", 407 "classic": "true", 408 }) 409 c.Assert(err, IsNil) 410 411 a, err := s.db.Find(asserts.SerialType, map[string]string{ 412 "brand-id": "generic", 413 "model": "generic-classic", 414 "serial": "9999", 415 }) 416 c.Assert(err, IsNil) 417 serial := a.(*asserts.Serial) 418 419 privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID()) 420 c.Assert(err, IsNil) 421 c.Check(privKey, NotNil) 422 423 c.Check(device.KeyID, Equals, privKey.PublicKey().ID()) 424 425 // auto-refreshes are possible 426 ok, err := devicestate.CanAutoRefresh(s.state) 427 c.Assert(err, IsNil) 428 c.Check(ok, Equals, true) 429 } 430 431 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationMyBrandAcceptGenericHappy(c *C) { 432 r1 := devicestate.MockKeyLength(testKeyLength) 433 defer r1() 434 435 mockServer := s.mockServer(c, "REQID-1", nil) 436 defer mockServer.Close() 437 438 r2 := devicestate.MockBaseStoreURL(mockServer.URL) 439 defer r2() 440 441 // setup state as will be done by first-boot 442 s.state.Lock() 443 defer s.state.Unlock() 444 445 s.makeModelAssertionInState(c, "my-brand", "my-model-accept-generic", map[string]interface{}{ 446 "classic": "true", 447 "store": "alt-store", 448 // accept generic as well to sign serials for this 449 "serial-authority": []interface{}{"generic"}, 450 }) 451 452 devicestatetest.MockGadget(c, s.state, "gadget", snap.R(2), nil) 453 454 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 455 Brand: "my-brand", 456 Model: "my-model-accept-generic", 457 }) 458 459 // avoid full seeding 460 s.seeding() 461 462 // runs the whole device registration process 463 s.state.Unlock() 464 s.settle(c) 465 s.state.Lock() 466 467 becomeOperational := s.findBecomeOperationalChange() 468 c.Assert(becomeOperational, NotNil) 469 470 c.Check(becomeOperational.Status().Ready(), Equals, true) 471 c.Check(becomeOperational.Err(), IsNil) 472 473 device, err := devicestatetest.Device(s.state) 474 c.Assert(err, IsNil) 475 c.Check(device.Brand, Equals, "my-brand") 476 c.Check(device.Model, Equals, "my-model-accept-generic") 477 c.Check(device.Serial, Equals, "9999") 478 479 a, err := s.db.Find(asserts.SerialType, map[string]string{ 480 "brand-id": "my-brand", 481 "model": "my-model-accept-generic", 482 "serial": "9999", 483 }) 484 c.Assert(err, IsNil) 485 serial := a.(*asserts.Serial) 486 c.Check(serial.AuthorityID(), Equals, "generic") 487 488 privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID()) 489 c.Assert(err, IsNil) 490 c.Check(privKey, NotNil) 491 492 c.Check(device.KeyID, Equals, privKey.PublicKey().ID()) 493 } 494 495 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationMyBrandMismatchedAuthority(c *C) { 496 r1 := devicestate.MockKeyLength(testKeyLength) 497 defer r1() 498 499 mockServer := s.mockServer(c, "REQID-1", nil) 500 defer mockServer.Close() 501 502 r2 := devicestate.MockBaseStoreURL(mockServer.URL) 503 defer r2() 504 505 // setup state as will be done by first-boot 506 s.state.Lock() 507 defer s.state.Unlock() 508 509 s.makeModelAssertionInState(c, "my-brand", "my-model-accept-generic", map[string]interface{}{ 510 "classic": "true", 511 "store": "alt-store", 512 // no serial-authority set 513 }) 514 515 devicestatetest.MockGadget(c, s.state, "gadget", snap.R(2), nil) 516 517 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 518 Brand: "my-brand", 519 Model: "my-model-accept-generic", 520 }) 521 522 // avoid full seeding 523 s.seeding() 524 525 // runs the whole device registration process 526 s.state.Unlock() 527 s.settle(c) 528 s.state.Lock() 529 530 becomeOperational := s.findBecomeOperationalChange() 531 c.Assert(becomeOperational, NotNil) 532 533 c.Check(becomeOperational.Status().Ready(), Equals, true) 534 c.Check(becomeOperational.Err(), ErrorMatches, `(?s).*obtained serial assertion is signed by authority "generic" different from brand "my-brand" without model assertion with serial-authority set to to allow for them.*`) 535 } 536 537 func (s *deviceMgrSerialSuite) TestDoRequestSerialIdempotentAfterAddSerial(c *C) { 538 privKey, _ := assertstest.GenerateKey(testKeyLength) 539 540 mockServer := s.mockServer(c, "REQID-1", nil) 541 defer mockServer.Close() 542 543 restore := devicestate.MockBaseStoreURL(mockServer.URL) 544 defer restore() 545 546 restore = devicestate.MockRepeatRequestSerial("after-add-serial") 547 defer restore() 548 549 // setup state as done by first-boot/Ensure/doGenerateDeviceKey 550 s.state.Lock() 551 defer s.state.Unlock() 552 553 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 554 "architecture": "amd64", 555 "kernel": "pc-kernel", 556 "gadget": "pc", 557 }) 558 559 devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil) 560 561 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 562 Brand: "canonical", 563 Model: "pc", 564 KeyID: privKey.PublicKey().ID(), 565 }) 566 devicestate.KeypairManager(s.mgr).Put(privKey) 567 568 t := s.state.NewTask("request-serial", "test") 569 chg := s.state.NewChange("become-operational", "...") 570 chg.AddTask(t) 571 572 // avoid full seeding 573 s.seeding() 574 575 s.state.Unlock() 576 s.se.Ensure() 577 s.se.Wait() 578 s.state.Lock() 579 580 c.Check(chg.Status(), Equals, state.DoingStatus) 581 c.Check(chg.Err(), IsNil) 582 device, err := devicestatetest.Device(s.state) 583 c.Check(err, IsNil) 584 _, err = s.db.Find(asserts.SerialType, map[string]string{ 585 "brand-id": "canonical", 586 "model": "pc", 587 "serial": "9999", 588 }) 589 c.Assert(err, IsNil) 590 591 ok := false 592 select { 593 case <-s.mgr.Registered(): 594 default: 595 ok = true 596 } 597 c.Check(ok, Equals, true) 598 599 s.state.Unlock() 600 s.se.Ensure() 601 s.se.Wait() 602 s.state.Lock() 603 604 // Repeated handler run but set original serial. 605 c.Check(chg.Status(), Equals, state.DoneStatus) 606 device, err = devicestatetest.Device(s.state) 607 c.Check(err, IsNil) 608 c.Check(device.Serial, Equals, "9999") 609 610 ok = false 611 select { 612 case <-s.mgr.Registered(): 613 ok = true 614 case <-time.After(5 * time.Second): 615 c.Fatal("should have been marked registered") 616 } 617 c.Check(ok, Equals, true) 618 } 619 620 func (s *deviceMgrSerialSuite) TestDoRequestSerialIdempotentAfterGotSerial(c *C) { 621 privKey, _ := assertstest.GenerateKey(testKeyLength) 622 623 mockServer := s.mockServer(c, "REQID-1", nil) 624 defer mockServer.Close() 625 626 restore := devicestate.MockBaseStoreURL(mockServer.URL) 627 defer restore() 628 629 restore = devicestate.MockRepeatRequestSerial("after-got-serial") 630 defer restore() 631 632 // setup state as done by first-boot/Ensure/doGenerateDeviceKey 633 s.state.Lock() 634 defer s.state.Unlock() 635 636 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 637 "architecture": "amd64", 638 "kernel": "pc-kernel", 639 "gadget": "pc", 640 }) 641 642 devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil) 643 644 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 645 Brand: "canonical", 646 Model: "pc", 647 KeyID: privKey.PublicKey().ID(), 648 }) 649 devicestate.KeypairManager(s.mgr).Put(privKey) 650 651 t := s.state.NewTask("request-serial", "test") 652 chg := s.state.NewChange("become-operational", "...") 653 chg.AddTask(t) 654 655 // avoid full seeding 656 s.seeding() 657 658 s.state.Unlock() 659 s.se.Ensure() 660 s.se.Wait() 661 s.state.Lock() 662 663 c.Check(chg.Status(), Equals, state.DoingStatus) 664 _, err := devicestatetest.Device(s.state) 665 c.Check(err, IsNil) 666 _, err = s.db.Find(asserts.SerialType, map[string]string{ 667 "brand-id": "canonical", 668 "model": "pc", 669 "serial": "9999", 670 }) 671 c.Assert(asserts.IsNotFound(err), Equals, true) 672 673 s.state.Unlock() 674 s.se.Ensure() 675 s.se.Wait() 676 s.state.Lock() 677 678 // Repeated handler run but set original serial. 679 c.Check(chg.Status(), Equals, state.DoneStatus) 680 c.Check(chg.Err(), IsNil) 681 device, err := devicestatetest.Device(s.state) 682 c.Check(err, IsNil) 683 c.Check(device.Serial, Equals, "9999") 684 } 685 686 func (s *deviceMgrSerialSuite) TestDoRequestSerialErrorsOnNoHost(c *C) { 687 if os.Getenv("http_proxy") != "" { 688 c.Skip("cannot run test when http proxy is in use, the error pattern is different") 689 } 690 691 const nonexistent_host = "nowhere.nowhere.test" 692 693 // check internet access 694 _, err := net.LookupHost(nonexistent_host) 695 if netErr, ok := err.(net.Error); !ok || netErr.Temporary() { 696 c.Skip("cannot run test with no internet access, the error pattern is different") 697 } 698 699 privKey, _ := assertstest.GenerateKey(testKeyLength) 700 701 nowhere := "http://" + nonexistent_host 702 703 restore := devicestate.MockBaseStoreURL(nowhere) 704 defer restore() 705 706 // setup state as done by first-boot/Ensure/doGenerateDeviceKey 707 s.state.Lock() 708 defer s.state.Unlock() 709 710 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 711 "architecture": "amd64", 712 "kernel": "pc-kernel", 713 "gadget": "pc", 714 }) 715 716 devicestatetest.MockGadget(c, s.state, "gadget", snap.R(2), nil) 717 718 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 719 Brand: "canonical", 720 Model: "pc", 721 KeyID: privKey.PublicKey().ID(), 722 }) 723 devicestate.KeypairManager(s.mgr).Put(privKey) 724 725 t := s.state.NewTask("request-serial", "test") 726 chg := s.state.NewChange("become-operational", "...") 727 chg.AddTask(t) 728 729 // avoid full seeding 730 s.seeding() 731 732 s.state.Unlock() 733 s.se.Ensure() 734 s.se.Wait() 735 s.state.Lock() 736 737 c.Check(chg.Status(), Equals, state.ErrorStatus) 738 } 739 740 func (s *deviceMgrSerialSuite) TestDoRequestSerialMaxTentatives(c *C) { 741 privKey, _ := assertstest.GenerateKey(testKeyLength) 742 743 // immediate 744 r := devicestate.MockRetryInterval(0) 745 defer r() 746 747 r = devicestate.MockMaxTentatives(2) 748 defer r() 749 750 // this will trigger a reply 501 in the mock server 751 mockServer := s.mockServer(c, devicestatetest.ReqIDFailID501, nil) 752 defer mockServer.Close() 753 754 restore := devicestate.MockBaseStoreURL(mockServer.URL) 755 defer restore() 756 757 restore = devicestate.MockRepeatRequestSerial("after-add-serial") 758 defer restore() 759 760 // setup state as done by first-boot/Ensure/doGenerateDeviceKey 761 s.state.Lock() 762 defer s.state.Unlock() 763 764 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 765 "architecture": "amd64", 766 "kernel": "pc-kernel", 767 "gadget": "pc", 768 }) 769 770 devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil) 771 772 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 773 Brand: "canonical", 774 Model: "pc", 775 KeyID: privKey.PublicKey().ID(), 776 }) 777 devicestate.KeypairManager(s.mgr).Put(privKey) 778 779 t := s.state.NewTask("request-serial", "test") 780 chg := s.state.NewChange("become-operational", "...") 781 chg.AddTask(t) 782 783 // avoid full seeding 784 s.seeding() 785 786 s.state.Unlock() 787 s.se.Ensure() 788 s.se.Wait() 789 s.state.Lock() 790 791 c.Check(chg.Status(), Equals, state.DoingStatus) 792 793 s.state.Unlock() 794 s.se.Ensure() 795 s.se.Wait() 796 s.state.Lock() 797 798 c.Check(chg.Status(), Equals, state.ErrorStatus) 799 c.Check(chg.Err(), ErrorMatches, `(?s).*cannot retrieve request-id for making a request for a serial: unexpected status 501.*`) 800 } 801 802 type simulateNoNetRoundTripper struct{} 803 804 func (s *simulateNoNetRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { 805 return nil, &net.OpError{ 806 Op: "dial", 807 Net: "tcp", 808 Addr: &net.TCPAddr{IP: net.IPv4(10, 0, 0, 2), Port: 80}, 809 Err: &os.SyscallError{ 810 Syscall: "connect", 811 Err: syscall.ENETUNREACH, 812 }, 813 } 814 } 815 816 func (s *deviceMgrSerialSuite) TestDoRequestSerialNoNetwork(c *C) { 817 s.testDoRequestSerialKeepsRetrying(c, &simulateNoNetRoundTripper{}) 818 } 819 820 type simulateNoDNSRoundTripper struct{} 821 822 func (s *simulateNoDNSRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { 823 return nil, &net.OpError{ 824 Op: "dial", 825 Net: "tcp", 826 Err: &net.DNSError{ 827 Err: "Temporary failure in name resolution", 828 Name: "www.ubuntu.com", 829 Server: "", 830 IsTemporary: true, 831 }, 832 } 833 } 834 835 func (s *deviceMgrSerialSuite) TestDoRequestSerialNoReachableDNS(c *C) { 836 s.testDoRequestSerialKeepsRetrying(c, &simulateNoDNSRoundTripper{}) 837 } 838 839 func (s *deviceMgrSerialSuite) testDoRequestSerialKeepsRetrying(c *C, rt http.RoundTripper) { 840 privKey, _ := assertstest.GenerateKey(testKeyLength) 841 842 // immediate 843 r := devicestate.MockRetryInterval(0) 844 defer r() 845 846 // set a low maxRetry value 847 r = devicestate.MockMaxTentatives(3) 848 defer r() 849 850 mockServer := s.mockServer(c, "REQID-1", nil) 851 defer mockServer.Close() 852 853 restore := devicestate.MockBaseStoreURL(mockServer.URL) 854 defer restore() 855 856 restore = devicestate.MockRepeatRequestSerial("after-add-serial") 857 defer restore() 858 859 restore = devicestate.MockHttputilNewHTTPClient(func(opts *httputil.ClientOptions) *http.Client { 860 c.Check(opts.ProxyConnectHeader, NotNil) 861 return &http.Client{Transport: rt} 862 }) 863 defer restore() 864 865 // setup state as done by first-boot/Ensure/doGenerateDeviceKey 866 s.state.Lock() 867 defer s.state.Unlock() 868 869 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 870 "architecture": "amd64", 871 "kernel": "pc-kernel", 872 "gadget": "pc", 873 }) 874 875 devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil) 876 877 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 878 Brand: "canonical", 879 Model: "pc", 880 KeyID: privKey.PublicKey().ID(), 881 }) 882 devicestate.KeypairManager(s.mgr).Put(privKey) 883 884 t := s.state.NewTask("request-serial", "test") 885 chg := s.state.NewChange("become-operational", "...") 886 chg.AddTask(t) 887 888 // avoid full seeding 889 s.seeding() 890 891 // ensure we keep trying even if we are well above maxTentative 892 for i := 0; i < 10; i++ { 893 s.state.Unlock() 894 s.se.Ensure() 895 s.se.Wait() 896 s.state.Lock() 897 898 c.Check(chg.Status(), Equals, state.DoingStatus) 899 c.Check(chg.Err(), IsNil) 900 } 901 902 c.Check(chg.Status(), Equals, state.DoingStatus) 903 904 var nTentatives int 905 err := t.Get("pre-poll-tentatives", &nTentatives) 906 c.Assert(err, IsNil) 907 c.Check(nTentatives, Equals, 0) 908 } 909 910 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationPollHappy(c *C) { 911 r1 := devicestate.MockKeyLength(testKeyLength) 912 defer r1() 913 914 mockServer := s.mockServer(c, devicestatetest.ReqIDPoll, nil) 915 defer mockServer.Close() 916 917 r2 := devicestate.MockBaseStoreURL(mockServer.URL) 918 defer r2() 919 920 // immediately 921 r3 := devicestate.MockRetryInterval(0) 922 defer r3() 923 924 // setup state as will be done by first-boot 925 s.state.Lock() 926 defer s.state.Unlock() 927 928 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 929 "architecture": "amd64", 930 "kernel": "pc-kernel", 931 "gadget": "pc", 932 }) 933 934 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 935 Brand: "canonical", 936 Model: "pc", 937 }) 938 939 devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil) 940 // mark as seeded 941 s.state.Set("seeded", true) 942 943 // runs the whole device registration process with polling 944 s.state.Unlock() 945 s.settle(c) 946 s.state.Lock() 947 948 becomeOperational := s.findBecomeOperationalChange() 949 c.Assert(becomeOperational, NotNil) 950 951 // needs 3 more Retry passes of polling 952 for i := 0; i < 3; i++ { 953 s.state.Unlock() 954 s.settle(c) 955 s.state.Lock() 956 } 957 958 c.Check(becomeOperational.Status().Ready(), Equals, true) 959 c.Check(becomeOperational.Err(), IsNil) 960 961 device, err := devicestatetest.Device(s.state) 962 c.Assert(err, IsNil) 963 c.Check(device.Brand, Equals, "canonical") 964 c.Check(device.Model, Equals, "pc") 965 c.Check(device.Serial, Equals, "10002") 966 967 a, err := s.db.Find(asserts.SerialType, map[string]string{ 968 "brand-id": "canonical", 969 "model": "pc", 970 "serial": "10002", 971 }) 972 c.Assert(err, IsNil) 973 serial := a.(*asserts.Serial) 974 975 privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID()) 976 c.Assert(err, IsNil) 977 c.Check(privKey, NotNil) 978 979 c.Check(device.KeyID, Equals, privKey.PublicKey().ID()) 980 } 981 982 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappyPrepareDeviceHook(c *C) { 983 r1 := devicestate.MockKeyLength(testKeyLength) 984 defer r1() 985 986 bhv := &devicestatetest.DeviceServiceBehavior{ 987 RequestIDURLPath: "/svc/request-id", 988 SerialURLPath: "/svc/serial", 989 } 990 bhv.PostPreflight = func(c *C, bhv *devicestatetest.DeviceServiceBehavior, w http.ResponseWriter, r *http.Request) { 991 c.Check(r.Header.Get("X-Extra-Header"), Equals, "extra") 992 } 993 994 mockServer := s.mockServer(c, "REQID-1", bhv) 995 defer mockServer.Close() 996 997 // setup state as will be done by first-boot 998 // & have a gadget with a prepare-device hook 999 s.state.Lock() 1000 defer s.state.Unlock() 1001 1002 pDBhv := &devicestatetest.PrepareDeviceBehavior{ 1003 DeviceSvcURL: mockServer.URL + "/svc/", 1004 Headers: map[string]string{ 1005 "x-extra-header": "extra", 1006 }, 1007 RegBody: map[string]string{ 1008 "mac": "00:00:00:00:ff:00", 1009 }, 1010 ProposedSerial: "Y9999", 1011 } 1012 1013 r2 := devicestatetest.MockGadget(c, s.state, "gadget", snap.R(2), pDBhv) 1014 defer r2() 1015 1016 // as device-service.url is set, should not need to do this but just in case 1017 r3 := devicestate.MockBaseStoreURL(mockServer.URL + "/direct/baad/") 1018 defer r3() 1019 1020 s.makeModelAssertionInState(c, "canonical", "pc2", map[string]interface{}{ 1021 "architecture": "amd64", 1022 "kernel": "pc-kernel", 1023 "gadget": "gadget", 1024 }) 1025 1026 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1027 Brand: "canonical", 1028 Model: "pc2", 1029 }) 1030 1031 // avoid full seeding 1032 s.seeding() 1033 1034 // runs the whole device registration process, note that the 1035 // device is not seeded yet 1036 s.state.Unlock() 1037 s.settle(c) 1038 s.state.Lock() 1039 1040 // without a seeded device, there is no become-operational change 1041 becomeOperational := s.findBecomeOperationalChange() 1042 c.Assert(becomeOperational, IsNil) 1043 1044 // now mark it as seeded 1045 s.state.Set("seeded", true) 1046 // and run the device registration again 1047 s.state.Unlock() 1048 s.settle(c) 1049 s.state.Lock() 1050 1051 becomeOperational = s.findBecomeOperationalChange() 1052 c.Assert(becomeOperational, NotNil) 1053 1054 c.Check(becomeOperational.Status().Ready(), Equals, true) 1055 c.Check(becomeOperational.Err(), IsNil) 1056 1057 device, err := devicestatetest.Device(s.state) 1058 c.Assert(err, IsNil) 1059 c.Check(device.Brand, Equals, "canonical") 1060 c.Check(device.Model, Equals, "pc2") 1061 c.Check(device.Serial, Equals, "Y9999") 1062 1063 a, err := s.db.Find(asserts.SerialType, map[string]string{ 1064 "brand-id": "canonical", 1065 "model": "pc2", 1066 "serial": "Y9999", 1067 }) 1068 c.Assert(err, IsNil) 1069 serial := a.(*asserts.Serial) 1070 1071 var details map[string]interface{} 1072 err = yaml.Unmarshal(serial.Body(), &details) 1073 c.Assert(err, IsNil) 1074 1075 c.Check(details, DeepEquals, map[string]interface{}{ 1076 "mac": "00:00:00:00:ff:00", 1077 }) 1078 1079 privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID()) 1080 c.Assert(err, IsNil) 1081 c.Check(privKey, NotNil) 1082 1083 c.Check(device.KeyID, Equals, privKey.PublicKey().ID()) 1084 } 1085 1086 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappyWithHookAndNewProxy(c *C) { 1087 s.testFullDeviceRegistrationHappyWithHookAndProxy(c, true) 1088 } 1089 1090 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationHappyWithHookAndOldProxy(c *C) { 1091 s.testFullDeviceRegistrationHappyWithHookAndProxy(c, false) 1092 } 1093 1094 func (s *deviceMgrSerialSuite) testFullDeviceRegistrationHappyWithHookAndProxy(c *C, newEnough bool) { 1095 r1 := devicestate.MockKeyLength(testKeyLength) 1096 defer r1() 1097 1098 var reqID string 1099 var storeVersion string 1100 head := func(c *C, bhv *devicestatetest.DeviceServiceBehavior, w http.ResponseWriter, r *http.Request) { 1101 w.Header().Set("Snap-Store-Version", storeVersion) 1102 } 1103 bhv := &devicestatetest.DeviceServiceBehavior{ 1104 Head: head, 1105 } 1106 svcPath := "/svc/" 1107 if newEnough { 1108 reqID = "REQID-42" 1109 storeVersion = "6" 1110 bhv.PostPreflight = func(c *C, bhv *devicestatetest.DeviceServiceBehavior, w http.ResponseWriter, r *http.Request) { 1111 c.Check(r.Header.Get("X-Snap-Device-Service-URL"), Matches, "http://[^/]*/bad/svc/") 1112 c.Check(r.Header.Get("X-Extra-Header"), Equals, "extra") 1113 } 1114 svcPath = "/bad/svc/" 1115 } else { 1116 reqID = "REQID-41" 1117 storeVersion = "5" 1118 bhv.RequestIDURLPath = "/svc/request-id" 1119 bhv.SerialURLPath = "/svc/serial" 1120 bhv.PostPreflight = func(c *C, bhv *devicestatetest.DeviceServiceBehavior, w http.ResponseWriter, r *http.Request) { 1121 c.Check(r.Header.Get("X-Extra-Header"), Equals, "extra") 1122 } 1123 } 1124 1125 mockServer := s.mockServer(c, reqID, bhv) 1126 defer mockServer.Close() 1127 1128 // setup state as will be done by first-boot 1129 // & have a gadget with a prepare-device hook 1130 s.state.Lock() 1131 defer s.state.Unlock() 1132 1133 pDBhv := &devicestatetest.PrepareDeviceBehavior{ 1134 DeviceSvcURL: mockServer.URL + svcPath, 1135 Headers: map[string]string{ 1136 "x-extra-header": "extra", 1137 }, 1138 } 1139 r2 := devicestatetest.MockGadget(c, s.state, "gadget", snap.R(2), pDBhv) 1140 defer r2() 1141 1142 // as device-service.url is set, should not need to do this but just in case 1143 r3 := devicestate.MockBaseStoreURL(mockServer.URL + "/direct/baad/") 1144 defer r3() 1145 1146 tr := config.NewTransaction(s.state) 1147 c.Assert(tr.Set("core", "proxy.store", "foo"), IsNil) 1148 tr.Commit() 1149 operatorAcct := assertstest.NewAccount(s.storeSigning, "foo-operator", nil, "") 1150 1151 // have a store assertion. 1152 stoAs, err := s.storeSigning.Sign(asserts.StoreType, map[string]interface{}{ 1153 "store": "foo", 1154 "url": mockServer.URL, 1155 "operator-id": operatorAcct.AccountID(), 1156 "timestamp": time.Now().Format(time.RFC3339), 1157 }, nil, "") 1158 c.Assert(err, IsNil) 1159 1160 assertstatetest.AddMany(s.state, operatorAcct, stoAs) 1161 1162 s.makeModelAssertionInState(c, "canonical", "pc2", map[string]interface{}{ 1163 "architecture": "amd64", 1164 "kernel": "pc-kernel", 1165 "gadget": "gadget", 1166 }) 1167 1168 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1169 Brand: "canonical", 1170 Model: "pc2", 1171 }) 1172 1173 // mark it as seeded 1174 s.state.Set("seeded", true) 1175 1176 // runs the whole device registration process 1177 s.state.Unlock() 1178 s.settle(c) 1179 s.state.Lock() 1180 1181 becomeOperational := s.findBecomeOperationalChange() 1182 c.Assert(becomeOperational, NotNil) 1183 1184 c.Check(becomeOperational.Status().Ready(), Equals, true) 1185 c.Check(becomeOperational.Err(), IsNil) 1186 1187 device, err := devicestatetest.Device(s.state) 1188 c.Assert(err, IsNil) 1189 c.Check(device.Brand, Equals, "canonical") 1190 c.Check(device.Model, Equals, "pc2") 1191 c.Check(device.Serial, Equals, "9999") 1192 1193 a, err := s.db.Find(asserts.SerialType, map[string]string{ 1194 "brand-id": "canonical", 1195 "model": "pc2", 1196 "serial": "9999", 1197 }) 1198 c.Assert(err, IsNil) 1199 serial := a.(*asserts.Serial) 1200 1201 privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID()) 1202 c.Assert(err, IsNil) 1203 c.Check(privKey, NotNil) 1204 1205 c.Check(device.KeyID, Equals, privKey.PublicKey().ID()) 1206 } 1207 1208 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationErrorBackoff(c *C) { 1209 r1 := devicestate.MockKeyLength(testKeyLength) 1210 defer r1() 1211 1212 bhv := &devicestatetest.DeviceServiceBehavior{} 1213 mockServer := s.mockServer(c, devicestatetest.ReqIDBadRequest, bhv) 1214 defer mockServer.Close() 1215 1216 r2 := devicestate.MockBaseStoreURL(mockServer.URL) 1217 defer r2() 1218 1219 // setup state as will be done by first-boot 1220 s.state.Lock() 1221 defer s.state.Unlock() 1222 1223 // sanity 1224 c.Check(devicestate.EnsureOperationalAttempts(s.state), Equals, 0) 1225 1226 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 1227 "architecture": "amd64", 1228 "kernel": "pc-kernel", 1229 "gadget": "pc", 1230 }) 1231 1232 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1233 Brand: "canonical", 1234 Model: "pc", 1235 }) 1236 1237 devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil) 1238 // mark as seeded 1239 s.state.Set("seeded", true) 1240 1241 // try the whole device registration process 1242 s.state.Unlock() 1243 s.settle(c) 1244 s.state.Lock() 1245 1246 becomeOperational := s.findBecomeOperationalChange() 1247 c.Assert(becomeOperational, NotNil) 1248 firstTryID := becomeOperational.ID() 1249 1250 c.Check(becomeOperational.Status().Ready(), Equals, true) 1251 c.Check(becomeOperational.Err(), ErrorMatches, `(?s).*cannot deliver device serial request: bad serial-request.*`) 1252 1253 device, err := devicestatetest.Device(s.state) 1254 c.Assert(err, IsNil) 1255 c.Check(device.KeyID, Not(Equals), "") 1256 keyID := device.KeyID 1257 1258 c.Check(devicestate.EnsureOperationalShouldBackoff(s.mgr, time.Now()), Equals, true) 1259 c.Check(devicestate.EnsureOperationalShouldBackoff(s.mgr, time.Now().Add(6*time.Minute)), Equals, false) 1260 c.Check(devicestate.EnsureOperationalAttempts(s.state), Equals, 1) 1261 1262 // try again the whole device registration process 1263 bhv.ReqID = "REQID-1" 1264 devicestate.SetLastBecomeOperationalAttempt(s.mgr, time.Now().Add(-15*time.Minute)) 1265 s.state.Unlock() 1266 s.settle(c) 1267 s.state.Lock() 1268 1269 becomeOperational = s.findBecomeOperationalChange(firstTryID) 1270 c.Assert(becomeOperational, NotNil) 1271 1272 c.Check(becomeOperational.Status().Ready(), Equals, true) 1273 c.Check(becomeOperational.Err(), IsNil) 1274 1275 c.Check(devicestate.EnsureOperationalAttempts(s.state), Equals, 2) 1276 1277 device, err = devicestatetest.Device(s.state) 1278 c.Assert(err, IsNil) 1279 c.Check(device.KeyID, Equals, keyID) 1280 c.Check(device.Serial, Equals, "10000") 1281 } 1282 1283 func (s *deviceMgrSerialSuite) TestEnsureBecomeOperationalShouldBackoff(c *C) { 1284 t0 := time.Now() 1285 c.Check(devicestate.EnsureOperationalShouldBackoff(s.mgr, t0), Equals, false) 1286 c.Check(devicestate.BecomeOperationalBackoff(s.mgr), Equals, 5*time.Minute) 1287 1288 backoffs := []time.Duration{5, 10, 20, 40, 80, 160, 320, 640, 1440, 1440} 1289 t1 := t0 1290 for _, m := range backoffs { 1291 c.Check(devicestate.EnsureOperationalShouldBackoff(s.mgr, t1.Add(time.Duration(m-1)*time.Minute)), Equals, true) 1292 1293 t1 = t1.Add(time.Duration(m+1) * time.Minute) 1294 c.Check(devicestate.EnsureOperationalShouldBackoff(s.mgr, t1), Equals, false) 1295 m *= 2 1296 if m > (12 * 60) { 1297 m = 24 * 60 1298 } 1299 c.Check(devicestate.BecomeOperationalBackoff(s.mgr), Equals, m*time.Minute) 1300 } 1301 } 1302 1303 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationMismatchedSerial(c *C) { 1304 r1 := devicestate.MockKeyLength(testKeyLength) 1305 defer r1() 1306 1307 mockServer := s.mockServer(c, devicestatetest.ReqIDSerialWithBadModel, nil) 1308 defer mockServer.Close() 1309 1310 r2 := devicestate.MockBaseStoreURL(mockServer.URL) 1311 defer r2() 1312 1313 // setup state as will be done by first-boot 1314 s.state.Lock() 1315 defer s.state.Unlock() 1316 1317 // sanity 1318 c.Check(devicestate.EnsureOperationalAttempts(s.state), Equals, 0) 1319 1320 devicestatetest.MockGadget(c, s.state, "gadget", snap.R(2), nil) 1321 1322 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 1323 "architecture": "amd64", 1324 "kernel": "pc-kernel", 1325 "gadget": "gadget", 1326 }) 1327 1328 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1329 Brand: "canonical", 1330 Model: "pc", 1331 }) 1332 1333 // mark as seeded 1334 s.state.Set("seeded", true) 1335 1336 // try the whole device registration process 1337 s.state.Unlock() 1338 s.settle(c) 1339 s.state.Lock() 1340 1341 becomeOperational := s.findBecomeOperationalChange() 1342 c.Assert(becomeOperational, NotNil) 1343 1344 c.Check(becomeOperational.Status().Ready(), Equals, true) 1345 c.Check(becomeOperational.Err(), ErrorMatches, `(?s).*obtained serial assertion does not match provided device identity information.*`) 1346 } 1347 1348 func (s *deviceMgrSerialSuite) TestModelAndSerial(c *C) { 1349 s.state.Lock() 1350 defer s.state.Unlock() 1351 // nothing in the state 1352 _, err := s.mgr.Model() 1353 c.Check(err, Equals, state.ErrNoState) 1354 _, err = s.mgr.Serial() 1355 c.Check(err, Equals, state.ErrNoState) 1356 1357 // just brand and model 1358 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1359 Brand: "canonical", 1360 Model: "pc", 1361 }) 1362 _, err = s.mgr.Model() 1363 c.Check(err, Equals, state.ErrNoState) 1364 _, err = s.mgr.Serial() 1365 c.Check(err, Equals, state.ErrNoState) 1366 1367 // have a model assertion 1368 model := s.brands.Model("canonical", "pc", map[string]interface{}{ 1369 "gadget": "pc", 1370 "kernel": "kernel", 1371 "architecture": "amd64", 1372 }) 1373 assertstatetest.AddMany(s.state, model) 1374 1375 mod, err := s.mgr.Model() 1376 c.Assert(err, IsNil) 1377 c.Assert(mod.BrandID(), Equals, "canonical") 1378 1379 _, err = s.mgr.Serial() 1380 c.Check(err, Equals, state.ErrNoState) 1381 1382 // have a serial as well 1383 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1384 Brand: "canonical", 1385 Model: "pc", 1386 Serial: "8989", 1387 }) 1388 _, err = s.mgr.Model() 1389 c.Assert(err, IsNil) 1390 _, err = s.mgr.Serial() 1391 c.Check(err, Equals, state.ErrNoState) 1392 1393 // have a serial assertion 1394 s.makeSerialAssertionInState(c, "canonical", "pc", "8989") 1395 1396 _, err = s.mgr.Model() 1397 c.Assert(err, IsNil) 1398 ser, err := s.mgr.Serial() 1399 c.Assert(err, IsNil) 1400 c.Check(ser.Serial(), Equals, "8989") 1401 } 1402 1403 func (s *deviceMgrSerialSuite) TestStoreContextBackendSetDevice(c *C) { 1404 s.state.Lock() 1405 defer s.state.Unlock() 1406 1407 scb := s.mgr.StoreContextBackend() 1408 1409 device, err := scb.Device() 1410 c.Check(err, IsNil) 1411 c.Check(device, DeepEquals, &auth.DeviceState{}) 1412 1413 err = scb.SetDevice(&auth.DeviceState{Brand: "some-brand"}) 1414 c.Check(err, IsNil) 1415 device, err = scb.Device() 1416 c.Check(err, IsNil) 1417 c.Check(device, DeepEquals, &auth.DeviceState{Brand: "some-brand"}) 1418 } 1419 1420 func (s *deviceMgrSerialSuite) TestStoreContextBackendModelAndSerial(c *C) { 1421 s.state.Lock() 1422 defer s.state.Unlock() 1423 1424 scb := s.mgr.StoreContextBackend() 1425 1426 // nothing in the state 1427 _, err := scb.Model() 1428 c.Check(err, Equals, state.ErrNoState) 1429 _, err = scb.Serial() 1430 c.Check(err, Equals, state.ErrNoState) 1431 1432 // just brand and model 1433 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1434 Brand: "canonical", 1435 Model: "pc", 1436 }) 1437 _, err = scb.Model() 1438 c.Check(err, Equals, state.ErrNoState) 1439 _, err = scb.Serial() 1440 c.Check(err, Equals, state.ErrNoState) 1441 1442 // have a model assertion 1443 model := s.brands.Model("canonical", "pc", map[string]interface{}{ 1444 "gadget": "pc", 1445 "kernel": "kernel", 1446 "architecture": "amd64", 1447 }) 1448 assertstatetest.AddMany(s.state, model) 1449 1450 mod, err := scb.Model() 1451 c.Assert(err, IsNil) 1452 c.Assert(mod.BrandID(), Equals, "canonical") 1453 1454 _, err = scb.Serial() 1455 c.Check(err, Equals, state.ErrNoState) 1456 1457 // have a serial as well 1458 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1459 Brand: "canonical", 1460 Model: "pc", 1461 Serial: "8989", 1462 }) 1463 _, err = scb.Model() 1464 c.Assert(err, IsNil) 1465 _, err = scb.Serial() 1466 c.Check(err, Equals, state.ErrNoState) 1467 1468 // have a serial assertion 1469 s.makeSerialAssertionInState(c, "canonical", "pc", "8989") 1470 1471 _, err = scb.Model() 1472 c.Assert(err, IsNil) 1473 ser, err := scb.Serial() 1474 c.Assert(err, IsNil) 1475 c.Check(ser.Serial(), Equals, "8989") 1476 } 1477 1478 var ( 1479 devKey, _ = assertstest.GenerateKey(testKeyLength) 1480 ) 1481 1482 func (s *deviceMgrSerialSuite) TestStoreContextBackendDeviceSessionRequestParams(c *C) { 1483 s.state.Lock() 1484 defer s.state.Unlock() 1485 1486 // set model as seeding would 1487 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 1488 "architecture": "amd64", 1489 "kernel": "pc-kernel", 1490 "gadget": "pc", 1491 }) 1492 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1493 Brand: "canonical", 1494 Model: "pc", 1495 }) 1496 1497 scb := s.mgr.StoreContextBackend() 1498 1499 // nothing there 1500 _, err := scb.SignDeviceSessionRequest(nil, "NONCE-1") 1501 c.Check(err, ErrorMatches, "internal error: cannot sign a session request without a serial") 1502 1503 // setup state as done by device initialisation 1504 encDevKey, err := asserts.EncodePublicKey(devKey.PublicKey()) 1505 c.Check(err, IsNil) 1506 seriala, err := s.storeSigning.Sign(asserts.SerialType, map[string]interface{}{ 1507 "brand-id": "canonical", 1508 "model": "pc", 1509 "serial": "8989", 1510 "device-key": string(encDevKey), 1511 "device-key-sha3-384": devKey.PublicKey().ID(), 1512 "timestamp": time.Now().Format(time.RFC3339), 1513 }, nil, "") 1514 c.Assert(err, IsNil) 1515 assertstatetest.AddMany(s.state, seriala) 1516 serial := seriala.(*asserts.Serial) 1517 1518 _, err = scb.SignDeviceSessionRequest(serial, "NONCE-1") 1519 c.Check(err, ErrorMatches, "internal error: inconsistent state with serial but no device key") 1520 1521 // have a key 1522 devicestate.KeypairManager(s.mgr).Put(devKey) 1523 1524 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1525 Brand: "canonical", 1526 Model: "pc", 1527 Serial: "8989", 1528 KeyID: devKey.PublicKey().ID(), 1529 }) 1530 1531 sessReq, err := scb.SignDeviceSessionRequest(serial, "NONCE-1") 1532 c.Assert(err, IsNil) 1533 1534 // correctly signed with device key 1535 err = asserts.SignatureCheck(sessReq, devKey.PublicKey()) 1536 c.Check(err, IsNil) 1537 1538 c.Check(sessReq.BrandID(), Equals, "canonical") 1539 c.Check(sessReq.Model(), Equals, "pc") 1540 c.Check(sessReq.Serial(), Equals, "8989") 1541 c.Check(sessReq.Nonce(), Equals, "NONCE-1") 1542 } 1543 1544 func (s *deviceMgrSerialSuite) TestStoreContextBackendProxyStore(c *C) { 1545 mockServer := s.mockServer(c, "", nil) 1546 defer mockServer.Close() 1547 s.state.Lock() 1548 defer s.state.Unlock() 1549 1550 scb := s.mgr.StoreContextBackend() 1551 1552 // nothing in the state 1553 _, err := scb.ProxyStore() 1554 c.Check(err, Equals, state.ErrNoState) 1555 1556 // have a store referenced 1557 tr := config.NewTransaction(s.state) 1558 err = tr.Set("core", "proxy.store", "foo") 1559 tr.Commit() 1560 c.Assert(err, IsNil) 1561 1562 _, err = scb.ProxyStore() 1563 c.Check(err, Equals, state.ErrNoState) 1564 1565 operatorAcct := assertstest.NewAccount(s.storeSigning, "foo-operator", nil, "") 1566 1567 // have a store assertion. 1568 stoAs, err := s.storeSigning.Sign(asserts.StoreType, map[string]interface{}{ 1569 "store": "foo", 1570 "operator-id": operatorAcct.AccountID(), 1571 "url": mockServer.URL, 1572 "timestamp": time.Now().Format(time.RFC3339), 1573 }, nil, "") 1574 c.Assert(err, IsNil) 1575 1576 assertstatetest.AddMany(s.state, operatorAcct, stoAs) 1577 1578 sto, err := scb.ProxyStore() 1579 c.Assert(err, IsNil) 1580 c.Assert(sto.Store(), Equals, "foo") 1581 c.Assert(sto.URL().String(), Equals, mockServer.URL) 1582 } 1583 1584 func (s *deviceMgrSerialSuite) TestInitialRegistrationContext(c *C) { 1585 s.state.Lock() 1586 defer s.state.Unlock() 1587 1588 // have a model assertion 1589 model, err := s.storeSigning.Sign(asserts.ModelType, map[string]interface{}{ 1590 "series": "16", 1591 "brand-id": "canonical", 1592 "model": "pc", 1593 "gadget": "pc-gadget", 1594 "kernel": "kernel", 1595 "architecture": "amd64", 1596 "timestamp": time.Now().Format(time.RFC3339), 1597 }, nil, "") 1598 c.Assert(err, IsNil) 1599 err = assertstate.Add(s.state, model) 1600 c.Assert(err, IsNil) 1601 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1602 Brand: "canonical", 1603 Model: "pc", 1604 }) 1605 1606 // TODO: will need to pass in a task later 1607 regCtx, err := devicestate.RegistrationCtx(s.mgr, nil) 1608 c.Assert(err, IsNil) 1609 c.Assert(regCtx, NotNil) 1610 1611 c.Check(regCtx.ForRemodeling(), Equals, false) 1612 1613 device, err := regCtx.Device() 1614 c.Check(err, IsNil) 1615 c.Check(device, DeepEquals, &auth.DeviceState{ 1616 Brand: "canonical", 1617 Model: "pc", 1618 }) 1619 1620 c.Check(regCtx.Model(), DeepEquals, model) 1621 1622 c.Check(regCtx.GadgetForSerialRequestConfig(), Equals, "pc-gadget") 1623 c.Check(regCtx.SerialRequestExtraHeaders(), HasLen, 0) 1624 ancillary := regCtx.SerialRequestAncillaryAssertions() 1625 c.Check(ancillary, HasLen, 1) 1626 reqMod, ok := ancillary[0].(*asserts.Model) 1627 c.Assert(ok, Equals, true) 1628 c.Check(reqMod, DeepEquals, model) 1629 1630 } 1631 1632 func (s *deviceMgrSerialSuite) TestNewEnoughProxyParse(c *C) { 1633 s.state.Lock() 1634 defer s.state.Unlock() 1635 1636 log, restore := logger.MockLogger() 1637 defer restore() 1638 os.Setenv("SNAPD_DEBUG", "1") 1639 defer os.Unsetenv("SNAPD_DEBUG") 1640 1641 badURL := &url.URL{Opaque: "%a"} // url.Parse(badURL.String()) needs to fail, which isn't easy :-) 1642 c.Check(devicestate.NewEnoughProxy(s.state, badURL, http.DefaultClient), Equals, false) 1643 c.Check(log.String(), Matches, "(?m).* DEBUG: Cannot check whether proxy store supports a custom serial vault: parse .*") 1644 } 1645 1646 func (s *deviceMgrSerialSuite) TestNewEnoughProxy(c *C) { 1647 s.state.Lock() 1648 defer s.state.Unlock() 1649 1650 expectedUserAgent := snapdenv.UserAgent() 1651 log, restore := logger.MockLogger() 1652 defer restore() 1653 os.Setenv("SNAPD_DEBUG", "1") 1654 defer os.Unsetenv("SNAPD_DEBUG") 1655 1656 expecteds := []string{ 1657 `Head \"?http://\S+\"?: EOF`, 1658 `Head request returned 403 Forbidden.`, 1659 `Bogus Snap-Store-Version header "5pre1".`, 1660 ``, 1661 } 1662 1663 n := 0 1664 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1665 c.Check(r.Header.Get("User-Agent"), Equals, expectedUserAgent) 1666 n++ 1667 switch n { 1668 case 1: 1669 conn, _, err := w.(http.Hijacker).Hijack() 1670 c.Assert(err, IsNil) 1671 conn.Close() 1672 case 2: 1673 w.WriteHeader(403) 1674 case 3: 1675 w.Header().Set("Snap-Store-Version", "5pre1") 1676 w.WriteHeader(200) 1677 case 4: 1678 w.Header().Set("Snap-Store-Version", "5") 1679 w.WriteHeader(200) 1680 case 5: 1681 w.Header().Set("Snap-Store-Version", "6") 1682 w.WriteHeader(200) 1683 default: 1684 c.Errorf("expected %d results, now on %d", len(expecteds), n) 1685 } 1686 })) 1687 defer server.Close() 1688 1689 u, err := url.Parse(server.URL) 1690 c.Assert(err, IsNil) 1691 for _, expected := range expecteds { 1692 log.Reset() 1693 c.Check(devicestate.NewEnoughProxy(s.state, u, http.DefaultClient), Equals, false) 1694 if len(expected) > 0 { 1695 expected = "(?m).* DEBUG: Cannot check whether proxy store supports a custom serial vault: " + expected 1696 } 1697 c.Check(log.String(), Matches, expected) 1698 } 1699 c.Check(n, Equals, len(expecteds)) 1700 1701 // and success at last 1702 log.Reset() 1703 c.Check(devicestate.NewEnoughProxy(s.state, u, http.DefaultClient), Equals, true) 1704 c.Check(log.String(), Equals, "") 1705 c.Check(n, Equals, len(expecteds)+1) 1706 } 1707 1708 func (s *deviceMgrSerialSuite) testDoRequestSerialReregistration(c *C, setAncillary func(origSerial *asserts.Serial)) *state.Task { 1709 mockServer := s.mockServer(c, "REQID-1", nil) 1710 defer mockServer.Close() 1711 1712 restore := devicestate.MockBaseStoreURL(mockServer.URL) 1713 defer restore() 1714 1715 // setup state as after initial registration 1716 s.state.Lock() 1717 defer s.state.Unlock() 1718 1719 s.makeModelAssertionInState(c, "my-brand", "my-model", map[string]interface{}{ 1720 "architecture": "amd64", 1721 "kernel": "pc-kernel", 1722 "gadget": "pc", 1723 }) 1724 1725 devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil) 1726 1727 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1728 Brand: "my-brand", 1729 Model: "my-model", 1730 KeyID: devKey.PublicKey().ID(), 1731 Serial: "9999", 1732 }) 1733 devicestate.KeypairManager(s.mgr).Put(devKey) 1734 1735 // have a serial assertion 1736 serial0 := s.makeSerialAssertionInState(c, "my-brand", "my-model", "9999") 1737 // give a chance to the test to setup returning a stream vs 1738 // just the serial assertion 1739 if setAncillary != nil { 1740 setAncillary(serial0) 1741 } 1742 1743 new := s.brands.Model("rereg-brand", "rereg-model", map[string]interface{}{ 1744 "architecture": "amd64", 1745 "kernel": "pc-kernel", 1746 "gadget": "pc", 1747 }) 1748 cur, err := s.mgr.Model() 1749 c.Assert(err, IsNil) 1750 1751 s.newFakeStore = func(devBE storecontext.DeviceBackend) snapstate.StoreService { 1752 mod, err := devBE.Model() 1753 c.Check(err, IsNil) 1754 if err == nil { 1755 c.Check(mod, DeepEquals, new) 1756 } 1757 return nil 1758 } 1759 1760 remodCtx, err := devicestate.RemodelCtx(s.state, cur, new) 1761 c.Assert(err, IsNil) 1762 c.Check(remodCtx.Kind(), Equals, devicestate.ReregRemodel) 1763 1764 t := s.state.NewTask("request-serial", "test") 1765 chg := s.state.NewChange("remodel", "...") 1766 // associate with context 1767 remodCtx.Init(chg) 1768 chg.AddTask(t) 1769 1770 // sanity 1771 regCtx, err := devicestate.RegistrationCtx(s.mgr, t) 1772 c.Assert(err, IsNil) 1773 c.Check(regCtx, Equals, remodCtx.(devicestate.RegistrationContext)) 1774 1775 // avoid full seeding 1776 s.seeding() 1777 1778 s.state.Unlock() 1779 s.se.Ensure() 1780 s.se.Wait() 1781 s.state.Lock() 1782 1783 return t 1784 } 1785 1786 func (s *deviceMgrSerialSuite) TestDoRequestSerialReregistration(c *C) { 1787 assertstest.AddMany(s.storeSigning, s.brands.AccountsAndKeys("rereg-brand")...) 1788 1789 t := s.testDoRequestSerialReregistration(c, nil) 1790 1791 s.state.Lock() 1792 defer s.state.Unlock() 1793 chg := t.Change() 1794 1795 c.Check(chg.Status(), Equals, state.DoneStatus, Commentf("%s", t.Log())) 1796 c.Check(chg.Err(), IsNil) 1797 device, err := devicestatetest.Device(s.state) 1798 c.Check(err, IsNil) 1799 c.Check(device.Serial, Equals, "9999") 1800 _, err = s.db.Find(asserts.SerialType, map[string]string{ 1801 "brand-id": "rereg-brand", 1802 "model": "rereg-model", 1803 "serial": "9999", 1804 }) 1805 c.Assert(err, IsNil) 1806 } 1807 1808 func (s *deviceMgrSerialSuite) TestDoRequestSerialReregistrationStreamFromService(c *C) { 1809 setAncillary := func(_ *asserts.Serial) { 1810 // sets up such that re-registration returns a stream 1811 // of assertions 1812 s.ancillary = s.brands.AccountsAndKeys("rereg-brand") 1813 } 1814 1815 t := s.testDoRequestSerialReregistration(c, setAncillary) 1816 1817 s.state.Lock() 1818 defer s.state.Unlock() 1819 chg := t.Change() 1820 1821 c.Check(chg.Status(), Equals, state.DoneStatus, Commentf("%s", t.Log())) 1822 c.Check(chg.Err(), IsNil) 1823 device, err := devicestatetest.Device(s.state) 1824 c.Check(err, IsNil) 1825 c.Check(device.Serial, Equals, "9999") 1826 _, err = s.db.Find(asserts.SerialType, map[string]string{ 1827 "brand-id": "rereg-brand", 1828 "model": "rereg-model", 1829 "serial": "9999", 1830 }) 1831 c.Assert(err, IsNil) 1832 } 1833 1834 func (s *deviceMgrSerialSuite) TestDoRequestSerialReregistrationIncompleteStreamFromService(c *C) { 1835 setAncillary := func(_ *asserts.Serial) { 1836 // will produce an incomplete stream! 1837 s.ancillary = s.brands.AccountsAndKeys("rereg-brand")[:1] 1838 } 1839 1840 t := s.testDoRequestSerialReregistration(c, setAncillary) 1841 1842 s.state.Lock() 1843 defer s.state.Unlock() 1844 chg := t.Change() 1845 1846 c.Check(chg.Status(), Equals, state.ErrorStatus, Commentf("%s", t.Log())) 1847 c.Check(chg.Err(), ErrorMatches, `(?ms).*cannot accept stream of assertions from device service:.*`) 1848 } 1849 1850 func (s *deviceMgrSerialSuite) TestDoRequestSerialReregistrationDoubleSerialStreamFromService(c *C) { 1851 setAncillary := func(serial0 *asserts.Serial) { 1852 // will produce a stream with confusingly two serial 1853 // assertions 1854 s.ancillary = s.brands.AccountsAndKeys("rereg-brand") 1855 s.ancillary = append(s.ancillary, serial0) 1856 } 1857 1858 t := s.testDoRequestSerialReregistration(c, setAncillary) 1859 1860 s.state.Lock() 1861 defer s.state.Unlock() 1862 chg := t.Change() 1863 1864 c.Check(chg.Status(), Equals, state.ErrorStatus, Commentf("%s", t.Log())) 1865 c.Check(chg.Err(), ErrorMatches, `(?ms).*cannot accept more than a single device serial assertion from the device service.*`) 1866 } 1867 1868 func (s *deviceMgrSerialSuite) TestDeviceRegistrationNotInInstallMode(c *C) { 1869 st := s.state 1870 // setup state as will be done by first-boot 1871 st.Lock() 1872 s.makeModelAssertionInState(c, "canonical", "pc", map[string]interface{}{ 1873 "architecture": "amd64", 1874 "kernel": "pc-kernel", 1875 "gadget": "pc", 1876 }) 1877 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1878 Brand: "canonical", 1879 Model: "pc", 1880 }) 1881 // mark it as seeded 1882 st.Set("seeded", true) 1883 // set run mode to "install" 1884 devicestate.SetSystemMode(s.mgr, "install") 1885 st.Unlock() 1886 1887 // runs the whole device registration process 1888 // but it will not actually create any changes because 1889 s.settle(c) 1890 1891 st.Lock() 1892 defer st.Unlock() 1893 becomeOperational := s.findBecomeOperationalChange() 1894 c.Assert(becomeOperational, IsNil) 1895 } 1896 1897 func (s *deviceMgrSerialSuite) TestFullDeviceRegistrationUC20Happy(c *C) { 1898 defer sysdb.InjectTrusted([]asserts.Assertion{s.storeSigning.TrustedKey})() 1899 1900 r1 := devicestate.MockKeyLength(testKeyLength) 1901 defer r1() 1902 1903 mockServer := s.mockServer(c, "REQID-1", nil) 1904 defer mockServer.Close() 1905 1906 r2 := devicestate.MockBaseStoreURL(mockServer.URL) 1907 defer r2() 1908 1909 // setup state as will be done by first-boot 1910 s.state.Lock() 1911 defer s.state.Unlock() 1912 1913 s.makeModelAssertionInState(c, "canonical", "pc-20", map[string]interface{}{ 1914 "architecture": "amd64", 1915 // UC20 1916 "base": "core20", 1917 "snaps": []interface{}{ 1918 map[string]interface{}{ 1919 "name": "pc-kernel", 1920 "id": snaptest.AssertedSnapID("oc-kernel"), 1921 "type": "kernel", 1922 "default-channel": "20", 1923 }, 1924 map[string]interface{}{ 1925 "name": "pc", 1926 "id": snaptest.AssertedSnapID("pc"), 1927 "type": "gadget", 1928 "default-channel": "20", 1929 }, 1930 }, 1931 }) 1932 1933 devicestatetest.SetDevice(s.state, &auth.DeviceState{ 1934 Brand: "canonical", 1935 Model: "pc-20", 1936 }) 1937 1938 // save is available 1939 devicestate.SetSaveAvailable(s.mgr, true) 1940 1941 // avoid full seeding 1942 s.seeding() 1943 1944 becomeOperational := s.findBecomeOperationalChange() 1945 c.Check(becomeOperational, IsNil) 1946 1947 devicestatetest.MockGadget(c, s.state, "pc", snap.R(2), nil) 1948 // mark it as seeded 1949 s.state.Set("seeded", true) 1950 // skip boot ok logic 1951 devicestate.SetBootOkRan(s.mgr, true) 1952 1953 // runs the whole device registration process 1954 s.state.Unlock() 1955 s.settle(c) 1956 s.state.Lock() 1957 1958 becomeOperational = s.findBecomeOperationalChange() 1959 c.Assert(becomeOperational, NotNil) 1960 1961 c.Check(becomeOperational.Status().Ready(), Equals, true) 1962 c.Check(becomeOperational.Err(), IsNil) 1963 1964 device, err := devicestatetest.Device(s.state) 1965 c.Assert(err, IsNil) 1966 c.Check(device.Brand, Equals, "canonical") 1967 c.Check(device.Model, Equals, "pc-20") 1968 c.Check(device.Serial, Equals, "9999") 1969 1970 ok := false 1971 select { 1972 case <-s.mgr.Registered(): 1973 ok = true 1974 case <-time.After(5 * time.Second): 1975 c.Fatal("should have been marked registered") 1976 } 1977 c.Check(ok, Equals, true) 1978 1979 a, err := s.db.Find(asserts.SerialType, map[string]string{ 1980 "brand-id": "canonical", 1981 "model": "pc-20", 1982 "serial": "9999", 1983 }) 1984 c.Assert(err, IsNil) 1985 serial := a.(*asserts.Serial) 1986 1987 privKey, err := devicestate.KeypairManager(s.mgr).Get(serial.DeviceKey().ID()) 1988 c.Assert(err, IsNil) 1989 c.Check(privKey, NotNil) 1990 1991 c.Check(device.KeyID, Equals, privKey.PublicKey().ID()) 1992 1993 // check that keypair manager is under save 1994 c.Check(osutil.IsDirectory(filepath.Join(dirs.SnapDeviceSaveDir, "private-keys-v1")), Equals, true) 1995 c.Check(filepath.Join(dirs.SnapDeviceDir, "private-keys-v1"), testutil.FileAbsent) 1996 1997 // check that the serial was saved to the device save assertion db 1998 // as well 1999 savedb, err := sysdb.OpenAt(dirs.SnapDeviceSaveDir) 2000 c.Assert(err, IsNil) 2001 // a copy of model was saved there 2002 _, err = savedb.Find(asserts.ModelType, map[string]string{ 2003 "series": "16", 2004 "brand-id": "canonical", 2005 "model": "pc-20", 2006 }) 2007 c.Assert(err, IsNil) 2008 // a copy of serial was backed up there 2009 _, err = savedb.Find(asserts.SerialType, map[string]string{ 2010 "brand-id": "canonical", 2011 "model": "pc-20", 2012 "serial": "9999", 2013 }) 2014 c.Assert(err, IsNil) 2015 }