vitess.io/vitess@v0.16.2/go/vt/topo/helpers/compare.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 helpers contains a few utility classes to handle topo.Server
    18  // objects, and transitions from one topo implementation to another.
    19  package helpers
    20  
    21  import (
    22  	"reflect"
    23  
    24  	"google.golang.org/protobuf/proto"
    25  
    26  	"context"
    27  
    28  	"vitess.io/vitess/go/vt/proto/vtrpc"
    29  	"vitess.io/vitess/go/vt/topo"
    30  	"vitess.io/vitess/go/vt/vterrors"
    31  )
    32  
    33  // CompareKeyspaces will compare the keyspaces in the destination topo.
    34  func CompareKeyspaces(ctx context.Context, fromTS, toTS *topo.Server) error {
    35  	keyspaces, err := fromTS.GetKeyspaces(ctx)
    36  	if err != nil {
    37  		return vterrors.Wrapf(err, "GetKeyspace(%v)", keyspaces)
    38  	}
    39  
    40  	for _, keyspace := range keyspaces {
    41  
    42  		fromKs, err := fromTS.GetKeyspace(ctx, keyspace)
    43  		if err != nil {
    44  			return vterrors.Wrapf(err, "GetKeyspace(%v)", keyspace)
    45  		}
    46  
    47  		toKs, err := toTS.GetKeyspace(ctx, keyspace)
    48  		if err != nil {
    49  			return vterrors.Wrapf(err, "GetKeyspace(%v)", keyspace)
    50  		}
    51  
    52  		if !reflect.DeepEqual(fromKs.Keyspace, toKs.Keyspace) {
    53  			return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Keyspace: %v does not match between from and to topology", keyspace)
    54  		}
    55  
    56  		fromVs, err := fromTS.GetVSchema(ctx, keyspace)
    57  		switch {
    58  		case err == nil:
    59  			// Nothing to do.
    60  		case topo.IsErrType(err, topo.NoNode):
    61  			// Nothing to do.
    62  		default:
    63  			return vterrors.Wrapf(err, "GetVSchema(%v)", keyspace)
    64  		}
    65  
    66  		toVs, err := toTS.GetVSchema(ctx, keyspace)
    67  		switch {
    68  		case err == nil:
    69  			// Nothing to do.
    70  		case topo.IsErrType(err, topo.NoNode):
    71  			// Nothing to do.
    72  		default:
    73  			return vterrors.Wrapf(err, "GetVSchema(%v)", keyspace)
    74  		}
    75  
    76  		if !reflect.DeepEqual(fromVs, toVs) {
    77  			return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Vschema for keyspace: %v does not match between from and to topology", keyspace)
    78  		}
    79  	}
    80  	return nil
    81  }
    82  
    83  // CompareShards will compare the shards in the destination topo.
    84  func CompareShards(ctx context.Context, fromTS, toTS *topo.Server) error {
    85  	keyspaces, err := fromTS.GetKeyspaces(ctx)
    86  	if err != nil {
    87  		return vterrors.Wrapf(err, "fromTS.GetKeyspaces")
    88  	}
    89  
    90  	for _, keyspace := range keyspaces {
    91  		shards, err := fromTS.GetShardNames(ctx, keyspace)
    92  		if err != nil {
    93  			return vterrors.Wrapf(err, "GetShardNames(%v)", keyspace)
    94  		}
    95  
    96  		for _, shard := range shards {
    97  			fromSi, err := fromTS.GetShard(ctx, keyspace, shard)
    98  			if err != nil {
    99  				return vterrors.Wrapf(err, "GetShard(%v, %v)", keyspace, shard)
   100  			}
   101  			toSi, err := toTS.GetShard(ctx, keyspace, shard)
   102  			if err != nil {
   103  				return vterrors.Wrapf(err, "GetShard(%v, %v)", keyspace, shard)
   104  			}
   105  
   106  			if !reflect.DeepEqual(fromSi.Shard, toSi.Shard) {
   107  				return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Shard %v for keyspace: %v does not match between from and to topology", shard, keyspace)
   108  			}
   109  		}
   110  	}
   111  	return nil
   112  }
   113  
   114  // CompareTablets will compare the tablets in the destination topo.
   115  func CompareTablets(ctx context.Context, fromTS, toTS *topo.Server) error {
   116  	cells, err := fromTS.GetKnownCells(ctx)
   117  	if err != nil {
   118  		return vterrors.Wrapf(err, "fromTS.GetKnownCells")
   119  	}
   120  
   121  	for _, cell := range cells {
   122  		tabletAliases, err := fromTS.GetTabletAliasesByCell(ctx, cell)
   123  		if err != nil {
   124  			return vterrors.Wrapf(err, "GetTabletsByCell(%v)", cell)
   125  		}
   126  		for _, tabletAlias := range tabletAliases {
   127  
   128  			// read the source tablet
   129  			fromTi, err := fromTS.GetTablet(ctx, tabletAlias)
   130  			if err != nil {
   131  				return vterrors.Wrapf(err, "GetTablet(%v)", tabletAlias)
   132  			}
   133  			toTi, err := toTS.GetTablet(ctx, tabletAlias)
   134  			if err != nil {
   135  				return vterrors.Wrapf(err, "GetTablet(%v)", tabletAlias)
   136  			}
   137  			if !reflect.DeepEqual(fromTi.Tablet, toTi.Tablet) {
   138  				return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Tablet %v:  does not match between from and to topology", tabletAlias)
   139  			}
   140  		}
   141  	}
   142  	return nil
   143  }
   144  
   145  // CompareShardReplications will compare the ShardReplication objects in
   146  // the destination topo.
   147  func CompareShardReplications(ctx context.Context, fromTS, toTS *topo.Server) error {
   148  	keyspaces, err := fromTS.GetKeyspaces(ctx)
   149  	if err != nil {
   150  		return vterrors.Wrapf(err, "fromTS.GetKeyspaces")
   151  	}
   152  	cells, err := fromTS.GetCellInfoNames(ctx)
   153  	if err != nil {
   154  		return vterrors.Wrap(err, "GetCellInfoNames()")
   155  	}
   156  
   157  	for _, keyspace := range keyspaces {
   158  		shards, err := fromTS.GetShardNames(ctx, keyspace)
   159  		if err != nil {
   160  			return vterrors.Wrapf(err, "GetShardNames(%v)", keyspace)
   161  		}
   162  
   163  		for _, shard := range shards {
   164  			for _, cell := range cells {
   165  				fromSRi, err := fromTS.GetShardReplication(ctx, cell, keyspace, shard)
   166  				if err != nil {
   167  					return vterrors.Wrapf(err, "GetShardReplication(%v, %v, %v)", cell, keyspace, shard)
   168  				}
   169  				toSRi, err := toTS.GetShardReplication(ctx, cell, keyspace, shard)
   170  				if err != nil {
   171  					return vterrors.Wrapf(err, "GetShardReplication(%v, %v, %v)", cell, keyspace, shard)
   172  				}
   173  				if !reflect.DeepEqual(fromSRi.ShardReplication, toSRi.ShardReplication) {
   174  					return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION,
   175  						"Shard Replication in cell %v, keyspace %v, shard %v:  does not match between from and to topology",
   176  						cell,
   177  						keyspace,
   178  						shard)
   179  				}
   180  			}
   181  		}
   182  	}
   183  	return nil
   184  }
   185  
   186  // CompareRoutingRules will compare the routing rules in the destination topo.
   187  func CompareRoutingRules(ctx context.Context, fromTS, toTS *topo.Server) error {
   188  	rrFrom, err := fromTS.GetRoutingRules(ctx)
   189  	if err != nil {
   190  		return vterrors.Wrapf(err, "GetKeyspace(from)")
   191  	}
   192  	rrTo, err := toTS.GetRoutingRules(ctx)
   193  	if err != nil {
   194  		return vterrors.Wrapf(err, "GetKeyspace(to)")
   195  	}
   196  	if !proto.Equal(rrFrom, rrTo) {
   197  		return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "routing rules: %v does not match %v", rrFrom, rrTo)
   198  	}
   199  	return nil
   200  }