github.com/m3db/m3@v1.5.0/src/dbnode/integration/serve.go (about)

     1  // Copyright (c) 2016 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package integration
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  	"net/http"
    27  	"strings"
    28  
    29  	"github.com/m3db/m3/src/cluster/shard"
    30  	"github.com/m3db/m3/src/dbnode/client"
    31  	hjcluster "github.com/m3db/m3/src/dbnode/network/server/httpjson/cluster"
    32  	hjnode "github.com/m3db/m3/src/dbnode/network/server/httpjson/node"
    33  	"github.com/m3db/m3/src/dbnode/network/server/tchannelthrift"
    34  	ttcluster "github.com/m3db/m3/src/dbnode/network/server/tchannelthrift/cluster"
    35  	ttnode "github.com/m3db/m3/src/dbnode/network/server/tchannelthrift/node"
    36  	"github.com/m3db/m3/src/dbnode/server"
    37  	"github.com/m3db/m3/src/dbnode/sharding"
    38  	"github.com/m3db/m3/src/dbnode/storage"
    39  	"github.com/m3db/m3/src/dbnode/topology"
    40  	xretry "github.com/m3db/m3/src/x/retry"
    41  
    42  	"go.uber.org/zap"
    43  )
    44  
    45  // TestShardSetOptions is a set of test shard set options.
    46  type TestShardSetOptions struct {
    47  	ShardState shard.State
    48  }
    49  
    50  // newTestShardSet creates a default shard set.
    51  func newTestShardSet(
    52  	numShards int,
    53  	opts *TestShardSetOptions,
    54  ) (sharding.ShardSet, error) {
    55  	if opts == nil {
    56  		opts = &TestShardSetOptions{
    57  			ShardState: shard.Available,
    58  		}
    59  	}
    60  
    61  	var ids []uint32
    62  	for i := uint32(0); i < uint32(numShards); i++ {
    63  		ids = append(ids, i)
    64  	}
    65  
    66  	shards := sharding.NewShards(ids, opts.ShardState)
    67  	return sharding.NewShardSet(shards, sharding.DefaultHashFn(numShards))
    68  }
    69  
    70  // newTopologyInitializerForShardSet creates a default topology initializer for a shard set
    71  func newTopologyInitializerForShardSet(
    72  	hostID string,
    73  	tchannelNodeAddr string,
    74  	shardSet sharding.ShardSet,
    75  ) (topology.Initializer, error) {
    76  	var localNodeAddr string
    77  	if !strings.ContainsRune(tchannelNodeAddr, ':') {
    78  		return nil, errors.New("tchannelthrift address does not specify port")
    79  	}
    80  	localNodeAddrComponents := strings.Split(tchannelNodeAddr, ":")
    81  	localNodeAddr = fmt.Sprintf("127.0.0.1:%s", localNodeAddrComponents[len(localNodeAddrComponents)-1])
    82  
    83  	hostShardSet := topology.NewHostShardSet(topology.NewHost(hostID, localNodeAddr), shardSet)
    84  	staticOptions := topology.NewStaticOptions().
    85  		SetShardSet(shardSet).
    86  		SetReplicas(1).
    87  		SetHostShardSets([]topology.HostShardSet{hostShardSet})
    88  
    89  	return topology.NewStaticInitializer(staticOptions), nil
    90  }
    91  
    92  // defaultClientOptions creates a default m3db client options
    93  func defaultClientOptions(initializer topology.Initializer) client.Options {
    94  	return client.NewOptions().
    95  		SetTopologyInitializer(initializer).
    96  		// Default to zero retries to prevent tests from taking too long in situations where
    97  		// errors are expected.
    98  		SetWriteRetrier(xretry.NewRetrier(xretry.NewOptions().SetMaxRetries(0))).
    99  		SetFetchRetrier(xretry.NewRetrier(xretry.NewOptions().SetMaxRetries(0)))
   100  }
   101  
   102  // openAndServe opens the database, starts up the RPC servers and bootstraps
   103  // the database for serving traffic
   104  func openAndServe(
   105  	httpClusterAddr string,
   106  	tchannelClusterAddr string,
   107  	httpNodeAddr string,
   108  	tchannelNodeAddr string,
   109  	httpDebugAddr string,
   110  	db storage.Database,
   111  	client client.Client,
   112  	opts storage.Options,
   113  	serverStorageOpts server.StorageOptions,
   114  	doneCh <-chan struct{},
   115  ) error {
   116  	logger := opts.InstrumentOptions().Logger()
   117  	if err := db.Open(); err != nil {
   118  		return fmt.Errorf("could not open database: %v", err)
   119  	}
   120  
   121  	contextPool := opts.ContextPool()
   122  	ttopts := tchannelthrift.NewOptions()
   123  	service := ttnode.NewService(db, ttopts)
   124  	nodeOpts := ttnode.NewOptions(nil).
   125  		SetInstrumentOptions(opts.InstrumentOptions())
   126  	if fn := serverStorageOpts.TChanChannelFn; fn != nil {
   127  		nodeOpts = nodeOpts.SetTChanChannelFn(fn)
   128  	}
   129  	if fn := serverStorageOpts.TChanNodeServerFn; fn != nil {
   130  		nodeOpts = nodeOpts.SetTChanNodeServerFn(fn)
   131  	}
   132  	nativeNodeClose, err := ttnode.NewServer(service, tchannelNodeAddr, contextPool, nodeOpts).ListenAndServe()
   133  	if err != nil {
   134  		return fmt.Errorf("could not open tchannelthrift interface %s: %v", tchannelNodeAddr, err)
   135  	}
   136  	defer nativeNodeClose()
   137  	logger.Info("node tchannelthrift: listening", zap.String("address", tchannelNodeAddr))
   138  
   139  	httpjsonNodeClose, err := hjnode.NewServer(service, httpNodeAddr, contextPool, nil).ListenAndServe()
   140  	if err != nil {
   141  		return fmt.Errorf("could not open httpjson interface %s: %v", httpNodeAddr, err)
   142  	}
   143  	defer httpjsonNodeClose()
   144  	logger.Info("node httpjson: listening", zap.String("address", httpNodeAddr))
   145  
   146  	nativeClusterClose, err := ttcluster.NewServer(client, tchannelClusterAddr, contextPool, nil).ListenAndServe()
   147  	if err != nil {
   148  		return fmt.Errorf("could not open tchannelthrift interface %s: %v", tchannelClusterAddr, err)
   149  	}
   150  	defer nativeClusterClose()
   151  	logger.Info("cluster tchannelthrift: listening", zap.String("address", tchannelClusterAddr))
   152  
   153  	httpjsonClusterClose, err := hjcluster.NewServer(client, httpClusterAddr, contextPool, nil).ListenAndServe()
   154  	if err != nil {
   155  		return fmt.Errorf("could not open httpjson interface %s: %v", httpClusterAddr, err)
   156  	}
   157  	defer httpjsonClusterClose()
   158  	logger.Info("cluster httpjson: listening", zap.String("address", httpClusterAddr))
   159  
   160  	if httpDebugAddr != "" {
   161  		go func() {
   162  			if err := http.ListenAndServe(httpDebugAddr, nil); err != nil {
   163  				logger.Warn("debug server could not listen", zap.String("address", httpDebugAddr), zap.Error(err))
   164  			}
   165  		}()
   166  	}
   167  
   168  	if err := db.Bootstrap(); err != nil {
   169  		return fmt.Errorf("bootstrapping database encountered error: %v", err)
   170  	}
   171  	logger.Debug("bootstrapped")
   172  
   173  	<-doneCh
   174  	logger.Debug("server closing")
   175  
   176  	return db.Terminate()
   177  }