From 2406a44e7312ba01f4bd335b24fe5aee9233f958 Mon Sep 17 00:00:00 2001 From: Sayan Samanta Date: Fri, 26 Sep 2025 15:18:31 -0700 Subject: [PATCH 1/7] stz plugin --- server/internal/plugins/manager.go | 2 + server/internal/plugins/scaletozero/config.go | 23 ++++++ .../internal/plugins/scaletozero/manager.go | 78 +++++++++++++++++++ server/internal/plugins/scaletozero/plugin.go | 33 ++++++++ server/internal/plugins/scaletozero/types.go | 3 + 5 files changed, 139 insertions(+) create mode 100644 server/internal/plugins/scaletozero/config.go create mode 100644 server/internal/plugins/scaletozero/manager.go create mode 100644 server/internal/plugins/scaletozero/plugin.go create mode 100644 server/internal/plugins/scaletozero/types.go diff --git a/server/internal/plugins/manager.go b/server/internal/plugins/manager.go index 5e18abf77..df51b6f8a 100644 --- a/server/internal/plugins/manager.go +++ b/server/internal/plugins/manager.go @@ -13,6 +13,7 @@ import ( "github.com/m1k1o/neko/server/internal/config" "github.com/m1k1o/neko/server/internal/plugins/chat" "github.com/m1k1o/neko/server/internal/plugins/filetransfer" + "github.com/m1k1o/neko/server/internal/plugins/scaletozero" "github.com/m1k1o/neko/server/pkg/types" ) @@ -47,6 +48,7 @@ func New(config *config.Plugins) *ManagerCtx { // add built-in plugins manager.plugins.addPlugin(filetransfer.NewPlugin()) manager.plugins.addPlugin(chat.NewPlugin()) + manager.plugins.addPlugin(scaletozero.NewPlugin()) return manager } diff --git a/server/internal/plugins/scaletozero/config.go b/server/internal/plugins/scaletozero/config.go new file mode 100644 index 000000000..a38a9f2d7 --- /dev/null +++ b/server/internal/plugins/scaletozero/config.go @@ -0,0 +1,23 @@ +package scaletozero + +import ( + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +type Config struct { + Enabled bool +} + +func (Config) Init(cmd *cobra.Command) error { + cmd.PersistentFlags().Bool("scaletozero.enabled", false, "enable scale-to-zero") + if err := viper.BindPFlag("scaletozero.enabled", cmd.PersistentFlags().Lookup("scaletozero.enabled")); err != nil { + return err + } + + return nil +} + +func (c *Config) Set() { + c.Enabled = viper.GetBool("scaletozero.enabled") +} diff --git a/server/internal/plugins/scaletozero/manager.go b/server/internal/plugins/scaletozero/manager.go new file mode 100644 index 000000000..ead8ac66a --- /dev/null +++ b/server/internal/plugins/scaletozero/manager.go @@ -0,0 +1,78 @@ +package scaletozero + +import ( + "context" + "sync" + + "github.com/m1k1o/neko/server/pkg/types" + "github.com/onkernel/kernel-images/server/lib/scaletozero" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +func NewManager( + sessions types.SessionManager, + config *Config, +) *Manager { + logger := log.With().Str("module", "scaletozero").Logger() + + return &Manager{ + logger: logger, + config: config, + sessions: sessions, + ctrl: scaletozero.NewUnikraftCloudController(), + } +} + +type Manager struct { + logger zerolog.Logger + config *Config + sessions types.SessionManager + ctrl scaletozero.Controller + mu sync.Mutex + shutdown bool + pending int +} + +func (m *Manager) Start() error { + if !m.config.Enabled { + return nil + } + m.logger.Info().Msg("scale-to-zero plugin enabled") + + m.sessions.OnConnected(func(session types.Session) { + m.mu.Lock() + defer m.mu.Unlock() + if m.shutdown { + return + } + + m.pending++ + m.ctrl.Disable(context.Background()) + }) + + m.sessions.OnDisconnected(func(session types.Session) { + m.mu.Lock() + defer m.mu.Unlock() + if m.shutdown { + return + } + m.pending-- + m.ctrl.Enable(context.Background()) + }) + + m.logger.Info().Msg("scale-to-zero hooks enabled") + return nil +} + +func (m *Manager) Shutdown() error { + m.mu.Lock() + defer m.mu.Unlock() + m.shutdown = true + + for i := 0; i < m.pending; i++ { + m.ctrl.Enable(context.Background()) + } + + return nil +} diff --git a/server/internal/plugins/scaletozero/plugin.go b/server/internal/plugins/scaletozero/plugin.go new file mode 100644 index 000000000..978cc7c40 --- /dev/null +++ b/server/internal/plugins/scaletozero/plugin.go @@ -0,0 +1,33 @@ +package scaletozero + +import ( + "github.com/m1k1o/neko/server/pkg/types" +) + +type Plugin struct { + config *Config + manager *Manager +} + +func NewPlugin() *Plugin { + return &Plugin{ + config: &Config{}, + } +} + +func (p *Plugin) Name() string { + return PluginName +} + +func (p *Plugin) Config() types.PluginConfig { + return p.config +} + +func (p *Plugin) Start(m types.PluginManagers) error { + p.manager = NewManager(m.SessionManager, p.config) + return p.manager.Start() +} + +func (p *Plugin) Shutdown() error { + return p.manager.Shutdown() +} diff --git a/server/internal/plugins/scaletozero/types.go b/server/internal/plugins/scaletozero/types.go new file mode 100644 index 000000000..8ceddf604 --- /dev/null +++ b/server/internal/plugins/scaletozero/types.go @@ -0,0 +1,3 @@ +package scaletozero + +const PluginName = "scaletozero" From 1d423fb7c9813169bba503e25a05775c28c44991 Mon Sep 17 00:00:00 2001 From: Sayan Samanta Date: Fri, 26 Sep 2025 15:43:40 -0700 Subject: [PATCH 2/7] go mod tidy --- server/go.mod | 5 ++--- server/go.sum | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/server/go.mod b/server/go.mod index 2b74dd7d5..2875bd792 100644 --- a/server/go.mod +++ b/server/go.mod @@ -1,8 +1,6 @@ module github.com/m1k1o/neko/server -go 1.24.0 - -toolchain go1.24.5 +go 1.25.0 require ( github.com/PaesslerAG/gval v1.2.4 @@ -12,6 +10,7 @@ require ( github.com/gorilla/websocket v1.5.3 github.com/kataras/go-events v0.0.3 github.com/mitchellh/mapstructure v1.5.0 + github.com/onkernel/kernel-images/server v0.0.0-20250912023508-e0ca1d95b771 github.com/pion/ice/v2 v2.3.38 github.com/pion/interceptor v0.1.40 github.com/pion/logging v0.2.4 diff --git a/server/go.sum b/server/go.sum index 4889a2418..bf54b1f90 100644 --- a/server/go.sum +++ b/server/go.sum @@ -56,6 +56,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/onkernel/kernel-images/server v0.0.0-20250912023508-e0ca1d95b771 h1:Z+Zu7ILww5/4q70h1oA+CYBCM0QCuNtAtGDUxjIyp1A= +github.com/onkernel/kernel-images/server v0.0.0-20250912023508-e0ca1d95b771/go.mod h1:8BxVW6vmlK9as98BTOYIjsVPpXObs+b4aZyZ23JZf4Y= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= From fa33e399845a9d841fa621b4f7ba429cbf317f3d Mon Sep 17 00:00:00 2001 From: Sayan Samanta Date: Fri, 26 Sep 2025 15:43:46 -0700 Subject: [PATCH 3/7] bump images --- server/Dockerfile | 2 +- server/Dockerfile.bookworm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/Dockerfile b/server/Dockerfile index 356096518..1aacd0b45 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,4 +1,4 @@ -ARG BASE_IMAGE=golang:1.24-bullseye +ARG BASE_IMAGE=golang:1.25.0 FROM $BASE_IMAGE AS server WORKDIR /src diff --git a/server/Dockerfile.bookworm b/server/Dockerfile.bookworm index e3f67371c..552880080 100644 --- a/server/Dockerfile.bookworm +++ b/server/Dockerfile.bookworm @@ -1,4 +1,4 @@ -ARG BASE_IMAGE=golang:1.24-bookworm +ARG BASE_IMAGE=golang:1.25-bookworm FROM $BASE_IMAGE AS server WORKDIR /src From fc6db6a83f5938fbe692d763bdb9188470e17cb8 Mon Sep 17 00:00:00 2001 From: Sayan Samanta Date: Fri, 26 Sep 2025 17:06:22 -0700 Subject: [PATCH 4/7] whups --- server/internal/plugins/scaletozero/manager.go | 1 - 1 file changed, 1 deletion(-) diff --git a/server/internal/plugins/scaletozero/manager.go b/server/internal/plugins/scaletozero/manager.go index ead8ac66a..34e813422 100644 --- a/server/internal/plugins/scaletozero/manager.go +++ b/server/internal/plugins/scaletozero/manager.go @@ -61,7 +61,6 @@ func (m *Manager) Start() error { m.ctrl.Enable(context.Background()) }) - m.logger.Info().Msg("scale-to-zero hooks enabled") return nil } From ae140ed7c12282ea9de7beb700e83d209c21604a Mon Sep 17 00:00:00 2001 From: Sayan Samanta Date: Fri, 26 Sep 2025 17:26:52 -0700 Subject: [PATCH 5/7] add some logs --- server/internal/plugins/scaletozero/manager.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/internal/plugins/scaletozero/manager.go b/server/internal/plugins/scaletozero/manager.go index 34e813422..cc80362a9 100644 --- a/server/internal/plugins/scaletozero/manager.go +++ b/server/internal/plugins/scaletozero/manager.go @@ -48,6 +48,7 @@ func (m *Manager) Start() error { } m.pending++ + m.logger.Info().Msgf("connection started, disabling scale-to-zero (pending: %d)", m.pending) m.ctrl.Disable(context.Background()) }) @@ -57,7 +58,9 @@ func (m *Manager) Start() error { if m.shutdown { return } + m.pending-- + m.logger.Info().Msgf("connection started, disabling scale-to-zero (pending: %d)", m.pending) m.ctrl.Enable(context.Background()) }) @@ -69,6 +72,7 @@ func (m *Manager) Shutdown() error { defer m.mu.Unlock() m.shutdown = true + m.logger.Info().Msgf("shutdown started, re-enabling scale-to-zero (pending: %d)", m.pending) for i := 0; i < m.pending; i++ { m.ctrl.Enable(context.Background()) } From 8718adc7a59cd4a322f5ff96ed809a0aaf8c2cb3 Mon Sep 17 00:00:00 2001 From: Sayan Samanta Date: Fri, 26 Sep 2025 17:27:05 -0700 Subject: [PATCH 6/7] also notify on sigterm --- server/cmd/serve.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/cmd/serve.go b/server/cmd/serve.go index b8ff37c47..38bd357c4 100644 --- a/server/cmd/serve.go +++ b/server/cmd/serve.go @@ -3,6 +3,7 @@ package cmd import ( "os" "os/signal" + "syscall" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -236,7 +237,7 @@ func (c *serve) Run(cmd *cobra.Command, args []string) { c.logger.Info().Msg("neko ready") quit := make(chan os.Signal, 1) - signal.Notify(quit, os.Interrupt) + signal.Notify(quit, os.Interrupt, syscall.SIGTERM) sig := <-quit c.logger.Warn().Msgf("received %s, attempting graceful shutdown", sig) From d650d7be929ac7cf07f737264928e7ce6d6d4b4e Mon Sep 17 00:00:00 2001 From: Sayan Samanta Date: Mon, 29 Sep 2025 12:55:54 -0700 Subject: [PATCH 7/7] readme --- KERNEL_README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 KERNEL_README.md diff --git a/KERNEL_README.md b/KERNEL_README.md new file mode 100644 index 000000000..c34a750d0 --- /dev/null +++ b/KERNEL_README.md @@ -0,0 +1,42 @@ +# neko fork for onkernel + +This is a public fork of the [m1k1o/neko](https://github.com/m1k1o/neko) repository. + +## Overview + +We maintain this fork to provide a customized `base` image that is used in our browser images at [onkernel/kernel-images](https://github.com/onkernel/kernel-images/tree/main/images). + +## Building + +To build images from this fork, use the build script from the repository root: + +```bash +# Build the base image +./build base + +# Build with custom repository and tag +./build base --repository your-repo/neko --tag custom-tag +``` + +The `--repository` and `--tag` options allow you to specify exactly which image you're building, making it easy to reference back to specific builds in `kernel-images`. + +## Keeping in sync with upstream + +To merge the latest changes from the upstream neko repository: + +```bash +# Run the sync script to create a new branch and merge upstream changes +./scripts/sync-upstream.sh + +# Or merge directly into your current branch +./scripts/sync-upstream.sh --no-new-branch + +# To merge a specific upstream branch +./scripts/sync-upstream.sh --upstream-branch $branch +``` + +After running the sync script: + +1. Resolve any merge conflicts +2. Test the build to ensure compatibility +3. Push the changes and create a PR for review