package server import ( "fmt" "log/slog" "net/http" "strings" "time" "level3.git.onstackit.cloud/LEVEL3/gabriel/src/api" "level3.git.onstackit.cloud/LEVEL3/gabriel/src/metrics" ) func (s *Server) CreateInstance(w http.ResponseWriter, r *http.Request) { slog.Debug("CreateInstance endpoint called") start := time.Now() req, err := reqBody[api.InstanceCreateRequest](r.Body) if err != nil { slog.Debug("Failed to parse create instance request body", "error", err) http.Error(w, fmt.Sprintf("Invalid request body: %v", err), http.StatusBadRequest) return } username, ok := s.usernameFromCtx(r) if !ok { http.Error(w, "Internal server error", http.StatusInternalServerError) return } if req.InstanceId == "" { slog.Debug("InstanceId is required") s.logs.Add("", api.CreateInstance, api.Failure, "Missing instanceId in request", username) http.Error(w, "instanceId is required", http.StatusBadRequest) return } instance, err := s.pagedb.Create(r.Context(), req.InstanceId, username) if err != nil { slog.Error("Failed to create Elasticsearch cluster", "instanceId", req.InstanceId, "error", err) metrics.RecordESOp("create", req.InstanceId, "error", start) s.logs.Add(req.InstanceId, api.CreateInstance, api.Failure, fmt.Sprintf("Failed to create instance: %v", err), username) if isAlreadyExistsErr(err) { http.Error(w, fmt.Sprintf("Elasticsearch instance '%s' already exists", req.InstanceId), http.StatusConflict) return } http.Error(w, fmt.Sprintf("Failed to create Elasticsearch cluster: %v", err), http.StatusInternalServerError) return } slog.Info("Successfully created Elasticsearch cluster", "instanceId", req.InstanceId) metrics.RecordESOp("create", req.InstanceId, "ok", start) s.logs.Add(req.InstanceId, api.CreateInstance, api.Success, "Instance created successfully", username) writeJSONResponse(w, http.StatusCreated, instance) } func (s *Server) GetInstance(w http.ResponseWriter, r *http.Request, instanceId string) { slog.Debug("GetInstance endpoint called", "instanceId", instanceId) start := time.Now() username, ok := s.usernameFromCtx(r) if !ok { http.Error(w, "Internal server error", http.StatusInternalServerError) return } instance, err := s.pagedb.Get(r.Context(), instanceId, username) if err != nil { slog.Debug("Elasticsearch instance not found", "instanceId", instanceId, "error", err) s.logs.Add(instanceId, api.GetInstance, api.Failure, fmt.Sprintf("Instance '%s' not found", instanceId), username) http.Error(w, fmt.Sprintf("Elasticsearch instance '%s' not found", instanceId), http.StatusNotFound) return } slog.Debug("Retrieved Elasticsearch instance", "instanceId", instanceId) metrics.RecordESOp("get", instanceId, "ok", start) s.logs.Add(instanceId, api.GetInstance, api.Success, "Instance details retrieved", username) writeJSONResponse(w, http.StatusOK, instance) } func (s *Server) ListInstances(w http.ResponseWriter, r *http.Request) { slog.Debug("ListInstances endpoint called") start := time.Now() username, ok := s.usernameFromCtx(r) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } items, err := s.pagedb.List(r.Context(), username) if err != nil { slog.Error("Failed to list Elasticsearch clusters", "error", err) s.logs.Add("", api.ListInstances, api.Failure, fmt.Sprintf("Failed to list instances: %v", err), username) http.Error(w, fmt.Sprintf("Failed to list Elasticsearch clusters: %v", err), http.StatusInternalServerError) return } slog.Debug("Returning instance list", "count", len(items)) metrics.RecordESOp("list", "", "ok", start) for _, inst := range items { s.logs.Add(inst.Id, api.ListInstances, api.Success, "Instance listed", username) } writeJSONResponse(w, http.StatusOK, items) } func (s *Server) DeleteInstance(w http.ResponseWriter, r *http.Request, instanceId string) { slog.Debug("DeleteInstance endpoint called", "instanceId", instanceId) start := time.Now() username, ok := s.usernameFromCtx(r) if !ok { http.Error(w, "Internal server error", http.StatusInternalServerError) return } if err := s.pagedb.Delete(r.Context(), instanceId, username); err != nil { slog.Error("Failed to delete Elasticsearch cluster", "instanceId", instanceId, "error", err) metrics.RecordESOp("delete", instanceId, "error", start) s.logs.Add(instanceId, api.DeleteInstance, api.Failure, fmt.Sprintf("Failed to delete instance: %v", err), username) http.Error(w, fmt.Sprintf("Failed to delete cluster '%s': %v", instanceId, err), http.StatusInternalServerError) return } slog.Info("Successfully deleted Elasticsearch cluster", "instanceId", instanceId) metrics.RecordESOp("delete", instanceId, "ok", start) s.logs.Add(instanceId, api.DeleteInstance, api.Success, "Instance deleted successfully", username) w.WriteHeader(http.StatusNoContent) } func isAlreadyExistsErr(err error) bool { return err != nil && strings.Contains(err.Error(), "already exists") }