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
kubeadm: add final fallback to constants.CurrentKubernetesVersion #72454
kubeadm: add final fallback to constants.CurrentKubernetesVersion #72454
Conversation
Hi @rojkov. Thanks for your PR. I'm waiting for a kubernetes member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
/cc @rosti |
/kind cleanup |
/ok-to-test |
cmd/kubeadm/app/util/version.go
Outdated
klog.Warningf("could not obtain client version; using remote version: %s", body) | ||
return KubernetesReleaseVersion(body) | ||
} | ||
|
||
if err != nil && clientVersionErr != nil { | ||
klog.Warningf("could not obtain neither client nor remote version; fall back to: %s", constants.CurrentKubernetesVersion) | ||
return KubernetesReleaseVersion(constants.CurrentKubernetesVersion.String()) |
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.
is there a unit test to ensure this constant is always correct? if not, it is very likely to drift and be forgotten
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.
after the resent refactor these should be the only constants that we bump on each minor release and we must bump them anyway:
https://github.com/kubernetes/kubernetes/blob/b500a95af34a8babf74191a246b5dae0fd764e56/cmd/kubeadm/app/constants/constants.go#L379-L386
having a unit test puts this in a weird space - i.e. to which value to compare the constant to?
the constant is a fallback: remote version -> client version -> constant version.
- we can potentially compare to the remote against
https://dl.k8s.io/release/stable-1.txt
(with patch=0), but arguably unit tests should not depend on remote connectivity....we do that already in a few places. - compare to the client version. problem here is that unit tests do not receive the version as
ldflags
.
i think this might be a problem only for the integration tests:
https://github.com/kubernetes/kubernetes/blob/master/hack/make-rules/test-kubeadm-cmd.sh
leaving the final call to @timothysc and @kad on this PR.
/assign @timothysc
/assign @kad
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.
these should be the only constants that we bump on each minor release and we must bump them anyway
Doesn't the current release constant require bumping on every patch version as well?
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.
CurrentKubernetesVersion
parses to a MAJOR.MINOR.PATCH object, but the important elements are MAJOR.MINOR.
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.
That seems like a misleading constant, then, and one that would be likely to be used incorrectly.
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.
Honestly speaking this recursive function with side effects smells suboptimal to me since it clearly violates the Single Responsibility principle. I would rather try to constrain ClusterConfig.KubernetesVersion to be a canonical version only and always. Then at config parsing/cmdline option setting time we'd detect whether the provided value is
- a version or
- just a version label supposed to be resolved remotely into a version or
- nil.
In the first case normalizedBuildVersion()
would be used once. In the second case KubernetesReleaseVersion()
would be limited to resolving the remote version only. And in the third case we could try to read the gitVersion
and fail if it's not set.
Then the only authoritative source of the version value would be ClusterConfig.KubernetesVersion
. With this approach the unit tests would not touch networking.
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.
Honestly speaking this recursive function with side effects smells suboptimal to me since it clearly violates the Single Responsibility principle
i support your concern here and the recursion can be avoided.
@kad and @luxas probably have opinions here as they authored the original?
I would rather try to constrain ClusterConfig.KubernetesVersion to be a canonical version only and always
isn't this the case already? if the user does not feed a KubernetesVersion and a config, the version has to come from somewhere. internet endpoint, client version, constant?
With this approach the unit tests would not touch networking.
there are calls like this one:
kubernetes/cmd/kubeadm/app/cmd/token.go
Lines 213 to 215 in b502b99
// KubernetesVersion is not used, but we set it explicitly to avoid the lookup | |
// of the version from the internet when executing ConfigFileAndDefaultsToInternalConfig | |
phaseutil.SetKubernetesVersion(cfg) |
that pre-set a version so that the version is later not fetched from the internet for commands that don't need internet. but this still needs a client that was built properly.
so potentially, unit tests can do the same.
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.
isn't this the case already? if the user does not feed a KubernetesVersion and a config, the version has to come from somewhere. internet endpoint, client version, constant?
IIRC some unit tests don't (can't) consult ClusterConfig.KubernetesVersion
relying solely on KubernetesReleaseVersion()
. I'll try to come up with a proposal.
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.
... in a separate PR that is.
cmd/kubeadm/app/util/version.go
Outdated
klog.Warningf("could not obtain client version; using remote version: %s", body) | ||
return KubernetesReleaseVersion(body) | ||
} | ||
|
||
if err != nil && clientVersionErr != nil { |
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.
why not unify the err != nil
and err == nil
branches under a clientVersionErr != nil
branch?
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 moved the branches under clientVersionErr != nil
.
cmd/kubeadm/app/util/version.go
Outdated
klog.Warningf("could not obtain client version; using remote version: %s", body) | ||
return KubernetesReleaseVersion(body) | ||
} | ||
|
||
if err != nil && clientVersionErr != nil { | ||
klog.Warningf("could not obtain neither client nor remote version; fall back to: %s", constants.CurrentKubernetesVersion) | ||
return KubernetesReleaseVersion(constants.CurrentKubernetesVersion.String()) |
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.
after the resent refactor these should be the only constants that we bump on each minor release and we must bump them anyway:
https://github.com/kubernetes/kubernetes/blob/b500a95af34a8babf74191a246b5dae0fd764e56/cmd/kubeadm/app/constants/constants.go#L379-L386
having a unit test puts this in a weird space - i.e. to which value to compare the constant to?
the constant is a fallback: remote version -> client version -> constant version.
- we can potentially compare to the remote against
https://dl.k8s.io/release/stable-1.txt
(with patch=0), but arguably unit tests should not depend on remote connectivity....we do that already in a few places. - compare to the client version. problem here is that unit tests do not receive the version as
ldflags
.
i think this might be a problem only for the integration tests:
https://github.com/kubernetes/kubernetes/blob/master/hack/make-rules/test-kubeadm-cmd.sh
leaving the final call to @timothysc and @kad on this PR.
/assign @timothysc
/assign @kad
b500a95
to
8ead090
Compare
/test pull-kubernetes-integration |
/lgtm |
BTW, as this has user visible behavior change (static default fallback version), it would be good to have release note line. |
Thanks! I've updated the release note. |
For feedback and approval |
cmd/kubeadm/app/util/version.go
Outdated
return KubernetesReleaseVersion(clientVersion) | ||
if clientVersionErr == nil { | ||
// Handle air-gapped environments by falling back to the client version. | ||
klog.Infof("could not fetch a Kubernetes version from the internet: %v", 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.
Technically speaking, this one should be a warning.
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.
Agree. Made them warnings now.
It may happen that both the git version and the remote version are broken/inaccessible. In this case the broken remote version would be used. To overcome this situation fall back to the constant CurrentKubernetesVersion. The alternative could be os.Exit(1). Also this change fixes Bazel-based unit tests in air-gapped environment.
8ead090
to
9e25a00
Compare
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.
@rojkov first of all sorry for the delay in reviewing this PR.
As per slack discussion, I understood that adding a third fallback rule for version discovery is a necessary evil in for following us cases:
- git version is broken when building unit tests with Bazel behind proxy (Bazel drops http_proxy= vars)
- running a build from the source tarball (not from git) in an air gaped environment
The proposed fallback method is not perfect, because it will always point at the .0 patch of each minor, but I think it is acceptable for the above use cases (running unit tests).
However, in my humble opinion, this function is already too complicated and I think that we cannot insert additional complexity without cleaning up some technical debt.
What do you think about the following proposal?
KubernetesReleaseVersion
should be given the only the responsibility to coordinate the fallback logic, something similar to
getKubernetesReleaseVersion (from internet)
if ok return
getGitVersion
if ok return
use constant
getKubernetesReleaseVersion
should have the single responsibility of resolving label to exact validated version string, with support for label->label->..->version resolving (as per @kad comment)
The expected benefit of the above proposal is to spilt the fallback logic from the label resolving/recursive logic, thus hopefully improving code readability/maintenabily/testability.
I'm going also to open a separated issue for improving the name of CurrentKubernetesVersion
as per @liggitt comment
@fabriziopandini Thank you for the review! Actually I've already rewritten the function in this commit rojkov@d991754
Basically it implements your suggestion already. I wanted to rebase it on top of this PR, but I can do the other way around. |
/hold |
@fabriziopandini why to hold this one? I think it can be merged. |
/hold cancel |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: rojkov, timothysc The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
What this PR does / why we need it:
It may happen that both the git version and the remote version
are broken/inaccessible. In this case the broken remote version
would be used.
To overcome this situation fall back to the constant CurrentKubernetesVersion.
The alternative could be os.Exit(1).
Also this change fixes bazel-based unit tests in air-gapped environment.
What type of PR is this?
Does this PR introduce a user-facing change?: