github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/api/v2/capture.go (about) 1 // Copyright 2023 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package v2 15 16 import ( 17 "net/http" 18 19 "github.com/gin-gonic/gin" 20 "github.com/pingcap/tiflow/cdc/api" 21 cerror "github.com/pingcap/tiflow/pkg/errors" 22 ) 23 24 const apiOpVarCaptureID = "capture_id" 25 26 // drainCapture remove all tables at the given capture. 27 func (h *OpenAPIV2) drainCapture(c *gin.Context) { 28 captureID := c.Param(apiOpVarCaptureID) 29 30 ctx := c.Request.Context() 31 captures, err := h.capture.StatusProvider().GetCaptures(ctx) 32 if err != nil { 33 _ = c.Error(err) 34 return 35 } 36 37 // drain capture only work if there is at least two alive captures, 38 // it cannot work properly if it has only one capture. 39 if len(captures) <= 1 { 40 _ = c.Error(cerror.ErrSchedulerRequestFailed. 41 GenWithStackByArgs("only one capture alive")) 42 return 43 } 44 45 target := captureID 46 checkCaptureFound := func() bool { 47 // make sure the target capture exist 48 for _, capture := range captures { 49 if capture.ID == target { 50 return true 51 } 52 } 53 return false 54 } 55 56 if !checkCaptureFound() { 57 _ = c.Error(cerror.ErrCaptureNotExist.GenWithStackByArgs(target)) 58 return 59 } 60 61 // only owner handle api request, so this must be the owner. 62 ownerInfo, err := h.capture.Info() 63 if err != nil { 64 _ = c.Error(err) 65 return 66 } 67 68 if ownerInfo.ID == target { 69 _ = c.Error(cerror.ErrSchedulerRequestFailed. 70 GenWithStackByArgs("cannot drain the owner")) 71 return 72 } 73 74 resp, err := api.HandleOwnerDrainCapture(ctx, h.capture, target) 75 if err != nil { 76 _ = c.AbortWithError(http.StatusServiceUnavailable, err) 77 return 78 } 79 80 c.JSON(http.StatusAccepted, resp) 81 } 82 83 // listCaptures lists all captures 84 // @Summary List captures 85 // @Description list all captures in cdc cluster 86 // @Tags capture,v2 87 // @Produce json 88 // @Success 200 {array} Capture 89 // @Failure 500,400 {object} model.HTTPError 90 // @Router /api/v2/captures [get] 91 func (h *OpenAPIV2) listCaptures(c *gin.Context) { 92 ctx := c.Request.Context() 93 controller, err := h.capture.GetController() 94 if err != nil { 95 _ = c.Error(err) 96 return 97 } 98 captureInfos, err := controller.GetCaptures(ctx) 99 if err != nil { 100 _ = c.Error(err) 101 return 102 } 103 info, err := h.capture.Info() 104 if err != nil { 105 _ = c.Error(err) 106 return 107 } 108 ownerID := info.ID 109 110 etcdClient := h.capture.GetEtcdClient() 111 112 captures := make([]Capture, 0, len(captureInfos)) 113 for _, c := range captureInfos { 114 isOwner := c.ID == ownerID 115 captures = append(captures, 116 Capture{ 117 ID: c.ID, 118 IsOwner: isOwner, 119 AdvertiseAddr: c.AdvertiseAddr, 120 ClusterID: etcdClient.GetClusterID(), 121 }) 122 } 123 resp := &ListResponse[Capture]{ 124 Total: len(captureInfos), 125 Items: captures, 126 } 127 c.JSON(http.StatusOK, resp) 128 }