func (r *Service) handleReplay(w http.ResponseWriter, req *http.Request) { name := req.URL.Query().Get("name") id := req.URL.Query().Get("id") clockTyp := req.URL.Query().Get("clock") recTimeStr := req.URL.Query().Get("rec-time") var recTime bool if recTimeStr != "" { var err error recTime, err = strconv.ParseBool(recTimeStr) if err != nil { httpd.HttpError(w, err.Error(), true, http.StatusBadRequest) return } } t, err := r.TaskStore.Load(name) if err != nil { httpd.HttpError(w, "task load: "+err.Error(), true, http.StatusNotFound) return } var clk clock.Clock switch clockTyp { case "", "wall": clk = clock.Wall() case "fast": clk = clock.Fast() } // Create new isolated task master tm := r.TaskMaster.New() tm.Open() defer tm.Close() et, err := tm.StartTask(t) if err != nil { httpd.HttpError(w, "task start: "+err.Error(), true, http.StatusBadRequest) return } replay := kapacitor.NewReplay(clk) var replayC <-chan error switch t.Type { case kapacitor.StreamTask: f, err := r.FindStreamRecording(id) if err != nil { httpd.HttpError(w, "replay find: "+err.Error(), true, http.StatusNotFound) return } stream, err := tm.Stream(id) if err != nil { httpd.HttpError(w, "stream start: "+err.Error(), true, http.StatusInternalServerError) return } replayC = replay.ReplayStream(f, stream, recTime, precision) case kapacitor.BatchTask: fs, err := r.FindBatchRecording(id) if err != nil { httpd.HttpError(w, "replay find: "+err.Error(), true, http.StatusNotFound) return } batches := tm.BatchCollectors(name) replayC = replay.ReplayBatch(fs, batches, recTime) } // Check for error on replay err = <-replayC if err != nil { httpd.HttpError(w, "replay: "+err.Error(), true, http.StatusInternalServerError) return } // Drain tm so the task can finish tm.Drain() // Check for error on task err = et.Err() if err != nil { httpd.HttpError(w, "task run: "+err.Error(), true, http.StatusInternalServerError) return } // Call close explicity to check for error err = tm.Close() if err != nil { httpd.HttpError(w, "closing: "+err.Error(), true, http.StatusInternalServerError) return } }
func (s *Service) handleCreateReplay(w http.ResponseWriter, req *http.Request) { var opt kclient.CreateReplayOptions // Default clock to the Fast clock opt.Clock = kclient.Fast dec := json.NewDecoder(req.Body) err := dec.Decode(&opt) if err != nil { httpd.HttpError(w, err.Error(), true, http.StatusBadRequest) return } if opt.ID == "" { opt.ID = uuid.NewV4().String() } if !validID.MatchString(opt.ID) { httpd.HttpError(w, fmt.Sprintf("replay ID must contain only letters, numbers, '-', '.' and '_'. %q", opt.ID), true, http.StatusBadRequest) return } t, err := s.TaskStore.Load(opt.Task) if err != nil { httpd.HttpError(w, "task load: "+err.Error(), true, http.StatusNotFound) return } recording, err := s.recordings.Get(opt.Recording) if err != nil { httpd.HttpError(w, "recording not found: "+err.Error(), true, http.StatusNotFound) return } var clk clock.Clock var clockType Clock switch opt.Clock { case kclient.Real: clk = clock.Wall() clockType = Real case kclient.Fast: clk = clock.Fast() clockType = Fast default: httpd.HttpError(w, fmt.Sprintf("invalid clock type %v", opt.Clock), true, http.StatusBadRequest) return } // Successfully started replay replay := Replay{ ID: opt.ID, RecordingID: opt.Recording, TaskID: opt.Task, RecordingTime: opt.RecordingTime, Clock: clockType, Date: time.Now(), Status: Running, } s.replays.Create(replay) go func(replay Replay) { err := s.doReplayFromRecording(opt.ID, t, recording, clk, opt.RecordingTime) s.updateReplayResult(replay, err) }(replay) w.WriteHeader(http.StatusCreated) w.Write(httpd.MarshalJSON(convertReplay(replay), true)) }
func (s *Service) handleReplayBatch(w http.ResponseWriter, req *http.Request) { var opt kclient.ReplayBatchOptions // Default clock to the Fast clock opt.Clock = kclient.Fast dec := json.NewDecoder(req.Body) err := dec.Decode(&opt) if err != nil { httpd.HttpError(w, err.Error(), true, http.StatusBadRequest) return } if opt.ID == "" { opt.ID = uuid.NewV4().String() } if !validID.MatchString(opt.ID) { httpd.HttpError(w, fmt.Sprintf("replay ID must match %v %q", validID, opt.ID), true, http.StatusBadRequest) return } t, err := s.TaskStore.Load(opt.Task) if err != nil { httpd.HttpError(w, "task load: "+err.Error(), true, http.StatusNotFound) return } var clk clock.Clock var clockType Clock switch opt.Clock { case kclient.Real: clk = clock.Wall() clockType = Real case kclient.Fast: clk = clock.Fast() clockType = Fast default: httpd.HttpError(w, fmt.Sprintf("invalid clock type %v", opt.Clock), true, http.StatusBadRequest) return } if t.Type == kapacitor.StreamTask { httpd.HttpError(w, fmt.Sprintf("cannot replay batch against stream task: %s", opt.Task), true, http.StatusBadRequest) return } // Successfully started replay replay := Replay{ ID: opt.ID, TaskID: opt.Task, RecordingTime: opt.RecordingTime, Clock: clockType, Date: time.Now(), Status: Running, } err = s.replays.Create(replay) if err != nil { httpd.HttpError(w, err.Error(), true, http.StatusInternalServerError) return } go func(replay Replay) { err := s.doLiveBatchReplay(opt.ID, t, clk, opt.RecordingTime, opt.Start, opt.Stop) s.updateReplayResult(replay, err) }(replay) w.WriteHeader(http.StatusCreated) w.Write(httpd.MarshalJSON(convertReplay(replay), true)) }
func (r *Service) handleReplayQuery(w http.ResponseWriter, req *http.Request) { var opt kclient.ReplayQueryOptions dec := json.NewDecoder(req.Body) err := dec.Decode(&opt) if err != nil { httpd.HttpError(w, err.Error(), true, http.StatusBadRequest) return } if opt.ID == "" { opt.ID = uuid.NewV4().String() } if !validID.MatchString(opt.ID) { httpd.HttpError(w, fmt.Sprintf("recording ID must match %v %q", validID, opt.ID), true, http.StatusBadRequest) return } if opt.Query == "" { httpd.HttpError(w, "must provide query", true, http.StatusBadRequest) return } t, err := r.TaskStore.Load(opt.Task) if err != nil { httpd.HttpError(w, "task load: "+err.Error(), true, http.StatusNotFound) return } var clk clock.Clock var clockType Clock switch opt.Clock { case kclient.Real: clk = clock.Wall() clockType = Real case kclient.Fast: clk = clock.Fast() clockType = Fast default: httpd.HttpError(w, fmt.Sprintf("invalid clock type %v", opt.Clock), true, http.StatusBadRequest) return } replay := Replay{ ID: opt.ID, TaskID: opt.Task, RecordingTime: opt.RecordingTime, Clock: clockType, Date: time.Now(), Status: Running, } err = r.replays.Create(replay) if err != nil { httpd.HttpError(w, err.Error(), true, http.StatusInternalServerError) return } go func(replay Replay) { err := r.doLiveQueryReplay(replay.ID, t, clk, opt.RecordingTime, opt.Query, opt.Cluster) r.updateReplayResult(replay, err) }(replay) w.WriteHeader(http.StatusCreated) w.Write(httpd.MarshalJSON(convertReplay(replay), true)) }