Skip to main content
Glama
admin_routes.go6.51 kB
package routing import ( "encoding/json" "errors" "fmt" "io" "lunar/engine/config" "lunar/engine/doctor" "lunar/engine/utils/writers" "net/http" "os" "github.com/rs/zerolog/log" ) const ( managedKey string = "LUNAR_MANAGED" ) var ( managedValue = os.Getenv(managedKey) managed = isManaged() ) func isManaged() bool { return managedValue == "true" } type handshake struct { Managed bool `json:"managed"` } func readJSONFile(filePath string) ([]byte, error) { content, err := os.ReadFile(filePath) if err != nil { log.Error().Err(err).Stack().Msgf("Failed to read %s", filePath) } return content, err } func handleJSONResponse(writer http.ResponseWriter, data []byte) { writer.Header().Set("Content-Type", "application/json") writer.WriteHeader(http.StatusOK) if err := json.NewEncoder(writer).Encode( map[string]string{"data": string(data)}); err != nil { log.Error().Err(err).Stack().Msg("Failed encoding response") } } func handleError(writer http.ResponseWriter, message string, status int, err error, ) { http.Error(writer, fmt.Sprintf(`{"msg": "%s", "error": "%v"}`, message, err), status) log.Error().Err(err).Stack().Msg(message) } func SuccessResponse(writer http.ResponseWriter, message string) { log.Trace().Msg(message) fmt.Fprintf(writer, `{"msg": "%s"}`, message) } func HandleApplyPolicies( policyAccessor *config.TxnPoliciesAccessor, exportWriter writers.Writer, ) func(http.ResponseWriter, *http.Request) { return func(writer http.ResponseWriter, req *http.Request) { switch req.Method { case http.MethodPost: // We close the writer to allow it to reconnect. // We need this as the Fluent Bit is restarted for the exports reload. _ = exportWriter.Close() body, err := io.ReadAll(req.Body) if err != nil { handleError(writer, "Error reading request body", http.StatusUnprocessableEntity, err) return } defer req.Body.Close() if len(body) > 0 { err = policyAccessor.UpdateRawData(body) if err != nil { handleError(writer, "Failed to apply policies from file", http.StatusUnprocessableEntity, err) return } } err = policyAccessor.ReloadFromFile() if err != nil { handleError(writer, "Failed to apply policies from file", http.StatusUnprocessableEntity, err) return } SuccessResponse(writer, "✅ Successfully applied policies from file") default: http.Error(writer, "Unsupported Method", http.StatusMethodNotAllowed) } } } func HandleRevertToDiagnosisFree( policyAccessor *config.TxnPoliciesAccessor, exportWriter writers.Writer, ) func(http.ResponseWriter, *http.Request) { return func(writer http.ResponseWriter, req *http.Request) { switch req.Method { case http.MethodPost: // We close the writer to allow it to reconnect. // We need this as the Fluent Bit is restarted for the exports reload. _ = exportWriter.Close() defer req.Body.Close() err := policyAccessor.RevertToDiagnosisFree() if err != nil { handleError(writer, "Failed to revert to diagnosis free", http.StatusUnprocessableEntity, err) return } SuccessResponse(writer, "✅ Successfully reverted to diagnosis free") default: http.Error(writer, "Unsupported Method", http.StatusMethodNotAllowed) } } } func HandleRevertToLastLoaded( policyAccessor *config.TxnPoliciesAccessor, exportWriter writers.Writer, ) func(http.ResponseWriter, *http.Request) { return func(writer http.ResponseWriter, req *http.Request) { switch req.Method { case http.MethodPost: // We close the writer to allow it to reconnect. // We need this as the Fluent Bit is restarted for the exports reload. _ = exportWriter.Close() defer req.Body.Close() err := policyAccessor.RevertToLastLoaded() if err != nil { handleError(writer, "Failed to revert to last loaded", http.StatusUnprocessableEntity, err) return } SuccessResponse(writer, "✅ Successfully reverted to last loaded") default: http.Error(writer, "Unsupported Method", http.StatusMethodNotAllowed) } } } func HandleValidatePolicies() func(http.ResponseWriter, *http.Request) { return func(writer http.ResponseWriter, req *http.Request) { switch req.Method { case http.MethodPost: _, err := config.GetPoliciesConfig() if err != nil { handleError(writer, fmt.Sprintf("Failed to validate policies: %v", err), http.StatusUnprocessableEntity, err) return } SuccessResponse(writer, "✅ Successfully validated policies from file") default: http.Error(writer, "Unsupported Method", http.StatusMethodNotAllowed) } } } func HandleJSONFileRead(location string) func( http.ResponseWriter, *http.Request) { return func(writer http.ResponseWriter, req *http.Request) { switch req.Method { case http.MethodGet: data, err := readJSONFile(location) if err != nil { handleError(writer, fmt.Sprintf("Failed to read %s: %v", location, err), http.StatusUnprocessableEntity, err) return } handleJSONResponse(writer, data) default: http.Error(writer, "Unsupported Method", http.StatusMethodNotAllowed) } } } func HandleHandshake() func( http.ResponseWriter, *http.Request) { return func(writer http.ResponseWriter, req *http.Request) { switch req.Method { case http.MethodGet: writer.Header().Set("Content-Type", "application/json") writer.WriteHeader(http.StatusOK) log.Debug().Msg("✅ Handshake successful.") err := json.NewEncoder(writer).Encode(&handshake{Managed: managed}) if err != nil { log.Error().Err(err).Stack().Msg("Failed encoding response") } default: http.Error(writer, "Unsupported Method", http.StatusMethodNotAllowed) } } } func HandleDoctorRequest(doctor *doctor.Doctor) func( http.ResponseWriter, *http.Request) { return func(writer http.ResponseWriter, req *http.Request) { switch req.Method { case http.MethodGet: writer.Header().Set("Content-Type", "application/json") if doctor == nil { handleError( writer, "Failed to encode doctor report", http.StatusUnprocessableEntity, errors.New("doctor is nil"), ) return } report := doctor.Run() err := json.NewEncoder(writer).Encode(report) if err != nil { handleError(writer, "Failed to encode doctor report", http.StatusUnprocessableEntity, err) return } default: http.Error(writer, "Unsupported Method", http.StatusMethodNotAllowed) } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TheLunarCompany/lunar'

If you have feedback or need assistance with the MCP directory API, please join our Discord server