added basic support

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

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,9 +37,19 @@ 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 {
DomainLabel string `yaml:"domain_label"`
DefaultDomain string `yaml:"default_domain"`
Browser BrowserConfig `yaml:"browser_middleware"`
DomainLabel string `yaml:"domain_label"`
DefaultDomain string `yaml:"default_domain"`
}
// ServerManagerReconciler reconciles a ServerManager object
@@ -84,63 +97,142 @@ 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 {
if errors.IsNotFound(err) {
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
}
} else {
return ctrl.Result{}, err
}
}
domain := r.Config.DefaultDomain
if r.Config.DomainLabel != "" {
node := &corev1.Node{}
err = r.Get(ctx, client.ObjectKeyFromObject(&corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: found.Spec.NodeName}}), node)
if err != nil {
logging.Error(err, fmt.Sprintf("Failed to find node %s", found.Spec.NodeName))
return ctrl.Result{}, err
}
logging.Info("verified pod")
labelDomain, ok := node.GetLabels()[r.Config.DomainLabel]
if ok {
domain = labelDomain
}
}
if found.Spec.NodeName == "" {
logging.Info("waiting for pod to start 2")
return ctrl.Result{RequeueAfter: time.Second * 10}, nil
}
if domain != s.Status.Server.Domain {
s.Status.Server.Domain = domain
err = r.Update(ctx, s)
domain := r.Config.DefaultDomain
if r.Config.DomainLabel != "" {
node := &corev1.Node{}
err = r.Get(ctx, client.ObjectKeyFromObject(&corev1.Node{ObjectMeta: metav1.ObjectMeta{Name: found.Spec.NodeName}}), node)
if err != nil {
logging.Error(err, fmt.Sprintf("Failed to find node %s", found.Spec.NodeName))
return ctrl.Result{}, err
}
labelDomain, ok := node.GetLabels()[r.Config.DomainLabel]
if ok {
domain = labelDomain
}
}
logging.Info("got domain", "domain", domain)
if domain != s.Status.Server.Domain {
s.Status.Server.Domain = domain
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
}
err = r.Create(ctx, service)
if err != nil {
return ctrl.Result{}, err
if s.Spec.Server.On {
err = r.Create(ctx, service)
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{
@@ -206,12 +300,13 @@ func (r *ServerManagerReconciler) ServerPod(s *servermanagerv1alpha1.ServerManag
},
Containers: []corev1.Container{
{
Name: "server",
Image: s.Spec.Server.Image,
Command: s.Spec.Server.Command,
Args: s.Spec.Server.Args,
WorkingDir: s.Spec.Server.WorkingDir,
Ports: ports,
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,
Ports: ports,
VolumeMounts: []corev1.VolumeMount{{
Name: "volume",
MountPath: s.Spec.Server.WorkingDir,