summaryrefslogtreecommitdiff
path: root/internal/config
diff options
context:
space:
mode:
Diffstat (limited to 'internal/config')
-rw-r--r--internal/config/args.go164
-rw-r--r--internal/config/client.go194
-rw-r--r--internal/config/common.go26
-rw-r--r--internal/config/config.go71
-rw-r--r--internal/config/env.go7
-rw-r--r--internal/config/initializer.go184
-rw-r--r--internal/config/read.go37
-rw-r--r--internal/config/server.go10
8 files changed, 599 insertions, 94 deletions
diff --git a/internal/config/args.go b/internal/config/args.go
new file mode 100644
index 0000000..3d7ac7d
--- /dev/null
+++ b/internal/config/args.go
@@ -0,0 +1,164 @@
+package config
+
+import (
+ "encoding/base64"
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/mimecast/dtail/internal/lcontext"
+ "github.com/mimecast/dtail/internal/omode"
+
+ gossh "golang.org/x/crypto/ssh"
+)
+
+// Args is a helper struct to summarize common client arguments.
+type Args struct {
+ lcontext.LContext
+ Arguments []string
+ ConfigFile string
+ ConnectionsPerCPU int
+ Discovery string
+ LogDir string
+ Logger string
+ LogLevel string
+ Mode omode.Mode
+ NoColor bool
+ PrivateKeyPathFile string
+ QueryStr string
+ Quiet bool
+ RegexInvert bool
+ RegexStr string
+ Serverless bool
+ ServersStr string
+ Spartan bool
+ SSHAuthMethods []gossh.AuthMethod
+ SSHBindAddress string
+ SSHHostKeyCallback gossh.HostKeyCallback
+ SSHPort int
+ Timeout int
+ TrustAllHosts bool
+ UserName string
+ What string
+}
+
+func (a *Args) String() string {
+ var sb strings.Builder
+
+ sb.WriteString("Args(")
+
+ sb.WriteString(fmt.Sprintf("%s:%v,", "Arguments", a.Arguments))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "ConfigFile", a.ConfigFile))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "ConnectionsPerCPU", a.ConnectionsPerCPU))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "Discovery", a.Discovery))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "LogDir", a.LogDir))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "LogLevel", a.LogLevel))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "Logger", a.Logger))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "Mode", a.Mode))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "NoColor", a.NoColor))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "PrivateKeyPathFile", a.PrivateKeyPathFile))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "QueryStr", a.QueryStr))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "Quiet", a.Quiet))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "RegexInvert", a.RegexInvert))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "RegexStr", a.RegexStr))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "SSHAuthMethods", a.SSHAuthMethods))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "SSHBindAddress", a.SSHBindAddress))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "SSHHostKeyCallback", a.SSHHostKeyCallback))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "SSHPort", a.SSHPort))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "Serverless", a.Serverless))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "ServersStr", a.ServersStr))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "Spartan", a.Spartan))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "Timeout", a.Timeout))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "TrustAllHosts", a.TrustAllHosts))
+ sb.WriteString(fmt.Sprintf("%s:%v,", "UserName", a.UserName))
+ sb.WriteString(fmt.Sprintf("%s:%v", "What", a.What))
+ sb.WriteString(")")
+
+ return sb.String()
+}
+
+// SerializeOptions returns a string ready to be sent over the wire to the server.
+func (a *Args) SerializeOptions() string {
+ options := make(map[string]string)
+
+ if a.Quiet {
+ options["quiet"] = fmt.Sprintf("%v", a.Quiet)
+ }
+ if a.Spartan {
+ options["spartan"] = fmt.Sprintf("%v", a.Spartan)
+ }
+ if a.Serverless {
+ options["serverless"] = fmt.Sprintf("%v", a.Serverless)
+ }
+ if a.LContext.MaxCount != 0 {
+ options["max"] = fmt.Sprintf("%d", a.LContext.MaxCount)
+ }
+ if a.LContext.BeforeContext != 0 {
+ options["before"] = fmt.Sprintf("%d", a.LContext.BeforeContext)
+ }
+ if a.LContext.AfterContext != 0 {
+ options["after"] = fmt.Sprintf("%d", a.LContext.AfterContext)
+ }
+
+ var sb strings.Builder
+ var i int
+ for k, v := range options {
+ if i > 0 {
+ sb.WriteString(":")
+ }
+ sb.WriteString(k)
+ sb.WriteString("=")
+ sb.WriteString(v)
+ i++
+ }
+ return sb.String()
+}
+
+// DeserializeOptions deserializes the options, but into a map.
+func DeserializeOptions(opts []string) (map[string]string, lcontext.LContext, error) {
+ options := make(map[string]string, len(opts))
+ var ltx lcontext.LContext
+
+ for _, o := range opts {
+ kv := strings.SplitN(o, "=", 2)
+ if len(kv) != 2 {
+ return options, ltx, fmt.Errorf("Unable to parse options: %v", kv)
+ }
+ key := kv[0]
+ val := kv[1]
+
+ if strings.HasPrefix(val, "base64%") {
+ s := strings.SplitN(val, "%", 2)
+ decoded, err := base64.StdEncoding.DecodeString(s[1])
+ if err != nil {
+ return options, ltx, err
+ }
+ val = string(decoded)
+ }
+
+ switch key {
+ case "before":
+ iVal, err := strconv.Atoi(val)
+ if err != nil {
+ return options, ltx, err
+ }
+ ltx.BeforeContext = iVal
+ case "after":
+ iVal, err := strconv.Atoi(val)
+ if err != nil {
+ return options, ltx, err
+ }
+ ltx.AfterContext = iVal
+ case "max":
+ iVal, err := strconv.Atoi(val)
+ if err != nil {
+ return options, ltx, err
+ }
+ ltx.MaxCount = iVal
+ default:
+ options[key] = val
+ }
+ }
+
+ return options, ltx, nil
+}
diff --git a/internal/config/client.go b/internal/config/client.go
index 1515aae..86f97f0 100644
--- a/internal/config/client.go
+++ b/internal/config/client.go
@@ -1,11 +1,203 @@
package config
+import "github.com/mimecast/dtail/internal/color"
+
+type remoteTermColors struct {
+ DelimiterAttr color.Attribute
+ DelimiterBg color.BgColor
+ DelimiterFg color.FgColor
+ RemoteAttr color.Attribute
+ RemoteBg color.BgColor
+ RemoteFg color.FgColor
+ CountAttr color.Attribute
+ CountBg color.BgColor
+ CountFg color.FgColor
+ HostnameAttr color.Attribute
+ HostnameBg color.BgColor
+ HostnameFg color.FgColor
+ IDAttr color.Attribute
+ IDBg color.BgColor
+ IDFg color.FgColor
+ StatsOkAttr color.Attribute
+ StatsOkBg color.BgColor
+ StatsOkFg color.FgColor
+ StatsWarnAttr color.Attribute
+ StatsWarnBg color.BgColor
+ StatsWarnFg color.FgColor
+ TextAttr color.Attribute
+ TextBg color.BgColor
+ TextFg color.FgColor
+}
+
+type clientTermColors struct {
+ DelimiterAttr color.Attribute
+ DelimiterBg color.BgColor
+ DelimiterFg color.FgColor
+ ClientAttr color.Attribute
+ ClientBg color.BgColor
+ ClientFg color.FgColor
+ HostnameAttr color.Attribute
+ HostnameBg color.BgColor
+ HostnameFg color.FgColor
+ TextAttr color.Attribute
+ TextBg color.BgColor
+ TextFg color.FgColor
+}
+
+type serverTermColors struct {
+ DelimiterAttr color.Attribute
+ DelimiterBg color.BgColor
+ DelimiterFg color.FgColor
+ ServerAttr color.Attribute
+ ServerBg color.BgColor
+ ServerFg color.FgColor
+ HostnameAttr color.Attribute
+ HostnameBg color.BgColor
+ HostnameFg color.FgColor
+ TextAttr color.Attribute
+ TextBg color.BgColor
+ TextFg color.FgColor
+}
+
+type commonTermColors struct {
+ SeverityErrorAttr color.Attribute
+ SeverityErrorBg color.BgColor
+ SeverityErrorFg color.FgColor
+ SeverityFatalAttr color.Attribute
+ SeverityFatalBg color.BgColor
+ SeverityFatalFg color.FgColor
+ SeverityWarnAttr color.Attribute
+ SeverityWarnBg color.BgColor
+ SeverityWarnFg color.FgColor
+}
+
+type maprTableTermColors struct {
+ DataAttr color.Attribute
+ DataBg color.BgColor
+ DataFg color.FgColor
+ DelimiterAttr color.Attribute
+ DelimiterBg color.BgColor
+ DelimiterFg color.FgColor
+ HeaderAttr color.Attribute
+ HeaderBg color.BgColor
+ HeaderDelimiterAttr color.Attribute
+ HeaderDelimiterBg color.BgColor
+ HeaderDelimiterFg color.FgColor
+ HeaderFg color.FgColor
+ HeaderGroupKeyAttr color.Attribute
+ HeaderSortKeyAttr color.Attribute
+ RawQueryAttr color.Attribute
+ RawQueryBg color.BgColor
+ RawQueryFg color.FgColor
+}
+
+type termColors struct {
+ Remote remoteTermColors
+ Client clientTermColors
+ Server serverTermColors
+ Common commonTermColors
+ MaprTable maprTableTermColors
+}
+
// ClientConfig represents a DTail client configuration (empty as of now as there
// are no available config options yet, but that may changes in the future).
type ClientConfig struct {
+ TermColorsEnable bool `json:",omitempty"`
+ TermColors termColors `json:",omitempty"`
+ // When unit testing in Jenkins you don't want to touch files in ~jenkins
+ // during integration tests really.
+ SSHDontAddHostsToKnownHostsFile bool `json:",omitempty"`
}
// Create a new default client configuration.
func newDefaultClientConfig() *ClientConfig {
- return &ClientConfig{}
+ return &ClientConfig{
+ TermColorsEnable: true,
+ TermColors: termColors{
+ Remote: remoteTermColors{
+ DelimiterAttr: color.AttrDim,
+ DelimiterBg: color.BgBlue,
+ DelimiterFg: color.FgCyan,
+ RemoteAttr: color.AttrDim,
+ RemoteBg: color.BgBlue,
+ RemoteFg: color.FgWhite,
+ CountAttr: color.AttrDim,
+ CountBg: color.BgBlue,
+ CountFg: color.FgWhite,
+ HostnameAttr: color.AttrBold,
+ HostnameBg: color.BgBlue,
+ HostnameFg: color.FgWhite,
+ IDAttr: color.AttrDim,
+ IDBg: color.BgBlue,
+ IDFg: color.FgWhite,
+ StatsOkAttr: color.AttrNone,
+ StatsOkBg: color.BgGreen,
+ StatsOkFg: color.FgBlack,
+ StatsWarnAttr: color.AttrNone,
+ StatsWarnBg: color.BgRed,
+ StatsWarnFg: color.FgWhite,
+ TextAttr: color.AttrNone,
+ TextBg: color.BgBlack,
+ TextFg: color.FgWhite,
+ },
+ Client: clientTermColors{
+ DelimiterAttr: color.AttrDim,
+ DelimiterBg: color.BgYellow,
+ DelimiterFg: color.FgBlack,
+ ClientAttr: color.AttrDim,
+ ClientBg: color.BgYellow,
+ ClientFg: color.FgBlack,
+ HostnameAttr: color.AttrDim,
+ HostnameBg: color.BgYellow,
+ HostnameFg: color.FgBlack,
+ TextAttr: color.AttrNone,
+ TextBg: color.BgBlack,
+ TextFg: color.FgWhite,
+ },
+ Server: serverTermColors{
+ DelimiterAttr: color.AttrDim,
+ DelimiterBg: color.BgCyan,
+ DelimiterFg: color.FgBlack,
+ ServerAttr: color.AttrDim,
+ ServerBg: color.BgCyan,
+ ServerFg: color.FgBlack,
+ HostnameAttr: color.AttrBold,
+ HostnameBg: color.BgCyan,
+ HostnameFg: color.FgBlack,
+ TextAttr: color.AttrNone,
+ TextBg: color.BgBlack,
+ TextFg: color.FgWhite,
+ },
+ Common: commonTermColors{
+ SeverityErrorAttr: color.AttrBold,
+ SeverityErrorBg: color.BgRed,
+ SeverityErrorFg: color.FgWhite,
+ SeverityFatalAttr: color.AttrBold,
+ SeverityFatalBg: color.BgMagenta,
+ SeverityFatalFg: color.FgWhite,
+ SeverityWarnAttr: color.AttrBold,
+ SeverityWarnBg: color.BgBlack,
+ SeverityWarnFg: color.FgWhite,
+ },
+ MaprTable: maprTableTermColors{
+ DataAttr: color.AttrNone,
+ DataBg: color.BgBlue,
+ DataFg: color.FgWhite,
+ DelimiterAttr: color.AttrDim,
+ DelimiterBg: color.BgBlue,
+ DelimiterFg: color.FgWhite,
+ HeaderAttr: color.AttrBold,
+ HeaderBg: color.BgBlue,
+ HeaderFg: color.FgWhite,
+ HeaderDelimiterAttr: color.AttrDim,
+ HeaderDelimiterBg: color.BgBlue,
+ HeaderDelimiterFg: color.FgWhite,
+ HeaderSortKeyAttr: color.AttrUnderline,
+ HeaderGroupKeyAttr: color.AttrReverse,
+ RawQueryAttr: color.AttrDim,
+ RawQueryBg: color.BgBlack,
+ RawQueryFg: color.FgCyan,
+ },
+ },
+ }
}
diff --git a/internal/config/common.go b/internal/config/common.go
index c3e203e..7a72cfe 100644
--- a/internal/config/common.go
+++ b/internal/config/common.go
@@ -6,31 +6,27 @@ type CommonConfig struct {
SSHPort int
// Enable experimental features (mainly for dev purposes)
ExperimentalFeaturesEnable bool `json:",omitempty"`
- // Enable debug logging. Don't enable in production.
- DebugEnable bool `json:",omitempty"`
- // Enable trace logging. Don't enable in production.
- TraceEnable bool `json:",omitempty"`
- // The log strategy to use, one of
- // stdout: only log to stdout (useful when used with systemd)
- // daily: create a log file for every day
- LogStrategy string
- // The log directory
+ // LogDir defines the log directory.
LogDir string
+ // Logger defines the name of the logger implementation.
+ Logger string
+ // LogLevel defines how much is logged.
+ LogLevel string `json:",omitempty"`
+ // LogRotation strategy to be used.
+ LogRotation string
// The cache directory
CacheDir string
- // The temp directory
- TmpDir string `json:",omitempty"`
}
// Create a new default configuration.
func newDefaultCommonConfig() *CommonConfig {
return &CommonConfig{
- SSHPort: 2222,
- DebugEnable: false,
- TraceEnable: false,
+ SSHPort: DefaultSSHPort,
ExperimentalFeaturesEnable: false,
LogDir: "log",
+ Logger: "stdout",
+ LogLevel: DefaultLogLevel,
+ LogRotation: "daily",
CacheDir: "cache",
- TmpDir: "/tmp",
}
}
diff --git a/internal/config/config.go b/internal/config/config.go
index 276ddcf..ee23829 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -1,23 +1,30 @@
package config
-import (
- "encoding/json"
- "io/ioutil"
- "os"
+import "github.com/mimecast/dtail/internal/source"
+
+const (
+ // HealthUser is used for the health check
+ HealthUser string = "DTAIL-HEALTH"
+ // ScheduleUser is used for non-interactive scheduled mapreduce queries.
+ ScheduleUser string = "DTAIL-SCHEDULE"
+ // ContinuousUser is used for non-interactive continuous mapreduce queries.
+ ContinuousUser string = "DTAIL-CONTINUOUS"
+ // InterruptTimeoutS specifies the Ctrl+C log pause interval.
+ InterruptTimeoutS int = 3
+ // DefaultConnectionsPerCPU controls how many connections are established concurrently.
+ DefaultConnectionsPerCPU int = 10
+ // DefaultSSHPort is the default DServer port.
+ DefaultSSHPort int = 2222
+ // DefaultLogLevel specifies the default log level (obviously)
+ DefaultLogLevel string = "info"
+ // DefaultClientLogger specifies the default logger for the client commands.
+ DefaultClientLogger string = "fout"
+ // DefaultServerLogger specifies the default logger for dtail server.
+ DefaultServerLogger string = "file"
+ // DefaultHealthCheckLogger specifies the default logger used for health checks.
+ DefaultHealthCheckLogger string = "none"
)
-// ControlUser is used for various DTail specific operations.
-const ControlUser string = "DTAIL-CONTROL"
-
-// ScheduleUser is used for non-interactive scheduled mapreduce queries.
-const ScheduleUser string = "DTAIL-SCHEDULE"
-
-// ContinuousUser is used for non-interactive continuous mapreduce queries.
-const ContinuousUser string = "DTAIL-CONTINUOUS"
-
-// InterruptTimeoutS is used to terminate DTail when Ctrl+C was pressed twice within a given interval.
-const InterruptTimeoutS int = 3
-
// Client holds a DTail client configuration.
var Client *ClientConfig
@@ -27,28 +34,22 @@ var Server *ServerConfig
// Common holds common configs of both both, client and server.
var Common *CommonConfig
-// Used to initialize the configuration.
-type configInitializer struct {
- Common *CommonConfig
- Server *ServerConfig
- Client *ClientConfig
-}
-
-// Parse and read a given config file in JSON format.
-func (c *configInitializer) parseConfig(configFile string) {
- fd, err := os.Open(configFile)
- if err != nil {
- panic(err)
+// Setup the DTail configuration.
+func Setup(sourceProcess source.Source, args *Args, additionalArgs []string) {
+ initializer := initializer{
+ Common: newDefaultCommonConfig(),
+ Server: newDefaultServerConfig(),
+ Client: newDefaultClientConfig(),
}
- defer fd.Close()
-
- cfgBytes, err := ioutil.ReadAll(fd)
- if err != nil {
+ if err := initializer.parseConfig(args); err != nil {
panic(err)
}
-
- err = json.Unmarshal([]byte(cfgBytes), c)
- if err != nil {
+ if err := initializer.transformConfig(sourceProcess, args, additionalArgs); err != nil {
panic(err)
}
+
+ // Make config accessible globally
+ Server = initializer.Server
+ Client = initializer.Client
+ Common = initializer.Common
}
diff --git a/internal/config/env.go b/internal/config/env.go
new file mode 100644
index 0000000..88b831d
--- /dev/null
+++ b/internal/config/env.go
@@ -0,0 +1,7 @@
+package config
+
+import "os"
+
+func Env(env string) bool {
+ return "yes" == os.Getenv(env)
+}
diff --git a/internal/config/initializer.go b/internal/config/initializer.go
new file mode 100644
index 0000000..4d6a73b
--- /dev/null
+++ b/internal/config/initializer.go
@@ -0,0 +1,184 @@
+package config
+
+import (
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+
+ "github.com/mimecast/dtail/internal/source"
+)
+
+// Used to initialize the configuration.
+type initializer struct {
+ Common *CommonConfig
+ Server *ServerConfig
+ Client *ClientConfig
+}
+
+type transformCb func(*initializer, *Args, []string) error
+
+func (in *initializer) parseConfig(args *Args) error {
+ if strings.ToUpper(args.ConfigFile) == "NONE" {
+ return nil
+ }
+
+ if args.ConfigFile != "" {
+ return in.parseSpecificConfig(args.ConfigFile)
+ }
+
+ if homeDir, err := os.UserHomeDir(); err != nil {
+ var paths []string
+ paths = append(paths, fmt.Sprintf("%s/.config/dtail/dtail.conf", homeDir))
+ paths = append(paths, fmt.Sprintf("%s/.dtail.conf", homeDir))
+ for _, configPath := range paths {
+ if _, err := os.Stat(configPath); !os.IsNotExist(err) {
+ in.parseSpecificConfig(configPath)
+ }
+ }
+ }
+
+ return nil
+}
+
+func (in *initializer) parseSpecificConfig(configFile string) error {
+ fd, err := os.Open(configFile)
+ if err != nil {
+ return fmt.Errorf("Unable to read config file: %v", err)
+ }
+ defer fd.Close()
+
+ cfgBytes, err := ioutil.ReadAll(fd)
+ if err != nil {
+ return fmt.Errorf("Unable to read config file %s: %v", configFile, err)
+ }
+
+ if err := json.Unmarshal([]byte(cfgBytes), in); err != nil {
+ return fmt.Errorf("Unable to parse config file %s: %v", configFile, err)
+ }
+
+ return nil
+}
+
+func (in *initializer) transformConfig(sourceProcess source.Source, args *Args,
+ additionalArgs []string) error {
+
+ in.readEnvironmentVars()
+
+ switch sourceProcess {
+ case source.Server:
+ return in.optimusPrime(transformServer, args, additionalArgs)
+ case source.Client:
+ return in.optimusPrime(transformClient, args, additionalArgs)
+ case source.HealthCheck:
+ return in.optimusPrime(transformHealthCheck, args, additionalArgs)
+ default:
+ return fmt.Errorf("Unable to transform config, unknown source '%s'",
+ sourceProcess)
+ }
+}
+
+// There are some special options which can be set by environment variable.
+func (in *initializer) readEnvironmentVars() {
+ if Env("DTAIL_SSH_DONT_ADD_HOSTS_TO_KNOWNHOSTS_FILE") ||
+ Env("DTAIL_JENKINS") {
+ in.Client.SSHDontAddHostsToKnownHostsFile = true
+ }
+}
+
+func (in *initializer) optimusPrime(sourceCb transformCb, args *Args,
+ additionalArgs []string) error {
+
+ // Copy args to config objects.
+ // NEXT: Maybe unify args and config structs?
+ if args.SSHPort != DefaultSSHPort {
+ in.Common.SSHPort = args.SSHPort
+ }
+ if args.LogLevel != DefaultLogLevel {
+ in.Common.LogLevel = args.LogLevel
+ }
+ if args.NoColor {
+ in.Client.TermColorsEnable = false
+ }
+ if args.LogDir != "" {
+ in.Common.LogDir = args.LogDir
+ }
+ if args.Logger != "" {
+ in.Common.Logger = args.Logger
+ }
+ if args.ConnectionsPerCPU == 0 {
+ args.ConnectionsPerCPU = DefaultConnectionsPerCPU
+ }
+
+ // Setup log directory.
+ if strings.Contains(in.Common.LogDir, "~/") {
+ homeDir, err := os.UserHomeDir()
+ if err != nil {
+ panic(err)
+ }
+ in.Common.LogDir = strings.ReplaceAll(in.Common.LogDir, "~/",
+ fmt.Sprintf("%s/", homeDir))
+ }
+
+ // Source type specific transormations.
+ sourceCb(in, args, additionalArgs)
+
+ // Spartan mode.
+ if args.Spartan {
+ args.Quiet = true
+ args.NoColor = true
+ in.Client.TermColorsEnable = false
+ if args.LogLevel == "" {
+ args.LogLevel = "ERROR"
+ in.Common.LogLevel = "ERROR"
+ }
+ }
+ // Interpret additional args as file list or as query.
+ if args.What == "" {
+ var files []string
+ for _, arg := range flag.Args() {
+ if args.QueryStr == "" && strings.Contains(strings.ToLower(arg), "select ") {
+ args.QueryStr = arg
+ continue
+ }
+ files = append(files, arg)
+ }
+ args.What = strings.Join(files, ",")
+ }
+
+ return nil
+}
+
+func transformClient(in *initializer, args *Args, additionalArgs []string) error {
+ // Serverless mode.
+ if args.Discovery == "" && (args.ServersStr == "" ||
+ strings.ToLower(args.ServersStr) == "serverless") {
+ // We are not connecting to any servers.
+ args.Serverless = true
+ if args.LogLevel == DefaultLogLevel {
+ in.Common.LogLevel = "warn"
+ }
+ }
+ return nil
+}
+
+func transformServer(in *initializer, args *Args, additionalArgs []string) error {
+ if args.SSHBindAddress != "" {
+ in.Server.SSHBindAddress = args.SSHBindAddress
+ }
+ return nil
+}
+
+func transformHealthCheck(in *initializer, args *Args, additionalArgs []string) error {
+ // Serverless mode.
+ if args.Discovery == "" && (args.ServersStr == "" ||
+ strings.ToLower(args.ServersStr) == "serverless") {
+ // We are not connecting to any servers.
+ args.Serverless = true
+ in.Common.LogLevel = "warn"
+ }
+ args.TrustAllHosts = true
+ return nil
+}
diff --git a/internal/config/read.go b/internal/config/read.go
deleted file mode 100644
index a4e605b..0000000
--- a/internal/config/read.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package config
-
-import (
- "os"
-)
-
-// Read the DTail configuration.
-func Read(configFile string, sshPort int) {
- initializer := configInitializer{
- Common: newDefaultCommonConfig(),
- Server: newDefaultServerConfig(),
- Client: newDefaultClientConfig(),
- }
-
- if configFile == "" {
- configFile = "./cfg/dtail.json"
- }
-
- if _, err := os.Stat(configFile); !os.IsNotExist(err) {
- initializer.parseConfig(configFile)
- }
-
- // Assign pointers to global variables, so that we can access the
- // configuration from any place of the program.
- Common = initializer.Common
- Server = initializer.Server
- Client = initializer.Client
-
- if Server.MapreduceLogFormat == "" {
- Server.MapreduceLogFormat = "default"
- }
-
- // If non-standard port specified, overwrite config
- if sshPort != 2222 {
- Common.SSHPort = sshPort
- }
-}
diff --git a/internal/config/server.go b/internal/config/server.go
index dc0d587..254ea0c 100644
--- a/internal/config/server.go
+++ b/internal/config/server.go
@@ -4,8 +4,8 @@ import (
"errors"
)
-// Permissions map. Each SSH user has a list of permissions which
-// log files it is allowed to follow and which ones not.
+// Permissions map. Each SSH user has a list of permissions which log files it
+// is allowed to follow and which ones not.
type Permissions struct {
// The default user permissions.
Default []string
@@ -47,7 +47,7 @@ type ServerConfig struct {
MaxConcurrentCats int
// The max amount of concurrent tails per server.
MaxConcurrentTails int
- // The user permissions.
+ // The user permissions. TODO: Add to JSON schema
Permissions Permissions `json:",omitempty"`
// The mapr log format
MapreduceLogFormat string `json:",omitempty"`
@@ -68,7 +68,6 @@ var ServerRelaxedAuthEnable bool
func newDefaultServerConfig() *ServerConfig {
defaultPermissions := []string{"^/.*"}
defaultBindAddress := "0.0.0.0"
-
return &ServerConfig{
SSHBindAddress: defaultBindAddress,
MaxConnections: 10,
@@ -76,6 +75,7 @@ func newDefaultServerConfig() *ServerConfig {
MaxConcurrentTails: 50,
HostKeyFile: "./cache/ssh_host_key",
HostKeyBits: 4096,
+ MapreduceLogFormat: "default",
Permissions: Permissions{
Default: defaultPermissions,
},
@@ -88,10 +88,8 @@ func ServerUserPermissions(userName string) (permissions []string, err error) {
if p, ok := Server.Permissions.Users[userName]; ok {
permissions = p
}
-
if len(permissions) == 0 {
err = errors.New("Empty set of permission, user won't be able to open any files")
}
-
return
}