func getSerialRequestConfig(t *state.Task) (*serialRequestConfig, error) { gadgetInfo, err := snapstate.GadgetInfo(t.State()) if err != nil { return nil, fmt.Errorf("cannot find gadget snap and its name: %v", err) } gadgetName := gadgetInfo.Name() tr := configstate.NewTransaction(t.State()) var svcURL string err = tr.GetMaybe(gadgetName, "device-service.url", &svcURL) if err != nil { return nil, err } if svcURL != "" { baseURL, err := url.Parse(svcURL) if err != nil { return nil, fmt.Errorf("cannot parse device registration base URL %q: %v", svcURL, err) } var headers map[string]string err = tr.GetMaybe(gadgetName, "device-service.headers", &headers) if err != nil { return nil, err } cfg := serialRequestConfig{ headers: headers, } reqIDURL, err := baseURL.Parse("request-id") if err != nil { return nil, fmt.Errorf("cannot build /request-id URL from %v: %v", baseURL, err) } cfg.requestIDURL = reqIDURL.String() var bodyStr string err = tr.GetMaybe(gadgetName, "registration.body", &bodyStr) if err != nil { return nil, err } cfg.body = []byte(bodyStr) serialURL, err := baseURL.Parse("serial") if err != nil { return nil, fmt.Errorf("cannot build /serial URL from %v: %v", baseURL, err) } cfg.serialRequestURL = serialURL.String() var proposedSerial string err = tr.GetMaybe(gadgetName, "registration.proposed-serial", &proposedSerial) if err != nil { return nil, err } cfg.proposedSerial = proposedSerial return &cfg, nil } return &serialRequestConfig{ requestIDURL: requestIDURL, serialRequestURL: serialRequestURL, }, nil }
func (m *DeviceManager) ensureOperational() error { m.state.Lock() defer m.state.Unlock() device, err := auth.Device(m.state) if err != nil { return err } if device.Serial != "" { // serial is set, we are all set return nil } if device.Brand == "" || device.Model == "" { // need first-boot, loading of model assertion info if release.OnClassic { // TODO: are we going to have model assertions on classic or need will need to cheat here? return nil } // cannot proceed yet, once first boot is done these will be set // and we can pick up from there return nil } if m.changeInFlight("become-operational") { return nil } if serialRequestURL == "" { // cannot do anything actually return nil } gadgetInfo, err := snapstate.GadgetInfo(m.state) if err == state.ErrNoState { // no gadget installed yet, cannot proceed return nil } if err != nil { return err } // XXX: some of these will need to be split and use hooks // retries might need to embrace more than one "task" then, // need to be careful tasks := []*state.Task{} var prepareDevice *state.Task if gadgetInfo.Hooks["prepare-device"] != nil { summary := i18n.G("Run prepare-device hook") hooksup := &hookstate.HookSetup{ Snap: gadgetInfo.Name(), Hook: "prepare-device", } prepareDevice = hookstate.HookTask(m.state, summary, hooksup, nil) tasks = append(tasks, prepareDevice) } genKey := m.state.NewTask("generate-device-key", i18n.G("Generate device key")) if prepareDevice != nil { genKey.WaitFor(prepareDevice) } tasks = append(tasks, genKey) requestSerial := m.state.NewTask("request-serial", i18n.G("Request device serial")) requestSerial.WaitFor(genKey) tasks = append(tasks, requestSerial) chg := m.state.NewChange("become-operational", i18n.G("Initialize device")) chg.AddAll(state.NewTaskSet(tasks...)) return nil }