feat(platform): add node orchestration and the felis entrypoint
The platform package that places servers across nodes and wires the operator, build, restore, and reaper subsystems, plus cmd/felis, the single binary that runs them.
This commit is contained in:
21 files changed
+3713
No files matched your search
@@ -0,0 +1,75 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"felis.lolicon.best/internal/apis/felis/v1alpha1"
|
||||
"felis.lolicon.best/internal/operator"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/cache"
|
||||
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
||||
)
|
||||
|
||||
// cmdOperator runs the MinecraftServer controller-manager (spec §5). It builds
|
||||
// the scheme, wires the Reconciler with the production RCON prober, and blocks
|
||||
// on the manager until the process receives a termination signal.
|
||||
func cmdOperator(args []string, _, stderr io.Writer) int {
|
||||
fs := flag.NewFlagSet("operator", flag.ContinueOnError)
|
||||
fs.SetOutput(stderr)
|
||||
metricsAddr := fs.String("metrics-bind-address", ":8080", "address the metric endpoint binds to")
|
||||
// namespace MUST equal the [k8s] namespace felis-api is configured with, and
|
||||
// the deployment manifests (felis manifests) render both from one value. It
|
||||
// scopes the manager's cache (informers) to a single namespace so the operator
|
||||
// can run under a namespaced Role instead of cluster-admin (spec §21). The
|
||||
// default matches config.defaultNamespace, so an unconfigured deployment
|
||||
// agrees; a mismatch would silently scope the cache to the wrong namespace and
|
||||
// every reconcile would see zero servers — hence the watched namespace is
|
||||
// logged at startup so a divergence surfaces immediately rather than silently.
|
||||
namespace := fs.String("namespace", "minecraft", "namespace to watch; must match felis-api's [k8s] namespace")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return 2
|
||||
}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
|
||||
utilruntime.Must(v1alpha1.AddToScheme(scheme))
|
||||
|
||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
|
||||
Scheme: scheme,
|
||||
Metrics: metricsserver.Options{BindAddress: *metricsAddr},
|
||||
// Scope every informer to the single watched namespace. Without this the
|
||||
// cached client (mgr.GetClient) would LIST/WATCH cluster-wide, which a
|
||||
// namespaced Role cannot grant — the operator would fail closed at runtime
|
||||
// or, worse, demand cluster-admin. With it, the platform.OperatorRole
|
||||
// (get/list/watch in one namespace) is exactly sufficient.
|
||||
Cache: cache.Options{
|
||||
DefaultNamespaces: map[string]cache.Config{*namespace: {}},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "felis operator: create manager: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
fmt.Fprintf(stderr, "felis operator: watching namespace %q\n", *namespace)
|
||||
|
||||
r := &operator.Reconciler{
|
||||
Client: mgr.GetClient(),
|
||||
Scheme: mgr.GetScheme(),
|
||||
Prober: operator.RconProber{},
|
||||
}
|
||||
if err := r.SetupWithManager(mgr); err != nil {
|
||||
fmt.Fprintf(stderr, "felis operator: setup controller: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
|
||||
fmt.Fprintf(stderr, "felis operator: manager exited: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
Reference in new issue
Block a user