added basic support

This commit is contained in:
ACoolName 2025-04-02 04:39:27 +03:00
parent d83bc3368a
commit 27d24e5b1d
6 changed files with 166 additions and 49 deletions

View File

@ -50,14 +50,13 @@ type ServerSpec struct {
}
type BrowserSpec struct {
Image string `json:"image,omitempty"`
On bool `json:"on,omitempty"`
Port Port `json:"port,omitempty"`
}
// ServerManagerSpec defines the desired state of ServerManager
type ServerManagerSpec struct {
Id string `json:"id,omitempty"`
Storage string `json:"storage,omitempty"`
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
Server ServerSpec `json:"server,omitempty"`

View File

@ -23,6 +23,7 @@ import (
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
"gopkg.in/yaml.v3"
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/apimachinery/pkg/runtime"
@ -37,6 +38,7 @@ import (
servermanagerv1alpha1 "git.acooldomain.co/server-manager/kubernetes-operator/api/v1alpha1"
"git.acooldomain.co/server-manager/kubernetes-operator/internal/controller"
traefikv3 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1"
// +kubebuilder:scaffold:imports
)
@ -49,6 +51,7 @@ func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(servermanagerv1alpha1.AddToScheme(scheme))
utilruntime.Must(traefikv3.AddToScheme(scheme))
// +kubebuilder:scaffold:scheme
}
@ -143,12 +146,20 @@ func main() {
setupLog.Error(err, "unable to start manager")
os.Exit(1)
}
config := controller.ServerManagerReconcilerConfig{}
config := &controller.ServerManagerReconcilerConfig{}
configData, err := os.ReadFile("config.yaml")
if err != nil {
setupLog.Error(err, "unable to read config file")
}
err = yaml.Unmarshal(configData, config)
if err != nil {
setupLog.Error(err, "failed to marshal data")
}
if err = (&controller.ServerManagerReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Config: config,
Config: *config,
}).SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "ServerManager")
os.Exit(1)

2
config.yaml Normal file
View File

@ -0,0 +1,2 @@
domain_label: "ddns.acooldomain.co/hostname"
default_domain: "acooldomain.co"

View File

@ -90,6 +90,8 @@ spec:
working_dir:
type: string
type: object
storage:
type: string
type: object
status:
description: ServerManagerStatus defines the observed state of ServerManager

View File

@ -6,4 +6,12 @@ metadata:
app.kubernetes.io/managed-by: kustomize
name: servermanager-sample
spec:
# TODO(user): Add fields here
id: test-serverr
storage: 10Gi
server:
"on": true
image: git.acooldomain.co/server-manager/minecraft:paper-1.21.4
working_dir: /opt/server
ports:
- protocol: TCP
port: 25565

View File

@ -19,10 +19,13 @@ package controller
import (
"context"
"fmt"
"strings"
"time"
traefikv3 "github.com/traefik/traefik/v3/pkg/provider/kubernetes/crd/traefikio/v1alpha1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
@ -34,7 +37,17 @@ import (
servermanagerv1alpha1 "git.acooldomain.co/server-manager/kubernetes-operator/api/v1alpha1"
)
type MiddlewareRef struct {
Name string `yaml:"name"`
Namespace string `yaml:"namespace"`
}
type BrowserConfig struct {
Middleware MiddlewareRef `yaml:"middleware"`
}
type ServerManagerReconcilerConfig struct {
Browser BrowserConfig `yaml:"browser_middleware"`
DomainLabel string `yaml:"domain_label"`
DefaultDomain string `yaml:"default_domain"`
}
@ -84,20 +97,34 @@ func (r *ServerManagerReconciler) Reconcile(ctx context.Context, req ctrl.Reques
return ctrl.Result{}, err
}
}
logging.Info("verified pvc")
serverPod := r.ServerPod(s, pvc)
if serverPod != nil {
found := &corev1.Pod{}
err = r.Get(ctx, client.ObjectKey{Namespace: pvc.Namespace, Name: pvc.Name}, found)
if err == nil && !s.Spec.Server.On {
err = r.Delete(ctx, serverPod)
return ctrl.Result{Requeue: true}, err
}
if err != nil {
if errors.IsNotFound(err) {
if s.Spec.Server.On {
err = r.Create(ctx, serverPod)
return ctrl.Result{Requeue: true}, err
}
} else {
return ctrl.Result{}, err
}
}
logging.Info("verified pod")
if found.Spec.NodeName == "" {
logging.Info("waiting for pod to start 2")
return ctrl.Result{RequeueAfter: time.Second * 10}, nil
}
domain := r.Config.DefaultDomain
if r.Config.DomainLabel != "" {
node := &corev1.Node{}
@ -113,34 +140,99 @@ func (r *ServerManagerReconciler) Reconcile(ctx context.Context, req ctrl.Reques
}
}
logging.Info("got domain", "domain", domain)
if domain != s.Status.Server.Domain {
s.Status.Server.Domain = domain
err = r.Update(ctx, s)
logging.Info("updating ServerManager object", "NewDomain", domain, "OldDomain", s.Status.Server.Domain)
err = r.Status().Update(ctx, s)
logging.Info(fmt.Sprintf("%#v", err))
return ctrl.Result{}, err
}
}
service := r.ServerService(s)
found_service := &corev1.Service{}
err = r.Get(ctx, client.ObjectKeyFromObject(service), found_service)
foundService := &corev1.Service{}
err = r.Get(ctx, client.ObjectKeyFromObject(service), foundService)
if err == nil && !s.Spec.Server.On {
err = r.Delete(ctx, service)
return ctrl.Result{Requeue: true}, err
}
if err != nil {
if !errors.IsNotFound(err) {
return ctrl.Result{}, err
}
if s.Spec.Server.On {
err = r.Create(ctx, service)
if err != nil {
return ctrl.Result{}, err
return ctrl.Result{Requeue: true}, err
}
}
logging.Info(fmt.Sprintf("verified service %#v", foundService))
return ctrl.Result{}, nil
}
func (r *ServerManagerReconciler) BrowserPod(s *servermanagerv1alpha1.ServerManager, pvc *corev1.PersistentVolumeClaim) *corev1.Pod {
ports := make([]corev1.ContainerPort, len(s.Spec.Server.Ports))
for i, port := range s.Spec.Server.Ports {
ports[i] = corev1.ContainerPort{
ContainerPort: port.Port,
Protocol: port.Protocol,
}
}
return ctrl.Result{}, nil
pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-browser", s.Name),
Namespace: s.Namespace,
Labels: map[string]string{"server": s.Name},
},
Spec: corev1.PodSpec{
Volumes: []corev1.Volume{
{
Name: "volume",
VolumeSource: corev1.VolumeSource{
PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
ClaimName: pvc.Name,
},
},
},
},
InitContainers: []corev1.Container{
{
Name: "proxy-setter",
Image: "filebrowser/filebrowser",
ImagePullPolicy: corev1.PullAlways,
WorkingDir: s.Spec.Server.WorkingDir,
Ports: ports,
Args: []string{},
},
},
Containers: []corev1.Container{
{
Name: "browser",
Image: "filebrowser/filebrowser",
ImagePullPolicy: corev1.PullAlways,
Ports: ports,
Args: []string{},
VolumeMounts: []corev1.VolumeMount{{
Name: "volume",
MountPath: s.Spec.Server.WorkingDir,
}},
Stdin: true,
TTY: true,
},
},
},
}
controllerutil.SetControllerReference(s, pod, r.Scheme)
return pod
}
func (r *ServerManagerReconciler) ServerService(s *servermanagerv1alpha1.ServerManager) *corev1.Service {
ports := make([]corev1.ServicePort, len(s.Spec.Server.Ports))
for i, port := range s.Spec.Server.Ports {
ports[i] = corev1.ServicePort{NodePort: 0, Port: port.Port, TargetPort: intstr.FromInt32(port.Port), Name: fmt.Sprintf("%s-%d", port.Protocol, port.Port)}
ports[i] = corev1.ServicePort{NodePort: 0, Port: port.Port, TargetPort: intstr.FromInt32(port.Port), Name: fmt.Sprintf("%s-%d", strings.ToLower(string(port.Protocol)), port.Port)}
}
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
@ -148,9 +240,10 @@ func (r *ServerManagerReconciler) ServerService(s *servermanagerv1alpha1.ServerM
Namespace: s.Namespace,
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeNodePort,
Ports: ports,
Selector: map[string]string{
"server": s.Spec.Id,
"server": s.Name,
},
},
}
@ -167,6 +260,9 @@ func (r *ServerManagerReconciler) ServerPvc(s *servermanagerv1alpha1.ServerManag
Spec: corev1.PersistentVolumeClaimSpec{
AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteMany},
Resources: corev1.VolumeResourceRequirements{
Requests: corev1.ResourceList{corev1.ResourceStorage: resource.MustParse(s.Spec.Storage)},
},
},
}
@ -176,9 +272,6 @@ func (r *ServerManagerReconciler) ServerPvc(s *servermanagerv1alpha1.ServerManag
}
func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManager, pvc *corev1.PersistentVolumeClaim) *corev1.Pod {
if !s.Spec.Server.On {
return nil
}
ports := make([]corev1.ContainerPort, len(s.Spec.Server.Ports))
for i, port := range s.Spec.Server.Ports {
@ -192,6 +285,7 @@ func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManag
ObjectMeta: metav1.ObjectMeta{
Name: s.Name,
Namespace: s.Namespace,
Labels: map[string]string{"server": s.Name},
},
Spec: corev1.PodSpec{
Volumes: []corev1.Volume{
@ -208,6 +302,7 @@ func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManag
{
Name: "server",
Image: s.Spec.Server.Image,
ImagePullPolicy: corev1.PullAlways,
Command: s.Spec.Server.Command,
Args: s.Spec.Server.Args,
WorkingDir: s.Spec.Server.WorkingDir,