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  }