vitess.io/vitess@v0.16.2/go/vt/wrangler/permissions.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 wrangler 18 19 import ( 20 "fmt" 21 "sort" 22 "sync" 23 24 "context" 25 26 "vitess.io/vitess/go/vt/concurrency" 27 "vitess.io/vitess/go/vt/log" 28 "vitess.io/vitess/go/vt/mysqlctl/tmutils" 29 "vitess.io/vitess/go/vt/topo/topoproto" 30 31 tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" 32 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 33 ) 34 35 // GetPermissions returns the permissions set on a remote tablet 36 func (wr *Wrangler) GetPermissions(ctx context.Context, tabletAlias *topodatapb.TabletAlias) (*tabletmanagerdatapb.Permissions, error) { 37 ti, err := wr.ts.GetTablet(ctx, tabletAlias) 38 if err != nil { 39 return nil, err 40 } 41 42 return wr.tmc.GetPermissions(ctx, ti.Tablet) 43 } 44 45 // diffPermissions is a helper method to asynchronously diff a permissions 46 func (wr *Wrangler) diffPermissions(ctx context.Context, primaryPermissions *tabletmanagerdatapb.Permissions, primaryAlias *topodatapb.TabletAlias, alias *topodatapb.TabletAlias, wg *sync.WaitGroup, er concurrency.ErrorRecorder) { 47 defer wg.Done() 48 log.Infof("Gathering permissions for %v", topoproto.TabletAliasString(alias)) 49 replicaPermissions, err := wr.GetPermissions(ctx, alias) 50 if err != nil { 51 er.RecordError(err) 52 return 53 } 54 55 log.Infof("Diffing permissions for %v", topoproto.TabletAliasString(alias)) 56 tmutils.DiffPermissions(topoproto.TabletAliasString(primaryAlias), primaryPermissions, topoproto.TabletAliasString(alias), replicaPermissions, er) 57 } 58 59 // ValidatePermissionsShard validates all the permissions are the same 60 // in a shard 61 func (wr *Wrangler) ValidatePermissionsShard(ctx context.Context, keyspace, shard string) error { 62 si, err := wr.ts.GetShard(ctx, keyspace, shard) 63 if err != nil { 64 return err 65 } 66 67 // get permissions from the primary, or error 68 if !si.HasPrimary() { 69 return fmt.Errorf("no primary in shard %v/%v", keyspace, shard) 70 } 71 log.Infof("Gathering permissions for primary %v", topoproto.TabletAliasString(si.PrimaryAlias)) 72 primaryPermissions, err := wr.GetPermissions(ctx, si.PrimaryAlias) 73 if err != nil { 74 return err 75 } 76 77 // read all the aliases in the shard, that is all tablets that are 78 // replicating from the primary 79 aliases, err := wr.ts.FindAllTabletAliasesInShard(ctx, keyspace, shard) 80 if err != nil { 81 return err 82 } 83 84 // then diff all of them, except primary 85 er := concurrency.AllErrorRecorder{} 86 wg := sync.WaitGroup{} 87 for _, alias := range aliases { 88 if topoproto.TabletAliasEqual(alias, si.PrimaryAlias) { 89 continue 90 } 91 wg.Add(1) 92 go wr.diffPermissions(ctx, primaryPermissions, si.PrimaryAlias, alias, &wg, &er) 93 } 94 wg.Wait() 95 if er.HasErrors() { 96 return fmt.Errorf("permissions diffs: %v", er.Error().Error()) 97 } 98 return nil 99 } 100 101 // ValidatePermissionsKeyspace validates all the permissions are the same 102 // in a keyspace 103 func (wr *Wrangler) ValidatePermissionsKeyspace(ctx context.Context, keyspace string) error { 104 // find all the shards 105 shards, err := wr.ts.GetShardNames(ctx, keyspace) 106 if err != nil { 107 return err 108 } 109 110 // corner cases 111 if len(shards) == 0 { 112 return fmt.Errorf("no shards in keyspace %v", keyspace) 113 } 114 sort.Strings(shards) 115 if len(shards) == 1 { 116 return wr.ValidatePermissionsShard(ctx, keyspace, shards[0]) 117 } 118 119 // find the reference permissions using the first shard's primary 120 si, err := wr.ts.GetShard(ctx, keyspace, shards[0]) 121 if err != nil { 122 return err 123 } 124 if !si.HasPrimary() { 125 return fmt.Errorf("no primary in shard %v/%v", keyspace, shards[0]) 126 } 127 referenceAlias := si.PrimaryAlias 128 log.Infof("Gathering permissions for reference primary %v", topoproto.TabletAliasString(referenceAlias)) 129 referencePermissions, err := wr.GetPermissions(ctx, si.PrimaryAlias) 130 if err != nil { 131 return err 132 } 133 134 // then diff with all tablets but primary 0 135 er := concurrency.AllErrorRecorder{} 136 wg := sync.WaitGroup{} 137 for _, shard := range shards { 138 aliases, err := wr.ts.FindAllTabletAliasesInShard(ctx, keyspace, shard) 139 if err != nil { 140 er.RecordError(err) 141 continue 142 } 143 144 for _, alias := range aliases { 145 if topoproto.TabletAliasEqual(alias, si.PrimaryAlias) { 146 continue 147 } 148 149 wg.Add(1) 150 go wr.diffPermissions(ctx, referencePermissions, referenceAlias, alias, &wg, &er) 151 } 152 } 153 wg.Wait() 154 if er.HasErrors() { 155 return fmt.Errorf("permissions diffs: %v", er.Error().Error()) 156 } 157 return nil 158 }