added kubernetes - NOT TESTED

This commit is contained in:
2025-04-06 23:52:48 +03:00
parent 658789cccb
commit caff230188
8 changed files with 209 additions and 31 deletions

View File

@@ -6,7 +6,6 @@ import (
"fmt"
"log"
"maps"
"net"
"strings"
instancemanager "git.acooldomain.co/server-manager/backend/instancemanager"
@@ -395,7 +394,7 @@ func (im *InstanceManager) DeleteServer(ctx context.Context, serverId string) er
// Terminal
// Status Changing
func (im *InstanceManager) InteractiveTerminal(ctx context.Context, serverId string) (*net.Conn, error) {
func (im *InstanceManager) InteractiveTerminal(ctx context.Context, serverId string) (*instancemanager.TerminalConnection, error) {
server, err := im.GetServer(ctx, serverId)
if err != nil {
return nil, err
@@ -430,7 +429,12 @@ func (im *InstanceManager) InteractiveTerminal(ctx context.Context, serverId str
return nil, err
}
return &attach.Conn, nil
return &instancemanager.TerminalConnection{
Conn: attach.Conn,
ResizerFunc: func(width uint, height uint) error {
return im.ResizeTerminal(ctx, serverId, width, height)
},
}, nil
}
func (im *InstanceManager) ResizeTerminal(ctx context.Context, serverId string, width uint, height uint) error {

View File

@@ -16,6 +16,11 @@ type Server struct {
Domain string
}
type TerminalConnection struct {
Conn net.Conn
ResizerFunc func(width uint, height uint) error
}
type Port struct {
Number uint16
Protocol models.PortProtocol
@@ -48,8 +53,7 @@ type InstanceManager interface {
// Terminal
// Status Changing
InteractiveTerminal(ctx context.Context, serverId string) (*net.Conn, error)
ResizeTerminal(ctx context.Context, serverId string, width uint, height uint) error
InteractiveTerminal(ctx context.Context, serverId string) (*TerminalConnection, error)
// File Browser

View File

@@ -2,29 +2,32 @@ package kubernetes
import (
"context"
"net"
"io"
"strings"
"time"
"git.acooldomain.co/server-manager/backend/instancemanager"
"git.acooldomain.co/server-manager/backend/models"
servermanagerv1 "git.acooldomain.co/server-manager/kubernetes-operator/api/v1alpha1"
"github.com/buildkite/shellwords"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/storage/names"
names "k8s.io/apiserver/pkg/storage/names"
kubernetesclient "k8s.io/client-go/kubernetes"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/remotecommand"
"sigs.k8s.io/controller-runtime/pkg/client"
)
type InstanceManager struct {
instancemanager.InstanceManager
Config models.KubernetesInstanceManagerConfig
client client.Client
Config models.KubernetesInstanceManagerConfig
client client.Client
restCfg *rest.Config
coreV1Cli *kubernetes.Clientset
coreV1Cli *kubernetesclient.Clientset
}
func convertServerManagerImage(image *servermanagerv1.Image) *instancemanager.Image {
@@ -222,32 +225,113 @@ func (i *InstanceManager) DeleteServer(ctx context.Context, serverId string) err
// Terminal
// Status Changing
func (i *InstanceManager) InteractiveTerminal(ctx context.Context, serverId string) (*net.Conn, error) {
i.client.RESTMapper()
return nil, nil
}
func (i *InstanceManager) InteractiveTerminal(ctx context.Context, serverId string) (*instancemanager.TerminalConnection, error) {
stdinReader, stdinWriter := io.Pipe()
stdoutReader, stdoutWriter := io.Pipe()
resizeChan := make(chan remotecommand.TerminalSize, 1)
queue := &sizeQueue{resizeChan: resizeChan}
req := i.coreV1Cli.CoreV1().RESTClient().
Post().
Resource("pods").
Namespace(i.Config.Namespace).
Name(serverId).
SubResource("attach").
VersionedParams(&corev1.PodAttachOptions{
Container: "server",
Stdin: true,
Stdout: true,
Stderr: true,
TTY: true,
}, clientgoscheme.ParameterCodec)
func (i *InstanceManager) ResizeTerminal(ctx context.Context, serverId string, width uint, height uint) error {
return nil
executor, err := remotecommand.NewSPDYExecutor(i.restCfg, "POST", req.URL())
go func() {
defer stdoutWriter.Close()
defer stdinReader.Close()
_ = executor.StreamWithContext(ctx, remotecommand.StreamOptions{Stdin: stdinReader, Stdout: stdoutWriter, Stderr: stdoutWriter, Tty: true, TerminalSizeQueue: queue})
}()
if err != nil {
return nil, err
}
k := newKubeCon(stdinWriter, stdoutReader)
return &instancemanager.TerminalConnection{
Conn: k,
ResizerFunc: func(width uint, height uint) error {
resizeChan <- remotecommand.TerminalSize{Width: uint16(width), Height: uint16(height)}
return nil
},
}, nil
}
// File Browser
// Read Only
func (i *InstanceManager) GetFileBrowser(ctx context.Context, serverId string) (*models.FileBrowser, error) {
return nil, nil
serverManager := &servermanagerv1.ServerManager{}
err := i.client.Get(ctx, client.ObjectKey{Namespace: i.Config.Namespace, Name: serverId}, serverManager)
if err != nil {
return nil, err
}
return &models.FileBrowser{ServerId: serverManager.Name, Id: serverManager.Name, Url: serverManager.Status.Browser.Url}, nil
}
func (i *InstanceManager) ListFileBrowsers(ctx context.Context) ([]models.FileBrowser, error) {
return nil, nil
serverManagers := &servermanagerv1.ServerManagerList{}
err := i.client.List(ctx, serverManagers, &client.ListOptions{Namespace: i.Config.Namespace})
if err != nil {
return nil, err
}
fileBrowsers := make([]models.FileBrowser, len(serverManagers.Items))
for i, serverManager := range serverManagers.Items {
fileBrowsers[i] = models.FileBrowser{ServerId: serverManager.Name, Id: serverManager.Name, Url: serverManager.Status.Browser.Url}
}
return fileBrowsers, nil
}
// Status Changing
func (i *InstanceManager) StartFileBrowser(ctx context.Context, serverId string) (*models.FileBrowser, error) {
return nil, nil
serverManager := &servermanagerv1.ServerManager{}
err := i.client.Get(ctx, client.ObjectKey{Namespace: i.Config.Namespace, Name: serverId}, serverManager)
if err != nil {
return nil, err
}
err = i.client.Update(ctx, serverManager)
if err != nil {
return nil, err
}
childContext, cancelFunc := context.WithTimeout(ctx, time.Second*30)
defer cancelFunc()
for !serverManager.Status.Browser.Running {
err = i.client.Get(childContext, client.ObjectKey{Name: serverId, Namespace: i.Config.Namespace}, serverManager)
if err != nil {
return nil, err
}
}
return &models.FileBrowser{Url: serverManager.Status.Browser.Url, Id: serverManager.Name, ServerId: serverManager.Name}, nil
}
func (i *InstanceManager) StopFileBrowser(ctx context.Context, serverId string) error {
serverManager := &servermanagerv1.ServerManager{}
err := i.client.Get(ctx, client.ObjectKey{Namespace: i.Config.Namespace, Name: serverId}, serverManager)
if err != nil {
return err
}
err = i.client.Update(ctx, serverManager)
if err != nil {
return err
}
return nil
}
@@ -266,10 +350,15 @@ func NewInstanceManager(config models.KubernetesInstanceManagerConfig) (*Instanc
if err != nil {
return nil, err
}
coreV1Cli, err := kubernetesclient.NewForConfig(c)
if err != nil {
return nil, err
}
return &InstanceManager{client: client}, nil
return &InstanceManager{
client: client,
coreV1Cli: coreV1Cli,
restCfg: c,
Config: config,
}, nil
}

View File

@@ -0,0 +1,60 @@
package kubernetes
import (
"io"
"net"
"time"
"k8s.io/client-go/tools/remotecommand"
)
type kubeConn struct {
stdinWriter *io.PipeWriter
stdoutReader *io.PipeReader
closeCh chan struct{}
}
func (c *kubeConn) Read(b []byte) (int, error) {
return c.stdoutReader.Read(b)
}
func (c *kubeConn) Write(b []byte) (int, error) {
return c.stdinWriter.Write(b)
}
func (c *kubeConn) Close() error {
close(c.closeCh)
c.stdinWriter.Close()
return nil
}
func (c *kubeConn) LocalAddr() net.Addr { return dummyAddr("local") }
func (c *kubeConn) RemoteAddr() net.Addr { return dummyAddr("remote") }
func (c *kubeConn) SetDeadline(t time.Time) error { return nil }
func (c *kubeConn) SetReadDeadline(t time.Time) error { return nil }
func (c *kubeConn) SetWriteDeadline(t time.Time) error { return nil }
type dummyAddr string
func (a dummyAddr) Network() string { return string(a) }
func (a dummyAddr) String() string { return string(a) }
func newKubeCon(stdin *io.PipeWriter, stdout *io.PipeReader) net.Conn {
return &kubeConn{
stdinWriter: stdin,
stdoutReader: stdout,
closeCh: make(chan struct{}),
}
}
type sizeQueue struct {
resizeChan chan remotecommand.TerminalSize
}
func (s *sizeQueue) Next() *remotecommand.TerminalSize {
size, ok := <-s.resizeChan
if !ok {
return nil
}
return &size
}