コード例 #1
0
ファイル: snap.go プロジェクト: clobrano/snappy
// allLocalSnapInfos returns the information about the all current snaps and their SnapStates.
func allLocalSnapInfos(st *state.State) ([]aboutSnap, error) {
	st.Lock()
	defer st.Unlock()

	snapStates, err := snapstate.All(st)
	if err != nil {
		return nil, err
	}
	about := make([]aboutSnap, 0, len(snapStates))

	var firstErr error
	for _, snapState := range snapStates {
		info, err := snapState.CurrentInfo()
		if err != nil {
			// XXX: aggregate instead?
			if firstErr == nil {
				firstErr = err
			}
			continue
		}
		about = append(about, aboutSnap{info, snapState})
	}

	return about, firstErr
}
コード例 #2
0
ファイル: patch5.go プロジェクト: niemeyer/snapd
// patch5:
//  - regenerate generated .service files
func patch5(st *state.State) error {
	log := log{}

	snapStates, err := snapstate.All(st)
	if err != nil {
		return err
	}

	for snapName, snapState := range snapStates {
		if !snapState.Active {
			continue
		}

		info, err := snapState.CurrentInfo()
		if err != nil {
			return err
		}

		if len(info.Apps) == 0 {
			logger.Debugf("patch 5: skipping for %q: no apps", snapName)
			continue
		}

		err = wrappers.StopSnapServices(info, log)
		if err != nil {
			return err
		}

		err = wrappers.AddSnapServices(info, log)
		if err != nil {
			return err
		}

		err = wrappers.StartSnapServices(info, log)
		if err != nil {
			return err
		}

		logger.Noticef("patch 5: %q updated", snapName)
	}

	return nil
}
コード例 #3
0
ファイル: snap.go プロジェクト: pete-woods/snapd
// allLocalSnapInfos returns the information about the all current snaps and their SnapStates.
func allLocalSnapInfos(st *state.State, all bool) ([]aboutSnap, error) {
	st.Lock()
	defer st.Unlock()

	snapStates, err := snapstate.All(st)
	if err != nil {
		return nil, err
	}
	about := make([]aboutSnap, 0, len(snapStates))

	var firstErr error
	for _, snapst := range snapStates {
		var infos []*snap.Info
		var info *snap.Info
		var err error
		if all {
			for _, seq := range snapst.Sequence {
				info, err = snap.ReadInfo(seq.RealName, seq)
				if err != nil {
					break
				}
				infos = append(infos, info)
			}
		} else {
			info, err = snapst.CurrentInfo()
			infos = append(infos, info)
		}

		if err != nil {
			// XXX: aggregate instead?
			if firstErr == nil {
				firstErr = err
			}
			continue
		}
		for _, info := range infos {
			about = append(about, aboutSnap{info, snapst})
		}
	}

	return about, firstErr
}
コード例 #4
0
ファイル: assertmgr.go プロジェクト: niemeyer/snapd
// RefreshSnapDeclarations refetches all the current snap declarations and their prerequisites.
func RefreshSnapDeclarations(s *state.State, userID int) error {
	snapStates, err := snapstate.All(s)
	if err != nil {
		return nil
	}
	fetching := func(f asserts.Fetcher) error {
		for _, snapState := range snapStates {
			info, err := snapState.CurrentInfo()
			if err != nil {
				return err
			}
			if info.SnapID == "" {
				continue
			}
			if err := snapasserts.FetchSnapDeclaration(f, info.SnapID); err != nil {
				return fmt.Errorf("cannot refresh snap-declaration for %q: %v", info.Name(), err)
			}
		}
		return nil
	}
	return doFetch(s, userID, fetching)
}
コード例 #5
0
ファイル: assertmgr.go プロジェクト: niemeyer/snapd
// ValidateRefreshes validates the refresh candidate revisions represented by the snapInfos, looking for the needed refresh control validation assertions, it returns a validated subset in validated and a summary error if not all candidates validated.
func ValidateRefreshes(s *state.State, snapInfos []*snap.Info, userID int) (validated []*snap.Info, err error) {
	// maps gated snap-ids to gating snap-ids
	controlled := make(map[string][]string)
	// maps gating snap-ids to their snap names
	gatingNames := make(map[string]string)

	db := DB(s)
	snapStates, err := snapstate.All(s)
	if err != nil {
		return nil, err
	}
	for snapName, snapState := range snapStates {
		info, err := snapState.CurrentInfo()
		if err != nil {
			return nil, err
		}
		if info.SnapID == "" {
			continue
		}
		gatingID := info.SnapID
		a, err := db.Find(asserts.SnapDeclarationType, map[string]string{
			"series":  release.Series,
			"snap-id": gatingID,
		})
		if err != nil {
			return nil, fmt.Errorf("internal error: cannot find snap declaration for installed snap %q (id %q): err", snapName, gatingID)
		}
		decl := a.(*asserts.SnapDeclaration)
		control := decl.RefreshControl()
		if len(control) == 0 {
			continue
		}
		gatingNames[gatingID] = decl.SnapName()
		for _, gatedID := range control {
			controlled[gatedID] = append(controlled[gatedID], gatingID)
		}
	}

	var errs []error
	for _, candInfo := range snapInfos {
		gatedID := candInfo.SnapID
		gating := controlled[gatedID]
		if len(gating) == 0 { // easy case, no refresh control
			validated = append(validated, candInfo)
			continue
		}

		var validationRefs []*asserts.Ref

		fetching := func(f asserts.Fetcher) error {
			for _, gatingID := range gating {
				valref := &asserts.Ref{
					Type:       asserts.ValidationType,
					PrimaryKey: []string{release.Series, gatingID, gatedID, candInfo.Revision.String()},
				}
				err := f.Fetch(valref)
				if notFound, ok := err.(*store.AssertionNotFoundError); ok && notFound.Ref.Type == asserts.ValidationType {
					return fmt.Errorf("no validation by %q", gatingNames[gatingID])
				}
				if err != nil {
					return fmt.Errorf("cannot find validation by %q: %v", gatingNames[gatingID], err)
				}
				validationRefs = append(validationRefs, valref)
			}
			return nil
		}
		err := doFetch(s, userID, fetching)
		if err != nil {
			errs = append(errs, fmt.Errorf("cannot refresh %q to revision %s: %v", candInfo.Name(), candInfo.Revision, err))
			continue
		}

		var revoked *asserts.Validation
		for _, valref := range validationRefs {
			a, err := valref.Resolve(db.Find)
			if err != nil {
				return nil, fmt.Errorf("internal error: cannot find just fetched %v: %v", valref, err)
			}
			if val := a.(*asserts.Validation); val.Revoked() {
				revoked = val
				break
			}
		}
		if revoked != nil {
			errs = append(errs, fmt.Errorf("cannot refresh %q to revision %s: validation by %q (id %q) revoked", candInfo.Name(), candInfo.Revision, gatingNames[revoked.SnapID()], revoked.SnapID()))
			continue
		}

		validated = append(validated, candInfo)
	}

	if errs != nil {
		return validated, &refreshControlError{errs}
	}

	return validated, nil
}
コード例 #6
0
ファイル: booted.go プロジェクト: clobrano/snappy
// UpdateRevisions synchronizes the active kernel and OS snap versions with
// the versions that actually booted. This is needed because a
// system may install "os=v2" but that fails to boot. The bootloader
// fallback logic will revert to "os=v1" but on the filesystem snappy
// still has the "active" version set to "v2" which is
// misleading. This code will check what kernel/os booted and set
// those versions active.
func UpdateRevisions(ovld *overlord.Overlord) error {
	const errorPrefix = "cannot update revisions after boot changes: "

	if release.OnClassic {
		return nil
	}

	bootloader, err := partition.FindBootloader()
	if err != nil {
		return fmt.Errorf(errorPrefix+"%s", err)
	}

	bv := "snap_kernel"
	kernelSnap, err := bootloader.GetBootVar(bv)
	if err != nil {
		return fmt.Errorf(errorPrefix+"%s", err)
	}
	bv = "snap_core"
	osSnap, err := bootloader.GetBootVar(bv)
	if err != nil {
		return fmt.Errorf(errorPrefix+"%s", err)
	}

	st := ovld.State()
	st.Lock()
	installed, err := snapstate.All(st)
	if err != nil {
		return fmt.Errorf(errorPrefix+"%s", err)
	}

	var tsAll []*state.TaskSet
	for _, snapNameAndRevno := range []string{kernelSnap, osSnap} {
		name, rev, err := nameAndRevnoFromSnap(snapNameAndRevno)
		if err != nil {
			logger.Noticef("cannot parse %q: %s", snapNameAndRevno, err)
			continue
		}
		for snapName, snapState := range installed {
			if name == snapName {
				if rev != snapState.Current {
					ts, err := snapstate.RevertToRevision(st, name, rev, snapstate.Flags(0))
					if err != nil {
						return err
					}
					tsAll = append(tsAll, ts)
				}
			}
		}
	}
	st.Unlock()

	if len(tsAll) == 0 {
		return nil
	}

	st.Lock()
	msg := fmt.Sprintf("Update kernel and core snap revisions")
	chg := st.NewChange("update-revisions", msg)
	for _, ts := range tsAll {
		chg.AddAll(ts)
	}
	st.Unlock()

	// do it and wait for ready
	ovld.Loop()

	timeoutTime := 10 * time.Second
	st.EnsureBefore(0)
	select {
	case <-chg.Ready():
	case <-time.After(timeoutTime):
		return fmt.Errorf("change did not apply after %s", timeoutTime)
	}

	st.Lock()
	status := chg.Status()
	err = chg.Err()
	st.Unlock()
	if status != state.DoneStatus {
		ovld.Stop()
		return fmt.Errorf(errorPrefix+"%s", err)
	}

	return ovld.Stop()
}