128 lines
3.4 KiB
Go
128 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"runtime"
|
|
"strconv"
|
|
)
|
|
|
|
type Server struct {
|
|
serviceProbe ServiceProbe
|
|
metricProbe MetricProbe
|
|
portalServices PortalServiceProvider
|
|
auth AuthConfig
|
|
}
|
|
|
|
func NewServer() *Server {
|
|
serviceProbe := NewServiceProbe()
|
|
return &Server{
|
|
serviceProbe: serviceProbe,
|
|
metricProbe: NewMetricProbe(),
|
|
portalServices: NewPortalServiceProvider(),
|
|
auth: NewAuthConfig(),
|
|
}
|
|
}
|
|
|
|
func (s *Server) ListenAndServe(addr string) error {
|
|
return http.ListenAndServe(addr, s.withCORS(s.routes()))
|
|
}
|
|
|
|
func (s *Server) routes() http.Handler {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/auth/status", s.authStatusHandler)
|
|
mux.HandleFunc("/health", s.healthHandler)
|
|
mux.HandleFunc("/services", s.servicesHandler)
|
|
mux.HandleFunc("/portal/services", s.portalServicesHandler)
|
|
mux.HandleFunc("/metrics/simple", s.metricsHandler)
|
|
return mux
|
|
}
|
|
|
|
func (s *Server) withCORS(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
origin := r.Header.Get("Origin")
|
|
if allowedOrigin(origin) {
|
|
w.Header().Set("Access-Control-Allow-Origin", origin)
|
|
} else {
|
|
w.Header().Set("Access-Control-Allow-Origin", "http://127.0.0.1:17000")
|
|
}
|
|
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
|
|
w.Header().Set("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Bridge-Token, X-XWorkspace-Token")
|
|
if r.Method == http.MethodOptions {
|
|
w.WriteHeader(http.StatusNoContent)
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
func allowedOrigin(origin string) bool {
|
|
switch origin {
|
|
case "http://127.0.0.1:17000", "http://localhost:17000", "http://127.0.0.1:3000", "https://console.svc.plus":
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (s *Server) authStatusHandler(w http.ResponseWriter, r *http.Request) {
|
|
writeJSON(w, AuthStatusResponse{Required: s.auth.Required()})
|
|
}
|
|
|
|
func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) {
|
|
if !s.requireAuth(w, r) {
|
|
return
|
|
}
|
|
services := s.serviceProbe.Probe()
|
|
writeJSON(w, HealthResponse{
|
|
Status: "ok",
|
|
Arch: runtime.GOARCH,
|
|
OS: runtime.GOOS,
|
|
CPU: runtime.NumCPU(),
|
|
Memory: "unknown",
|
|
Disk: "unknown",
|
|
Services: services,
|
|
Metrics: s.metricProbe.Probe(services),
|
|
})
|
|
}
|
|
|
|
func (s *Server) servicesHandler(w http.ResponseWriter, r *http.Request) {
|
|
if !s.requireAuth(w, r) {
|
|
return
|
|
}
|
|
writeJSON(w, s.serviceProbe.Probe())
|
|
}
|
|
|
|
func (s *Server) portalServicesHandler(w http.ResponseWriter, r *http.Request) {
|
|
if !s.requireAuth(w, r) {
|
|
return
|
|
}
|
|
writeJSON(w, PortalServicesResponse{Services: s.portalServices.Services()})
|
|
}
|
|
|
|
func (s *Server) metricsHandler(w http.ResponseWriter, r *http.Request) {
|
|
if !s.requireAuth(w, r) {
|
|
return
|
|
}
|
|
_, _ = w.Write([]byte("xworkspace_systemd_services " + strconv.Itoa(len(s.serviceProbe.Probe())) + "\n"))
|
|
}
|
|
|
|
func (s *Server) requireAuth(w http.ResponseWriter, r *http.Request) bool {
|
|
if s.auth.Authorize(r) {
|
|
return true
|
|
}
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
_ = json.NewEncoder(w).Encode(map[string]string{"error": "unauthorized"})
|
|
return false
|
|
}
|
|
|
|
func writeJSON(w http.ResponseWriter, v any) {
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
enc := json.NewEncoder(w)
|
|
enc.SetIndent("", " ")
|
|
if err := enc.Encode(v); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
}
|