From ac7f7a9c8eb115c1d7c6ebf3895ddd6c9200d0b2 Mon Sep 17 00:00:00 2001 From: ehila Date: Thu, 29 Jun 2023 23:03:54 -0400 Subject: [PATCH] feat: support prerun with minimal services added function to launch minimal microshift services when needed Signed-off-by: ehila --- pkg/admin/prerun/prerun.go | 14 +++++- pkg/admin/prerun/run_minimal.go | 87 +++++++++++++++++++++++++++++++++ pkg/cmd/run.go | 6 +-- 3 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 pkg/admin/prerun/run_minimal.go diff --git a/pkg/admin/prerun/prerun.go b/pkg/admin/prerun/prerun.go index f8718e980a..9fe7a0a5a3 100644 --- a/pkg/admin/prerun/prerun.go +++ b/pkg/admin/prerun/prerun.go @@ -36,11 +36,13 @@ func (hi *HealthInfo) IsHealthy() bool { type PreRun struct { dataManager data.Manager + config *config.Config } -func New(dataManager data.Manager) *PreRun { +func New(dataManager data.Manager, config *config.Config) *PreRun { return &PreRun{ dataManager: dataManager, + config: config, } } @@ -187,6 +189,11 @@ func (pr *PreRun) regularPrerun() error { if migrationNeeded { _ = migrationNeeded + stop, err := runMinimalMicroshift(pr.config) + if err != nil { + return fmt.Errorf("minimal MicroShift run failed to be ready: %w", err) + } + defer stop() // TODO: data migration if err := writeExecVersionToData(); err != nil { @@ -210,6 +217,11 @@ func (pr *PreRun) upgradeFrom413() error { return fmt.Errorf("failed to create new backup %q: %w", backupName, err) } + stop, err := runMinimalMicroshift(pr.config) + if err != nil { + return fmt.Errorf("minimal MicroShift run failed to be ready: %w", err) + } + defer stop() // TODO: data migration if err := writeExecVersionToData(); err != nil { diff --git a/pkg/admin/prerun/run_minimal.go b/pkg/admin/prerun/run_minimal.go new file mode 100644 index 0000000000..93f5448763 --- /dev/null +++ b/pkg/admin/prerun/run_minimal.go @@ -0,0 +1,87 @@ +package prerun + +import ( + "context" + "fmt" + "os" + "os/signal" + "syscall" + "time" + + "github.com/openshift/microshift/pkg/config" + "github.com/openshift/microshift/pkg/controllers" + "github.com/openshift/microshift/pkg/node" + "github.com/openshift/microshift/pkg/servicemanager" + "github.com/openshift/microshift/pkg/util" + + "k8s.io/klog/v2" +) + +const ( + gracefulShutdownTimeout = time.Second * 30 + readyStateTimeout = time.Second * 10 +) + +// runMinimalMicroshift initializes a minimum run of microshift core services during pre-run +// to help with storage migration. +// +// Returns a handler to shutdown MicroShfit services and error if services never became ready. +func runMinimalMicroshift(cfg *config.Config) (context.CancelFunc, error) { + // Establish the context we will use to control execution + runCtx, runCancel := context.WithCancel(context.Background()) + m := servicemanager.NewServiceManager() + util.Must(m.AddService(node.NewNetworkConfiguration(cfg))) + util.Must(m.AddService(controllers.NewEtcd(cfg))) + util.Must(m.AddService(controllers.NewKubeAPIServer(cfg))) + + // Start core services up + ready, stopped := make(chan struct{}), make(chan struct{}) + go func() { + klog.Infof("Started %s", m.Name()) + if err := m.Run(runCtx, ready, stopped); err != nil { + klog.Errorf("Stopped %s: %v", m.Name(), err) + } else { + klog.Infof("%s completed", m.Name()) + } + }() + + // Connect os signal handler + sigTerm := make(chan os.Signal, 1) + signal.Notify(sigTerm, os.Interrupt, syscall.SIGTERM) + + go func() { + select { + case <-sigTerm: + klog.Info("Interrupt received") + klog.Info("Stopping services") + runCancel() + case <-runCtx.Done(): + klog.Info("Done signal from context received") + } + }() + + // Provides a function to call when you want to stop the services + // because this is a blocking call it serves as a call and wait for + // all the services to stop. + stopFunc := func() { + runCancel() + select { + case <-stopped: + case <-time.After(gracefulShutdownTimeout): + klog.Infof("Timed out waiting for services to stop") + } + klog.Infof("MicroShift Sevices stopped") + } + + // If Microshift does not become ready by the deadline, we consider that an error + select { + case <-ready: + klog.Infof("MicroShift is ready in minimal state") + case <-time.After(readyStateTimeout): + klog.Error("MicroShift never became ready in minimal state") + stopFunc() + return nil, fmt.Errorf("services failed to be in ready state by timeout(%s)", readyStateTimeout) + } + + return stopFunc, nil +} diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go index ccdb9a342a..b597e4d9a2 100644 --- a/pkg/cmd/run.go +++ b/pkg/cmd/run.go @@ -78,13 +78,13 @@ func logConfig(cfg *config.Config) { } } -func performPrerun() error { +func performPrerun(cfg *config.Config) error { dataManager, err := data.NewManager(config.BackupsDir) if err != nil { return err } - return prerun.New(dataManager).Perform() + return prerun.New(dataManager, cfg).Perform() } func RunMicroshift(cfg *config.Config) error { @@ -93,7 +93,7 @@ func RunMicroshift(cfg *config.Config) error { klog.Fatalf("MicroShift must be run privileged") } - if err := performPrerun(); err != nil { + if err := performPrerun(cfg); err != nil { klog.ErrorS(err, "Pre-run procedure failed") return err }