Skip to content

Commit

Permalink
Release v2021.05.12.1 (#921)
Browse files Browse the repository at this point in the history
* fix(ttlcache): goroutine leak (#892)
* tidb: forwarder only uses tidb whose status is Up (#893)
* keyviz: Add tips for enabled config (#901)
* ui: rocksdb fields (#896)
* monitoring: setup sentry (#895)
* tidb_client: improve behavior when no alive tidb instance (#900)
* feat(stmt): support config maximum number of stmt kept in memory (#914)
* feat: debug api (#898)
* ui: Improve settings description for Statement (#920)
* feat(ui): add tiflash profiling option (#859)
* ui: Add a warning for the debug API (#922)
  • Loading branch information
shhdgit authored May 12, 2021
1 parent 293938e commit 4ee3e39
Show file tree
Hide file tree
Showing 90 changed files with 3,222 additions and 1,220 deletions.
5 changes: 0 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
Expand Down Expand Up @@ -349,7 +348,6 @@ go.uber.org/dig v1.8.0 h1:1rR6hnL/bu1EVcjnRDN5kx1vbIjEJDTGhSQ2B3ddpcI=
go.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw=
go.uber.org/fx v1.10.0 h1:S2K/H8oNied0Je/mLKdWzEWKZfv9jtxSDm8CnwK+5Fg=
go.uber.org/fx v1.10.0/go.mod h1:vLRicqpG/qQEzno4SYU86iCwfT95EZza+Eba0ItuxqY=
go.uber.org/goleak v0.10.0 h1:G3eWbSNIskeRqtsN/1uI5B+eP73y3JUuBsv9AZjehb4=
go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
Expand All @@ -373,7 +371,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72 h1:+ELyKg6m8UBf0nPFSqD0mi7zUfwPyXo23HNjMnXPz7w=
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
Expand Down Expand Up @@ -413,7 +410,6 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
Expand All @@ -435,7 +431,6 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
Expand Down
6 changes: 5 additions & 1 deletion pkg/apiserver/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ import (

"github.com/pingcap/tidb-dashboard/pkg/apiserver/clusterinfo"
"github.com/pingcap/tidb-dashboard/pkg/apiserver/configuration"
"github.com/pingcap/tidb-dashboard/pkg/apiserver/debugapi"
"github.com/pingcap/tidb-dashboard/pkg/apiserver/diagnose"
"github.com/pingcap/tidb-dashboard/pkg/apiserver/info"
"github.com/pingcap/tidb-dashboard/pkg/apiserver/logsearch"
"github.com/pingcap/tidb-dashboard/pkg/apiserver/metrics"
"github.com/pingcap/tidb-dashboard/pkg/apiserver/profiling"
"github.com/pingcap/tidb-dashboard/pkg/apiserver/queryeditor"
"github.com/pingcap/tidb-dashboard/pkg/tiflash"

// "github.com/pingcap/tidb-dashboard/pkg/apiserver/__APP_NAME__"
// NOTE: Don't remove above comment line, it is a placeholder for code generator
Expand Down Expand Up @@ -114,11 +116,11 @@ func (s *Service) Start(ctx context.Context) error {
config.NewDynamicConfigManager,
tidb.NewTiDBClient,
tikv.NewTiKVClient,
tiflash.NewTiFlashClient,
utils.NewSysSchema,
user.NewAuthService,
info.NewService,
clusterinfo.NewService,
profiling.NewService,
logsearch.NewService,
diagnose.NewService,
keyvisual.NewService,
Expand All @@ -130,6 +132,8 @@ func (s *Service) Start(ctx context.Context) error {
),
statement.Module,
slowquery.Module,
debugapi.Module,
profiling.Module,
fx.Populate(&s.apiHandlerEngine),
fx.Invoke(
user.RegisterRouter,
Expand Down
106 changes: 106 additions & 0 deletions pkg/apiserver/debugapi/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright 2021 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package debugapi

import (
"fmt"

"go.uber.org/fx"

"github.com/pingcap/tidb-dashboard/pkg/apiserver/model"
"github.com/pingcap/tidb-dashboard/pkg/pd"
"github.com/pingcap/tidb-dashboard/pkg/tidb"
"github.com/pingcap/tidb-dashboard/pkg/tiflash"
"github.com/pingcap/tidb-dashboard/pkg/tikv"
)

type Client interface {
Send(request *Request) ([]byte, error)
Get(request *Request) ([]byte, error)
}

type ClientMap map[model.NodeKind]Client

func newClientMap(tidbImpl tidbImplement, tikvImpl tikvImplement, tiflashImpl tiflashImplement, pdImpl pdImplement) *ClientMap {
clientMap := ClientMap{
model.NodeKindTiDB: &tidbImpl,
model.NodeKindTiKV: &tikvImpl,
model.NodeKindTiFlash: &tiflashImpl,
model.NodeKindPD: &pdImpl,
}
return &clientMap
}

func defaultSendRequest(client Client, req *Request) ([]byte, error) {
switch req.Method {
case EndpointMethodGet:
return client.Get(req)
default:
return nil, fmt.Errorf("invalid request method `%s`, host: %s, path: %s", req.Method, req.Host, req.Path)
}
}

type tidbImplement struct {
fx.In
Client *tidb.Client
}

func (impl *tidbImplement) Get(req *Request) ([]byte, error) {
return impl.Client.WithEnforcedStatusAPIAddress(req.Host, req.Port).SendGetRequest(req.Path)
}

func (impl *tidbImplement) Send(req *Request) ([]byte, error) {
return defaultSendRequest(impl, req)
}

// TODO: tikv/tiflash/pd forwarder impl

type tikvImplement struct {
fx.In
Client *tikv.Client
}

func (impl *tikvImplement) Get(req *Request) ([]byte, error) {
return impl.Client.SendGetRequest(req.Host, req.Port, req.Path)
}

func (impl *tikvImplement) Send(req *Request) ([]byte, error) {
return defaultSendRequest(impl, req)
}

type tiflashImplement struct {
fx.In
Client *tiflash.Client
}

func (impl *tiflashImplement) Get(req *Request) ([]byte, error) {
return impl.Client.SendGetRequest(req.Host, req.Port, req.Path)
}

func (impl *tiflashImplement) Send(req *Request) ([]byte, error) {
return defaultSendRequest(impl, req)
}

type pdImplement struct {
fx.In
Client *pd.Client
}

func (impl *pdImplement) Get(req *Request) ([]byte, error) {
return impl.Client.SendGetRequest(req.Path)
}

func (impl *pdImplement) Send(req *Request) ([]byte, error) {
return defaultSendRequest(impl, req)
}
172 changes: 172 additions & 0 deletions pkg/apiserver/debugapi/endpoint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Copyright 2021 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package debugapi

import (
"net/http"
"net/url"
"regexp"

"github.com/pingcap/tidb-dashboard/pkg/apiserver/model"
)

var (
ErrMissingRequiredParam = ErrNS.NewType("missing_require_parameter")
ErrInvalidParam = ErrNS.NewType("invalid_parameter")
)

type EndpointAPIModel struct {
ID string `json:"id"`
Component model.NodeKind `json:"component"`
Path string `json:"path"`
Method EndpointMethod `json:"method"`
PathParams []EndpointAPIParam `json:"path_params"` // e.g. /stats/dump/{db}/{table} -> db, table
QueryParams []EndpointAPIParam `json:"query_params"` // e.g. /debug/pprof?seconds=1 -> seconds
}

type EndpointMethod string

const (
EndpointMethodGet EndpointMethod = http.MethodGet
)

type Request struct {
Method EndpointMethod
Host string
Port int
Path string
Query string
}

func (e *EndpointAPIModel) NewRequest(host string, port int, value map[string]string) (*Request, error) {
req := &Request{
Method: e.Method,
Host: host,
Port: port,
}

pathValues, err := transformValues(e.PathParams, value)
if err != nil {
return nil, err
}
path, err := e.PopulatePath(pathValues)
if err != nil {
return nil, err
}
req.Path = path

queryValues, err := transformValues(e.QueryParams, value)
if err != nil {
return nil, err
}
query, err := e.EncodeQuery(queryValues)
if err != nil {
return nil, err
}
req.Query = query

return req, nil
}

var paramRegexp *regexp.Regexp = regexp.MustCompile(`\{(\w+)\}`)

func (e *EndpointAPIModel) PopulatePath(valMap map[string]string) (string, error) {
var returnErr error
replacedPath := e.Path
replacedPath = paramRegexp.ReplaceAllStringFunc(replacedPath, func(s string) string {
if returnErr != nil {
return s
}

key := paramRegexp.ReplaceAllString(s, "${1}")
val, ok := valMap[key]
// means the param can be found in the endpoint path, but not in the param value map
if !ok {
returnErr = ErrMissingRequiredParam.New("missing required path param, path: %s, param: %s", e.Path, key)
return s
}

return val
})
return replacedPath, returnErr
}

func (e *EndpointAPIModel) EncodeQuery(valMap map[string]string) (string, error) {
query := url.Values{}
for _, q := range e.QueryParams {
// cuz paramValues was generated by e.Query, paramValues can always find param by q.Name
val, ok := valMap[q.Name]
if q.Required && !ok {
return "", ErrMissingRequiredParam.New("missing required query param: %s", q.Name)
}
query.Add(q.Name, val)
}
return query.Encode(), nil
}

func transformValues(params []EndpointAPIParam, values map[string]string) (map[string]string, error) {
pvMap := map[string]string{}
for _, p := range params {
v, ok := values[p.Name]
if !ok {
continue
}
tVal, err := p.Transform(v)
if err != nil {
return nil, ErrInvalidParam.WrapWithNoMessage(err)
}
pvMap[p.Name] = tVal
}
return pvMap, nil
}

type EndpointAPIParam struct {
Name string `json:"name"`
Required bool `json:"required"`
// represents what param is
Model EndpointAPIParamModel `json:"model"`
PreModelTransformer ModelTransformer `json:"-"`
PostModelTransformer ModelTransformer `json:"-"`
}

// Transform incoming param's value by transformer at endpoint / model definition
func (p *EndpointAPIParam) Transform(value string) (string, error) {
transfomers := []ModelTransformer{
p.PreModelTransformer,
p.Model.Transformer,
p.PostModelTransformer,
}

for _, t := range transfomers {
if t == nil {
continue
}
v, err := t(value)
if err != nil {
return "", err
}
value = v
}

return value, nil
}

// Transformer can transform the incoming param's value in special scenarios
// Also, now are used as validation function
type ModelTransformer func(value string) (string, error)

type EndpointAPIParamModel struct {
Type string `json:"type"`
Transformer ModelTransformer `json:"-"`
}
Loading

0 comments on commit 4ee3e39

Please sign in to comment.