This repository has been archived by the owner on Aug 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
fix: k8s upgrades not working in airgapped environments #265
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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 |
---|---|---|
|
@@ -30,6 +30,7 @@ import ( | |
k0sv1beta1 "github.com/k0sproject/k0s/pkg/apis/k0s/v1beta1" | ||
apcore "github.com/k0sproject/k0s/pkg/autopilot/controller/plans/core" | ||
"github.com/k0sproject/version" | ||
ectypes "github.com/replicatedhq/embedded-cluster-kinds/types" | ||
batchv1 "k8s.io/api/batch/v1" | ||
corev1 "k8s.io/api/core/v1" | ||
"k8s.io/apimachinery/pkg/api/errors" | ||
|
@@ -283,6 +284,8 @@ func (r *InstallationReconciler) HasOnlyOneInstallation(ctx context.Context) (bo | |
// upgrade plan already exists we make sure the installation status is updated with the | ||
// latest plan status. | ||
func (r *InstallationReconciler) ReconcileK0sVersion(ctx context.Context, in *v1beta1.Installation) error { | ||
log := ctrl.LoggerFrom(ctx) | ||
|
||
// starts by checking if this is the unique installation object in the cluster. if | ||
// this is true then we don't need to sync anything as this is part of the initial | ||
// cluster installation. | ||
|
@@ -354,12 +357,27 @@ func (r *InstallationReconciler) ReconcileK0sVersion(ctx context.Context, in *v1 | |
if err := r.Get(ctx, okey, &plan); err != nil && !errors.IsNotFound(err) { | ||
return fmt.Errorf("failed to get upgrade plan: %w", err) | ||
} else if errors.IsNotFound(err) { | ||
// there is no autopilot plan in the cluster so we are free to | ||
// start our own plan. here we link the plan to the installation | ||
// by its name. | ||
if err := r.StartAutopilotUpgrade(ctx, in); err != nil { | ||
return fmt.Errorf("failed to start upgrade: %w", err) | ||
// if the kubernetes version has changed we create an upgrade command | ||
shouldUpgrade, err := r.shouldUpgradeK0s(ctx, in, meta.Versions["Kubernetes"]) | ||
if err != nil { | ||
return fmt.Errorf("failed to determine if k0s should be upgraded: %w", err) | ||
} | ||
if shouldUpgrade { | ||
log.Info("Starting k0s autopilot upgrade plan", "version", desiredVersion) | ||
|
||
// there is no autopilot plan in the cluster so we are free to | ||
// start our own plan. here we link the plan to the installation | ||
// by its name. | ||
if err := r.StartAutopilotUpgrade(ctx, in, meta); err != nil { | ||
return fmt.Errorf("failed to start upgrade: %w", err) | ||
} | ||
return nil | ||
} | ||
|
||
// if we are here it means that the k0s version has not changed and there is no | ||
// autopilot plan in the cluster. we can safely set the installation state to | ||
// installed and continue on the next reconcile cycle. | ||
in.Status.SetState(v1beta1.InstallationStateKubernetesInstalled, "", nil) | ||
return nil | ||
} | ||
|
||
|
@@ -369,8 +387,14 @@ func (r *InstallationReconciler) ReconcileK0sVersion(ctx context.Context, in *v1 | |
// of the plan id is deprecated in favour of the annotation. | ||
annotation := plan.Annotations[InstallationNameAnnotation] | ||
if annotation == in.Name || plan.Spec.ID == in.Name { | ||
r.SetStateBasedOnPlan(in, plan) | ||
return nil | ||
// there are two plans needed to be run in sequence for airgap upgrades. the first one is | ||
// the one that copies the artifacts to the nodes and the second one is the one that | ||
// actually upgrades the k0s version. we need to make sure that this is the second plan | ||
// before setting the installation state to the plan state. | ||
if isAutopilotUpgradeToVersion(&plan, desiredVersion) { | ||
r.SetStateBasedOnPlan(in, plan) | ||
return nil | ||
} | ||
} | ||
|
||
// this is most likely a plan that has been created by a previous installation | ||
|
@@ -391,6 +415,15 @@ func (r *InstallationReconciler) ReconcileK0sVersion(ctx context.Context, in *v1 | |
return nil | ||
} | ||
|
||
func isAutopilotUpgradeToVersion(plan *apv1b2.Plan, version string) bool { | ||
for _, command := range plan.Spec.Commands { | ||
if command.K0sUpdate != nil && command.K0sUpdate.Version == version { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func (r *InstallationReconciler) ReconcileOpenebs(ctx context.Context, in *v1beta1.Installation) error { | ||
log := ctrl.LoggerFrom(ctx) | ||
|
||
|
@@ -709,64 +742,46 @@ func (r *InstallationReconciler) DetermineUpgradeTargets(ctx context.Context) (a | |
} | ||
|
||
// StartAutopilotUpgrade creates an autopilot plan to upgrade to version specified in spec.config.version. | ||
func (r *InstallationReconciler) StartAutopilotUpgrade(ctx context.Context, in *v1beta1.Installation) error { | ||
func (r *InstallationReconciler) StartAutopilotUpgrade(ctx context.Context, in *v1beta1.Installation, meta *ectypes.ReleaseMetadata) error { | ||
targets, err := r.DetermineUpgradeTargets(ctx) | ||
if err != nil { | ||
return fmt.Errorf("failed to determine upgrade targets: %w", err) | ||
} | ||
meta, err := release.MetadataFor(ctx, in, r.Client) | ||
if err != nil { | ||
return fmt.Errorf("failed to get release bundle: %w", err) | ||
} | ||
|
||
k0surl := fmt.Sprintf( | ||
"%s/embedded-cluster-public-files/k0s-binaries/%s", | ||
in.Spec.MetricsBaseURL, | ||
meta.Versions["Kubernetes"], | ||
) | ||
|
||
// we need to assess what commands should autopilot run upon this upgrade. we can have four | ||
// different scenarios: 1) we are upgrading only the airgap artifacts, 2) we are upgrading | ||
// only k0s binaries, 3) we are upgrading both, 4) we are upgrading neither. we populate the | ||
// 'commands' slice with the commands necessary to execute these operations. | ||
var commands []apv1b2.PlanCommand | ||
|
||
// if the kubernetes version has changed we create an upgrade command | ||
shouldUpgrade, err := r.shouldUpgradeK0s(ctx, in, meta.Versions["Kubernetes"]) | ||
if err != nil { | ||
return fmt.Errorf("failed to determine if k0s should be upgraded: %w", err) | ||
} | ||
if shouldUpgrade { | ||
commands = append(commands, apv1b2.PlanCommand{ | ||
K0sUpdate: &apv1b2.PlanCommandK0sUpdate{ | ||
Version: meta.Versions["Kubernetes"], | ||
Targets: targets, | ||
Platforms: apv1b2.PlanPlatformResourceURLMap{ | ||
"linux-amd64": {URL: k0surl, Sha256: meta.K0sSHA}, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
// if no airgap nor k0s upgrade has been defined it means we are up to date so we set | ||
// the installation state to 'Installed' and return. no extra autopilot plan creation | ||
// is necessary at this stage. | ||
if len(commands) == 0 { | ||
in.Status.SetState(v1beta1.InstallationStateKubernetesInstalled, "", nil) | ||
return nil | ||
if in.Spec.AirGap { | ||
// if we are running in an airgap environment all assets are already present in the | ||
// node and are served by the local-artifact-mirror binary listening on localhost | ||
// port 50000. we just need to get autopilot to fetch the k0s binary from there. | ||
k0surl = "http://127.0.0.1:50000/bin/k0s-upgrade" | ||
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. this was missing from the original refactor |
||
} | ||
|
||
plan := apv1b2.Plan{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "autopilot", | ||
Name: "autopilot", // this is a fixed name and should not be changed | ||
Annotations: map[string]string{ | ||
InstallationNameAnnotation: in.Name, | ||
}, | ||
}, | ||
Spec: apv1b2.PlanSpec{ | ||
Timestamp: "now", | ||
ID: uuid.New().String(), | ||
Commands: commands, | ||
Commands: []apv1b2.PlanCommand{ | ||
apv1b2.PlanCommand{ | ||
K0sUpdate: &apv1b2.PlanCommandK0sUpdate{ | ||
Version: meta.Versions["Kubernetes"], | ||
Targets: targets, | ||
Platforms: apv1b2.PlanPlatformResourceURLMap{ | ||
"linux-amd64": {URL: k0surl, Sha256: meta.K0sSHA}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
if err := r.Create(ctx, &plan); err != nil { | ||
|
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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
this was needed otherwise an upgrade was never attempted as it would set the status to kubernetesinstalled based on the distribute airgap artifacts plan. the rest is just moving some code around.