-
Notifications
You must be signed in to change notification settings - Fork 847
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
AUTH-2993 added workers updater logic
- Loading branch information
Dalton
committed
Oct 1, 2020
1 parent
2c9b736
commit ba4c8d8
Showing
8 changed files
with
768 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package updater | ||
|
||
// Version is the functions needed to perform an update | ||
type Version interface { | ||
Apply() error | ||
String() string | ||
} | ||
|
||
// Service is the functions to get check for new updates | ||
type Service interface { | ||
Check() (Version, error) | ||
} | ||
|
||
const ( | ||
// OSKeyName is the url parameter key to send to the checkin API for the operating system of the local cloudflared (e.g. windows, darwin, linux) | ||
OSKeyName = "os" | ||
|
||
// ArchitectureKeyName is the url parameter key to send to the checkin API for the architecture of the local cloudflared (e.g. amd64, x86) | ||
ArchitectureKeyName = "arch" | ||
|
||
// BetaKeyName is the url parameter key to send to the checkin API to signal if the update should be a beta version or not | ||
BetaKeyName = "beta" | ||
|
||
// VersionKeyName is the url parameter key to send to the checkin API to specific what version to upgrade or downgrade to | ||
VersionKeyName = "version" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
package updater | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"net/http" | ||
"runtime" | ||
"strconv" | ||
"strings" | ||
"time" | ||
) | ||
|
||
// Options are the update options supported by the | ||
type Options struct { | ||
// IsBeta is for beta updates to be installed if available | ||
IsBeta bool | ||
|
||
// IsForced is to forcibly download the latest version regardless of the current version | ||
IsForced bool | ||
|
||
// RequestedVersion is the specific version to upgrade or downgrade to | ||
RequestedVersion string | ||
} | ||
|
||
// VersionResponse is the JSON response from the Workers API endpoint | ||
type VersionResponse struct { | ||
URL string `json:"url"` | ||
Version string `json:"version"` | ||
Checksum string `json:"checksum"` | ||
IsCompressed bool `json:"compressed"` | ||
Error string `json:"error"` | ||
} | ||
|
||
// WorkersService implements Service. | ||
// It contains everything needed to check in with the WorkersAPI and download and apply the updates | ||
type WorkersService struct { | ||
currentVersion string | ||
url string | ||
targetPath string | ||
opts Options | ||
} | ||
|
||
// NewWorkersService creates a new updater Service object. | ||
func NewWorkersService(currentVersion, url, targetPath string, opts Options) Service { | ||
return &WorkersService{ | ||
currentVersion: currentVersion, | ||
url: url, | ||
targetPath: targetPath, | ||
opts: opts, | ||
} | ||
} | ||
|
||
// Check does a check in with the Workers API to get a new version update | ||
func (s *WorkersService) Check() (Version, error) { | ||
client := &http.Client{ | ||
Timeout: time.Second * 5, | ||
} | ||
|
||
req, err := http.NewRequest(http.MethodGet, s.url, nil) | ||
q := req.URL.Query() | ||
q.Add(OSKeyName, runtime.GOOS) | ||
q.Add(ArchitectureKeyName, runtime.GOARCH) | ||
|
||
if s.opts.IsBeta { | ||
q.Add(BetaKeyName, "true") | ||
} | ||
|
||
if s.opts.RequestedVersion != "" { | ||
q.Add(VersionKeyName, s.opts.RequestedVersion) | ||
} | ||
|
||
req.URL.RawQuery = q.Encode() | ||
resp, err := client.Do(req) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer resp.Body.Close() | ||
|
||
var v VersionResponse | ||
if err := json.NewDecoder(resp.Body).Decode(&v); err != nil { | ||
return nil, err | ||
} | ||
|
||
if v.Error != "" { | ||
return nil, errors.New(v.Error) | ||
} | ||
|
||
if !s.opts.IsForced && !IsNewerVersion(s.currentVersion, v.Version) { | ||
return nil, nil | ||
} | ||
|
||
return NewWorkersVersion(v.URL, v.Version, v.Checksum, s.targetPath, v.IsCompressed), nil | ||
} | ||
|
||
// IsNewerVersion checks semantic versioning for the latest version | ||
// cloudflared tagging is more of a date than a semantic version, | ||
// but the same comparision logic still holds for major.minor.patch | ||
// e.g. 2020.8.2 is newer than 2020.8.1. | ||
func IsNewerVersion(current string, check string) bool { | ||
if strings.Contains(strings.ToLower(current), "dev") { | ||
return false // dev builds shouldn't update | ||
} | ||
|
||
cMajor, cMinor, cPatch, err := SemanticParts(current) | ||
if err != nil { | ||
return false | ||
} | ||
|
||
nMajor, nMinor, nPatch, err := SemanticParts(check) | ||
if err != nil { | ||
return false | ||
} | ||
|
||
if nMajor > cMajor { | ||
return true | ||
} | ||
|
||
if nMajor == cMajor && nMinor > cMinor { | ||
return true | ||
} | ||
|
||
if nMajor == cMajor && nMinor == cMinor && nPatch > cPatch { | ||
return true | ||
} | ||
return false | ||
} | ||
|
||
// SemanticParts gets the major, minor, and patch version of a semantic version string | ||
// e.g. 3.1.2 would return 3, 1, 2, nil | ||
func SemanticParts(version string) (major int, minor int, patch int, err error) { | ||
major = 0 | ||
minor = 0 | ||
patch = 0 | ||
parts := strings.Split(version, ".") | ||
if len(parts) != 3 { | ||
err = errors.New("invalid version") | ||
return | ||
} | ||
major, err = strconv.Atoi(parts[0]) | ||
if err != nil { | ||
return | ||
} | ||
|
||
minor, err = strconv.Atoi(parts[1]) | ||
if err != nil { | ||
return | ||
} | ||
|
||
patch, err = strconv.Atoi(parts[2]) | ||
if err != nil { | ||
return | ||
} | ||
return | ||
} |
Oops, something went wrong.