penguin/monok8s

k8s image for Mono Gateway Dev Kit

clitools/pkg/controller/osupgrade/handler.go

raw ยท 3526 bytes

package osupgrade

import (
	"context"
	"fmt"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/klog/v2"

	monov1alpha1 "example.com/monok8s/pkg/apis/monok8s/v1alpha1"
	"example.com/monok8s/pkg/buildinfo"
	"example.com/monok8s/pkg/catalog"
	"example.com/monok8s/pkg/controller/osimage"
	"example.com/monok8s/pkg/kube"
)

func HandleOSUpgrade(ctx context.Context, clients *kube.Clients,
	namespace string, nodeName string,
	osu *monov1alpha1.OSUpgrade,
) error {
	osup, err := ensureProgressHeartbeat(ctx, clients, namespace, nodeName, osu)
	if err != nil {
		return err
	}

	klog.InfoS("handling osupgrade",
		"name", osu.Name,
		"node", nodeName,
		"desiredVersion", osu.Spec.DesiredVersion,
	)

	kata, err := catalog.ResolveCatalog(ctx, clients.Kubernetes, namespace, osu.Spec.Catalog)
	if err != nil {
		return failProgress(ctx, clients, osup, "resolve catalog", err)
	}

	plan, err := PlanUpgrade(buildinfo.KubeVersion, osu, kata)
	if err != nil {
		return failProgress(ctx, clients, osup, "plan upgrade", err)
	}

	if len(plan.Path) == 0 {
		osup.Status.CurrentVersion = buildinfo.KubeVersion
		osup.Status.TargetVersion = buildinfo.KubeVersion
		if err := markProgressCompleted(ctx, clients, osup, "already at target version"); err != nil {
			return err
		}
		klog.InfoS("osupgrade already satisfied",
			"name", osu.Name,
			"node", nodeName,
			"target", plan.ResolvedTarget,
		)
		return nil
	}

	first := plan.Path[0]

	osup.Status.TargetVersion = plan.ResolvedTarget
	osup.Status.Phase = monov1alpha1.OSUpgradeProgressPhaseDownloading
	osup.Status.Message = fmt.Sprintf("downloading image: %s", first.URL)

	now := metav1.Now()
	osup.Status.LastUpdatedAt = &now
	osup, err = updateProgressStatus(ctx, clients, osup_gvr, osup)

	if err != nil {
		return fmt.Errorf("update progress status: %w", err)
	}

	klog.InfoS("planned osupgrade",
		"name", osu.Name,
		"node", nodeName,
		"resolvedTarget", plan.ResolvedTarget,
		"steps", len(plan.Path),
		"currentVersion", buildinfo.KubeVersion,
		"fSHA256irstVersion", first.Version,
		"firstURL", first.URL,
		"size", first.Size,
	)

	imageSHA, err := first.SHA256()
	if err != nil {
		now = metav1.Now()
		return failProgress(ctx, clients, osup, "apply image", err)
	}

	pLogger := osimage.NewProgressLogger(2, 25)
	statusUpdater := osimage.NewTimeBasedUpdater(15)

	imageOptions := osimage.ApplyOptions{
		URL:               first.URL,
		TargetPath:        "./out/flash.img",
		ExpectedRawSHA256: imageSHA,
		ExpectedRawSize:   first.Size,
		BufferSize:        6 * 1024 * 1024,
		Progress: func(p osimage.Progress) {
			pLogger.Log(p)
			if err := statusUpdater.Run(func() error {

				now := metav1.Now()
				switch p.Stage {
				case "flash":
					osup.Status.Phase = monov1alpha1.OSUpgradeProgressPhaseWriting
				case "verify":
					osup.Status.Phase = monov1alpha1.OSUpgradeProgressPhaseVerifying
				}
				osup.Status.LastUpdatedAt = &now
				osup.Status.Message = fmt.Sprintf("%s: %d%%", p.Stage, osimage.PercentOf(p.BytesComplete, p.BytesTotal))

				updated, err := updateProgressStatus(ctx, clients, osup_gvr, osup)
				if err != nil {
					klog.ErrorS(err, "update progress status")
					return err
				}

				osup = updated
				return nil
			}); err != nil {
				klog.ErrorS(err, "throttled progress update failed")
			}
		},
	}

	result, err := osimage.ApplyImageStreamed(ctx, imageOptions)
	if err != nil {
		now = metav1.Now()
		return failProgress(ctx, clients, osup, "apply image", err)
	}

	klog.Info(result)
	// TODO: fw_setenv

	return nil
}