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 }