Skip to content

Commit

Permalink
feat(ec): migration from v1 to v2 - fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
emosbaugh committed Jan 21, 2025
1 parent f386880 commit 7b47030
Show file tree
Hide file tree
Showing 11 changed files with 299 additions and 235 deletions.
4 changes: 3 additions & 1 deletion kinds/apis/v1beta1/installation_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const (
InstallationStateInstalled string = "Installed"
InstallationStateKubernetesInstalled string = "KubernetesInstalled"
InstallationStateAddonsInstalling string = "AddonsInstalling"
InstallationStateAddonsInstalled string = "AddonsInstalled"
InstallationStateHelmChartUpdateFailure string = "HelmChartUpdateFailure"
InstallationStateObsolete string = "Obsolete"
InstallationStateFailed string = "Failed"
Expand All @@ -49,7 +50,8 @@ const (
)

const (
DisableReconcileConditionType = "DisableReconcile"
ConditionTypeV2MigrationInProgress = "V2MigrationInProgress"
ConditionTypeDisableReconcile = "DisableReconcile"
)

// ConfigSecretEntryName holds the entry name we are looking for in the secret
Expand Down
2 changes: 1 addition & 1 deletion operator/controllers/installation_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ func (r *InstallationReconciler) Reconcile(ctx context.Context, req ctrl.Request
return ctrl.Result{}, nil
}

if k8sutil.CheckConditionStatus(in.Status, v1beta1.DisableReconcileConditionType) == metav1.ConditionTrue {
if k8sutil.CheckConditionStatus(in.Status, v1beta1.ConditionTypeDisableReconcile) == metav1.ConditionTrue {
log.Info("Installation reconciliation is disabled, reconciliation ended")
return ctrl.Result{}, nil
}
Expand Down
8 changes: 7 additions & 1 deletion operator/pkg/charts/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import (
k0shelmv1beta1 "github.com/k0sproject/k0s/pkg/apis/helm/v1beta1"
k0sv1beta1 "github.com/k0sproject/k0s/pkg/apis/k0s/v1beta1"
"github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
"github.com/replicatedhq/embedded-cluster/operator/pkg/k8sutil"
"github.com/replicatedhq/embedded-cluster/operator/pkg/release"
"github.com/replicatedhq/embedded-cluster/pkg/helpers"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
controllerruntime "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)
Expand Down Expand Up @@ -120,7 +122,11 @@ func ReconcileHelmCharts(ctx context.Context, cli client.Client, in *v1beta1.Ins
if in.Status.State != v1beta1.InstallationStateInstalled {
ev = &RecordedEvent{Reason: "AddonsUpgraded", Message: "Addons upgraded"}
}
in.Status.SetState(v1beta1.InstallationStateInstalled, "Addons upgraded", nil)
if k8sutil.CheckConditionStatus(in.Status, v1beta1.ConditionTypeV2MigrationInProgress) == metav1.ConditionTrue {
in.Status.SetState(v1beta1.InstallationStateAddonsInstalled, "Addons upgraded", nil)
} else {
in.Status.SetState(v1beta1.InstallationStateInstalled, "Addons upgraded", nil)
}
return ev, nil
}

Expand Down
3 changes: 3 additions & 0 deletions operator/pkg/cli/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ func NewLogger(level logrus.Level) (logr.Logger, error) {
log := logrusr.New(logrusLog)
return log, nil
}

// LogFunc can be used as an argument to functions that log messages.
type LogFunc func(string, ...any)
3 changes: 0 additions & 3 deletions operator/pkg/cli/migrate_v2_pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@ var _migrateV2PodSpec = corev1.Pod{
},
}

// LogFunc can be used as an argument to Run to log messages.
type LogFunc func(string, ...any)

// runMigrateV2PodAndWait runs the v2 migration pod and waits for the pod to finish.
func runMigrateV2PodAndWait(
ctx context.Context, logf LogFunc, cli client.Client,
Expand Down
102 changes: 101 additions & 1 deletion operator/pkg/cli/migratev2/installation.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,72 @@ package migratev2
import (
"context"
"fmt"
"time"

"github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
ecv1beta1 "github.com/replicatedhq/embedded-cluster/kinds/apis/v1beta1"
"github.com/replicatedhq/embedded-cluster/pkg/kubeutils"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// setV2MigrationInProgress sets the Installation condition to indicate that the v2 migration is in
// progress.
func setV2MigrationInProgress(ctx context.Context, logf LogFunc, cli client.Client, in *ecv1beta1.Installation) error {
logf("Setting v2 migration in progress")

err := setInstallationCondition(ctx, cli, in, metav1.Condition{
Type: ecv1beta1.ConditionTypeV2MigrationInProgress,
Status: metav1.ConditionTrue,
Reason: "V2MigrationInProgress",
})
if err != nil {
return fmt.Errorf("set v2 migration in progress condition: %w", err)
}

logf("Successfully set v2 migration in progress")
return nil
}

// waitForInstallationStateInstalled waits for the installation to be in a successful state and
// ready for the migration.
func waitForInstallationStateInstalled(ctx context.Context, logf LogFunc, cli client.Client, installation *ecv1beta1.Installation) error {
logf("Waiting for installation to reconcile")

err := wait.PollUntilContextCancel(ctx, 2*time.Second, true, func(ctx context.Context) (bool, error) {
in, err := kubeutils.GetCRDInstallation(ctx, cli, installation.Name)
if err != nil {
return false, fmt.Errorf("get installation: %w", err)
}

switch in.Status.State {
// Success states
case ecv1beta1.InstallationStateInstalled, ecv1beta1.InstallationStateAddonsInstalled:
return true, nil

// Failure states
case ecv1beta1.InstallationStateFailed, ecv1beta1.InstallationStateHelmChartUpdateFailure:
return false, fmt.Errorf("installation failed: %s", in.Status.Reason)
case ecv1beta1.InstallationStateObsolete:
return false, fmt.Errorf("installation is obsolete")

// In progress states
default:
return false, nil
}
})
if err != nil {
return err
}

logf("Installation reconciled")
return nil
}

// copyInstallationsToConfigMaps copies the Installation CRs to ConfigMaps.
func copyInstallationsToConfigMaps(ctx context.Context, logf LogFunc, cli client.Client) error {
var installationList ecv1beta1.InstallationList
Expand All @@ -37,7 +95,6 @@ func copyInstallationsToConfigMaps(ctx context.Context, logf LogFunc, cli client

func ensureInstallationConfigMap(ctx context.Context, cli client.Client, in *ecv1beta1.Installation) error {
copy := in.DeepCopy()
copy.Spec.SourceType = ecv1beta1.InstallationSourceTypeConfigMap
err := kubeutils.CreateInstallation(ctx, cli, copy)
if k8serrors.IsAlreadyExists(err) {
err := kubeutils.UpdateInstallation(ctx, cli, copy)
Expand All @@ -49,3 +106,46 @@ func ensureInstallationConfigMap(ctx context.Context, cli client.Client, in *ecv
}
return nil
}

// ensureInstallationStateInstalled sets the ConfigMap installation state to installed and updates
// the status to mark the upgrade as complete.
func ensureInstallationStateInstalled(ctx context.Context, logf LogFunc, cli client.Client, in *ecv1beta1.Installation) error {
logf("Setting installation state to installed")

// the installation will be in a ConfigMap at this point
copy, err := kubeutils.GetInstallation(ctx, cli, in.Name)
if err != nil {
return fmt.Errorf("get installation: %w", err)
}

copy.Status.SetState(v1beta1.InstallationStateInstalled, "V2MigrationComplete", nil)
meta.RemoveStatusCondition(&copy.Status.Conditions, ecv1beta1.ConditionTypeV2MigrationInProgress)
meta.RemoveStatusCondition(&copy.Status.Conditions, ecv1beta1.ConditionTypeDisableReconcile)

err = kubeutils.UpdateInstallationStatus(ctx, cli, copy)
if err != nil {
return fmt.Errorf("update installation status: %w", err)
}

logf("Successfully set installation state to installed")
return nil
}

func setInstallationCondition(ctx context.Context, cli client.Client, in *ecv1beta1.Installation, condition metav1.Condition) error {
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
var copy ecv1beta1.Installation
err := cli.Get(ctx, client.ObjectKey{Name: in.Name}, &copy)
if err != nil {
return fmt.Errorf("get installation: %w", err)
}

copy.Status.SetCondition(condition)

err = cli.Status().Update(ctx, &copy)
if err != nil {
return fmt.Errorf("update installation status: %w", err)
}

return nil
})
}
Loading

0 comments on commit 7b47030

Please sign in to comment.