2021-03-01 19:49:43 +00:00
package steward
import (
"flag"
"fmt"
2021-03-25 10:28:26 +00:00
"log"
2021-03-01 19:49:43 +00:00
"os"
"path/filepath"
toml "github.com/pelletier/go-toml"
)
2021-03-24 06:05:41 +00:00
// --- Configuration
2021-03-01 19:49:43 +00:00
type Configuration struct {
// The configuration folder on disk
ConfigFolder string
2021-05-12 07:50:03 +00:00
// The folder where the socket file should live
SocketFolder string
2021-08-23 14:00:48 +00:00
// TCP Listener for sending messages to the system
TCPListener string
2021-05-12 07:50:03 +00:00
// The folder where the database should live
DatabaseFolder string
2021-03-01 19:49:43 +00:00
// some unique string to identify this Edge unit
NodeName string
// the address of the message broker
BrokerAddress string
2021-09-01 11:39:54 +00:00
// nats connect retry
NatsConnectRetryInterval int
2021-03-01 19:49:43 +00:00
// The number of the profiling port
ProfilingPort string
// host and port for prometheus listener, e.g. localhost:2112
PromHostAndPort string
// set to true if this is the node that should receive the error log's from other nodes
DefaultMessageTimeout int
// default amount of retries that will be done before a message is thrown away, and out of the system
DefaultMessageRetries int
2021-03-02 12:46:02 +00:00
// Publisher data folder
SubscribersDataFolder string
2021-03-12 09:41:03 +00:00
// central node to receive messages published from nodes
2021-03-12 10:13:42 +00:00
CentralNodeName string
2021-04-19 19:06:37 +00:00
// Path to the certificate of the root CA
RootCAPath string
2021-05-14 13:23:04 +00:00
// Full path to the NKEY's seed file
NkeySeedFile string
2021-08-23 10:47:33 +00:00
// The host and port to expose the data folder
ExposeDataFolder string
2021-09-07 07:43:54 +00:00
// Timeout for error messages
ErrorMessageTimeout int
// Retries for error messages.
ErrorMessageRetries int
2021-04-05 06:37:24 +00:00
// Make the current node send hello messages to central at given interval in seconds
2021-04-06 03:46:07 +00:00
StartPubREQHello int
2021-03-24 09:14:17 +00:00
// Start the central error logger.
// Takes a comma separated string of nodes to receive from or "*" for all nodes.
2021-09-08 16:56:23 +00:00
StartSubREQErrorLog bool
2021-03-25 12:39:59 +00:00
// Subscriber for hello messages
2021-09-08 16:56:23 +00:00
StartSubREQHello bool
2021-03-26 08:08:47 +00:00
// Subscriber for text logging
2021-09-08 16:56:23 +00:00
StartSubREQToFileAppend bool
2021-04-06 17:42:03 +00:00
// Subscriber for writing to file
2021-09-08 16:56:23 +00:00
StartSubREQToFile bool
2021-03-26 08:08:47 +00:00
// Subscriber for Echo Request
2021-09-08 16:56:23 +00:00
StartSubREQPing bool
2021-03-26 08:08:47 +00:00
// Subscriber for Echo Reply
2021-09-08 16:56:23 +00:00
StartSubREQPong bool
2021-03-26 08:08:47 +00:00
// Subscriber for CLICommandRequest
2021-09-08 16:56:23 +00:00
StartSubREQCliCommand bool
2021-04-05 04:54:18 +00:00
// Subscriber for REQnCliCommand
2021-09-08 16:56:23 +00:00
StartSubREQnCliCommand bool
2021-04-13 15:22:25 +00:00
// Subscriber for REQToConsole
2021-09-08 16:56:23 +00:00
StartSubREQToConsole bool
2021-04-06 17:42:03 +00:00
// Subscriber for REQHttpGet
2021-09-08 16:56:23 +00:00
StartSubREQHttpGet bool
2021-04-13 09:28:52 +00:00
// Subscriber for tailing log files
2021-09-08 16:56:23 +00:00
StartSubREQTailFile bool
2021-08-10 10:49:42 +00:00
// Subscriber for continously delivery of output from cli commands.
2021-09-08 16:56:23 +00:00
StartSubREQnCliCommandCont bool
2021-03-01 19:49:43 +00:00
}
2021-04-06 09:02:58 +00:00
// NewConfiguration will set a default Configuration,
// and return a *Configuration.
2021-03-01 19:49:43 +00:00
func NewConfiguration ( ) * Configuration {
c := Configuration { }
return & c
}
2021-03-12 10:13:42 +00:00
// Default configuration
2021-03-02 05:51:08 +00:00
func newConfigurationDefaults ( ) Configuration {
c := Configuration {
2021-09-07 07:43:54 +00:00
ConfigFolder : "./etc/" ,
SocketFolder : "./tmp" ,
TCPListener : "" ,
DatabaseFolder : "./var/lib" ,
BrokerAddress : "127.0.0.1:4222" ,
NatsConnectRetryInterval : 10 ,
ProfilingPort : "" ,
PromHostAndPort : "" ,
DefaultMessageTimeout : 10 ,
DefaultMessageRetries : 1 ,
StartPubREQHello : 30 ,
SubscribersDataFolder : "./data" ,
CentralNodeName : "" ,
RootCAPath : "" ,
NkeySeedFile : "" ,
ExposeDataFolder : "" ,
ErrorMessageTimeout : 60 ,
ErrorMessageRetries : 10 ,
2021-09-08 16:56:23 +00:00
StartSubREQErrorLog : true ,
StartSubREQHello : true ,
StartSubREQToFileAppend : true ,
StartSubREQToFile : true ,
StartSubREQPing : true ,
StartSubREQPong : true ,
StartSubREQCliCommand : true ,
StartSubREQnCliCommand : true ,
StartSubREQToConsole : true ,
StartSubREQHttpGet : true ,
StartSubREQTailFile : true ,
StartSubREQnCliCommandCont : true ,
2021-03-02 05:51:08 +00:00
}
return c
}
2021-04-06 09:02:58 +00:00
// CheckFlags will parse all flags
2021-03-24 09:14:17 +00:00
func ( c * Configuration ) CheckFlags ( ) error {
2021-03-02 05:51:08 +00:00
// Create an empty default config
var fc Configuration
2021-08-23 09:45:31 +00:00
// Set default configfolder if no env was provided.
2021-08-27 08:49:06 +00:00
configFolder := os . Getenv ( "CONFIG_FOLDER" )
2021-08-23 09:45:31 +00:00
2021-08-27 10:19:35 +00:00
if configFolder == "" {
configFolder = "./etc/"
}
2021-08-23 09:45:31 +00:00
// Read file config. Set system default if it can't find config file.
2021-05-28 12:48:53 +00:00
fc , err := c . ReadConfigFile ( configFolder )
2021-03-25 10:28:26 +00:00
if err != nil {
log . Printf ( "%v\n" , err )
fc = newConfigurationDefaults ( )
}
2021-08-27 08:49:06 +00:00
if configFolder == "" {
fc . ConfigFolder = "./etc/"
} else {
fc . ConfigFolder = configFolder
}
2021-03-25 10:28:26 +00:00
* c = fc
2021-03-01 19:49:43 +00:00
2021-08-23 09:45:31 +00:00
//flag.StringVar(&c.ConfigFolder, "configFolder", fc.ConfigFolder, "Defaults to ./usr/local/steward/etc/. *NB* This flag is not used, if your config file are located somwhere else than default set the location in an env variable named CONFIGFOLDER")
2021-05-12 07:50:03 +00:00
flag . StringVar ( & c . SocketFolder , "socketFolder" , fc . SocketFolder , "folder who contains the socket file. Defaults to ./tmp/. If other folder is used this flag must be specified at startup." )
2021-08-23 14:00:48 +00:00
flag . StringVar ( & c . TCPListener , "tcpListener" , fc . TCPListener , "start up a TCP listener in addition to the Unix Socket, to give messages to the system. e.g. localhost:8888. No value means not to start the listener, which is default. NB: You probably don't want to start this on any other interface than localhost" )
2021-05-12 07:50:03 +00:00
flag . StringVar ( & c . DatabaseFolder , "databaseFolder" , fc . DatabaseFolder , "folder who contains the database file. Defaults to ./var/lib/. If other folder is used this flag must be specified at startup." )
2021-03-24 09:14:17 +00:00
flag . StringVar ( & c . NodeName , "nodeName" , fc . NodeName , "some unique string to identify this Edge unit" )
2021-03-01 19:49:43 +00:00
flag . StringVar ( & c . BrokerAddress , "brokerAddress" , fc . BrokerAddress , "the address of the message broker" )
2021-09-01 11:39:54 +00:00
flag . IntVar ( & c . NatsConnectRetryInterval , "natsConnectRetryInterval" , fc . NatsConnectRetryInterval , "default nats retry connect interval in seconds." )
2021-03-01 19:49:43 +00:00
flag . StringVar ( & c . ProfilingPort , "profilingPort" , fc . ProfilingPort , "The number of the profiling port" )
flag . StringVar ( & c . PromHostAndPort , "promHostAndPort" , fc . PromHostAndPort , "host and port for prometheus listener, e.g. localhost:2112" )
flag . IntVar ( & c . DefaultMessageTimeout , "defaultMessageTimeout" , fc . DefaultMessageTimeout , "default message timeout in seconds. This can be overridden on the message level" )
flag . IntVar ( & c . DefaultMessageRetries , "defaultMessageRetries" , fc . DefaultMessageRetries , "default amount of retries that will be done before a message is thrown away, and out of the system" )
2021-03-02 12:46:02 +00:00
flag . StringVar ( & c . SubscribersDataFolder , "subscribersDataFolder" , fc . SubscribersDataFolder , "The data folder where subscribers are allowed to write their data if needed" )
2021-03-12 10:13:42 +00:00
flag . StringVar ( & c . CentralNodeName , "centralNodeName" , fc . CentralNodeName , "The name of the central node to receive messages published by this node" )
2021-04-19 19:06:37 +00:00
flag . StringVar ( & c . RootCAPath , "rootCAPath" , fc . RootCAPath , "If TLS, enter the path for where to find the root CA certificate" )
2021-05-14 13:23:04 +00:00
flag . StringVar ( & c . NkeySeedFile , "nkeySeedFile" , fc . NkeySeedFile , "The full path of the nkeys seed file" )
2021-08-23 10:47:33 +00:00
flag . StringVar ( & c . ExposeDataFolder , "exposeDataFolder" , fc . ExposeDataFolder , "If set the data folder will be exposed on the given host:port. Default value is not exposed at all" )
2021-09-07 07:43:54 +00:00
flag . IntVar ( & c . ErrorMessageTimeout , "errorMessageTimeout" , fc . ErrorMessageTimeout , "The number of seconds to wait for an error message to time out" )
flag . IntVar ( & c . ErrorMessageRetries , "errorMessageRetries" , fc . ErrorMessageRetries , "The number of if times to retry an error message before we drop it" )
2021-03-02 12:46:02 +00:00
2021-04-06 03:46:07 +00:00
flag . IntVar ( & c . StartPubREQHello , "startPubREQHello" , fc . StartPubREQHello , "Make the current node send hello messages to central at given interval in seconds" )
2021-03-25 12:39:59 +00:00
2021-09-08 16:56:23 +00:00
flag . BoolVar ( & c . StartSubREQErrorLog , "startSubREQErrorLog" , fc . StartSubREQErrorLog , "true/false" )
flag . BoolVar ( & c . StartSubREQHello , "startSubREQHello" , fc . StartSubREQHello , "true/false" )
flag . BoolVar ( & c . StartSubREQToFileAppend , "startSubREQToFileAppend" , fc . StartSubREQToFileAppend , "true/false" )
flag . BoolVar ( & c . StartSubREQToFile , "startSubREQToFile" , fc . StartSubREQToFile , "true/false" )
flag . BoolVar ( & c . StartSubREQPing , "startSubREQPing" , fc . StartSubREQPing , "true/false" )
flag . BoolVar ( & c . StartSubREQPong , "startSubREQPong" , fc . StartSubREQPong , "true/false" )
flag . BoolVar ( & c . StartSubREQCliCommand , "startSubREQCliCommand" , fc . StartSubREQCliCommand , "true/false" )
flag . BoolVar ( & c . StartSubREQnCliCommand , "startSubREQnCliCommand" , fc . StartSubREQnCliCommand , "true/false" )
flag . BoolVar ( & c . StartSubREQToConsole , "startSubREQToConsole" , fc . StartSubREQToConsole , "true/false" )
flag . BoolVar ( & c . StartSubREQHttpGet , "startSubREQHttpGet" , fc . StartSubREQHttpGet , "true/false" )
flag . BoolVar ( & c . StartSubREQTailFile , "startSubREQTailFile" , fc . StartSubREQTailFile , "true/false" )
flag . BoolVar ( & c . StartSubREQnCliCommandCont , "startSubREQnCliCommandCont" , fc . StartSubREQnCliCommandCont , "true/false" )
2021-03-24 09:14:17 +00:00
2021-03-01 19:49:43 +00:00
flag . Parse ( )
2021-03-24 09:14:17 +00:00
// Check that mandatory flag values have been set.
switch {
case c . NodeName == "" :
return fmt . Errorf ( "error: the nodeName config option or flag cannot be empty, check -help" )
case c . CentralNodeName == "" :
return fmt . Errorf ( "error: the centralNodeName config option or flag cannot be empty, check -help" )
2021-03-01 19:49:43 +00:00
}
2021-03-24 09:14:17 +00:00
2021-03-25 10:28:26 +00:00
if err := c . WriteConfigFile ( ) ; err != nil {
log . Printf ( "error: checkFlags: failed writing config file: %v\n" , err )
os . Exit ( 1 )
}
2021-03-24 09:14:17 +00:00
return nil
2021-03-01 19:49:43 +00:00
}
2021-03-24 06:05:41 +00:00
// Reads the current config file from disk.
2021-05-28 12:48:53 +00:00
func ( c * Configuration ) ReadConfigFile ( configFolder string ) ( Configuration , error ) {
fp := filepath . Join ( configFolder , "config.toml" )
2021-03-01 19:49:43 +00:00
if _ , err := os . Stat ( fp ) ; os . IsNotExist ( err ) {
return Configuration { } , fmt . Errorf ( "error: no config file found %v: %v" , fp , err )
}
f , err := os . OpenFile ( fp , os . O_RDONLY , 0600 )
if err != nil {
2021-03-02 12:46:02 +00:00
return Configuration { } , fmt . Errorf ( "error: ReadConfigFile: failed to open file: %v" , err )
2021-03-01 19:49:43 +00:00
}
defer f . Close ( )
var conf Configuration
dec := toml . NewDecoder ( f )
err = dec . Decode ( & conf )
if err != nil {
return Configuration { } , fmt . Errorf ( "error: decode toml file %v: %v" , fp , err )
}
2021-04-16 11:43:58 +00:00
// fmt.Printf("%+v\n", c)
2021-03-01 19:49:43 +00:00
return conf , nil
}
2021-03-02 05:51:08 +00:00
// WriteConfigFile will write the current config to file. If the file or the
// directory for the config file does not exist it will be created.
2021-03-01 19:49:43 +00:00
func ( c * Configuration ) WriteConfigFile ( ) error {
if _ , err := os . Stat ( c . ConfigFolder ) ; os . IsNotExist ( err ) {
2021-05-12 07:50:03 +00:00
err := os . MkdirAll ( c . ConfigFolder , 0700 )
2021-03-01 19:49:43 +00:00
if err != nil {
2021-05-20 10:27:25 +00:00
return fmt . Errorf ( "error: failed to create config directory %v: %v" , c . ConfigFolder , err )
2021-03-01 19:49:43 +00:00
}
}
fp := filepath . Join ( c . ConfigFolder , "config.toml" )
f , err := os . OpenFile ( fp , os . O_RDWR | os . O_CREATE | os . O_TRUNC , 0600 )
if err != nil {
2021-03-02 12:46:02 +00:00
return fmt . Errorf ( "error: WriteConfigFile: failed to open file: %v" , err )
2021-03-01 19:49:43 +00:00
}
defer f . Close ( )
enc := toml . NewEncoder ( f )
enc . Encode ( c )
return nil
}