Refactor RDP proxy handling and update related tests
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
package webingress
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ListenerConfig struct {
|
||||
RuntimeConfig
|
||||
HTTPAddr string
|
||||
HTTPSAddr string
|
||||
TLSCertFile string
|
||||
TLSKeyFile string
|
||||
Binder FabricBinder
|
||||
}
|
||||
|
||||
type ListenerStatus struct {
|
||||
SchemaVersion string `json:"schema_version"`
|
||||
Running bool `json:"running"`
|
||||
HTTPRunning bool `json:"http_running"`
|
||||
HTTPSRunning bool `json:"https_running"`
|
||||
HTTPAddr string `json:"http_addr,omitempty"`
|
||||
HTTPSAddr string `json:"https_addr,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
Errors []string `json:"errors,omitempty"`
|
||||
ObservedAt string `json:"observed_at"`
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
mu sync.Mutex
|
||||
http *http.Server
|
||||
https *http.Server
|
||||
status ListenerStatus
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
func NewManager() *Manager {
|
||||
return &Manager{now: time.Now}
|
||||
}
|
||||
|
||||
func (m *Manager) Apply(ctx context.Context, cfg ListenerConfig) ListenerStatus {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
_ = m.stopLocked(ctx)
|
||||
|
||||
runtime := Runtime{Config: cfg.RuntimeConfig, Binder: cfg.Binder, Now: m.now}
|
||||
status := ListenerStatus{
|
||||
SchemaVersion: "rap.web_ingress.listener_status.v1",
|
||||
Reason: "started",
|
||||
ObservedAt: m.observedAt(),
|
||||
}
|
||||
errorsOut := []string{}
|
||||
if strings.TrimSpace(cfg.HTTPAddr) == "" {
|
||||
cfg.HTTPAddr = ":80"
|
||||
}
|
||||
if strings.TrimSpace(cfg.HTTPSAddr) == "" {
|
||||
cfg.HTTPSAddr = ":443"
|
||||
}
|
||||
if server, addr, err := startHTTPServer(ctx, cfg.HTTPAddr, runtime.HTTPHandler()); err == nil {
|
||||
m.http = server
|
||||
status.HTTPRunning = true
|
||||
status.HTTPAddr = addr
|
||||
} else {
|
||||
errorsOut = append(errorsOut, "http:"+err.Error())
|
||||
}
|
||||
if cfg.TLSCertFile == "" || cfg.TLSKeyFile == "" {
|
||||
errorsOut = append(errorsOut, "https:tls_cert_file_and_key_file_required")
|
||||
} else if server, addr, err := startHTTPSServer(ctx, cfg.HTTPSAddr, cfg.TLSCertFile, cfg.TLSKeyFile, runtime.HTTPSHandler()); err == nil {
|
||||
m.https = server
|
||||
status.HTTPSRunning = true
|
||||
status.HTTPSAddr = addr
|
||||
} else {
|
||||
errorsOut = append(errorsOut, "https:"+err.Error())
|
||||
}
|
||||
status.Running = status.HTTPRunning || status.HTTPSRunning
|
||||
if len(errorsOut) > 0 {
|
||||
status.Errors = errorsOut
|
||||
if status.Running {
|
||||
status.Reason = "partial"
|
||||
} else {
|
||||
status.Reason = "blocked"
|
||||
}
|
||||
}
|
||||
m.status = status
|
||||
return status
|
||||
}
|
||||
|
||||
func (m *Manager) Stop(ctx context.Context) ListenerStatus {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
_ = m.stopLocked(ctx)
|
||||
m.status = ListenerStatus{
|
||||
SchemaVersion: "rap.web_ingress.listener_status.v1",
|
||||
Reason: "stopped",
|
||||
ObservedAt: m.observedAt(),
|
||||
}
|
||||
return m.status
|
||||
}
|
||||
|
||||
func (m *Manager) Status() ListenerStatus {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if m.status.SchemaVersion == "" {
|
||||
return ListenerStatus{
|
||||
SchemaVersion: "rap.web_ingress.listener_status.v1",
|
||||
Reason: "not_started",
|
||||
ObservedAt: m.observedAt(),
|
||||
}
|
||||
}
|
||||
return m.status
|
||||
}
|
||||
|
||||
func (m *Manager) stopLocked(ctx context.Context) error {
|
||||
var out error
|
||||
if m.http != nil {
|
||||
out = errors.Join(out, m.http.Shutdown(ctx))
|
||||
m.http = nil
|
||||
}
|
||||
if m.https != nil {
|
||||
out = errors.Join(out, m.https.Shutdown(ctx))
|
||||
m.https = nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (m *Manager) observedAt() string {
|
||||
now := time.Now().UTC()
|
||||
if m.now != nil {
|
||||
now = m.now().UTC()
|
||||
}
|
||||
return now.Format(time.RFC3339Nano)
|
||||
}
|
||||
|
||||
func startHTTPServer(ctx context.Context, addr string, handler http.Handler) (*http.Server, string, error) {
|
||||
listener, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
server := &http.Server{Handler: handler, ReadHeaderTimeout: 5 * time.Second}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
_ = server.Shutdown(context.Background())
|
||||
}()
|
||||
go func() {
|
||||
if err := server.Serve(listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
_ = server.Close()
|
||||
}
|
||||
}()
|
||||
return server, listener.Addr().String(), nil
|
||||
}
|
||||
|
||||
func startHTTPSServer(ctx context.Context, addr, certFile, keyFile string, handler http.Handler) (*http.Server, string, error) {
|
||||
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
listener, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
server := &http.Server{
|
||||
Handler: handler,
|
||||
ReadHeaderTimeout: 5 * time.Second,
|
||||
TLSConfig: &tls.Config{MinVersion: tls.VersionTLS12, Certificates: []tls.Certificate{cert}},
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
_ = server.Shutdown(context.Background())
|
||||
}()
|
||||
go func() {
|
||||
if err := server.ServeTLS(listener, "", ""); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
_ = server.Close()
|
||||
}
|
||||
}()
|
||||
return server, listener.Addr().String(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user