-
Notifications
You must be signed in to change notification settings - Fork 776
server: restrict GlobalConfig to its namespace #11076
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 5 commits
60f6b19
9823c66
623e00f
5fa6a32
ce15cba
2d2943d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,7 +18,6 @@ import ( | |
| "context" | ||
| "fmt" | ||
| "io" | ||
| "path" | ||
| "runtime" | ||
| "runtime/trace" | ||
| "strconv" | ||
|
|
@@ -30,6 +29,8 @@ import ( | |
| clientv3 "go.etcd.io/etcd/client/v3" | ||
| "go.uber.org/zap" | ||
| "google.golang.org/grpc" | ||
| "google.golang.org/grpc/codes" | ||
| "google.golang.org/grpc/status" | ||
|
|
||
| "github.com/pingcap/errors" | ||
| "github.com/pingcap/failpoint" | ||
|
|
@@ -2376,8 +2377,39 @@ func (*GrpcServer) GetDCLocationInfo(_ context.Context, _ *pdpb.GetDCLocationInf | |
| }, nil | ||
| } | ||
|
|
||
| // for CDC compatibility, we need to initialize config path to `globalConfigPath` | ||
| const globalConfigPath = "/global/config/" | ||
| const ( | ||
| // For CDC compatibility, we need to initialize an empty config path to | ||
| // `globalConfigPath`. | ||
| globalConfigPath = "/global/config/" | ||
| // cloud-storage-engine stores its resource controller configs under this | ||
| // prefix through the GlobalConfig API. | ||
| resourceGroupControllerPath = "resource_group/controller" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] Please reuse |
||
| ) | ||
|
|
||
| func normalizeGlobalConfigPath(configPath string) (string, error) { | ||
| if configPath == "" { | ||
| return globalConfigPath, nil | ||
| } | ||
| rootPath := strings.TrimSuffix(globalConfigPath, "/") | ||
| if configPath == rootPath { | ||
| return globalConfigPath, nil | ||
| } | ||
| if !strings.HasPrefix(configPath, globalConfigPath) && | ||
| !strings.HasPrefix(configPath, resourceGroupControllerPath) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [blocking] The current check conflates two separate concerns: which client-provided As written, it accepts I checked current cloud-storage-engine, its history, TiDB/tidb-cse, and I am not necessarily asking to remove |
||
| return "", status.Errorf(codes.InvalidArgument, "global config path %q is not allowed", configPath) | ||
| } | ||
| return configPath, nil | ||
| } | ||
|
|
||
| func resolveGlobalConfigKey(configPath, name string) string { | ||
| if name == "" { | ||
| return strings.TrimSuffix(configPath, "/") | ||
| } | ||
| if strings.HasSuffix(configPath, "/") { | ||
| return configPath + name | ||
| } | ||
| return configPath + "/" + name | ||
| } | ||
|
|
||
| // StoreGlobalConfig store global config into etcd by transaction | ||
| // Since item value needs to support marshal of different struct types, | ||
|
|
@@ -2393,23 +2425,23 @@ func (s *GrpcServer) StoreGlobalConfig(_ context.Context, request *pdpb.StoreGlo | |
| if done != nil { | ||
| defer done() | ||
| } | ||
| configPath := request.GetConfigPath() | ||
| if configPath == "" { | ||
| configPath = globalConfigPath | ||
| configPath, err := normalizeGlobalConfigPath(request.GetConfigPath()) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| ops := make([]clientv3.Op, len(request.Changes)) | ||
| for i, item := range request.Changes { | ||
| name := path.Join(configPath, item.GetName()) | ||
| key := resolveGlobalConfigKey(configPath, item.GetName()) | ||
| switch item.GetKind() { | ||
| case pdpb.EventType_PUT: | ||
| // For CDC compatibility, we need to check the Value field firstly. | ||
| value := item.GetValue() | ||
| if value == "" { | ||
| value = string(item.GetPayload()) | ||
| } | ||
| ops[i] = clientv3.OpPut(name, value) | ||
| ops[i] = clientv3.OpPut(key, value) | ||
| case pdpb.EventType_DELETE: | ||
| ops[i] = clientv3.OpDelete(name) | ||
| ops[i] = clientv3.OpDelete(key) | ||
| } | ||
| } | ||
| res, err := | ||
|
|
@@ -2437,16 +2469,16 @@ func (s *GrpcServer) LoadGlobalConfig(ctx context.Context, request *pdpb.LoadGlo | |
| if done != nil { | ||
| defer done() | ||
| } | ||
| configPath := request.GetConfigPath() | ||
| if configPath == "" { | ||
| configPath = globalConfigPath | ||
| configPath, err := normalizeGlobalConfigPath(request.GetConfigPath()) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| // Since item value needs to support marshal of different struct types, | ||
| // it should be set to `Payload bytes` instead of `Value string`. | ||
| if request.Names != nil { | ||
| res := make([]*pdpb.GlobalConfigItem, len(request.Names)) | ||
| for i, name := range request.Names { | ||
| r, err := s.client.Get(ctx, path.Join(configPath, name)) | ||
| r, err := s.client.Get(ctx, resolveGlobalConfigKey(configPath, name)) | ||
| if err != nil { | ||
| res[i] = &pdpb.GlobalConfigItem{Name: name, Error: &pdpb.Error{Type: pdpb.ErrorType_UNKNOWN, Message: err.Error()}} | ||
| } else if len(r.Kvs) == 0 { | ||
|
|
@@ -2483,12 +2515,12 @@ func (s *GrpcServer) WatchGlobalConfig(req *pdpb.WatchGlobalConfigRequest, serve | |
| if done != nil { | ||
| defer done() | ||
| } | ||
| configPath, err := normalizeGlobalConfigPath(req.GetConfigPath()) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| ctx, cancel := context.WithCancel(server.Context()) | ||
| defer cancel() | ||
| configPath := req.GetConfigPath() | ||
| if configPath == "" { | ||
| configPath = globalConfigPath | ||
| } | ||
| revision := req.GetRevision() | ||
| // If the revision is compacted, will meet required revision has been compacted error. | ||
| // - If required revision < CompactRevision, we need to reload all configs to avoid losing data. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This compatibility comment does not match the actual consumer: cloud-storage-engine only loads the exact
resource_group/controllerkey; it does not store controller configs through GlobalConfig.Also, are we still expected to maintain
tidbcloud/tikv-oneas a supported compatibility target? Its master has not moved since 2024-12-06 and the repository is not archived. If old deployed binaries remain supported, could we document the owner and supported versions? Either way, its code has the same exact-Load-only behavior as cloud-storage-engine and does not justify broader Store/Watch or sibling-prefix access.