package hostguard import ( "context" "sort" "strings" ) // GenerationInstallations enumerates independently of generation reservations. // Pending or quarantined installations cannot certify a destructive snapshot. func (a *RootAuthority) GenerationInstallations(ctx context.Context) ([]FenceView, error) { if a == nil || a.store == nil { return nil, ErrInvalidInput } names, err := a.store.Names() if err != nil { return nil, err } sort.Strings(names) var out []FenceView for _, name := range names { if err := ctx.Err(); err != nil { return nil, err } if strings.HasSuffix(name, ".lock") { continue } if !strings.HasSuffix(name, ".json") { return nil, ErrMalformedRecord } host := strings.TrimSuffix(name, ".json") view, err := a.generationInstallation(ctx, host) if err != nil { return nil, err } if view.Installation.InventoryRevision == 0 { return nil, ErrNoRecord } out = append(out, view) } return out, nil } func (a *RootAuthority) generationInstallation(ctx context.Context, host string) (FenceView, error) { unlock, err := a.store.Lock(ctx, host+".lock") if err != nil { return FenceView{}, err } defer unlock() r, err := a.read(host) if err != nil { return FenceView{}, err } view, err := a.viewLocked(host, Captured{Incarnation: r.Incarnation, Stamp: r.installation.Stamp}) if err != nil { return FenceView{}, err } // A visible final rename may have failed its directory sync. Recommit under // the same host lock before these requirements can certify a generation read. if err := a.write(r); err != nil { return FenceView{}, err } return view, nil }