mirror of https://github.com/tikv/pd.git
140 lines
4.6 KiB
Go
140 lines
4.6 KiB
Go
// Copyright 2016 TiKV Project Authors.
|
|
//
|
|
// 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,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package server
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/coreos/go-semver/semver"
|
|
"github.com/gorilla/mux"
|
|
"github.com/urfave/negroni/v3"
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/pingcap/errors"
|
|
"github.com/pingcap/kvproto/pkg/pdpb"
|
|
"github.com/pingcap/log"
|
|
|
|
"github.com/tikv/pd/pkg/errs"
|
|
"github.com/tikv/pd/pkg/utils/apiutil"
|
|
"github.com/tikv/pd/pkg/utils/keypath"
|
|
"github.com/tikv/pd/pkg/versioninfo"
|
|
"github.com/tikv/pd/server/config"
|
|
)
|
|
|
|
// CheckAndGetPDVersion checks and returns the PD version.
|
|
func CheckAndGetPDVersion() *semver.Version {
|
|
pdVersion := versioninfo.MinSupportedVersion(versioninfo.Base)
|
|
if versioninfo.PDReleaseVersion != "None" {
|
|
pdVersion = versioninfo.MustParseVersion(versioninfo.PDReleaseVersion)
|
|
}
|
|
return pdVersion
|
|
}
|
|
|
|
// CheckPDVersionWithClusterVersion checks if PD needs to be upgraded by comparing the PD version with the cluster version.
|
|
func CheckPDVersionWithClusterVersion(opt *config.PersistOptions) {
|
|
pdVersion := CheckAndGetPDVersion()
|
|
clusterVersion := *opt.GetClusterVersion()
|
|
log.Info("load pd and cluster version",
|
|
zap.Stringer("pd-version", pdVersion), zap.Stringer("cluster-version", clusterVersion))
|
|
if pdVersion.LessThan(clusterVersion) {
|
|
log.Warn(
|
|
"PD version less than cluster version, please upgrade PD",
|
|
zap.String("pd-version", pdVersion.String()),
|
|
zap.String("cluster-version", clusterVersion.String()))
|
|
}
|
|
}
|
|
|
|
func checkBootstrapRequest(req *pdpb.BootstrapRequest) error {
|
|
clusterID := keypath.ClusterID()
|
|
// TODO: do more check for request fields validation.
|
|
|
|
storeMeta := req.GetStore()
|
|
if storeMeta == nil {
|
|
return errors.Errorf("missing store meta for bootstrap %d", clusterID)
|
|
} else if storeMeta.GetId() == 0 {
|
|
return errors.New("invalid zero store id")
|
|
}
|
|
|
|
regionMeta := req.GetRegion()
|
|
if regionMeta == nil {
|
|
return errors.Errorf("missing region meta for bootstrap %d", clusterID)
|
|
} else if len(regionMeta.GetStartKey()) > 0 || len(regionMeta.GetEndKey()) > 0 {
|
|
// first region start/end key must be empty
|
|
return errors.Errorf("invalid first region key range, must all be empty for bootstrap %d", clusterID)
|
|
} else if regionMeta.GetId() == 0 {
|
|
return errors.New("invalid zero region id")
|
|
}
|
|
|
|
peers := regionMeta.GetPeers()
|
|
if len(peers) != 1 {
|
|
return errors.Errorf("invalid first region peer count %d, must be 1 for bootstrap %d", len(peers), clusterID)
|
|
}
|
|
|
|
peer := peers[0]
|
|
if peer.GetStoreId() != storeMeta.GetId() {
|
|
return errors.Errorf("invalid peer store id %d != %d for bootstrap %d", peer.GetStoreId(), storeMeta.GetId(), clusterID)
|
|
}
|
|
if peer.GetId() == 0 {
|
|
return errors.New("invalid zero peer id")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func combineBuilderServerHTTPService(ctx context.Context, svr *Server, serviceBuilders ...HandlerBuilder) (map[string]http.Handler, error) {
|
|
userHandlers := make(map[string]http.Handler)
|
|
registerMap := make(map[string]http.Handler)
|
|
|
|
apiService := negroni.New()
|
|
recovery := negroni.NewRecovery()
|
|
apiService.Use(recovery)
|
|
router := mux.NewRouter()
|
|
|
|
for _, build := range serviceBuilders {
|
|
handler, info, err := build(ctx, svr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !info.IsCore && len(info.PathPrefix) == 0 && (len(info.Name) == 0 || len(info.Version) == 0) {
|
|
return nil, errs.ErrAPIInformationInvalid.FastGenByArgs(info.Name, info.Version)
|
|
}
|
|
|
|
if err := apiutil.RegisterUserDefinedHandlers(registerMap, &info, handler); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Combine the pd service to the router. the extension service will be added to the userHandlers.
|
|
for pathPrefix, handler := range registerMap {
|
|
if strings.Contains(pathPrefix, apiutil.CorePath) || strings.Contains(pathPrefix, apiutil.ExtensionsPath) {
|
|
router.PathPrefix(pathPrefix).Handler(handler)
|
|
if pathPrefix == apiutil.CorePath {
|
|
// Deprecated
|
|
router.Path("/pd/health").Handler(handler)
|
|
// Deprecated
|
|
router.Path("/pd/ping").Handler(handler)
|
|
}
|
|
} else {
|
|
userHandlers[pathPrefix] = handler
|
|
}
|
|
}
|
|
|
|
apiService.UseHandler(router)
|
|
userHandlers[pdAPIPrefix] = apiService
|
|
return userHandlers, nil
|
|
}
|