Newer
Older
// Copyright 2015, 2016 Eris Industries (UK) Ltd.
// This file is part of Eris-RT
// Eris-RT is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Eris-RT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Eris-RT. If not, see <http://www.gnu.org/licenses/>.
package commands
import (
"os/signal"
"syscall"
core "github.com/eris-ltd/eris-db/core"
util "github.com/eris-ltd/eris-db/util"
const (
DefaultConfigBasename = "config"
DefaultConfigType = "toml"
)
var DefaultConfigFilename = fmt.Sprintf("%s.%s",
DefaultConfigBasename,
DefaultConfigType)
var ServeCmd = &cobra.Command{
Use: "serve",
Short: "Eris-DB serve starts an eris-db node with client API enabled by default.",
Long: `Eris-DB serve starts an eris-db node with client API enabled by default.
Benjamin Bollen
committed
The Eris-DB node is modularly configured for the consensus engine and application
manager. The client API can be disabled.`,
Example: fmt.Sprintf(`$ eris-db serve -- will start the Eris-DB node based on the configuration file "%s" in the current working directory
$ eris-db serve --work-dir <path-to-working-directory> -- will start the Eris-DB node based on the configuration file "%s" in the provided working directory
$ eris-db serve --chain-id <CHAIN_ID> -- will overrule the configuration entry assert_chain_id`,
DefaultConfigFilename, DefaultConfigFilename),
PreRun: func(cmd *cobra.Command, args []string) {
// if WorkDir was not set by a flag or by $ERIS_DB_WORKDIR
// NOTE [ben]: we can consider an `Explicit` flag that eliminates
// the use of any assumptions while starting Eris-DB
if do.WorkDir == "" {
if currentDirectory, err := os.Getwd(); err != nil {
log.Fatalf("No directory provided and failed to get current working directory: %v", err)
os.Exit(1)
} else {
do.WorkDir = currentDirectory
}
}
if !util.IsDir(do.WorkDir) {
log.Fatalf("Provided working directory %s is not a directory", do.WorkDir)
}
},
Run: Serve,
}
// build the serve subcommand
func buildServeCommand() {
}
func addServeFlags() {
ServeCmd.PersistentFlags().StringVarP(&do.ChainId, "chain-id", "c",
defaultChainId(), "specify the chain id to use for assertion against the genesis file or the existing state. If omitted, and no id is set in $CHAIN_ID, then assert_chain_id is used from the configuration file.")
ServeCmd.PersistentFlags().StringVarP(&do.WorkDir, "work-dir", "w",
defaultWorkDir(), "specify the working directory for the chain to run. If omitted, and no path set in $ERIS_DB_WORKDIR, the current working directory is taken.")
ServeCmd.PersistentFlags().StringVarP(&do.DataDir, "data-dir", "",
defaultDataDir(), "specify the data directory. If omitted and not set in $ERIS_DB_DATADIR, <working_directory>/data is taken.")
ServeCmd.PersistentFlags().BoolVarP(&do.DisableRpc, "disable-rpc", "",
defaultDisableRpc(), "indicate for the RPC to be disabled. If omitted the RPC is enabled by default, unless (deprecated) $ERISDB_API is set to false.")
Benjamin Bollen
committed
}
//------------------------------------------------------------------------------
// functions
// serve() prepares the environment and sets up the core for Eris_DB to run.
// After the setup succeeds, serve() starts the core and halts for core to
// terminate.
func Serve(cmd *cobra.Command, args []string) {
// load configuration from a single location to avoid a wrong configuration
// file is loaded.
err := do.ReadConfig(do.WorkDir, DefaultConfigBasename, DefaultConfigType)
if err != nil {
log.WithFields(log.Fields{
"directory": do.WorkDir,
}).Fatalf("Fatal error reading configuration")
os.Exit(1)
}
// if do.ChainId is not yet set, load chain_id for assertion from configuration file
if do.ChainId == "" {
if do.ChainId = do.Config.GetString("chain.assert_chain_id"); do.ChainId == "" {
log.Fatalf("Failed to read non-empty string for ChainId from config.")
os.Exit(1)
}
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
}
// load the genesis file path
do.GenesisFile = path.Join(do.WorkDir,
do.Config.GetString("chain.genesis_file"))
if do.Config.GetString("chain.genesis_file") == "" {
log.Fatalf("Failed to read non-empty string for genesis file from config.")
os.Exit(1)
}
// Ensure data directory is set and accessible
if err := do.InitialiseDataDirectory(); err != nil {
log.Fatalf("Failed to initialise data directory (%s): %v", do.DataDir, err)
os.Exit(1)
}
log.WithFields(log.Fields{
"chainId": do.ChainId,
"workingDirectory": do.WorkDir,
"dataDirectory": do.DataDir,
"genesisFile": do.GenesisFile,
}).Info("Eris-DB serve configuring")
consensusConfig, err := core.LoadConsensusModuleConfig(do)
if err != nil {
log.Fatalf("Failed to load consensus module configuration: %s.", err)
os.Exit(1)
}
managerConfig, err := core.LoadApplicationManagerModuleConfig(do)
if err != nil {
log.Fatalf("Failed to load application manager module configuration: %s.", err)
os.Exit(1)
}
log.WithFields(log.Fields{
"consensusModule": consensusConfig.Version,
"applicationManager": managerConfig.Version,
}).Debug("Modules configured")
newCore, err := core.NewCore(do.ChainId, consensusConfig, managerConfig)
if err != nil {
log.Fatalf("Failed to load core: %s", err)
}
if !do.DisableRpc {
serverConfig, err := core.LoadServerConfig(do)
if err != nil {
log.Fatalf("Failed to load server configuration: %s.", err)
os.Exit(1)
}
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
serverProcess, err := newCore.NewGatewayV0(serverConfig)
if err != nil {
log.Fatalf("Failed to load servers: %s.", err)
os.Exit(1)
}
err = serverProcess.Start()
if err != nil {
log.Fatalf("Failed to start servers: %s.", err)
os.Exit(1)
}
_, err = newCore.NewGatewayTendermint(serverConfig)
if err != nil {
log.Fatalf("Failed to start Tendermint gateway")
}
<-serverProcess.StopEventChannel()
} else {
signals := make(chan os.Signal, 1)
done := make(chan bool, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
go func() {
signal := <-signals
// TODO: [ben] clean up core; in a manner consistent with enabled rpc
log.Fatalf("Received %s signal. Marmots out.", signal)
done <- true
}()
<-done
//------------------------------------------------------------------------------
// Defaults
Benjamin Bollen
committed
func defaultChainId() string {
// if CHAIN_ID environment variable is not set, keep do.ChainId empty to read
// assert_chain_id from configuration file
return setDefaultString("CHAIN_ID", "")
}
func defaultWorkDir() string {
// if ERIS_DB_WORKDIR environment variable is not set, keep do.WorkDir empty
// as do.WorkDir is set by the PreRun
}
func defaultDataDir() string {
// As the default data directory depends on the default working directory,
// wait setting a default value, and initialise the data directory from serve()
return setDefaultString("ERIS_DB_DATADIR", "")
Benjamin Bollen
committed
}
func defaultDisableRpc() bool {
// we currently observe environment variable ERISDB_API (true = enable)
// and default to enabling the RPC if it is not set.
// TODO: [ben] deprecate ERISDB_API across the stack for 0.12.1, and only disable
// the rpc through a command line flag --disable-rpc
return !setDefaultBool("ERISDB_API", true)
}