-
Notifications
You must be signed in to change notification settings - Fork 1
/
selfupdate.go
107 lines (86 loc) · 3.12 KB
/
selfupdate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package main
import (
"context"
"fmt"
"log"
"net/http"
"github.com/antihax/optional"
"github.com/gokrazy/gokapi/gusapi"
"github.com/gokrazy/updater"
)
func checkForUpdates(ctx context.Context, gusCli *gusapi.APIClient, machineID string) (gusapi.UpdateResponse, error) {
response, _, err := gusCli.UpdateApi.Update(ctx, &gusapi.UpdateApiUpdateOpts{
Body: optional.NewInterface(&gusapi.UpdateRequest{
MachineId: machineID,
}),
})
if err != nil {
return gusapi.UpdateResponse{}, fmt.Errorf("error making http request: %w", err)
}
return response, nil
}
func shouldUpdate(response gusapi.UpdateResponse, sbomHash string) bool {
if response.SbomHash == sbomHash {
log.Printf("device's gokrazy version: %s is already the desired one, skipping", response.SbomHash)
return false
}
log.Printf("device's gokrazy version: %s, desired version: %s, proceeding with the update", sbomHash, response.SbomHash)
return true
}
func selfupdate(ctx context.Context, gusCli *gusapi.APIClient, gusServer, machineID, destinationDir string, response gusapi.UpdateResponse, httpPassword, httpPort string) error {
log.Print("starting self-update procedure")
if _, _, err := gusCli.UpdateApi.Attempt(ctx, &gusapi.UpdateApiAttemptOpts{
Body: optional.NewInterface(&gusapi.AttemptRequest{
MachineId: machineID,
SbomHash: response.SbomHash,
}),
}); err != nil {
return fmt.Errorf("error registering update attempt: %w", err)
}
var readClosers rcs
var err error
switch response.RegistryType {
case "http", "localdisk":
readClosers, err = httpFetcher(response, gusServer, destinationDir)
if err != nil {
return fmt.Errorf("error fetching %q update from link %q: %w", response.RegistryType, response.DownloadLink, err)
}
default:
return fmt.Errorf("unrecognized registry type %q", response.RegistryType)
}
uri := fmt.Sprintf("http://gokrazy:%s@localhost:%s/", httpPassword, httpPort)
log.Print("checking target partuuid support")
target, err := updater.NewTarget(uri, http.DefaultClient)
if err != nil {
return fmt.Errorf("checking target partuuid support: %v", err)
}
// Start with the root file system because writing to the non-active
// partition cannot break the currently running system.
log.Print("updating root file system")
if err := target.StreamTo("root", readClosers.root); err != nil {
return fmt.Errorf("updating root file system: %v", err)
}
readClosers.root.Close()
log.Print("updating boot file system")
if err := target.StreamTo("boot", readClosers.boot); err != nil {
return fmt.Errorf("updating boot file system: %v", err)
}
readClosers.boot.Close()
// Only relevant when running on non-Raspberry Pi devices.
// As it does not use an MBR.
log.Print("updating MBR")
if err := target.StreamTo("mbr", readClosers.mbr); err != nil {
return fmt.Errorf("updating MBR: %v", err)
}
readClosers.mbr.Close()
readClosers.zip.Close()
log.Print("switching to non-active partition")
if err := target.Switch(); err != nil {
return fmt.Errorf("switching to non-active partition: %v", err)
}
log.Print("reboot")
if err := target.Reboot(); err != nil {
return fmt.Errorf("reboot: %v", err)
}
return nil
}