Compare commits
7 Commits
feacb83274
...
5fe0629b0f
Author | SHA1 | Date | |
---|---|---|---|
5fe0629b0f | |||
7d6acd77b5 | |||
9d646297c7 | |||
bf8d261cf3 | |||
686cd0019a | |||
b7b002bd72 | |||
b8a63f39f5 |
@ -1,3 +1,3 @@
|
|||||||
kind: Added
|
kind: Added
|
||||||
body: Lists config can now go in a file. See docs for more information.
|
body: Lists can now go in a file. See docs for more information.
|
||||||
time: 2024-08-28T14:27:30.427754114-05:00
|
time: 2024-08-28T14:27:30.427754114-05:00
|
||||||
|
3
.changes/unreleased/Added-20241114-210148.yaml
Normal file
3
.changes/unreleased/Added-20241114-210148.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
kind: Added
|
||||||
|
body: Hooks for Commands.[name]. Error, success, and final. [#12]
|
||||||
|
time: 2024-11-14T21:01:48.823426401-06:00
|
3
.changes/unreleased/Fixed-20241114-211306.yaml
Normal file
3
.changes/unreleased/Fixed-20241114-211306.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
kind: Fixed
|
||||||
|
body: make command logger be used for errors, not just when running the command
|
||||||
|
time: 2024-11-14T21:13:06.404134926-06:00
|
@ -7,4 +7,4 @@ steps:
|
|||||||
release:
|
release:
|
||||||
image: golangci/golangci-lint:v1.53.3
|
image: golangci/golangci-lint:v1.53.3
|
||||||
commands:
|
commands:
|
||||||
- golangci-lint run -v
|
- golangci-lint run -v --timeout 5m
|
@ -20,7 +20,7 @@ package cmd
|
|||||||
|
|
||||||
// func config(cmd *cobra.Command, args []string) {
|
// func config(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
// opts := backy.NewOpts(cfgFile, backy.UseCron())
|
// opts := backy.NewOpts(cfgFile, backy.cronEnabled())
|
||||||
// opts.InitConfig()
|
// opts.InitConfig()
|
||||||
|
|
||||||
// }
|
// }
|
||||||
|
@ -17,7 +17,7 @@ var (
|
|||||||
|
|
||||||
func cron(cmd *cobra.Command, args []string) {
|
func cron(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
opts := backy.NewOpts(cfgFile, backy.UseCron())
|
opts := backy.NewOpts(cfgFile, backy.CronEnabled())
|
||||||
opts.InitConfig()
|
opts.InitConfig()
|
||||||
backy.ReadConfig(opts)
|
backy.ReadConfig(opts)
|
||||||
opts.Cron()
|
opts.Cron()
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
const versionStr = "0.4.0"
|
const versionStr = "0.5.0"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
versionCmd = &cobra.Command{
|
versionCmd = &cobra.Command{
|
||||||
|
@ -9,6 +9,11 @@ Command lists are for executing commands in sequence and getting notifications f
|
|||||||
|
|
||||||
The top-level object key can be anything you want but not the same as another.
|
The top-level object key can be anything you want but not the same as another.
|
||||||
|
|
||||||
|
Lists can go in a separate file. Command lists should be in a separate file if:
|
||||||
|
|
||||||
|
1. key 'cmd-lists.file' is found
|
||||||
|
2. hosts.yml or hosts.yaml is found in the same directory as the backy config file
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
test2:
|
test2:
|
||||||
name: test2
|
name: test2
|
||||||
@ -51,7 +56,7 @@ An array of notification IDs to use on success and failure. Must match any of th
|
|||||||
|
|
||||||
### Name
|
### Name
|
||||||
|
|
||||||
Name is optional for logging. If name is not defined, name will be the object's map key.
|
Name is optional. If name is not defined, name will be the object's map key.
|
||||||
|
|
||||||
### Cron mode
|
### Cron mode
|
||||||
|
|
||||||
|
@ -19,7 +19,14 @@ commands:
|
|||||||
- down
|
- down
|
||||||
# if host is not defined, command will be run locally
|
# if host is not defined, command will be run locally
|
||||||
# The host has to be defined in either the config file or the SSH Config files
|
# The host has to be defined in either the config file or the SSH Config files
|
||||||
host: some-host
|
host: some-host
|
||||||
|
hooks
|
||||||
|
error:
|
||||||
|
- some-other-command-when-failing
|
||||||
|
success:
|
||||||
|
- success-command
|
||||||
|
final:
|
||||||
|
- final-command
|
||||||
backup-docker-container-script:
|
backup-docker-container-script:
|
||||||
cmd: /path/to/local/script
|
cmd: /path/to/local/script
|
||||||
# script file is input as stdin to SSH
|
# script file is input as stdin to SSH
|
||||||
@ -41,6 +48,7 @@ Values available for this section:
|
|||||||
| `host` | If not specified, the command will execute locally. | `string` | no |
|
| `host` | If not specified, the command will execute locally. | `string` | no |
|
||||||
| `scriptEnvFile` | When type is `scriptFile`, the script is appended to this file. | `string` | no |
|
| `scriptEnvFile` | When type is `scriptFile`, the script is appended to this file. | `string` | no |
|
||||||
| `shell` | Only applicable when host is not specified | `string` | no |
|
| `shell` | Only applicable when host is not specified | `string` | no |
|
||||||
|
| `hooks` | Hooks are used at the end of the individual command. Must be another command. | `[]string` | no |
|
||||||
|
|
||||||
#### cmd
|
#### cmd
|
||||||
|
|
||||||
@ -93,9 +101,9 @@ Make sure to escape any shell input.
|
|||||||
|
|
||||||
Path to a file.
|
Path to a file.
|
||||||
|
|
||||||
When type is `scriptFile`, the script is appended to this file.
|
When type is specified, the script is appended to this file.
|
||||||
|
|
||||||
This is useful for specifiing environment variables or other things so they don't have to be included in the script.
|
This is useful for specifying environment variables or other things so they don't have to be included in the script.
|
||||||
|
|
||||||
### type
|
### type
|
||||||
|
|
||||||
@ -116,3 +124,23 @@ For now, the variables have to be defined in an `.env` file in the same director
|
|||||||
If using it with host specified, the SSH server has to be configured to accept those env variables.
|
If using it with host specified, the SSH server has to be configured to accept those env variables.
|
||||||
|
|
||||||
If the command is run locally, the OS's environment is added.
|
If the command is run locally, the OS's environment is added.
|
||||||
|
|
||||||
|
### hooks
|
||||||
|
|
||||||
|
Hooks are run after the command is run.
|
||||||
|
|
||||||
|
Errors are run if the command errors, success if it returns no error. Final hooks are run regardless of error condition.
|
||||||
|
|
||||||
|
Values for hooks are as follows:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
command:
|
||||||
|
hook:
|
||||||
|
# these commands are defined elsewhere in the file
|
||||||
|
error:
|
||||||
|
- errcommand
|
||||||
|
success:
|
||||||
|
- successcommand
|
||||||
|
final:
|
||||||
|
- donecommand
|
||||||
|
```
|
@ -30,6 +30,8 @@ var Sprintf = fmt.Sprintf
|
|||||||
// The environment of local commands will be the machine's environment plus any extra
|
// The environment of local commands will be the machine's environment plus any extra
|
||||||
// variables specified in the Env file or Environment.
|
// variables specified in the Env file or Environment.
|
||||||
// Dir can also be specified for local commands.
|
// Dir can also be specified for local commands.
|
||||||
|
//
|
||||||
|
// Returns the output as a slice and an error, if any
|
||||||
func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([]string, error) {
|
func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([]string, error) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -53,9 +55,9 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
|||||||
command.Type = strings.TrimSpace(command.Type)
|
command.Type = strings.TrimSpace(command.Type)
|
||||||
|
|
||||||
if command.Type != "" {
|
if command.Type != "" {
|
||||||
cmdCtxLogger.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.Name, *command.Host)).Send()
|
||||||
} else {
|
} else {
|
||||||
cmdCtxLogger.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 on host %s", command.Name, *command.Host)).Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
if command.RemoteHost.SshClient == nil {
|
if command.RemoteHost.SshClient == nil {
|
||||||
@ -165,7 +167,7 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
|||||||
outScanner := bufio.NewScanner(&cmdOutBuf)
|
outScanner := bufio.NewScanner(&cmdOutBuf)
|
||||||
for outScanner.Scan() {
|
for outScanner.Scan() {
|
||||||
outMap := make(map[string]interface{})
|
outMap := make(map[string]interface{})
|
||||||
outMap["cmd"] = cmd
|
outMap["cmd"] = command.Name
|
||||||
outMap["output"] = outScanner.Text()
|
outMap["output"] = outScanner.Text()
|
||||||
if str, ok := outMap["output"].(string); ok {
|
if str, ok := outMap["output"].(string); ok {
|
||||||
outputArr = append(outputArr, str)
|
outputArr = append(outputArr, str)
|
||||||
@ -178,7 +180,7 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
|||||||
outScanner := bufio.NewScanner(&cmdOutBuf)
|
outScanner := bufio.NewScanner(&cmdOutBuf)
|
||||||
for outScanner.Scan() {
|
for outScanner.Scan() {
|
||||||
outMap := make(map[string]interface{})
|
outMap := make(map[string]interface{})
|
||||||
outMap["cmd"] = cmd
|
outMap["cmd"] = command.Name
|
||||||
outMap["output"] = outScanner.Text()
|
outMap["output"] = outScanner.Text()
|
||||||
if str, ok := outMap["output"].(string); ok {
|
if str, ok := outMap["output"].(string); ok {
|
||||||
outputArr = append(outputArr, str)
|
outputArr = append(outputArr, str)
|
||||||
@ -288,7 +290,7 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
|||||||
outScanner := bufio.NewScanner(&cmdOutBuf)
|
outScanner := bufio.NewScanner(&cmdOutBuf)
|
||||||
for outScanner.Scan() {
|
for outScanner.Scan() {
|
||||||
outMap := make(map[string]interface{})
|
outMap := make(map[string]interface{})
|
||||||
outMap["cmd"] = cmd
|
outMap["cmd"] = command.Name
|
||||||
outMap["output"] = outScanner.Text()
|
outMap["output"] = outScanner.Text()
|
||||||
if str, ok := outMap["output"].(string); ok {
|
if str, ok := outMap["output"].(string); ok {
|
||||||
outputArr = append(outputArr, str)
|
outputArr = append(outputArr, str)
|
||||||
@ -297,14 +299,14 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmdCtxLogger.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.Name, err)).Send()
|
||||||
return outputArr, err
|
return outputArr, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if command.Shell != "" {
|
if command.Shell != "" {
|
||||||
cmdCtxLogger.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 on local machine in %s", command.Name, command.Shell)).Send()
|
||||||
|
|
||||||
ArgsStr = fmt.Sprintf("%s %s", command.Cmd, ArgsStr)
|
ArgsStr = fmt.Sprintf("%s %s", command.Cmd, ArgsStr)
|
||||||
|
|
||||||
@ -330,7 +332,7 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
|||||||
|
|
||||||
for outScanner.Scan() {
|
for outScanner.Scan() {
|
||||||
outMap := make(map[string]interface{})
|
outMap := make(map[string]interface{})
|
||||||
outMap["cmd"] = command.Cmd
|
outMap["cmd"] = command.Name
|
||||||
outMap["output"] = outScanner.Text()
|
outMap["output"] = outScanner.Text()
|
||||||
if str, ok := outMap["output"].(string); ok {
|
if str, ok := outMap["output"].(string); ok {
|
||||||
outputArr = append(outputArr, str)
|
outputArr = append(outputArr, str)
|
||||||
@ -339,13 +341,13 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmdCtxLogger.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.Name, err)).Send()
|
||||||
return outputArr, err
|
return outputArr, err
|
||||||
}
|
}
|
||||||
return outputArr, nil
|
return outputArr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdCtxLogger.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 on local machine", command.Name)).Send()
|
||||||
|
|
||||||
localCMD := exec.Command(command.Cmd, command.Args...)
|
localCMD := exec.Command(command.Cmd, command.Args...)
|
||||||
|
|
||||||
@ -379,7 +381,7 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
|||||||
cmdCtxLogger.Info().Fields(outMap).Send()
|
cmdCtxLogger.Info().Fields(outMap).Send()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmdCtxLogger.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.Name, err)).Send()
|
||||||
return outputArr, err
|
return outputArr, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -388,42 +390,35 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
|||||||
|
|
||||||
// cmdListWorker
|
// cmdListWorker
|
||||||
func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<- string, opts *ConfigOpts) {
|
func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<- string, opts *ConfigOpts) {
|
||||||
|
|
||||||
// iterate over list to run
|
// iterate over list to run
|
||||||
|
res := CmdListResults{}
|
||||||
for list := range jobs {
|
for list := range jobs {
|
||||||
fieldsMap := make(map[string]interface{})
|
fieldsMap := make(map[string]interface{})
|
||||||
fieldsMap["list"] = list.Name
|
fieldsMap["list"] = list.Name
|
||||||
|
var cmdLogger zerolog.Logger
|
||||||
cmdLog := opts.Logger.Info()
|
|
||||||
|
|
||||||
var count int // count of how many commands have been executed
|
var count int // count of how many commands have been executed
|
||||||
var cmdsRan []string // store the commands that have been executed
|
var cmdsRan []string // store the commands that have been executed
|
||||||
var outStructArr []outStruct // stores output messages
|
var outStructArr []outStruct // stores output messages
|
||||||
|
|
||||||
for _, cmd := range list.Order {
|
for _, cmd := range list.Order {
|
||||||
currentCmd := opts.Cmds[cmd].Cmd
|
|
||||||
|
|
||||||
fieldsMap["cmd"] = opts.Cmds[cmd].Cmd
|
currentCmd := opts.Cmds[cmd].Name
|
||||||
|
|
||||||
|
fieldsMap["cmd"] = opts.Cmds[cmd].Name
|
||||||
cmdToRun := opts.Cmds[cmd]
|
cmdToRun := opts.Cmds[cmd]
|
||||||
cmdLog.Fields(fieldsMap).Send()
|
|
||||||
|
|
||||||
cmdLogger := opts.Logger.With().
|
cmdLogger = cmdToRun.generateLogger(opts)
|
||||||
Str("backy-cmd", cmd).Str("Host", "local machine").
|
cmdLogger.Info().Fields(fieldsMap).Send()
|
||||||
Logger()
|
|
||||||
|
|
||||||
if cmdToRun.Host != nil {
|
|
||||||
cmdLogger = opts.Logger.With().
|
|
||||||
Str("backy-cmd", cmd).Str("Host", *cmdToRun.Host).
|
|
||||||
Logger()
|
|
||||||
}
|
|
||||||
|
|
||||||
outputArr, runOutErr := cmdToRun.RunCmd(cmdLogger, opts)
|
outputArr, runOutErr := cmdToRun.RunCmd(cmdLogger, opts)
|
||||||
|
|
||||||
if list.NotifyConfig != nil {
|
if list.NotifyConfig != nil {
|
||||||
|
|
||||||
// check if the command output should be included
|
// check if the command output should be included
|
||||||
if cmdToRun.GetOutput || list.GetOutput {
|
if cmdToRun.GetOutput || list.GetOutput {
|
||||||
outputStruct := outStruct{
|
outputStruct := outStruct{
|
||||||
CmdName: cmd,
|
CmdName: cmdToRun.Name,
|
||||||
CmdExecuted: currentCmd,
|
CmdExecuted: currentCmd,
|
||||||
Output: outputArr,
|
Output: outputArr,
|
||||||
}
|
}
|
||||||
@ -434,6 +429,7 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<-
|
|||||||
}
|
}
|
||||||
count++
|
count++
|
||||||
if runOutErr != nil {
|
if runOutErr != nil {
|
||||||
|
res.ErrCmd = cmd
|
||||||
if list.NotifyConfig != nil {
|
if list.NotifyConfig != nil {
|
||||||
var errMsg bytes.Buffer
|
var errMsg bytes.Buffer
|
||||||
errStruct := make(map[string]interface{})
|
errStruct := make(map[string]interface{})
|
||||||
@ -451,23 +447,24 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<-
|
|||||||
tmpErr := msgTemps.err.Execute(&errMsg, errStruct)
|
tmpErr := msgTemps.err.Execute(&errMsg, errStruct)
|
||||||
|
|
||||||
if tmpErr != nil {
|
if tmpErr != nil {
|
||||||
opts.Logger.Err(tmpErr).Send()
|
cmdLogger.Err(tmpErr).Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
notifySendErr := list.NotifyConfig.Send(context.Background(), fmt.Sprintf("List %s failed", list.Name), errMsg.String())
|
notifySendErr := list.NotifyConfig.Send(context.Background(), fmt.Sprintf("List %s failed", list.Name), errMsg.String())
|
||||||
|
|
||||||
if notifySendErr != nil {
|
if notifySendErr != nil {
|
||||||
opts.Logger.Err(notifySendErr).Send()
|
cmdLogger.Err(notifySendErr).Send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.Logger.Err(runOutErr).Send()
|
cmdLogger.Err(runOutErr).Send()
|
||||||
|
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
cmdsRan = append(cmdsRan, cmd)
|
||||||
|
|
||||||
if count == len(list.Order) {
|
if count == len(list.Order) {
|
||||||
cmdsRan = append(cmdsRan, cmd)
|
|
||||||
var successMsg bytes.Buffer
|
var successMsg bytes.Buffer
|
||||||
|
|
||||||
// if notification config is not nil, and NotifyOnSuccess is true or GetOuput is true,
|
// if notification config is not nil, and NotifyOnSuccess is true or GetOuput is true,
|
||||||
@ -483,23 +480,21 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<-
|
|||||||
tmpErr := msgTemps.success.Execute(&successMsg, successStruct)
|
tmpErr := msgTemps.success.Execute(&successMsg, successStruct)
|
||||||
|
|
||||||
if tmpErr != nil {
|
if tmpErr != nil {
|
||||||
opts.Logger.Err(tmpErr).Send()
|
cmdLogger.Err(tmpErr).Send()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
err := list.NotifyConfig.Send(context.Background(), fmt.Sprintf("List %s succeded", list.Name), successMsg.String())
|
err := list.NotifyConfig.Send(context.Background(), fmt.Sprintf("List %s succeeded", list.Name), successMsg.String())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
opts.Logger.Err(err).Send()
|
cmdLogger.Err(err).Send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
cmdsRan = append(cmdsRan, cmd)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
results <- "done"
|
results <- res.ErrCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -535,7 +530,23 @@ func (opts *ConfigOpts) RunListConfig(cron string) {
|
|||||||
close(listChan)
|
close(listChan)
|
||||||
|
|
||||||
for a := 1; a <= configListsLen; a++ {
|
for a := 1; a <= configListsLen; a++ {
|
||||||
<-results
|
l := <-results
|
||||||
|
|
||||||
|
opts.Logger.Debug().Msg(l)
|
||||||
|
|
||||||
|
if l != "" {
|
||||||
|
// execute error hooks
|
||||||
|
opts.Logger.Debug().Msg("hooks are working")
|
||||||
|
opts.Cmds[l].ExecuteHooks("error", opts)
|
||||||
|
} else {
|
||||||
|
// execute success hooks
|
||||||
|
opts.Cmds[l].ExecuteHooks("success", opts)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute final hooks
|
||||||
|
opts.Cmds[l].ExecuteHooks("final", opts)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.closeHostConnections()
|
opts.closeHostConnections()
|
||||||
@ -544,13 +555,18 @@ func (opts *ConfigOpts) RunListConfig(cron string) {
|
|||||||
func (config *ConfigOpts) ExecuteCmds(opts *ConfigOpts) {
|
func (config *ConfigOpts) ExecuteCmds(opts *ConfigOpts) {
|
||||||
for _, cmd := range opts.executeCmds {
|
for _, cmd := range opts.executeCmds {
|
||||||
cmdToRun := opts.Cmds[cmd]
|
cmdToRun := opts.Cmds[cmd]
|
||||||
cmdLogger := opts.Logger.With().
|
cmdLogger := cmdToRun.generateLogger(opts)
|
||||||
Str("backy-cmd", cmd).
|
|
||||||
Logger()
|
|
||||||
_, runErr := cmdToRun.RunCmd(cmdLogger, opts)
|
_, runErr := cmdToRun.RunCmd(cmdLogger, opts)
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
opts.Logger.Err(runErr).Send()
|
opts.Logger.Err(runErr).Send()
|
||||||
|
|
||||||
|
cmdToRun.ExecuteHooks("error", opts)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
cmdToRun.ExecuteHooks("success", opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmdToRun.ExecuteHooks("final", opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.closeHostConnections()
|
opts.closeHostConnections()
|
||||||
@ -593,3 +609,50 @@ func (c *ConfigOpts) closeHostConnections() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cmd *Command) ExecuteHooks(hookType string, opts *ConfigOpts) {
|
||||||
|
if cmd.Hooks == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch hookType {
|
||||||
|
case "error":
|
||||||
|
for _, v := range cmd.Hooks.Error {
|
||||||
|
errCmd := opts.Cmds[v]
|
||||||
|
cmdLogger := opts.Logger.With().
|
||||||
|
Str("backy-cmd", v).
|
||||||
|
Logger()
|
||||||
|
errCmd.RunCmd(cmdLogger, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
case "success":
|
||||||
|
for _, v := range cmd.Hooks.Success {
|
||||||
|
successCmd := opts.Cmds[v]
|
||||||
|
cmdLogger := opts.Logger.With().
|
||||||
|
Str("backy-cmd", v).
|
||||||
|
Logger()
|
||||||
|
successCmd.RunCmd(cmdLogger, opts)
|
||||||
|
}
|
||||||
|
case "final":
|
||||||
|
for _, v := range cmd.Hooks.Final {
|
||||||
|
finalCmd := opts.Cmds[v]
|
||||||
|
cmdLogger := opts.Logger.With().
|
||||||
|
Str("backy-cmd", v).
|
||||||
|
Logger()
|
||||||
|
finalCmd.RunCmd(cmdLogger, opts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *Command) generateLogger(opts *ConfigOpts) zerolog.Logger {
|
||||||
|
cmdLogger := opts.Logger.With().
|
||||||
|
Str("backy-cmd", cmd.Name).Str("Host", "local machine").
|
||||||
|
Logger()
|
||||||
|
|
||||||
|
if cmd.Host != nil {
|
||||||
|
cmdLogger = opts.Logger.With().
|
||||||
|
Str("backy-cmd", cmd.Name).Str("Host", *cmd.Host).
|
||||||
|
Logger()
|
||||||
|
|
||||||
|
}
|
||||||
|
return cmdLogger
|
||||||
|
}
|
||||||
|
@ -245,6 +245,7 @@ func ReadConfig(opts *ConfigOpts) *ConfigOpts {
|
|||||||
|
|
||||||
cmdListFilePath := path.Clean(opts.CmdListFile)
|
cmdListFilePath := path.Clean(opts.CmdListFile)
|
||||||
|
|
||||||
|
// if path is not absolute, check config directory
|
||||||
if !strings.HasPrefix(cmdListFilePath, "/") {
|
if !strings.HasPrefix(cmdListFilePath, "/") {
|
||||||
opts.CmdListFile = path.Join(backyConfigFileDir, cmdListFilePath)
|
opts.CmdListFile = path.Join(backyConfigFileDir, cmdListFilePath)
|
||||||
}
|
}
|
||||||
@ -259,7 +260,7 @@ func ReadConfig(opts *ConfigOpts) *ConfigOpts {
|
|||||||
logging.ExitWithMSG(fmt.Sprintf("error loading config: %v", err), 1, &opts.Logger)
|
logging.ExitWithMSG(fmt.Sprintf("error loading config: %v", err), 1, &opts.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Str("lists config file", opts.CmdListFile).Send()
|
log.Info().Str("using lists config file", opts.CmdListFile).Send()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,7 +270,7 @@ func ReadConfig(opts *ConfigOpts) *ConfigOpts {
|
|||||||
|
|
||||||
var cmdNotFoundSliceErr []error
|
var cmdNotFoundSliceErr []error
|
||||||
for cmdListName, cmdList := range opts.CmdConfigLists {
|
for cmdListName, cmdList := range opts.CmdConfigLists {
|
||||||
if opts.useCron {
|
if opts.cronEnabled {
|
||||||
cron := strings.TrimSpace(cmdList.Cron)
|
cron := strings.TrimSpace(cmdList.Cron)
|
||||||
if cron == "" {
|
if cron == "" {
|
||||||
delete(opts.CmdConfigLists, cmdListName)
|
delete(opts.CmdConfigLists, cmdListName)
|
||||||
@ -291,14 +292,13 @@ func ReadConfig(opts *ConfigOpts) *ConfigOpts {
|
|||||||
cmdNotFoundErrorLog.Errs("commands not found", cmdNotFoundSliceErr).Send()
|
cmdNotFoundErrorLog.Errs("commands not found", cmdNotFoundSliceErr).Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.useCron && (len(opts.CmdConfigLists) == 0) {
|
if opts.cronEnabled && (len(opts.CmdConfigLists) == 0) {
|
||||||
logging.ExitWithMSG("No cron fields detected in any command lists", 1, nil)
|
logging.ExitWithMSG("No cron fields detected in any command lists", 1, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
for c := range opts.Cmds {
|
// process commands
|
||||||
if opts.executeCmds != nil && !contains(opts.executeCmds, c) {
|
if err := processCmds(opts); err != nil {
|
||||||
delete(opts.Cmds, c)
|
logging.ExitWithMSG(err.Error(), 1, &opts.Logger)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(opts.executeLists) > 0 {
|
if len(opts.executeLists) > 0 {
|
||||||
@ -317,23 +317,8 @@ func ReadConfig(opts *ConfigOpts) *ConfigOpts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cmd := range opts.Cmds {
|
|
||||||
if cmd.Host != nil {
|
|
||||||
host, hostFound := opts.Hosts[*cmd.Host]
|
|
||||||
if hostFound {
|
|
||||||
cmd.RemoteHost = host
|
|
||||||
cmd.RemoteHost.Host = host.Host
|
|
||||||
if host.HostName != "" {
|
|
||||||
cmd.RemoteHost.HostName = host.HostName
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
opts.Hosts[*cmd.Host] = &Host{Host: *cmd.Host}
|
|
||||||
cmd.RemoteHost = &Host{Host: *cmd.Host}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
opts.SetupNotify()
|
opts.SetupNotify()
|
||||||
|
|
||||||
if err := opts.setupVault(); err != nil {
|
if err := opts.setupVault(); err != nil {
|
||||||
log.Err(err).Send()
|
log.Err(err).Send()
|
||||||
}
|
}
|
||||||
@ -460,3 +445,88 @@ func GetVaultKey(str string, opts *ConfigOpts, log zerolog.Logger) string {
|
|||||||
}
|
}
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func processCmds(opts *ConfigOpts) error {
|
||||||
|
// process commands
|
||||||
|
for cmdName, cmd := range opts.Cmds {
|
||||||
|
|
||||||
|
if cmd.Name == "" {
|
||||||
|
cmd.Name = cmdName
|
||||||
|
}
|
||||||
|
// println("Cmd.Name = " + cmd.Name)
|
||||||
|
hooks := cmd.Hooks
|
||||||
|
// resolve hooks
|
||||||
|
if hooks != nil {
|
||||||
|
|
||||||
|
processHookSuccess := processHooks(cmd, hooks.Error, opts, "error")
|
||||||
|
if processHookSuccess != nil {
|
||||||
|
return processHookSuccess
|
||||||
|
}
|
||||||
|
processHookSuccess = processHooks(cmd, hooks.Success, opts, "success")
|
||||||
|
if processHookSuccess != nil {
|
||||||
|
return processHookSuccess
|
||||||
|
}
|
||||||
|
processHookSuccess = processHooks(cmd, hooks.Final, opts, "final")
|
||||||
|
if processHookSuccess != nil {
|
||||||
|
return processHookSuccess
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve hosts
|
||||||
|
if cmd.Host != nil {
|
||||||
|
host, hostFound := opts.Hosts[*cmd.Host]
|
||||||
|
if hostFound {
|
||||||
|
cmd.RemoteHost = host
|
||||||
|
cmd.RemoteHost.Host = host.Host
|
||||||
|
if host.HostName != "" {
|
||||||
|
cmd.RemoteHost.HostName = host.HostName
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
opts.Hosts[*cmd.Host] = &Host{Host: *cmd.Host}
|
||||||
|
cmd.RemoteHost = &Host{Host: *cmd.Host}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// processHooks evaluates if hooks are valid Commands
|
||||||
|
//
|
||||||
|
// Takes the following arguments:
|
||||||
|
//
|
||||||
|
// 1. a []string of hooks
|
||||||
|
// 2. a map of Commands as arguments
|
||||||
|
// 3. a string hookType, must be the hook type
|
||||||
|
//
|
||||||
|
// The cmds.hookRef is modified in this function.
|
||||||
|
//
|
||||||
|
// Returns the following:
|
||||||
|
//
|
||||||
|
// An error, if any, if the command is not found
|
||||||
|
func processHooks(cmd *Command, hooks []string, opts *ConfigOpts, hookType string) error {
|
||||||
|
|
||||||
|
// initialize hook type
|
||||||
|
var hookCmdFound bool
|
||||||
|
cmd.hookRefs = map[string]map[string]*Command{}
|
||||||
|
cmd.hookRefs[hookType] = map[string]*Command{}
|
||||||
|
|
||||||
|
for _, hook := range hooks {
|
||||||
|
|
||||||
|
var hookCmd *Command
|
||||||
|
// TODO: match by Command.Name
|
||||||
|
|
||||||
|
hookCmd, hookCmdFound = opts.Cmds[hook]
|
||||||
|
|
||||||
|
if !hookCmdFound {
|
||||||
|
return fmt.Errorf("error in command %s hook %s list: command %s not found", cmd.Name, hookType, hook)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.hookRefs[hookType][hook] = hookCmd
|
||||||
|
|
||||||
|
// Recursive, decide if this is good
|
||||||
|
// if hookCmd.hookRefs == nil {
|
||||||
|
// }
|
||||||
|
// hookRef[hookType][h] = hookCmd
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -43,17 +43,24 @@ type (
|
|||||||
}
|
}
|
||||||
|
|
||||||
Command struct {
|
Command struct {
|
||||||
|
Name string `yaml:"name,omitempty"`
|
||||||
|
|
||||||
// command to run
|
// command to run
|
||||||
Cmd string `yaml:"cmd"`
|
Cmd string `yaml:"cmd"`
|
||||||
|
|
||||||
// Possible values: script, scriptFile
|
// Possible values: script, scriptFile
|
||||||
// If blank, it is regualar command.
|
// If blank, it is regular command.
|
||||||
Type string `yaml:"type"`
|
Type string `yaml:"type,omitempty"`
|
||||||
|
|
||||||
// host on which to run cmd
|
// host on which to run cmd
|
||||||
Host *string `yaml:"host,omitempty"`
|
Host *string `yaml:"host,omitempty"`
|
||||||
|
|
||||||
|
// Hooks are for running commands on certain events
|
||||||
|
Hooks *Hooks `yaml:"hooks,omitempty"`
|
||||||
|
|
||||||
|
// hook refs are internal references of commands for each hook type
|
||||||
|
hookRefs map[string]map[string]*Command
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Shell specifies which shell to run the command in, if any.
|
Shell specifies which shell to run the command in, if any.
|
||||||
Not applicable when host is defined.
|
Not applicable when host is defined.
|
||||||
@ -123,7 +130,7 @@ type (
|
|||||||
CmdListFile string
|
CmdListFile string
|
||||||
|
|
||||||
// use command lists using cron
|
// use command lists using cron
|
||||||
useCron bool
|
cronEnabled bool
|
||||||
// Holds commands to execute for the exec command
|
// Holds commands to execute for the exec command
|
||||||
executeCmds []string
|
executeCmds []string
|
||||||
// Holds lists to execute for the backup command
|
// Holds lists to execute for the backup command
|
||||||
@ -188,4 +195,17 @@ type (
|
|||||||
Commands []string
|
Commands []string
|
||||||
Hosts []string
|
Hosts []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Hooks struct {
|
||||||
|
Error []string `yaml:"error,omitempty"`
|
||||||
|
Success []string `yaml:"success,omitempty"`
|
||||||
|
Final []string `yaml:"final,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
CmdListResults struct {
|
||||||
|
// name of the list
|
||||||
|
ListName string
|
||||||
|
// command that caused the list to fail
|
||||||
|
ErrCmd string
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
@ -56,10 +56,10 @@ func SetCmdsToSearch(cmds []string) BackyOptionFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UseCron enables the execution of command lists at specified times
|
// cronEnabled enables the execution of command lists at specified times
|
||||||
func UseCron() BackyOptionFunc {
|
func CronEnabled() BackyOptionFunc {
|
||||||
return func(bco *ConfigOpts) {
|
return func(bco *ConfigOpts) {
|
||||||
bco.useCron = true
|
bco.cronEnabled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user