-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
build, upgrade: Disable upgrades on unsupported OS version (fixes #9290) #9656
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
1. The build process creates a compatability.json for the runtime used. 2. The release process adds compatability.json as a release artifact 3. The upgrade server reads compatability.yaml and merges it into its /meta.json response. 4. The upgrading client reads the compatability.json file in the release bundle, and using the go runtime setting found in it, looks up the minimum OS versions listed in the upgrade server's /meta.json response. 5. If the upgrading client's OS version is lower than the minimum OS version listed, the upgrade is aborted.
…-smaller * upstream/main: build: use Go 1.23, require minimum 1.22 (syncthing#9651) gui, man, authors: Update docs, translations, and contributors
* main: lib/protocol: Further interface refactor (syncthing#9396) gui: Replace global "Panel padding decrease" style with targeted class (syncthing#9659)
if CompareVersions(minKernel, currentKernel) > Equal { | ||
return fmt.Errorf("runtime %v requires OS version %v but this system is version %v", runtimeReqs.Runtime, minKernel, currentKernel) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we think yolo upgrading because we can't find the goos/arch combo is right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we have to, otherwise we need to cover all possible OSes. And we currently don't and I doubt we even could if we wanted to, there's always going to be something esoteric we'll miss.
Couldn't we flip this on it's head? Post goos goarch kernel version when looking for upgrades to the upgrade server, and handle it there? Return nothing if its the last version supported. Feels like scooping up that mess would be easier than asking everyone to upgrade because we broke autoupgrade. Also, when we find something critical, we could retro-fix it. |
if asset.Name == "compat.json" { | ||
resp, err := insecureGet(asset.BrowserURL, current) | ||
if err != nil { | ||
l.Infoln("Fetching compat.json:", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe worth knowing which release failed (same for the error below):
l.Infoln("Fetching compat.json:", err) | |
l.Infof("Fetching compat.json for %v: %v", rel.Tag, err) |
if CompareVersions(minKernel, currentKernel) > Equal { | ||
return fmt.Errorf("runtime %v requires OS version %v but this system is version %v", runtimeReqs.Runtime, minKernel, currentKernel) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we have to, otherwise we need to cover all possible OSes. And we currently don't and I doubt we even could if we wanted to, there's always going to be something esoteric we'll miss.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like we shouldn't silently stop upgrading, but log a warning (and thus generate a banner in the UI) if we detect a newer version that isn't compatible anymore. The user should be aware that they are out of date. If just for our own sake when getting bug reports.
if found && arch != runtime.GOARCH { | ||
continue | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the intent of the arch check? Asking because currently I don't see arch in any arch requirements/input anywhere else. Is it for future extensibility if go's OS version requirements start to differ between arches? I'd tend towards adding that only once we use it. And if we already want to have it now, it should also feature in the error message below besides the version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// normalizeKernelVersion strips off anything after the kernel version's patch | ||
// level. So Windows' "10.0.22631.3880 Build 22631.3880" becomes "10.0.22631", | ||
// and Linux's "6.8.0-39-generic" becomes "6.8.0". | ||
func normalizeKernelVersion(version string) string { | ||
version, _, _ = strings.Cut(version, " ") | ||
version, _, _ = strings.Cut(version, "-") | ||
|
||
parts := strings.Split(version, ".") | ||
maxParts := min(len(parts), 3) | ||
return strings.Join(parts[:maxParts], ".") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel a bit squeamish about this generic way of parsing a version string we don't control. I don't see why the format would change, but if it did it could break auto-upgrading. E.g. if the host version got a string prefix (other than "v"), our comparison would try to parse that as an int, ignore the error and use 0. Which is then guaranteed lower than min requirement and auto-upgrade is broken. I'd prefer to auto-upgrade when in doubt.
One option to do that (and it feels wrong to suggest that as "more safe" :P ), would be to have a quite strict regex per OS for the expected version format. If the regex doesn't match, we upgrade (and log a failure so we know about it happening). I first wanted to have a unit test to find this, but test runners likely upgrade much later than user machines.
@@ -38,6 +39,13 @@ type Asset struct { | |||
BrowserURL string `json:"browser_download_url,omitempty"` | |||
} | |||
|
|||
// RuntimeReqs defines the structure of compat.json, which is included | |||
// with each elease. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// with each elease. | |
// with each release. |
This is to add the generation of `compat.json` as a release artifact. It describes the runtime requirements of the release in question. The next step is to have the upgrade server use this information to filter releases provided to clients. This is per the discussion in #9656 --------- Co-authored-by: Ross Smith II <ross@smithii.com>
We will, shortly. This is currently implemented in the upgrade server on the infrastructure branch. |
Simplification of #9635. Mechanism in short:
compat.yaml
which holds the Go runtime requirements for the Go versions we currently support building. (Yaml, because it supports comments and is a bit friendlier to use than raw json.)compat.json
, holding the requirements for the actual Go version used for the build. (Lacking data in compat.yaml at this point is a build failure.) (JSON because this is just for machine consumption.)compat.json
together with all other release artifacts.The end result should be that machines that do not support upgrading to a given release will ignore it and get stuck on the last supported release.