-
Notifications
You must be signed in to change notification settings - Fork 440
CNTRLPLANE-350: add NodePool minor version compatibility check #5873
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,13 +9,17 @@ import ( | |
| "github.com/openshift/hypershift/cmd/log" | ||
| "github.com/openshift/hypershift/cmd/util" | ||
| hyperapi "github.com/openshift/hypershift/support/api" | ||
| "github.com/openshift/hypershift/support/releaseinfo" | ||
|
|
||
| corev1 "k8s.io/api/core/v1" | ||
| apierrors "k8s.io/apimachinery/pkg/api/errors" | ||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| "k8s.io/apimachinery/pkg/types" | ||
|
|
||
| ctrl "sigs.k8s.io/controller-runtime" | ||
| crclient "sigs.k8s.io/controller-runtime/pkg/client" | ||
|
|
||
| "github.com/blang/semver" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
|
|
@@ -54,6 +58,10 @@ func (o *CreateNodePoolOptions) Validate(ctx context.Context, c crclient.Client) | |
| return err | ||
| } | ||
|
|
||
| if err := validMinorVersionCompatibility(ctx, c, o.ClusterName, o.Namespace, o.ReleaseImage, &releaseinfo.RegistryClientProvider{}); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
|
|
@@ -184,3 +192,95 @@ func validateHostedClusterPayloadSupportsNodePoolCPUArch(ctx context.Context, cl | |
|
|
||
| return nil | ||
| } | ||
|
|
||
| // validMinorVersionCompatibility validates that the NodePool version is compatible with the HostedCluster version. | ||
| // For 4.even versions, it allows y-2 difference. | ||
| // For 4.odd versions, it allows y-1 difference. | ||
| // NodePool version cannot be higher than control plane version. | ||
| func validMinorVersionCompatibility(ctx context.Context, client crclient.Client, name, namespace, nodePoolReleaseImage string, releaseProvider releaseinfo.Provider) error { | ||
| if nodePoolReleaseImage == "" { | ||
| return nil | ||
| } | ||
| logger := ctrl.LoggerFrom(ctx) | ||
|
|
||
| hcluster := &hyperv1.HostedCluster{} | ||
| if err := client.Get(ctx, types.NamespacedName{Namespace: namespace, Name: name}, hcluster); err != nil { | ||
| if !apierrors.IsNotFound(err) { | ||
| // For other errors (e.g. API server issues, RBAC problems), we should return the error | ||
| return fmt.Errorf("failed to get HostedCluster to check version compatibility: %w", err) | ||
| } | ||
|
|
||
| // This is expected to happen when we create a cluster since there is no created HostedCluster CR to check the | ||
| // payload from. | ||
| logger.Info("WARNING: failed to get HostedCluster to check version compatibility") | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. but do you have to allow NodePool creation to complete before there's a HostedCluster? You could decide to block until the HostedCluster exists and have the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When creating a HostedCluster using the HyperShift CLI, a default NodePool is also created. This is just CLI test code—we also add validation on the controller side.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds like that controller-side validation is future-plans, not current-implementation. But I'm fine assuming that there will be some controller-side backstops, and that this client code is just best-effort attempts to warn command-line users without bothering to go as far and slow as an API NodePool creation attempt, and letting these through here with the warning 👍
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #5931 is following up with the HyperShift-operator side validation discussed in this thread. |
||
| return nil | ||
| } | ||
|
|
||
| // Get the control plane version string | ||
| var controlPlaneVersionStr string | ||
| if len(hcluster.Status.Version.History) == 0 { | ||
| // If the cluster is in the process of installation, there is no history | ||
| // Use the desired version as the control plane version | ||
| controlPlaneVersionStr = hcluster.Status.Version.Desired.Version | ||
| } else { | ||
| // If the cluster is installed or upgrading | ||
| // Start with the most recent version from history as the default | ||
| controlPlaneVersionStr = hcluster.Status.Version.History[len(hcluster.Status.Version.History)-1].Version | ||
| // Update with any more recent Completed version if found | ||
| for _, history := range hcluster.Status.Version.History { | ||
| if history.State == "Completed" { | ||
LiangquanLi930 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| controlPlaneVersionStr = history.Version | ||
| break | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Parse control plane version | ||
| controlPlaneVersion, err := semver.Parse(controlPlaneVersionStr) | ||
| if err != nil { | ||
| return fmt.Errorf("parsing control plane version (%s): %w", controlPlaneVersionStr, err) | ||
| } | ||
|
|
||
| pullSecret := &corev1.Secret{} | ||
| if err = client.Get(ctx, types.NamespacedName{Namespace: namespace, Name: hcluster.Spec.PullSecret.Name}, pullSecret); err != nil { | ||
| return fmt.Errorf("failed to get pull secret: %w", err) | ||
| } | ||
|
|
||
| releaseImage, err := releaseProvider.Lookup(ctx, nodePoolReleaseImage, pullSecret.Data[corev1.DockerConfigJsonKey]) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't this result in the unit tests actually pulling images? the func should receive the release info provider interface and let the units use a fake implementation, we have some precedents for this
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! done |
||
| if err != nil { | ||
| // Skip version check in disconnected environment where registry access is not available | ||
| logger.Info("WARNING: Unable to access the payload, skipping the Minor Version check.", "error", err.Error()) | ||
| return nil | ||
| } | ||
|
|
||
| // Parse NodePool version | ||
| nodePoolVersion, err := semver.Parse(releaseImage.Version()) | ||
| if err != nil { | ||
| return fmt.Errorf("parsing NodePool version (%s): %w", releaseImage.Version(), err) | ||
| } | ||
|
|
||
| // NodePool version cannot be higher than control plane version | ||
| if nodePoolVersion.GT(controlPlaneVersion) { | ||
| return fmt.Errorf("NodePool version %s cannot be higher than the HostedCluster version %s", | ||
| nodePoolVersion, controlPlaneVersion) | ||
| } | ||
|
|
||
| // Calculate minor version difference | ||
| versionDiff := int64(controlPlaneVersion.Minor - nodePoolVersion.Minor) | ||
|
|
||
| // For 4.even versions, allow y-2 difference | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. where is the even/odd distinction coming from?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. https://issues.redhat.com/browse/OCPSTRAT-1707
|
||
| // For 4.odd versions, allow y-1 difference | ||
| maxAllowedDiff := int64(2) | ||
| if controlPlaneVersion.Minor%2 == 1 { | ||
| maxAllowedDiff = 1 | ||
| } | ||
|
|
||
| if versionDiff > maxAllowedDiff { | ||
| return fmt.Errorf("NodePool minor version %d.%d is not compatible with the HostedCluster minor version %d.%d (max allowed difference: %d)", | ||
| nodePoolVersion.Major, nodePoolVersion.Minor, | ||
| controlPlaneVersion.Major, controlPlaneVersion.Minor, | ||
| maxAllowedDiff) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.