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