v0.4.0
Some checks failed
ci/woodpecker/push/gitea Pipeline was successful
ci/woodpecker/push/go-lint Pipeline failed
ci/woodpecker/tag/gitea Pipeline failed
ci/woodpecker/tag/go-lint Pipeline failed
ci/woodpecker/tag/publish-docs Pipeline is running
ci/woodpecker/push/publish-docs Pipeline was successful
Some checks failed
ci/woodpecker/push/gitea Pipeline was successful
ci/woodpecker/push/go-lint Pipeline failed
ci/woodpecker/tag/gitea Pipeline failed
ci/woodpecker/tag/go-lint Pipeline failed
ci/woodpecker/tag/publish-docs Pipeline is running
ci/woodpecker/push/publish-docs Pipeline was successful
This commit is contained in:
@ -17,12 +17,13 @@ import (
|
||||
"embed"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
//go:embed templates/*.txt
|
||||
var templates embed.FS
|
||||
|
||||
var requiredKeys = []string{"commands", "cmd-configs"}
|
||||
var requiredKeys = []string{"commands"}
|
||||
|
||||
var Sprintf = fmt.Sprintf
|
||||
|
||||
@ -30,7 +31,7 @@ var Sprintf = fmt.Sprintf
|
||||
// The environment of local commands will be the machine's environment plus any extra
|
||||
// variables specified in the Env file or Environment.
|
||||
// Dir can also be specified for local commands.
|
||||
func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *ConfigOpts) ([]string, error) {
|
||||
func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([]string, error) {
|
||||
|
||||
var (
|
||||
outputArr []string
|
||||
@ -52,13 +53,13 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
|
||||
command.Type = strings.TrimSpace(command.Type)
|
||||
|
||||
if command.Type != "" {
|
||||
log.Info().Str("Command", fmt.Sprintf("Running script %s on host %s", command.Cmd, *command.Host)).Send()
|
||||
cmdCtxLogger.Info().Str("Command", fmt.Sprintf("Running script %s on host %s", command.Cmd, *command.Host)).Send()
|
||||
} else {
|
||||
log.Info().Str("Command", fmt.Sprintf("Running command %s %s on host %s", command.Cmd, ArgsStr, *command.Host)).Send()
|
||||
cmdCtxLogger.Info().Str("Command", fmt.Sprintf("Running command %s %s on host %s", command.Cmd, ArgsStr, *command.Host)).Send()
|
||||
}
|
||||
|
||||
if command.RemoteHost.SshClient == nil {
|
||||
err := command.RemoteHost.ConnectToSSHHost(opts, backyConf)
|
||||
err := command.RemoteHost.ConnectToSSHHost(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -67,7 +68,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
|
||||
|
||||
// Retry connecting to host; if that fails, error. If it does not fail, try to create new session
|
||||
if err != nil {
|
||||
connErr := command.RemoteHost.ConnectToSSHHost(opts, backyConf)
|
||||
connErr := command.RemoteHost.ConnectToSSHHost(opts)
|
||||
if connErr != nil {
|
||||
return nil, fmt.Errorf("error creating session: %v, and error creating new connection to host: %v", err, connErr)
|
||||
}
|
||||
@ -80,7 +81,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
|
||||
|
||||
defer commandSession.Close()
|
||||
|
||||
injectEnvIntoSSH(envVars, commandSession, opts, log)
|
||||
injectEnvIntoSSH(envVars, commandSession, opts, cmdCtxLogger)
|
||||
cmd := command.Cmd
|
||||
for _, a := range command.Args {
|
||||
cmd += " " + a
|
||||
@ -98,7 +99,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
|
||||
// did the program panic while writing to the buffer?
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Info().Msg(fmt.Sprintf("panic occured writing to buffer: %x", err))
|
||||
cmdCtxLogger.Info().Msg(fmt.Sprintf("panic occured writing to buffer: %x", err))
|
||||
}
|
||||
}()
|
||||
|
||||
@ -119,7 +120,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
|
||||
if str, ok := outMap["output"].(string); ok {
|
||||
outputArr = append(outputArr, str)
|
||||
}
|
||||
log.Info().Fields(outMap).Send()
|
||||
cmdCtxLogger.Info().Fields(outMap).Send()
|
||||
}
|
||||
return outputArr, err
|
||||
}
|
||||
@ -211,7 +212,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
|
||||
if str, ok := outMap["output"].(string); ok {
|
||||
outputArr = append(outputArr, str)
|
||||
}
|
||||
log.Info().Fields(outMap).Send()
|
||||
cmdCtxLogger.Info().Fields(outMap).Send()
|
||||
}
|
||||
return outputArr, err
|
||||
}
|
||||
@ -224,7 +225,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
|
||||
if str, ok := outMap["output"].(string); ok {
|
||||
outputArr = append(outputArr, str)
|
||||
}
|
||||
log.Info().Fields(outMap).Send()
|
||||
cmdCtxLogger.Info().Fields(outMap).Send()
|
||||
}
|
||||
return outputArr, nil
|
||||
}
|
||||
@ -240,18 +241,18 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
|
||||
if str, ok := outMap["output"].(string); ok {
|
||||
outputArr = append(outputArr, str)
|
||||
}
|
||||
log.Info().Fields(outMap).Send()
|
||||
cmdCtxLogger.Info().Fields(outMap).Send()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error().Err(fmt.Errorf("error when running cmd: %s: %w", command.Cmd, err)).Send()
|
||||
cmdCtxLogger.Error().Err(fmt.Errorf("error when running cmd: %s: %w", command.Cmd, err)).Send()
|
||||
return outputArr, err
|
||||
}
|
||||
} else {
|
||||
|
||||
var err error
|
||||
if command.Shell != "" {
|
||||
log.Info().Str("Command", fmt.Sprintf("Running command %s %s on local machine in %s", command.Cmd, ArgsStr, command.Shell)).Send()
|
||||
cmdCtxLogger.Info().Str("Command", fmt.Sprintf("Running command %s %s on local machine in %s", command.Cmd, ArgsStr, command.Shell)).Send()
|
||||
|
||||
ArgsStr = fmt.Sprintf("%s %s", command.Cmd, ArgsStr)
|
||||
|
||||
@ -260,7 +261,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
|
||||
if command.Dir != nil {
|
||||
localCMD.Dir = *command.Dir
|
||||
}
|
||||
injectEnvIntoLocalCMD(envVars, localCMD, log)
|
||||
injectEnvIntoLocalCMD(envVars, localCMD, cmdCtxLogger)
|
||||
|
||||
cmdOutWriters = io.MultiWriter(&cmdOutBuf)
|
||||
|
||||
@ -286,12 +287,12 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error().Err(fmt.Errorf("error when running cmd %s: %w", command.Cmd, err)).Send()
|
||||
cmdCtxLogger.Error().Err(fmt.Errorf("error when running cmd %s: %w", command.Cmd, err)).Send()
|
||||
return outputArr, err
|
||||
}
|
||||
return outputArr, nil
|
||||
}
|
||||
log.Info().Str("Command", fmt.Sprintf("Running command %s %s on local machine", command.Cmd, ArgsStr)).Send()
|
||||
cmdCtxLogger.Info().Str("Command", fmt.Sprintf("Running command %s %s on local machine", command.Cmd, ArgsStr)).Send()
|
||||
|
||||
localCMD := exec.Command(command.Cmd, command.Args...)
|
||||
if command.Dir != nil {
|
||||
@ -299,7 +300,7 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
|
||||
}
|
||||
// fmt.Printf("%v\n", envVars.env)
|
||||
|
||||
injectEnvIntoLocalCMD(envVars, localCMD, log)
|
||||
injectEnvIntoLocalCMD(envVars, localCMD, cmdCtxLogger)
|
||||
cmdOutWriters = io.MultiWriter(&cmdOutBuf)
|
||||
// fmt.Printf("%v\n", localCMD.Environ())
|
||||
|
||||
@ -318,46 +319,46 @@ func (command *Command) RunCmd(log zerolog.Logger, backyConf *ConfigFile, opts *
|
||||
if str, ok := outMap["output"].(string); ok {
|
||||
outputArr = append(outputArr, str)
|
||||
}
|
||||
log.Info().Fields(outMap).Send()
|
||||
cmdCtxLogger.Info().Fields(outMap).Send()
|
||||
}
|
||||
if err != nil {
|
||||
log.Error().Err(fmt.Errorf("error when running cmd %s: %w", command.Cmd, err)).Send()
|
||||
cmdCtxLogger.Error().Err(fmt.Errorf("error when running cmd %s: %w", command.Cmd, err)).Send()
|
||||
return outputArr, err
|
||||
}
|
||||
}
|
||||
return outputArr, nil
|
||||
}
|
||||
|
||||
func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, config *ConfigFile, results chan<- string, opts *ConfigOpts) {
|
||||
func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<- string, opts *ConfigOpts) {
|
||||
|
||||
for list := range jobs {
|
||||
fieldsMap := make(map[string]interface{})
|
||||
fieldsMap["list"] = list.Name
|
||||
|
||||
cmdLog := config.Logger.Info()
|
||||
cmdLog := opts.Logger.Info()
|
||||
|
||||
var count int
|
||||
var cmdsRan []string
|
||||
var outStructArr []outStruct
|
||||
|
||||
for _, cmd := range list.Order {
|
||||
currentCmd := config.Cmds[cmd].Cmd
|
||||
currentCmd := opts.Cmds[cmd].Cmd
|
||||
|
||||
fieldsMap["cmd"] = config.Cmds[cmd].Cmd
|
||||
cmdToRun := config.Cmds[cmd]
|
||||
fieldsMap["cmd"] = opts.Cmds[cmd].Cmd
|
||||
cmdToRun := opts.Cmds[cmd]
|
||||
cmdLog.Fields(fieldsMap).Send()
|
||||
|
||||
cmdLogger := config.Logger.With().
|
||||
cmdLogger := opts.Logger.With().
|
||||
Str("backy-cmd", cmd).Str("Host", "local machine").
|
||||
Logger()
|
||||
|
||||
if cmdToRun.Host != nil {
|
||||
cmdLogger = config.Logger.With().
|
||||
cmdLogger = opts.Logger.With().
|
||||
Str("backy-cmd", cmd).Str("Host", *cmdToRun.Host).
|
||||
Logger()
|
||||
}
|
||||
|
||||
outputArr, runOutErr := cmdToRun.RunCmd(cmdLogger, config, opts)
|
||||
outputArr, runOutErr := cmdToRun.RunCmd(cmdLogger, opts)
|
||||
if list.NotifyConfig != nil {
|
||||
|
||||
if cmdToRun.GetOutput || list.GetOutput {
|
||||
@ -380,7 +381,7 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, config *ConfigF
|
||||
errStruct["listName"] = list.Name
|
||||
errStruct["Command"] = currentCmd
|
||||
errStruct["Cmd"] = cmd
|
||||
errStruct["Args"] = config.Cmds[cmd].Args
|
||||
errStruct["Args"] = opts.Cmds[cmd].Args
|
||||
errStruct["Err"] = runOutErr
|
||||
errStruct["CmdsRan"] = cmdsRan
|
||||
errStruct["Output"] = outputArr
|
||||
@ -390,17 +391,17 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, config *ConfigF
|
||||
tmpErr := msgTemps.err.Execute(&errMsg, errStruct)
|
||||
|
||||
if tmpErr != nil {
|
||||
config.Logger.Err(tmpErr).Send()
|
||||
opts.Logger.Err(tmpErr).Send()
|
||||
}
|
||||
|
||||
notifySendErr := list.NotifyConfig.Send(context.Background(), fmt.Sprintf("List %s failed on command %s ", list.Name, cmd), errMsg.String())
|
||||
notifySendErr := list.NotifyConfig.Send(context.Background(), fmt.Sprintf("List %s failed", list.Name), errMsg.String())
|
||||
|
||||
if notifySendErr != nil {
|
||||
config.Logger.Err(notifySendErr).Send()
|
||||
opts.Logger.Err(notifySendErr).Send()
|
||||
}
|
||||
}
|
||||
|
||||
config.Logger.Err(runOutErr).Send()
|
||||
opts.Logger.Err(runOutErr).Send()
|
||||
|
||||
break
|
||||
} else {
|
||||
@ -420,14 +421,14 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, config *ConfigF
|
||||
tmpErr := msgTemps.success.Execute(&successMsg, successStruct)
|
||||
|
||||
if tmpErr != nil {
|
||||
config.Logger.Err(tmpErr).Send()
|
||||
opts.Logger.Err(tmpErr).Send()
|
||||
break
|
||||
}
|
||||
|
||||
err := list.NotifyConfig.Send(context.Background(), fmt.Sprintf("List %s succeded", list.Name), successMsg.String())
|
||||
|
||||
if err != nil {
|
||||
config.Logger.Err(err).Send()
|
||||
opts.Logger.Err(err).Send()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -442,22 +443,22 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, config *ConfigF
|
||||
}
|
||||
|
||||
// RunListConfig runs a command list from the ConfigFile.
|
||||
func (config *ConfigFile) RunListConfig(cron string, opts *ConfigOpts) {
|
||||
func (opts *ConfigOpts) RunListConfig(cron string) {
|
||||
mTemps := &msgTemplates{
|
||||
err: template.Must(template.New("error.txt").ParseFS(templates, "templates/error.txt")),
|
||||
success: template.Must(template.New("success.txt").ParseFS(templates, "templates/success.txt")),
|
||||
}
|
||||
configListsLen := len(config.CmdConfigLists)
|
||||
configListsLen := len(opts.CmdConfigLists)
|
||||
listChan := make(chan *CmdList, configListsLen)
|
||||
results := make(chan string)
|
||||
|
||||
// This starts up list workers, initially blocked
|
||||
// because there are no jobs yet.
|
||||
for w := 1; w <= configListsLen; w++ {
|
||||
go cmdListWorker(mTemps, listChan, config, results, opts)
|
||||
go cmdListWorker(mTemps, listChan, results, opts)
|
||||
}
|
||||
|
||||
for listName, cmdConfig := range config.CmdConfigLists {
|
||||
for listName, cmdConfig := range opts.CmdConfigLists {
|
||||
if cmdConfig.Name == "" {
|
||||
cmdConfig.Name = listName
|
||||
}
|
||||
@ -475,26 +476,26 @@ func (config *ConfigFile) RunListConfig(cron string, opts *ConfigOpts) {
|
||||
<-results
|
||||
}
|
||||
|
||||
config.closeHostConnections()
|
||||
opts.closeHostConnections()
|
||||
}
|
||||
|
||||
func (config *ConfigFile) ExecuteCmds(opts *ConfigOpts) {
|
||||
func (config *ConfigOpts) ExecuteCmds(opts *ConfigOpts) {
|
||||
for _, cmd := range opts.executeCmds {
|
||||
cmdToRun := config.Cmds[cmd]
|
||||
cmdLogger := config.Logger.With().
|
||||
cmdToRun := opts.Cmds[cmd]
|
||||
cmdLogger := opts.Logger.With().
|
||||
Str("backy-cmd", cmd).
|
||||
Logger()
|
||||
_, runErr := cmdToRun.RunCmd(cmdLogger, config, opts)
|
||||
_, runErr := cmdToRun.RunCmd(cmdLogger, opts)
|
||||
if runErr != nil {
|
||||
config.Logger.Err(runErr).Send()
|
||||
opts.Logger.Err(runErr).Send()
|
||||
}
|
||||
}
|
||||
|
||||
config.closeHostConnections()
|
||||
opts.closeHostConnections()
|
||||
|
||||
}
|
||||
|
||||
func (c *ConfigFile) closeHostConnections() {
|
||||
func (c *ConfigOpts) closeHostConnections() {
|
||||
for _, host := range c.Hosts {
|
||||
c.Logger.Info().Str("server", host.HostName)
|
||||
if host.isProxyHost {
|
||||
|
@ -10,40 +10,58 @@ import (
|
||||
|
||||
"git.andrewnw.xyz/CyberShell/backy/pkg/logging"
|
||||
vault "github.com/hashicorp/vault/api"
|
||||
"github.com/knadh/koanf/parsers/yaml"
|
||||
"github.com/knadh/koanf/providers/file"
|
||||
"github.com/knadh/koanf/v2"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func (opts *ConfigOpts) InitConfig() {
|
||||
if opts.viper != nil {
|
||||
return
|
||||
}
|
||||
backyViper := viper.New()
|
||||
var homeDir string
|
||||
var homeDirErr error
|
||||
var backyHomeConfDir string
|
||||
var configFiles []string
|
||||
|
||||
if strings.TrimSpace(opts.ConfigFilePath) != "" {
|
||||
func (opts *ConfigOpts) InitConfig() {
|
||||
|
||||
homeDir, homeDirErr = os.UserHomeDir()
|
||||
if homeDirErr != nil {
|
||||
fmt.Println(homeDirErr)
|
||||
}
|
||||
backyHomeConfDir = homeDir + "/.config/backy/"
|
||||
configFiles = []string{"./backy.yml", "./backy.yaml", backyHomeConfDir + "backy.yml", backyHomeConfDir + "backy.yaml"}
|
||||
backyKoanf := koanf.New(".")
|
||||
opts.ConfigFilePath = strings.TrimSpace(opts.ConfigFilePath)
|
||||
if opts.ConfigFilePath != "" {
|
||||
err := testFile(opts.ConfigFilePath)
|
||||
if err != nil {
|
||||
logging.ExitWithMSG(fmt.Sprintf("Could not open config file %s: %v", opts.ConfigFilePath, err), 1, nil)
|
||||
}
|
||||
backyViper.SetConfigFile(opts.ConfigFilePath)
|
||||
|
||||
if err := backyKoanf.Load(file.Provider(opts.ConfigFilePath), yaml.Parser()); err != nil {
|
||||
logging.ExitWithMSG(fmt.Sprintf("error loading config: %v", err), 1, &opts.Logger)
|
||||
}
|
||||
} else {
|
||||
backyViper.SetConfigName("backy.yml") // name of config file (with extension)
|
||||
backyViper.SetConfigName("backy.yaml") // name of config file (with extension)
|
||||
backyViper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
|
||||
backyViper.AddConfigPath(".") // optionally look for config in the working directory
|
||||
backyViper.AddConfigPath("$HOME/.config/backy") // call multiple times to add many search paths
|
||||
|
||||
cFileFalures := 0
|
||||
for _, c := range configFiles {
|
||||
if err := backyKoanf.Load(file.Provider(c), yaml.Parser()); err != nil {
|
||||
cFileFalures++
|
||||
} else {
|
||||
opts.ConfigFilePath = c
|
||||
break
|
||||
}
|
||||
}
|
||||
if cFileFalures == len(configFiles) {
|
||||
logging.ExitWithMSG(fmt.Sprintf("could not find a config file. Put one in the following paths: %v", configFiles), 1, &opts.Logger)
|
||||
}
|
||||
}
|
||||
err := backyViper.ReadInConfig() // Find and read the config file
|
||||
if err != nil { // Handle errors reading the config file
|
||||
msg := fmt.Sprintf("fatal error reading config file %s: %v", backyViper.ConfigFileUsed(), err)
|
||||
logging.ExitWithMSG(msg, 1, nil)
|
||||
}
|
||||
opts.viper = backyViper
|
||||
|
||||
opts.koanf = backyKoanf
|
||||
}
|
||||
|
||||
// ReadConfig validates and reads the config file.
|
||||
func ReadConfig(opts *ConfigOpts) *ConfigFile {
|
||||
func ReadConfig(opts *ConfigOpts) *ConfigOpts {
|
||||
|
||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
os.Setenv("BACKY_TERM", "enabled")
|
||||
@ -53,44 +71,38 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
|
||||
os.Setenv("BACKY_TERM", "disabled")
|
||||
}
|
||||
|
||||
backyConfigFile := NewConfig()
|
||||
backyViper := opts.viper
|
||||
backyKoanf := opts.koanf
|
||||
|
||||
opts.loadEnv()
|
||||
// envFileInConfigDir := fmt.Sprintf("%s/.env", path.Dir(backyViper.ConfigFileUsed()))
|
||||
|
||||
// load the .env file in config file directory
|
||||
// _ = godotenv.Load(envFileInConfigDir)
|
||||
|
||||
if backyViper.GetBool(getNestedConfig("logging", "cmd-std-out")) {
|
||||
if backyKoanf.Bool(getNestedConfig("logging", "cmd-std-out")) {
|
||||
os.Setenv("BACKY_STDOUT", "enabled")
|
||||
}
|
||||
|
||||
CheckConfigValues(backyViper)
|
||||
CheckConfigValues(backyKoanf, opts.ConfigFilePath)
|
||||
for _, c := range opts.executeCmds {
|
||||
if !backyViper.IsSet(getCmdFromConfig(c)) {
|
||||
logging.ExitWithMSG(Sprintf("command %s is not in config file %s", c, backyViper.ConfigFileUsed()), 1, nil)
|
||||
if !backyKoanf.Exists(getCmdFromConfig(c)) {
|
||||
logging.ExitWithMSG(Sprintf("command %s is not in config file %s", c, opts.ConfigFilePath), 1, nil)
|
||||
}
|
||||
}
|
||||
|
||||
for _, l := range opts.executeLists {
|
||||
if !backyViper.IsSet(getCmdListFromConfig(l)) {
|
||||
if !backyKoanf.Exists(getCmdListFromConfig(l)) {
|
||||
logging.ExitWithMSG(Sprintf("list %s not found", l), 1, nil)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// backyLoggingOpts *viper.Viper
|
||||
verbose bool
|
||||
logFile string
|
||||
)
|
||||
|
||||
verbose = backyViper.GetBool(getLoggingKeyFromConfig("verbose"))
|
||||
verbose = backyKoanf.Bool(getLoggingKeyFromConfig("verbose"))
|
||||
|
||||
logFile = fmt.Sprintf("%s/backy.log", path.Dir(backyViper.ConfigFileUsed()))
|
||||
if backyViper.IsSet(getLoggingKeyFromConfig("file")) {
|
||||
logFile = backyViper.GetString(getLoggingKeyFromConfig("file"))
|
||||
logFile = fmt.Sprintf("%s/backy.log", path.Dir(opts.ConfigFilePath))
|
||||
if backyKoanf.Exists(getLoggingKeyFromConfig("file")) {
|
||||
logFile = backyKoanf.String(getLoggingKeyFromConfig("file"))
|
||||
}
|
||||
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
|
||||
if verbose {
|
||||
@ -99,7 +111,7 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
|
||||
os.Setenv("BACKY_LOGLEVEL", Sprintf("%v", globalLvl))
|
||||
}
|
||||
|
||||
consoleLoggingDisabled := backyViper.GetBool(getLoggingKeyFromConfig("console-disabled"))
|
||||
consoleLoggingDisabled := backyKoanf.Bool(getLoggingKeyFromConfig("console-disabled"))
|
||||
|
||||
os.Setenv("BACKY_CONSOLE_LOGGING", "enabled")
|
||||
// Other qualifiers can go here as well
|
||||
@ -111,42 +123,30 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
|
||||
|
||||
log := zerolog.New(writers).With().Timestamp().Logger()
|
||||
|
||||
backyConfigFile.Logger = log
|
||||
opts.Logger = log
|
||||
|
||||
log.Info().Str("config file", backyViper.ConfigFileUsed()).Send()
|
||||
commandsMap := backyViper.GetStringMapString("commands")
|
||||
commandsMapViper := backyViper.Sub("commands")
|
||||
unmarshalErr := commandsMapViper.Unmarshal(&backyConfigFile.Cmds)
|
||||
log.Info().Str("config file", opts.ConfigFilePath).Send()
|
||||
|
||||
unmarshalErr := backyKoanf.UnmarshalWithConf("commands", &opts.Cmds, koanf.UnmarshalConf{Tag: "yaml"})
|
||||
if unmarshalErr != nil {
|
||||
panic(fmt.Errorf("error unmarshalling cmds struct: %w", unmarshalErr))
|
||||
}
|
||||
|
||||
hostConfigsMap := make(map[string]*viper.Viper)
|
||||
|
||||
for cmdName, cmdConf := range backyConfigFile.Cmds {
|
||||
for cmdName, cmdConf := range opts.Cmds {
|
||||
envFileErr := testFile(cmdConf.Env)
|
||||
if envFileErr != nil {
|
||||
backyConfigFile.Logger.Info().Str("cmd", cmdName).Err(envFileErr).Send()
|
||||
opts.Logger.Info().Str("cmd", cmdName).Err(envFileErr).Send()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
expandEnvVars(opts.backyEnv, cmdConf.Environment)
|
||||
|
||||
host := cmdConf.Host
|
||||
if host != nil {
|
||||
if backyViper.IsSet(getNestedConfig("hosts", *host)) {
|
||||
hostconfig := backyViper.Sub(getNestedConfig("hosts", *host))
|
||||
hostConfigsMap[*host] = hostconfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hostsMapViper := backyViper.Sub("hosts")
|
||||
unmarshalErr = hostsMapViper.Unmarshal(&backyConfigFile.Hosts)
|
||||
unmarshalErr = backyKoanf.UnmarshalWithConf("hosts", &opts.Hosts, koanf.UnmarshalConf{Tag: "yaml"})
|
||||
if unmarshalErr != nil {
|
||||
panic(fmt.Errorf("error unmarshalling hosts struct: %w", unmarshalErr))
|
||||
}
|
||||
for hostConfigName, host := range backyConfigFile.Hosts {
|
||||
for hostConfigName, host := range opts.Hosts {
|
||||
if host.Host == "" {
|
||||
host.Host = hostConfigName
|
||||
}
|
||||
@ -155,7 +155,7 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
|
||||
if len(proxyHosts) > 1 {
|
||||
for hostNum, h := range proxyHosts {
|
||||
if hostNum > 1 {
|
||||
proxyHost, defined := backyConfigFile.Hosts[h]
|
||||
proxyHost, defined := opts.Hosts[h]
|
||||
if defined {
|
||||
host.ProxyHost = append(host.ProxyHost, proxyHost)
|
||||
} else {
|
||||
@ -163,7 +163,7 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
|
||||
host.ProxyHost = append(host.ProxyHost, newProxy)
|
||||
}
|
||||
} else {
|
||||
proxyHost, defined := backyConfigFile.Hosts[h]
|
||||
proxyHost, defined := opts.Hosts[h]
|
||||
if defined {
|
||||
host.ProxyHost = append(host.ProxyHost, proxyHost)
|
||||
} else {
|
||||
@ -173,7 +173,7 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
proxyHost, defined := backyConfigFile.Hosts[proxyHosts[0]]
|
||||
proxyHost, defined := opts.Hosts[proxyHosts[0]]
|
||||
if defined {
|
||||
host.ProxyHost = append(host.ProxyHost, proxyHost)
|
||||
} else {
|
||||
@ -184,33 +184,29 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
|
||||
}
|
||||
}
|
||||
|
||||
cmdListCfg := backyViper.Sub("cmd-configs")
|
||||
unmarshalErr = cmdListCfg.Unmarshal(&backyConfigFile.CmdConfigLists)
|
||||
if unmarshalErr != nil {
|
||||
panic(fmt.Errorf("error unmarshalling cmd list struct: %w", unmarshalErr))
|
||||
if backyKoanf.Exists("cmd-lists") {
|
||||
unmarshalErr = backyKoanf.UnmarshalWithConf("cmd-lists", &opts.CmdConfigLists, koanf.UnmarshalConf{Tag: "yaml"})
|
||||
if unmarshalErr != nil {
|
||||
logging.ExitWithMSG((fmt.Sprintf("error unmarshalling cmd list struct: %v", unmarshalErr)), 1, &opts.Logger)
|
||||
}
|
||||
}
|
||||
|
||||
var cmdNotFoundSliceErr []error
|
||||
for cmdListName, cmdList := range backyConfigFile.CmdConfigLists {
|
||||
for cmdListName, cmdList := range opts.CmdConfigLists {
|
||||
if opts.useCron {
|
||||
cron := strings.TrimSpace(cmdList.Cron)
|
||||
if cron == "" {
|
||||
delete(backyConfigFile.CmdConfigLists, cmdListName)
|
||||
delete(opts.CmdConfigLists, cmdListName)
|
||||
}
|
||||
}
|
||||
for _, cmdInList := range cmdList.Order {
|
||||
_, cmdNameFound := backyConfigFile.Cmds[cmdInList]
|
||||
_, cmdNameFound := opts.Cmds[cmdInList]
|
||||
if !cmdNameFound {
|
||||
cmdNotFoundStr := fmt.Sprintf("command %s in list %s is not defined in commands section in config file", cmdInList, cmdListName)
|
||||
cmdNotFoundErr := errors.New(cmdNotFoundStr)
|
||||
cmdNotFoundSliceErr = append(cmdNotFoundSliceErr, cmdNotFoundErr)
|
||||
}
|
||||
}
|
||||
for _, notificationID := range cmdList.Notifications {
|
||||
if !backyViper.IsSet(getNestedConfig("notifications", notificationID)) {
|
||||
logging.ExitWithMSG(fmt.Sprintf("%s in list %s not found in notifications", notificationID, cmdListName), 1, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(cmdNotFoundSliceErr) > 0 {
|
||||
@ -218,39 +214,35 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
|
||||
cmdNotFoundErrorLog.Errs("commands not found", cmdNotFoundSliceErr).Send()
|
||||
}
|
||||
|
||||
if opts.useCron && (len(backyConfigFile.CmdConfigLists) == 0) {
|
||||
if opts.useCron && (len(opts.CmdConfigLists) == 0) {
|
||||
logging.ExitWithMSG("No cron fields detected in any command lists", 1, nil)
|
||||
}
|
||||
|
||||
for c := range commandsMap {
|
||||
for c := range opts.Cmds {
|
||||
if opts.executeCmds != nil && !contains(opts.executeCmds, c) {
|
||||
delete(backyConfigFile.Cmds, c)
|
||||
delete(opts.Cmds, c)
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts.executeLists) > 0 {
|
||||
for l := range backyConfigFile.CmdConfigLists {
|
||||
for l := range opts.CmdConfigLists {
|
||||
if !contains(opts.executeLists, l) {
|
||||
delete(backyConfigFile.CmdConfigLists, l)
|
||||
delete(opts.CmdConfigLists, l)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if backyViper.IsSet("notifications") {
|
||||
notificationsMap := backyViper.GetStringMap("notifications")
|
||||
for id := range notificationsMap {
|
||||
notifConfig := backyViper.Sub(getNestedConfig("notifications", id))
|
||||
config := &NotificationsConfig{
|
||||
Config: notifConfig,
|
||||
Enabled: true,
|
||||
}
|
||||
backyConfigFile.Notifications[id] = config
|
||||
if backyKoanf.Exists("notifications") {
|
||||
|
||||
unmarshalErr = backyKoanf.UnmarshalWithConf("notifications", &opts.NotificationConf, koanf.UnmarshalConf{Tag: "yaml"})
|
||||
if unmarshalErr != nil {
|
||||
fmt.Printf("error unmarshalling notifications object: %v", unmarshalErr)
|
||||
}
|
||||
}
|
||||
|
||||
for _, cmd := range backyConfigFile.Cmds {
|
||||
for _, cmd := range opts.Cmds {
|
||||
if cmd.Host != nil {
|
||||
host, hostFound := backyConfigFile.Hosts[*cmd.Host]
|
||||
host, hostFound := opts.Hosts[*cmd.Host]
|
||||
if hostFound {
|
||||
cmd.RemoteHost = host
|
||||
cmd.RemoteHost.Host = host.Host
|
||||
@ -258,19 +250,18 @@ func ReadConfig(opts *ConfigOpts) *ConfigFile {
|
||||
cmd.RemoteHost.HostName = host.HostName
|
||||
}
|
||||
} else {
|
||||
backyConfigFile.Hosts[*cmd.Host] = &Host{Host: *cmd.Host}
|
||||
opts.Hosts[*cmd.Host] = &Host{Host: *cmd.Host}
|
||||
cmd.RemoteHost = &Host{Host: *cmd.Host}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
backyConfigFile.SetupNotify()
|
||||
opts.ConfigFile = backyConfigFile
|
||||
opts.SetupNotify()
|
||||
if err := opts.setupVault(); err != nil {
|
||||
log.Err(err).Send()
|
||||
}
|
||||
opts.ConfigFile = backyConfigFile
|
||||
return backyConfigFile
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
func getNestedConfig(nestedConfig, key string) string {
|
||||
@ -289,16 +280,16 @@ func getLoggingKeyFromConfig(key string) string {
|
||||
}
|
||||
|
||||
func getCmdListFromConfig(list string) string {
|
||||
return fmt.Sprintf("cmd-configs.%s", list)
|
||||
return fmt.Sprintf("cmd-lists.%s", list)
|
||||
}
|
||||
|
||||
func (opts *ConfigOpts) setupVault() error {
|
||||
if !opts.viper.GetBool("vault.enabled") {
|
||||
if !opts.koanf.Bool("vault.enabled") {
|
||||
return nil
|
||||
}
|
||||
config := vault.DefaultConfig()
|
||||
|
||||
config.Address = opts.viper.GetString("vault.address")
|
||||
config.Address = opts.koanf.String("vault.address")
|
||||
if strings.TrimSpace(config.Address) == "" {
|
||||
config.Address = os.Getenv("VAULT_ADDR")
|
||||
}
|
||||
@ -308,7 +299,7 @@ func (opts *ConfigOpts) setupVault() error {
|
||||
return err
|
||||
}
|
||||
|
||||
token := opts.viper.GetString("vault.token")
|
||||
token := opts.koanf.String("vault.token")
|
||||
if strings.TrimSpace(token) == "" {
|
||||
token = os.Getenv("VAULT_TOKEN")
|
||||
}
|
||||
@ -318,10 +309,9 @@ func (opts *ConfigOpts) setupVault() error {
|
||||
|
||||
client.SetToken(token)
|
||||
|
||||
cmdListCfg := opts.viper.Sub("viper.keys")
|
||||
unmarshalErr := cmdListCfg.Unmarshal(&opts.VaultKeys)
|
||||
unmarshalErr := opts.koanf.UnmarshalWithConf("vault.keys", &opts.VaultKeys, koanf.UnmarshalConf{Tag: "yaml"})
|
||||
if unmarshalErr != nil {
|
||||
panic(fmt.Errorf("error unmarshalling viper.keys into struct: %w", unmarshalErr))
|
||||
logging.ExitWithMSG(fmt.Sprintf("error unmarshalling vault.keys into struct: %v", unmarshalErr), 1, &opts.Logger)
|
||||
}
|
||||
|
||||
opts.vaultClient = client
|
||||
|
@ -5,31 +5,34 @@
|
||||
package backy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.andrewnw.xyz/CyberShell/backy/pkg/logging"
|
||||
"github.com/go-co-op/gocron"
|
||||
)
|
||||
|
||||
func (opts *ConfigOpts) Cron() {
|
||||
s := gocron.NewScheduler(time.Local)
|
||||
s.TagsUnique()
|
||||
cmdLists := opts.ConfigFile.CmdConfigLists
|
||||
cmdLists := opts.CmdConfigLists
|
||||
for listName, config := range cmdLists {
|
||||
if config.Name == "" {
|
||||
config.Name = listName
|
||||
}
|
||||
|
||||
cron := strings.TrimSpace(config.Cron)
|
||||
if cron != "" {
|
||||
opts.ConfigFile.Logger.Info().Str("Scheduling cron list", config.Name).Str("Time", cron).Send()
|
||||
opts.Logger.Info().Str("Scheduling cron list", config.Name).Str("Time", cron).Send()
|
||||
_, err := s.CronWithSeconds(cron).Tag(config.Name).Do(func(cron string) {
|
||||
opts.ConfigFile.RunListConfig(cron, opts)
|
||||
opts.RunListConfig(cron)
|
||||
}, cron)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
logging.ExitWithMSG(fmt.Sprintf("error: %v", err), 1, &opts.Logger)
|
||||
}
|
||||
}
|
||||
}
|
||||
opts.ConfigFile.Logger.Info().Msg("Starting cron mode...")
|
||||
opts.Logger.Info().Msg("Starting cron mode...")
|
||||
s.StartBlocking()
|
||||
}
|
||||
|
5
pkg/backy/list.go
Normal file
5
pkg/backy/list.go
Normal file
@ -0,0 +1,5 @@
|
||||
package backy
|
||||
|
||||
func (opts *ConfigOpts) ListConfiguration() {
|
||||
|
||||
}
|
@ -18,7 +18,7 @@ const mongoConfigKey = "global.mongo"
|
||||
|
||||
func (opts *ConfigOpts) InitMongo() {
|
||||
|
||||
if !opts.viper.GetBool(getMongoConfigKey("enabled")) {
|
||||
if !opts.koanf.Bool(getMongoConfigKey("enabled")) {
|
||||
return
|
||||
}
|
||||
var (
|
||||
@ -27,37 +27,37 @@ func (opts *ConfigOpts) InitMongo() {
|
||||
)
|
||||
|
||||
// TODO: Get uri and creditials from config
|
||||
host := opts.viper.GetString(getMongoConfigKey("host"))
|
||||
port := opts.viper.GetInt32(getMongoConfigKey("port"))
|
||||
host := opts.koanf.String(getMongoConfigKey("host"))
|
||||
port := opts.koanf.Int64(getMongoConfigKey("port"))
|
||||
|
||||
ctx, ctxCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer ctxCancel()
|
||||
client, err = mongo.Connect(ctx, options.Client().ApplyURI(fmt.Sprintf("mongo://%s:%d", host, port)))
|
||||
if opts.viper.GetBool(getMongoConfigKey("prod")) {
|
||||
mongoEnvFileSet := opts.viper.IsSet(getMongoConfigKey("env"))
|
||||
if opts.koanf.Bool(getMongoConfigKey("prod")) {
|
||||
mongoEnvFileSet := opts.koanf.Exists(getMongoConfigKey("env"))
|
||||
if mongoEnvFileSet {
|
||||
getMongoConfigFromEnv(opts)
|
||||
}
|
||||
auth := options.Credential{}
|
||||
auth.Password = opts.viper.GetString("global.mongo.password")
|
||||
auth.Username = opts.viper.GetString("global.mongo.username")
|
||||
auth.Password = opts.koanf.String("global.mongo.password")
|
||||
auth.Username = opts.koanf.String("global.mongo.username")
|
||||
client, err = mongo.Connect(ctx, options.Client().SetAuth(auth).ApplyURI("mongodb://localhost:27017"))
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
opts.ConfigFile.Logger.Fatal().Err(err).Send()
|
||||
opts.Logger.Fatal().Err(err).Send()
|
||||
}
|
||||
if err != nil {
|
||||
opts.ConfigFile.Logger.Fatal().Err(err).Send()
|
||||
opts.Logger.Fatal().Err(err).Send()
|
||||
}
|
||||
defer client.Disconnect(ctx)
|
||||
err = client.Ping(ctx, readpref.Primary())
|
||||
if err != nil {
|
||||
opts.ConfigFile.Logger.Fatal().Err(err).Send()
|
||||
opts.Logger.Fatal().Err(err).Send()
|
||||
}
|
||||
databases, err := client.ListDatabaseNames(ctx, bson.M{})
|
||||
if err != nil {
|
||||
opts.ConfigFile.Logger.Fatal().Err(err).Send()
|
||||
opts.Logger.Fatal().Err(err).Send()
|
||||
}
|
||||
fmt.Println(databases)
|
||||
backyDB := client.Database("backy")
|
||||
@ -68,7 +68,7 @@ func (opts *ConfigOpts) InitMongo() {
|
||||
}
|
||||
|
||||
func getMongoConfigFromEnv(opts *ConfigOpts) error {
|
||||
mongoEnvFile, err := os.Open(opts.viper.GetString("global.mongo.env"))
|
||||
mongoEnvFile, err := os.Open(opts.koanf.String("global.mongo.env"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -84,8 +84,8 @@ func getMongoConfigFromEnv(opts *ConfigOpts) error {
|
||||
if !mongoUserFound {
|
||||
return errors.New("MONGO_PASSWORD not set in " + mongoEnvFile.Name())
|
||||
}
|
||||
opts.viper.Set(mongoConfigKey+".password", mongoPW)
|
||||
opts.viper.Set(mongoConfigKey+".username", mongoUser)
|
||||
opts.koanf.Set(mongoConfigKey+".password", mongoPW)
|
||||
opts.koanf.Set(mongoConfigKey+".username", mongoUser)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -5,67 +5,76 @@ package backy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.andrewnw.xyz/CyberShell/backy/pkg/logging"
|
||||
"github.com/nikoksr/notify"
|
||||
"github.com/nikoksr/notify/service/mail"
|
||||
"github.com/nikoksr/notify/service/matrix"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type matrixStruct struct {
|
||||
homeserver string
|
||||
roomid id.RoomID
|
||||
accessToken string
|
||||
userId id.UserID
|
||||
type MatrixStruct struct {
|
||||
Homeserver string `yaml:"homeserver"`
|
||||
Roomid id.RoomID `yaml:"room-id"`
|
||||
AccessToken string `yaml:"access-token"`
|
||||
UserId id.UserID `yaml:"user-id"`
|
||||
}
|
||||
|
||||
type mailConfig struct {
|
||||
senderaddress string
|
||||
host string
|
||||
to []string
|
||||
username string
|
||||
password string
|
||||
port string
|
||||
}
|
||||
|
||||
func SetupCommandsNotifiers(backyConfig ConfigFile, ids ...string) {
|
||||
|
||||
type MailConfig struct {
|
||||
Host string `yaml:"host"`
|
||||
Port string `yaml:"port"`
|
||||
Username string `yaml:"username"`
|
||||
SenderAddress string `yaml:"senderaddress"`
|
||||
To []string `yaml:"to"`
|
||||
Password string `yaml:"password"`
|
||||
}
|
||||
|
||||
// SetupNotify sets up notify instances for each command list.
|
||||
func (opts *ConfigOpts) SetupNotify() {
|
||||
|
||||
func (backyConfig *ConfigFile) SetupNotify() {
|
||||
// check if we have individual commands instead of lists to execute
|
||||
if len(opts.executeCmds) != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for _, cmdConfig := range backyConfig.CmdConfigLists {
|
||||
for confName, cmdConfig := range opts.CmdConfigLists {
|
||||
var services []notify.Notifier
|
||||
for notifyID := range backyConfig.Notifications {
|
||||
if contains(cmdConfig.Notifications, notifyID) {
|
||||
for _, id := range cmdConfig.Notifications {
|
||||
if !strings.Contains(id, ".") {
|
||||
opts.Logger.Info().Str("id", id).Str("list", cmdConfig.Name).Msg("key does not contain a \".\" Make sure to follow the docs: https://backy.cybershell.xyz/config/notifications/")
|
||||
logging.ExitWithMSG(fmt.Sprintf("notification id %s in cmd list %s does not contain a \".\" \nMake sure to follow the docs: https://backy.cybershell.xyz/config/notifications/", id, cmdConfig.Name), 1, &opts.Logger)
|
||||
}
|
||||
|
||||
if backyConfig.Notifications[notifyID].Enabled {
|
||||
config := backyConfig.Notifications[notifyID].Config
|
||||
switch config.GetString("type") {
|
||||
case "matrix":
|
||||
mtrx := matrixStruct{
|
||||
userId: id.UserID(config.GetString("user-id")),
|
||||
roomid: id.RoomID(config.GetString("room-id")),
|
||||
accessToken: config.GetString("access-token"),
|
||||
homeserver: config.GetString("homeserver"),
|
||||
}
|
||||
mtrxClient, _ := setupMatrix(mtrx)
|
||||
services = append(services, mtrxClient)
|
||||
case "mail":
|
||||
mailCfg := mailConfig{
|
||||
senderaddress: config.GetString("senderaddress"),
|
||||
password: config.GetString("password"),
|
||||
username: config.GetString("username"),
|
||||
to: config.GetStringSlice("to"),
|
||||
host: config.GetString("host"),
|
||||
port: fmt.Sprint(config.GetUint16("port")),
|
||||
}
|
||||
mailClient := setupMail(mailCfg)
|
||||
services = append(services, mailClient)
|
||||
}
|
||||
confSplit := strings.Split(id, ".")
|
||||
confType := confSplit[0]
|
||||
confId := confSplit[1]
|
||||
switch confType {
|
||||
|
||||
case "mail":
|
||||
conf, ok := opts.NotificationConf.MailConfig[confId]
|
||||
if !ok {
|
||||
opts.Logger.Info().Err(fmt.Errorf("error: ID %s not found in mail object", confId)).Str("list", confName).Send()
|
||||
continue
|
||||
}
|
||||
mailConf := setupMail(conf)
|
||||
services = append(services, mailConf)
|
||||
case "matrix":
|
||||
conf, ok := opts.NotificationConf.MatrixConfig[confId]
|
||||
if !ok {
|
||||
opts.Logger.Info().Err(fmt.Errorf("error: ID %s not found in matrix object", confId)).Str("list", confName).Send()
|
||||
continue
|
||||
}
|
||||
mtrxConf, mtrxErr := setupMatrix(conf)
|
||||
if mtrxErr != nil {
|
||||
opts.Logger.Info().Str("list", confName).Err(fmt.Errorf("error: configuring matrix id %s failed during setup: %w", id, mtrxErr))
|
||||
continue
|
||||
}
|
||||
// append the services
|
||||
services = append(services, mtrxConf)
|
||||
// service is not recognized
|
||||
default:
|
||||
opts.Logger.Info().Err(fmt.Errorf("id %s not found", id)).Str("list", confName).Send()
|
||||
}
|
||||
}
|
||||
cmdConfig.NotifyConfig = notify.NewWithServices(services...)
|
||||
@ -74,19 +83,18 @@ func (backyConfig *ConfigFile) SetupNotify() {
|
||||
// logging.ExitWithMSG("This was a test of notifications", 0, nil)
|
||||
}
|
||||
|
||||
func setupMatrix(config matrixStruct) (*matrix.Matrix, error) {
|
||||
matrixClient, matrixErr := matrix.New(config.userId, config.roomid, config.homeserver, config.accessToken)
|
||||
func setupMatrix(config MatrixStruct) (*matrix.Matrix, error) {
|
||||
matrixClient, matrixErr := matrix.New(config.UserId, config.Roomid, config.Homeserver, config.AccessToken)
|
||||
if matrixErr != nil {
|
||||
panic(matrixErr)
|
||||
return nil, matrixErr
|
||||
}
|
||||
return matrixClient, nil
|
||||
|
||||
}
|
||||
|
||||
func setupMail(config mailConfig) *mail.Mail {
|
||||
mailClient := mail.New(config.senderaddress, config.host+":"+config.port)
|
||||
mailClient.AuthenticateSMTP("", config.username, config.password, config.host)
|
||||
mailClient.AddReceivers(config.to...)
|
||||
func setupMail(config MailConfig) *mail.Mail {
|
||||
mailClient := mail.New(config.SenderAddress, config.Host+":"+config.Port)
|
||||
mailClient.AuthenticateSMTP("", config.Username, config.Password, config.Host)
|
||||
mailClient.AddReceivers(config.To...)
|
||||
mailClient.BodyFormat(mail.PlainText)
|
||||
return mailClient
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ var TS = strings.TrimSpace
|
||||
// It returns an ssh.Client used to run commands against.
|
||||
// If configFile is empty, any required configuration is looked up in the default config files
|
||||
// If any value is not found, defaults are used
|
||||
func (remoteConfig *Host) ConnectToSSHHost(opts *ConfigOpts, config *ConfigFile) error {
|
||||
func (remoteConfig *Host) ConnectToSSHHost(opts *ConfigOpts) error {
|
||||
|
||||
// var sshClient *ssh.Client
|
||||
var connectErr error
|
||||
@ -47,6 +47,11 @@ func (remoteConfig *Host) ConnectToSSHHost(opts *ConfigOpts, config *ConfigFile)
|
||||
var configFile *os.File
|
||||
var sshConfigFileOpenErr error
|
||||
if !remoteConfig.useDefaultConfig {
|
||||
var err error
|
||||
remoteConfig.ConfigFilePath, err = resolveDir(remoteConfig.ConfigFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configFile, sshConfigFileOpenErr = os.Open(remoteConfig.ConfigFilePath)
|
||||
if sshConfigFileOpenErr != nil {
|
||||
return sshConfigFileOpenErr
|
||||
@ -66,14 +71,14 @@ func (remoteConfig *Host) ConnectToSSHHost(opts *ConfigOpts, config *ConfigFile)
|
||||
return decodeErr
|
||||
}
|
||||
|
||||
err := remoteConfig.GetProxyJumpFromConfig(config.Hosts)
|
||||
err := remoteConfig.GetProxyJumpFromConfig(opts.Hosts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if remoteConfig.ProxyHost != nil {
|
||||
for _, proxyHost := range remoteConfig.ProxyHost {
|
||||
err := proxyHost.GetProxyJumpConfig(config.Hosts, opts)
|
||||
opts.ConfigFile.Logger.Info().Msgf("Proxy host: %s", proxyHost.Host)
|
||||
err := proxyHost.GetProxyJumpConfig(opts.Hosts, opts)
|
||||
opts.Logger.Info().Msgf("Proxy host: %s", proxyHost.Host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -101,24 +106,24 @@ func (remoteConfig *Host) ConnectToSSHHost(opts *ConfigOpts, config *ConfigFile)
|
||||
return errors.Wrap(err, "could not create hostkeycallback function")
|
||||
}
|
||||
remoteConfig.ClientConfig.HostKeyCallback = hostKeyCallback
|
||||
opts.ConfigFile.Logger.Info().Str("user", remoteConfig.ClientConfig.User).Send()
|
||||
opts.Logger.Info().Str("user", remoteConfig.ClientConfig.User).Send()
|
||||
|
||||
remoteConfig.SshClient, connectErr = remoteConfig.ConnectThroughBastion(opts.ConfigFile.Logger)
|
||||
remoteConfig.SshClient, connectErr = remoteConfig.ConnectThroughBastion(opts.Logger)
|
||||
if connectErr != nil {
|
||||
return connectErr
|
||||
}
|
||||
if remoteConfig.SshClient != nil {
|
||||
config.Hosts[remoteConfig.Host] = remoteConfig
|
||||
opts.Hosts[remoteConfig.Host] = remoteConfig
|
||||
return nil
|
||||
}
|
||||
|
||||
opts.ConfigFile.Logger.Info().Msgf("Connecting to host %s", remoteConfig.HostName)
|
||||
opts.Logger.Info().Msgf("Connecting to host %s", remoteConfig.HostName)
|
||||
remoteConfig.SshClient, connectErr = ssh.Dial("tcp", remoteConfig.HostName, remoteConfig.ClientConfig)
|
||||
if connectErr != nil {
|
||||
return connectErr
|
||||
}
|
||||
|
||||
config.Hosts[remoteConfig.Host] = remoteConfig
|
||||
opts.Hosts[remoteConfig.Host] = remoteConfig
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -148,7 +153,7 @@ func (remoteHost *Host) GetAuthMethods(opts *ConfigOpts) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remoteHost.PrivateKeyPassword, err = GetPrivateKeyPassword(remoteHost.PrivateKeyPassword, opts, opts.ConfigFile.Logger)
|
||||
remoteHost.PrivateKeyPassword, err = GetPrivateKeyPassword(remoteHost.PrivateKeyPassword, opts, opts.Logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -167,7 +172,7 @@ func (remoteHost *Host) GetAuthMethods(opts *ConfigOpts) error {
|
||||
}
|
||||
}
|
||||
if remoteHost.Password == "" {
|
||||
remoteHost.Password, err = GetPassword(remoteHost.Password, opts, opts.ConfigFile.Logger)
|
||||
remoteHost.Password, err = GetPassword(remoteHost.Password, opts, opts.Logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -297,7 +302,7 @@ func GetPrivateKeyPassword(key string, opts *ConfigOpts, log zerolog.Logger) (st
|
||||
} else {
|
||||
prKeyPassword = key
|
||||
}
|
||||
prKeyPassword = GetVaultKey(prKeyPassword, opts, opts.ConfigFile.Logger)
|
||||
prKeyPassword = GetVaultKey(prKeyPassword, opts, opts.Logger)
|
||||
return prKeyPassword, nil
|
||||
}
|
||||
|
||||
@ -328,7 +333,7 @@ func GetPassword(pass string, opts *ConfigOpts, log zerolog.Logger) (string, err
|
||||
} else {
|
||||
password = pass
|
||||
}
|
||||
password = GetVaultKey(password, opts, opts.ConfigFile.Logger)
|
||||
password = GetVaultKey(password, opts, opts.Logger)
|
||||
|
||||
return password, nil
|
||||
}
|
||||
|
@ -6,9 +6,9 @@ import (
|
||||
|
||||
vaultapi "github.com/hashicorp/vault/api"
|
||||
"github.com/kevinburke/ssh_config"
|
||||
"github.com/knadh/koanf/v2"
|
||||
"github.com/nikoksr/notify"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/spf13/viper"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"golang.org/x/crypto/ssh"
|
||||
@ -37,7 +37,7 @@ type (
|
||||
// Host defines a host to which to connect.
|
||||
// If not provided, the values will be looked up in the default ssh config files
|
||||
Host struct {
|
||||
ConfigFilePath string `yaml:"configfilepath,omitempty"`
|
||||
ConfigFilePath string `yaml:"config,omitempty"`
|
||||
Host string `yaml:"host,omitempty"`
|
||||
HostName string `yaml:"hostname,omitempty"`
|
||||
KnownHostsFile string `yaml:"knownhostsfile,omitempty"`
|
||||
@ -113,35 +113,26 @@ type (
|
||||
Notifications []string `yaml:"notifications,omitempty"`
|
||||
GetOutput bool `yaml:"getOutput,omitempty"`
|
||||
NotifyConfig *notify.Notify
|
||||
// NotificationsConfig map[string]*NotificationsConfig
|
||||
// NotifyConfig map[string]*notify.Notify
|
||||
}
|
||||
|
||||
ConfigFile struct {
|
||||
|
||||
ConfigOpts struct {
|
||||
// Cmds holds the commands for a list.
|
||||
// Key is the name of the command,
|
||||
Cmds map[string]*Command `yaml:"commands"`
|
||||
|
||||
// CmdConfigLists holds the lists of commands to be run in order.
|
||||
// Key is the command list name.
|
||||
CmdConfigLists map[string]*CmdList `yaml:"cmd-configs"`
|
||||
CmdConfigLists map[string]*CmdList `yaml:"cmd-lists"`
|
||||
|
||||
// Hosts holds the Host config.
|
||||
// key is the host.
|
||||
Hosts map[string]*Host `yaml:"hosts"`
|
||||
|
||||
// Notifications holds the config for different notifications.
|
||||
Notifications map[string]*NotificationsConfig
|
||||
|
||||
Logger zerolog.Logger
|
||||
}
|
||||
|
||||
ConfigOpts struct {
|
||||
// Global log level
|
||||
BackyLogLvl *string
|
||||
// Holds config file
|
||||
ConfigFile *ConfigFile
|
||||
|
||||
// Holds config file
|
||||
ConfigFilePath string
|
||||
|
||||
@ -160,9 +151,13 @@ type (
|
||||
|
||||
vaultClient *vaultapi.Client
|
||||
|
||||
List ListConfig
|
||||
|
||||
VaultKeys []*VaultKey `yaml:"keys"`
|
||||
|
||||
viper *viper.Viper
|
||||
koanf *koanf.Koanf
|
||||
|
||||
NotificationConf *Notifications `yaml:"notifications"`
|
||||
}
|
||||
|
||||
outStruct struct {
|
||||
@ -185,9 +180,9 @@ type (
|
||||
Keys []*VaultKey `yaml:"keys"`
|
||||
}
|
||||
|
||||
NotificationsConfig struct {
|
||||
Config *viper.Viper
|
||||
Enabled bool
|
||||
Notifications struct {
|
||||
MailConfig map[string]MailConfig `yaml:"mail,omitempty"`
|
||||
MatrixConfig map[string]MatrixStruct `yaml:"matrix,omitempty"`
|
||||
}
|
||||
|
||||
CmdOutput struct {
|
||||
@ -204,4 +199,10 @@ type (
|
||||
success *template.Template
|
||||
err *template.Template
|
||||
}
|
||||
|
||||
ListConfig struct {
|
||||
Lists []string
|
||||
Commands []string
|
||||
Hosts []string
|
||||
}
|
||||
)
|
||||
|
@ -15,12 +15,65 @@ import (
|
||||
|
||||
"git.andrewnw.xyz/CyberShell/backy/pkg/logging"
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/knadh/koanf/v2"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"mvdan.cc/sh/v3/shell"
|
||||
)
|
||||
|
||||
func (c *ConfigOpts) LogLvl(level string) BackyOptionFunc {
|
||||
|
||||
return func(bco *ConfigOpts) {
|
||||
c.BackyLogLvl = &level
|
||||
}
|
||||
}
|
||||
|
||||
// AddCommands adds commands to ConfigOpts
|
||||
func AddCommands(commands []string) BackyOptionFunc {
|
||||
return func(bco *ConfigOpts) {
|
||||
bco.executeCmds = append(bco.executeCmds, commands...)
|
||||
}
|
||||
}
|
||||
|
||||
// AddCommandLists adds lists to ConfigOpts
|
||||
func AddCommandLists(lists []string) BackyOptionFunc {
|
||||
return func(bco *ConfigOpts) {
|
||||
bco.executeLists = append(bco.executeLists, lists...)
|
||||
}
|
||||
}
|
||||
|
||||
// AddPrintLists adds lists to print out
|
||||
func SetListsToSearch(lists []string) BackyOptionFunc {
|
||||
return func(bco *ConfigOpts) {
|
||||
bco.List.Lists = append(bco.List.Lists, lists...)
|
||||
}
|
||||
}
|
||||
|
||||
// AddPrintLists adds lists to print out
|
||||
func SetCmdsToSearch(cmds []string) BackyOptionFunc {
|
||||
return func(bco *ConfigOpts) {
|
||||
bco.List.Commands = append(bco.List.Commands, cmds...)
|
||||
}
|
||||
}
|
||||
|
||||
// UseCron enables the execution of command lists at specified times
|
||||
func UseCron() BackyOptionFunc {
|
||||
return func(bco *ConfigOpts) {
|
||||
bco.useCron = true
|
||||
}
|
||||
}
|
||||
|
||||
func NewOpts(configFilePath string, opts ...BackyOptionFunc) *ConfigOpts {
|
||||
b := &ConfigOpts{}
|
||||
b.ConfigFilePath = configFilePath
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
opt(b)
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func injectEnvIntoSSH(envVarsToInject environmentVars, process *ssh.Session, opts *ConfigOpts, log zerolog.Logger) {
|
||||
if envVarsToInject.file != "" {
|
||||
envPath, envPathErr := resolveDir(envVarsToInject.file)
|
||||
@ -94,12 +147,12 @@ func contains(s []string, e string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func CheckConfigValues(config *viper.Viper) {
|
||||
func CheckConfigValues(config *koanf.Koanf, file string) {
|
||||
|
||||
for _, key := range requiredKeys {
|
||||
isKeySet := config.IsSet(key)
|
||||
isKeySet := config.Exists(key)
|
||||
if !isKeySet {
|
||||
logging.ExitWithMSG(Sprintf("Config key %s is not defined in %s. Please make sure this value is set and has the appropriate keys set.", key, config.ConfigFileUsed()), 1, nil)
|
||||
logging.ExitWithMSG(Sprintf("Config key %s is not defined in %s. Please make sure this value is set and has the appropriate keys set.", key, file), 1, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,64 +169,6 @@ func testFile(c string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConfigOpts) LogLvl(level string) BackyOptionFunc {
|
||||
|
||||
return func(bco *ConfigOpts) {
|
||||
c.BackyLogLvl = &level
|
||||
}
|
||||
}
|
||||
|
||||
// AddCommands adds commands to ConfigOpts
|
||||
func AddCommands(commands []string) BackyOptionFunc {
|
||||
return func(bco *ConfigOpts) {
|
||||
bco.executeCmds = append(bco.executeCmds, commands...)
|
||||
}
|
||||
}
|
||||
|
||||
// AddCommandLists adds lists to ConfigOpts
|
||||
func AddCommandLists(lists []string) BackyOptionFunc {
|
||||
return func(bco *ConfigOpts) {
|
||||
bco.executeLists = append(bco.executeLists, lists...)
|
||||
}
|
||||
}
|
||||
|
||||
// UseCron enables the execution of command lists at specified times
|
||||
func UseCron() BackyOptionFunc {
|
||||
return func(bco *ConfigOpts) {
|
||||
bco.useCron = true
|
||||
}
|
||||
}
|
||||
|
||||
// UseCron enables the execution of command lists at specified times
|
||||
func (c *ConfigOpts) AddViper(v *viper.Viper) BackyOptionFunc {
|
||||
return func(bco *ConfigOpts) {
|
||||
c.viper = v
|
||||
}
|
||||
}
|
||||
|
||||
func NewOpts(configFilePath string, opts ...BackyOptionFunc) *ConfigOpts {
|
||||
b := &ConfigOpts{}
|
||||
b.ConfigFilePath = configFilePath
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
opt(b)
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
/*
|
||||
NewConfig initializes new config that holds information from the config file
|
||||
*/
|
||||
func NewConfig() *ConfigFile {
|
||||
return &ConfigFile{
|
||||
Cmds: make(map[string]*Command),
|
||||
CmdConfigLists: make(map[string]*CmdList),
|
||||
Hosts: make(map[string]*Host),
|
||||
Notifications: make(map[string]*NotificationsConfig),
|
||||
}
|
||||
}
|
||||
|
||||
func IsTerminalActive() bool {
|
||||
return os.Getenv("BACKY_TERM") == "enabled"
|
||||
}
|
||||
@ -203,7 +198,7 @@ func resolveDir(path string) (string, error) {
|
||||
}
|
||||
|
||||
func (opts *ConfigOpts) loadEnv() {
|
||||
envFileInConfigDir := fmt.Sprintf("%s/.env", path.Dir(opts.viper.ConfigFileUsed()))
|
||||
envFileInConfigDir := fmt.Sprintf("%s/.env", path.Dir(opts.ConfigFilePath))
|
||||
var backyEnv map[string]string
|
||||
backyEnv, envFileErr := godotenv.Read(envFileInConfigDir)
|
||||
if envFileErr != nil {
|
||||
|
Reference in New Issue
Block a user