vitess.io/vitess@v0.16.2/go/vt/srvtopo/keyspace_filtering_server.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package srvtopo 18 19 import ( 20 "context" 21 "fmt" 22 23 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 24 vschemapb "vitess.io/vitess/go/vt/proto/vschema" 25 "vitess.io/vitess/go/vt/topo" 26 ) 27 28 var ( 29 // ErrNilUnderlyingServer is returned when attempting to create a new keyspace 30 // filtering server if a nil underlying server implementation is provided. 31 ErrNilUnderlyingServer = fmt.Errorf("unable to construct filtering server without an underlying server") 32 ) 33 34 // NewKeyspaceFilteringServer constructs a new server based on the provided 35 // implementation that prevents the specified keyspaces from being exposed 36 // to consumers of the new Server. 37 // 38 // A filtering server will only allow read-only access to the topo.Server to prevent 39 // updates that may corrupt the global VSchema keyspace. 40 func NewKeyspaceFilteringServer(underlying Server, selectedKeyspaces []string) (Server, error) { 41 if underlying == nil { 42 return nil, ErrNilUnderlyingServer 43 } 44 45 keyspaces := map[string]bool{} 46 for _, ks := range selectedKeyspaces { 47 keyspaces[ks] = true 48 } 49 50 readOnlyServer, err := NewReadOnlyServer(underlying) 51 if err != nil { 52 return nil, err 53 } 54 55 return keyspaceFilteringServer{ 56 server: readOnlyServer, 57 selectKeyspaces: keyspaces, 58 }, nil 59 } 60 61 type keyspaceFilteringServer struct { 62 server Server 63 selectKeyspaces map[string]bool 64 } 65 66 // GetTopoServer returns a read-only topo server 67 func (ksf keyspaceFilteringServer) GetTopoServer() (*topo.Server, error) { 68 return ksf.server.GetTopoServer() 69 } 70 71 func (ksf keyspaceFilteringServer) GetSrvKeyspaceNames( 72 ctx context.Context, 73 cell string, 74 staleOK bool, 75 ) ([]string, error) { 76 keyspaces, err := ksf.server.GetSrvKeyspaceNames(ctx, cell, staleOK) 77 ret := make([]string, 0, len(keyspaces)) 78 for _, ks := range keyspaces { 79 if ksf.selectKeyspaces[ks] { 80 ret = append(ret, ks) 81 } 82 } 83 return ret, err 84 } 85 86 func (ksf keyspaceFilteringServer) GetSrvKeyspace( 87 ctx context.Context, 88 cell, 89 keyspace string, 90 ) (*topodatapb.SrvKeyspace, error) { 91 if !ksf.selectKeyspaces[keyspace] { 92 return nil, topo.NewError(topo.NoNode, keyspace) 93 } 94 95 return ksf.server.GetSrvKeyspace(ctx, cell, keyspace) 96 } 97 98 func (ksf keyspaceFilteringServer) WatchSrvKeyspace( 99 ctx context.Context, 100 cell, keyspace string, 101 callback func(*topodatapb.SrvKeyspace, error) bool, 102 ) { 103 filteringCallback := func(ks *topodatapb.SrvKeyspace, err error) bool { 104 if ks != nil { 105 if !ksf.selectKeyspaces[keyspace] { 106 return callback(nil, topo.NewError(topo.NoNode, keyspace)) 107 } 108 } 109 return callback(ks, err) 110 } 111 112 ksf.server.WatchSrvKeyspace(ctx, cell, keyspace, filteringCallback) 113 } 114 115 func (ksf keyspaceFilteringServer) WatchSrvVSchema( 116 ctx context.Context, 117 cell string, 118 callback func(*vschemapb.SrvVSchema, error) bool, 119 ) { 120 filteringCallback := func(schema *vschemapb.SrvVSchema, err error) bool { 121 if schema != nil { 122 for ks := range schema.Keyspaces { 123 if !ksf.selectKeyspaces[ks] { 124 delete(schema.Keyspaces, ks) 125 } 126 } 127 } 128 129 return callback(schema, err) 130 } 131 132 ksf.server.WatchSrvVSchema(ctx, cell, filteringCallback) 133 }