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 }