github.com/polarismesh/polaris@v1.17.8/apiserver/httpserver/admin_access.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package httpserver 19 20 import ( 21 "context" 22 "encoding/json" 23 "net/http" 24 "strconv" 25 26 "github.com/emicklei/go-restful/v3" 27 apimodel "github.com/polarismesh/specification/source/go/api/v1/model" 28 apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" 29 30 "github.com/polarismesh/polaris/admin" 31 "github.com/polarismesh/polaris/apiserver/httpserver/docs" 32 httpcommon "github.com/polarismesh/polaris/apiserver/httpserver/utils" 33 api "github.com/polarismesh/polaris/common/api/v1" 34 "github.com/polarismesh/polaris/common/model" 35 "github.com/polarismesh/polaris/common/utils" 36 ) 37 38 // GetIndexServer get index server 39 func (h *HTTPServer) GetIndexServer() *restful.WebService { 40 ws := new(restful.WebService) 41 42 ws.Route(ws.GET("/").To(h.index)) 43 44 return ws 45 } 46 47 // index URL: "/" 48 func (h *HTTPServer) index(_ *restful.Request, rsp *restful.Response) { 49 _, _ = rsp.Write([]byte("Polaris Server")) 50 } 51 52 // GetMaintainAccessServer 运维接口 53 func (h *HTTPServer) GetAdminAccessServer() *restful.WebService { 54 ws := new(restful.WebService) 55 ws.Path("/maintain/v1").Consumes(restful.MIME_JSON).Produces(restful.MIME_JSON) 56 57 ws.Route(docs.EnrichGetServerConnectionsApiDocs(ws.GET("/apiserver/conn").To(h.GetServerConnections))) 58 ws.Route(docs.EnrichGetServerConnStatsApiDocs(ws.GET("/apiserver/conn/stats").To(h.GetServerConnStats))) 59 ws.Route(docs.EnrichCloseConnectionsApiDocs(ws.POST("apiserver/conn/close").To(h.CloseConnections))) 60 ws.Route(docs.EnrichFreeOSMemoryApiDocs(ws.POST("/memory/free").To(h.FreeOSMemory))) 61 ws.Route(docs.EnrichCleanInstanceApiDocs(ws.POST("/instance/clean").To(h.CleanInstance))) 62 ws.Route(docs.EnrichBatchCleanInstancesApiDocs(ws.POST("/instance/batchclean").To(h.BatchCleanInstances))) 63 ws.Route(docs.EnrichGetLastHeartbeatApiDocs(ws.GET("/instance/heartbeat").To(h.GetLastHeartbeat))) 64 ws.Route(docs.EnrichGetLogOutputLevelApiDocs(ws.GET("/log/outputlevel").To(h.GetLogOutputLevel))) 65 ws.Route(docs.EnrichSetLogOutputLevelApiDocs(ws.PUT("/log/outputlevel").To(h.SetLogOutputLevel))) 66 ws.Route(docs.EnrichListLeaderElectionsApiDocs(ws.GET("/leaders").To(h.ListLeaderElections))) 67 ws.Route(docs.EnrichReleaseLeaderElectionApiDocs(ws.POST("/leaders/release").To(h.ReleaseLeaderElection))) 68 ws.Route(docs.EnrichGetCMDBInfoApiDocs(ws.GET("/cmdb/info").To(h.GetCMDBInfo))) 69 ws.Route(docs.EnrichGetReportClientsApiDocs(ws.GET("/report/clients").To(h.GetReportClients))) 70 return ws 71 } 72 73 // GetServerConnections 查看server的连接数 74 // query参数:protocol,必须,查看指定协议server 75 // 76 // host,可选,查看指定host 77 func (h *HTTPServer) GetServerConnections(req *restful.Request, rsp *restful.Response) { 78 ctx := initContext(req) 79 params := httpcommon.ParseQueryParams(req) 80 connReq := admin.ConnReq{ 81 Protocol: params["protocol"], 82 Host: params["host"], 83 } 84 85 ret, err := h.maintainServer.GetServerConnections(ctx, &connReq) 86 if err != nil { 87 _ = rsp.WriteError(http.StatusBadRequest, err) 88 } else { 89 _ = rsp.WriteEntity(ret) 90 } 91 } 92 93 // GetServerConnStats 获取连接缓存里面的统计信息 94 func (h *HTTPServer) GetServerConnStats(req *restful.Request, rsp *restful.Response) { 95 ctx := initContext(req) 96 params := httpcommon.ParseQueryParams(req) 97 98 var amount int 99 if amountStr, ok := params["amount"]; ok { 100 if n, err := strconv.Atoi(amountStr); err == nil { 101 amount = n 102 } 103 } 104 105 connReq := admin.ConnReq{ 106 Protocol: params["protocol"], 107 Host: params["host"], 108 Amount: amount, 109 } 110 111 ret, err := h.maintainServer.GetServerConnStats(ctx, &connReq) 112 if err != nil { 113 _ = rsp.WriteError(http.StatusBadRequest, err) 114 } else { 115 _ = rsp.WriteAsJson(ret) 116 } 117 } 118 119 // CloseConnections 关闭指定client ip的连接 120 func (h *HTTPServer) CloseConnections(req *restful.Request, rsp *restful.Response) { 121 log.Info("[MAINTAIN] Start doing close connections") 122 ctx := initContext(req) 123 var connReqs []admin.ConnReq 124 decoder := json.NewDecoder(req.Request.Body) 125 if err := decoder.Decode(&connReqs); err != nil { 126 log.Errorf("[MAINTAIN] close connection decode body err: %s", err.Error()) 127 _ = rsp.WriteError(http.StatusBadRequest, err) 128 return 129 } 130 for _, entry := range connReqs { 131 if entry.Protocol == "" { 132 log.Errorf("[MAINTAIN] close connection missing protocol") 133 _ = rsp.WriteErrorString(http.StatusBadRequest, "missing protocol") 134 return 135 } 136 if entry.Host == "" { 137 log.Errorf("[MAINTAIN] close connection missing host") 138 _ = rsp.WriteErrorString(http.StatusBadRequest, "missing host") 139 return 140 } 141 } 142 143 if err := h.maintainServer.CloseConnections(ctx, connReqs); err != nil { 144 _ = rsp.WriteError(http.StatusBadRequest, err) 145 } 146 } 147 148 // FreeOSMemory 增加一个释放系统内存的接口 149 func (h *HTTPServer) FreeOSMemory(req *restful.Request, rsp *restful.Response) { 150 ctx := initContext(req) 151 if err := h.maintainServer.FreeOSMemory(ctx); err != nil { 152 _ = rsp.WriteError(http.StatusBadRequest, err) 153 } 154 } 155 156 // CleanInstance 彻底清理flag=1的实例运维接口 157 // 支持一个个清理 158 func (h *HTTPServer) CleanInstance(req *restful.Request, rsp *restful.Response) { 159 handler := &httpcommon.Handler{ 160 Request: req, 161 Response: rsp, 162 } 163 164 instance := &apiservice.Instance{} 165 ctx, err := handler.Parse(instance) 166 if err != nil { 167 handler.WriteHeaderAndProto(api.NewResponseWithMsg(apimodel.Code_ParseException, err.Error())) 168 return 169 } 170 171 handler.WriteHeaderAndProto(h.maintainServer.CleanInstance(ctx, instance)) 172 } 173 174 func (h *HTTPServer) BatchCleanInstances(req *restful.Request, rsp *restful.Response) { 175 ctx := initContext(req) 176 177 var param struct { 178 BatchSize uint32 `json:"batch_size"` 179 } 180 181 if err := httpcommon.ParseJsonBody(req, ¶m); err != nil { 182 _ = rsp.WriteError(http.StatusBadRequest, err) 183 return 184 } 185 186 if count, err := h.maintainServer.BatchCleanInstances(ctx, param.BatchSize); err != nil { 187 _ = rsp.WriteError(http.StatusInternalServerError, err) 188 } else { 189 var ret struct { 190 RowsAffected uint32 `json:"rows_affected"` 191 } 192 ret.RowsAffected = count 193 _ = rsp.WriteAsJson(ret) 194 } 195 196 } 197 198 // GetLastHeartbeat 获取实例,上一次心跳的时间 199 func (h *HTTPServer) GetLastHeartbeat(req *restful.Request, rsp *restful.Response) { 200 ctx := initContext(req) 201 handler := &httpcommon.Handler{ 202 Request: req, 203 Response: rsp, 204 } 205 params := httpcommon.ParseQueryParams(req) 206 instance := &apiservice.Instance{} 207 if id, ok := params["id"]; ok && id != "" { 208 instance.Id = utils.NewStringValue(id) 209 } else { 210 instance.Service = utils.NewStringValue(params["service"]) 211 instance.Namespace = utils.NewStringValue(params["namespace"]) 212 instance.VpcId = utils.NewStringValue(params["vpc_id"]) 213 instance.Host = utils.NewStringValue(params["host"]) 214 port, _ := strconv.Atoi(params["port"]) 215 instance.Port = utils.NewUInt32Value(uint32(port)) 216 } 217 218 ret := h.maintainServer.GetLastHeartbeat(ctx, instance) 219 handler.WriteHeaderAndProto(ret) 220 } 221 222 // GetLogOutputLevel 获取日志输出级别 223 func (h *HTTPServer) GetLogOutputLevel(req *restful.Request, rsp *restful.Response) { 224 ctx := initContext(req) 225 226 out, err := h.maintainServer.GetLogOutputLevel(ctx) 227 if err != nil { 228 _ = rsp.WriteError(http.StatusBadRequest, err) 229 } else { 230 _ = rsp.WriteAsJson(out) 231 } 232 } 233 234 // SetLogOutputLevel 设置日志输出级别 235 func (h *HTTPServer) SetLogOutputLevel(req *restful.Request, rsp *restful.Response) { 236 ctx := initContext(req) 237 238 var scopeLogLevel struct { 239 Scope string `json:"scope"` 240 Level string `json:"level"` 241 } 242 243 if err := httpcommon.ParseJsonBody(req, &scopeLogLevel); err != nil { 244 _ = rsp.WriteErrorString(http.StatusBadRequest, err.Error()) 245 return 246 } 247 248 if err := h.maintainServer.SetLogOutputLevel(ctx, scopeLogLevel.Scope, scopeLogLevel.Level); err != nil { 249 _ = rsp.WriteErrorString(http.StatusBadRequest, err.Error()) 250 return 251 } 252 253 _ = rsp.WriteEntity("ok") 254 } 255 256 func (h *HTTPServer) ListLeaderElections(req *restful.Request, rsp *restful.Response) { 257 ctx := initContext(req) 258 leaders, err := h.maintainServer.ListLeaderElections(ctx) 259 if err != nil { 260 _ = rsp.WriteError(http.StatusBadRequest, err) 261 return 262 } 263 if leaders == nil { 264 leaders = []*model.LeaderElection{} 265 } 266 267 _ = rsp.WriteAsJson(leaders) 268 } 269 270 func (h *HTTPServer) ReleaseLeaderElection(req *restful.Request, rsp *restful.Response) { 271 ctx := initContext(req) 272 var releasedElection struct { 273 ElectKey string `json:"electKey"` 274 } 275 if err := httpcommon.ParseJsonBody(req, &releasedElection); err != nil { 276 _ = rsp.WriteErrorString(http.StatusBadRequest, err.Error()) 277 return 278 } 279 if err := h.maintainServer.ReleaseLeaderElection(ctx, releasedElection.ElectKey); err != nil { 280 _ = rsp.WriteErrorString(http.StatusBadRequest, err.Error()) 281 return 282 } 283 _ = rsp.WriteEntity("ok") 284 } 285 286 func (h *HTTPServer) GetCMDBInfo(req *restful.Request, rsp *restful.Response) { 287 ctx := initContext(req) 288 289 ret, err := h.maintainServer.GetCMDBInfo(ctx) 290 if err != nil { 291 _ = rsp.WriteErrorString(http.StatusBadRequest, err.Error()) 292 return 293 } 294 _ = rsp.WriteAsJson(ret) 295 } 296 297 func initContext(req *restful.Request) context.Context { 298 ctx := context.Background() 299 300 authToken := req.HeaderParameter(utils.HeaderAuthTokenKey) 301 if authToken != "" { 302 ctx = context.WithValue(ctx, utils.ContextAuthTokenKey, authToken) 303 } 304 305 return ctx 306 }