Example #1
0
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
}
Example #2
0
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
}