Skip to content

Commit

Permalink
Add remaining components to updater (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlCutter authored Oct 11, 2023
1 parent 6a39370 commit 11b48b0
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 29 deletions.
94 changes: 65 additions & 29 deletions release/firmware/update/fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,13 @@ type Fetcher struct {

manifestVerifiers map[string][]note.Verifier

mu sync.Mutex
latestOS *firmwareRelease
latestApplet *firmwareRelease
logState client.LogStateTracker
scanFrom uint64
mu sync.Mutex
latestOS *firmwareRelease
latestApplet *firmwareRelease
latestBoot *firmwareRelease
latestRecovery *firmwareRelease
logState client.LogStateTracker
scanFrom uint64
}

func (f *Fetcher) GetLatestVersions(_ context.Context) (os semver.Version, applet semver.Version, err error) {
Expand Down Expand Up @@ -185,6 +187,40 @@ func (f *Fetcher) GetApplet(ctx context.Context) (firmware.Bundle, error) {
return *f.latestApplet.bundle, nil
}

func (f *Fetcher) GetBoot(ctx context.Context) (firmware.Bundle, error) {
f.mu.Lock()
defer f.mu.Unlock()

if f.latestBoot == nil {
return firmware.Bundle{}, errors.New("no latest boot available")
}
if f.latestBoot.bundle.Firmware == nil {
binary, err := f.binFetcher(ctx, f.latestBoot.manifest)
if err != nil {
return firmware.Bundle{}, fmt.Errorf("BinaryFetcher(): %v", err)
}
f.latestBoot.bundle.Firmware = binary
}
return *f.latestBoot.bundle, nil
}

func (f *Fetcher) GetRecovery(ctx context.Context) (firmware.Bundle, error) {
f.mu.Lock()
defer f.mu.Unlock()

if f.latestRecovery == nil {
return firmware.Bundle{}, errors.New("no latest recovery available")
}
if f.latestRecovery.bundle.Firmware == nil {
binary, err := f.binFetcher(ctx, f.latestRecovery.manifest)
if err != nil {
return firmware.Bundle{}, fmt.Errorf("BinaryFetcher(): %v", err)
}
f.latestRecovery.bundle.Firmware = binary
}
return *f.latestRecovery.bundle, nil
}

// Scan gets the latest checkpoint from the log and updates the fetcher's state
// to reflect the latest OS and Applet available in the log.
func (f *Fetcher) Scan(ctx context.Context) error {
Expand Down Expand Up @@ -231,31 +267,13 @@ func (f *Fetcher) Scan(ctx context.Context) error {

switch manifest.Component {
case ftlog.ComponentOS:
// According to the SemVer2.0 spec, equal revisions have no precedence defined.
// In general this won't be an issue; production releases will always be tagged appropriately,
// and there should never be two different releases with the same semver for a given component,
// however, during development, this may not hold.
// To tighten the definition of precedence, we'll use the fact that logs define ordering
// and say that "later" entries take precedence over "earlier" entries with the same version
// numbering.
if f.latestOS == nil ||
f.latestOS.manifest.GitTagName.LessThan(manifest.GitTagName) ||
f.latestOS.manifest.GitTagName.Equal(manifest.GitTagName) {
f.latestOS = &firmwareRelease{
bundle: bundle,
manifest: manifest,
}
}
f.latestOS = highestRelease(f.latestOS, &firmwareRelease{bundle: bundle, manifest: manifest})
case ftlog.ComponentApplet:
// See comment above about the Equal case.
if f.latestApplet == nil ||
f.latestApplet.manifest.GitTagName.LessThan(manifest.GitTagName) ||
f.latestApplet.manifest.GitTagName.Equal(manifest.GitTagName) {
f.latestApplet = &firmwareRelease{
bundle: bundle,
manifest: manifest,
}
}
f.latestApplet = highestRelease(f.latestApplet, &firmwareRelease{bundle: bundle, manifest: manifest})
case ftlog.ComponentBoot:
f.latestBoot = highestRelease(f.latestBoot, &firmwareRelease{bundle: bundle, manifest: manifest})
case ftlog.ComponentRecovery:
f.latestRecovery = highestRelease(f.latestRecovery, &firmwareRelease{bundle: bundle, manifest: manifest})
default:
klog.Warningf("unknown component type in log: %q", manifest.Component)
}
Expand All @@ -264,6 +282,24 @@ func (f *Fetcher) Scan(ctx context.Context) error {
return nil
}

// highestRelease returns the "higher" of the two releases passed in according to SemVer rules.
//
// According to the SemVer2.0 spec, equal revisions have no precedence defined.
// In general this won't be an issue; production releases will always be tagged appropriately,
// and there should never be two different releases with the same semver for a given component,
// however, during development, this may not hold.
// To tighten the definition of precedence, we'll use the fact that logs define ordering
// and say that "later" entries take precedence over "earlier" entries with the same version
// numbering.
func highestRelease(current *firmwareRelease, candidate *firmwareRelease) *firmwareRelease {
if current == nil ||
current.manifest.GitTagName.LessThan(candidate.manifest.GitTagName) ||
current.manifest.GitTagName.Equal(candidate.manifest.GitTagName) {
return candidate
}
return current
}

func parseLeaf(leaf []byte, verifiers map[string][]note.Verifier) (ftlog.FirmwareRelease, error) {
var n *note.Note
var err error
Expand Down
29 changes: 29 additions & 0 deletions release/firmware/update/fetch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,14 @@ func TestFetcher(t *testing.T) {
{
{Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.1")},
{Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.1.1")},
{Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.3.1")},
{Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.1.1")},
},
{
{Component: ftlog.ComponentOS, GitTagName: *semver.New("1.2.1")},
{Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.3.1")},
{Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.3.1")},
{Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.1.1")},
},
},
want: [][]ftlog.FirmwareRelease{
Expand All @@ -115,6 +119,8 @@ func TestFetcher(t *testing.T) {
{
{Component: ftlog.ComponentOS, GitTagName: *semver.New("1.2.1")},
{Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.3.1")},
{Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.3.1")},
{Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.1.1")},
},
},
}, {
Expand All @@ -123,14 +129,20 @@ func TestFetcher(t *testing.T) {
{
{Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.1")},
{Component: ftlog.ComponentApplet, GitTagName: *semver.New("1.1.1")},
{Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.3.1")},
{Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.1.1")},
{Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.2")},
{Component: ftlog.ComponentApplet, GitTagName: *semver.New("2.0.1")},
{Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.7.1")},
{Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.8.1")},
},
},
want: [][]ftlog.FirmwareRelease{
{
{Component: ftlog.ComponentOS, GitTagName: *semver.New("1.0.2")},
{Component: ftlog.ComponentApplet, GitTagName: *semver.New("2.0.1")},
{Component: ftlog.ComponentBoot, GitTagName: *semver.New("1.7.1")},
{Component: ftlog.ComponentRecovery, GitTagName: *semver.New("1.8.1")},
},
},
}, {
Expand Down Expand Up @@ -208,9 +220,26 @@ func TestFetcher(t *testing.T) {
switch want.Component {
case ftlog.ComponentApplet:
got = applet
if _, err = f.GetApplet(ctx); err != nil {
t.Fatalf("GetApplet: %v", err)
}
case ftlog.ComponentBoot:
if _, err = f.GetBoot(ctx); err != nil {
t.Fatalf("GetBoot: %v", err)
}
got = f.latestBoot.manifest.GitTagName
case ftlog.ComponentOS:
got = os
if _, err = f.GetOS(ctx); err != nil {
t.Fatalf("GetOS: %v", err)
}
case ftlog.ComponentRecovery:
if _, err = f.GetRecovery(ctx); err != nil {
t.Fatalf("GetRecovery: %v", err)
}
got = f.latestRecovery.manifest.GitTagName
}

if got.String() != want.GitTagName.String() {
t.Errorf("got %v, want %v", got, want)
}
Expand Down

0 comments on commit 11b48b0

Please sign in to comment.