This commit is contained in:
parent
feacb83274
commit
b8a63f39f5
@ -20,7 +20,7 @@ package cmd
|
||||
|
||||
// func config(cmd *cobra.Command, args []string) {
|
||||
|
||||
// opts := backy.NewOpts(cfgFile, backy.UseCron())
|
||||
// opts := backy.NewOpts(cfgFile, backy.cronEnabled())
|
||||
// opts.InitConfig()
|
||||
|
||||
// }
|
||||
|
@ -17,7 +17,7 @@ var (
|
||||
|
||||
func cron(cmd *cobra.Command, args []string) {
|
||||
|
||||
opts := backy.NewOpts(cfgFile, backy.UseCron())
|
||||
opts := backy.NewOpts(cfgFile, backy.CronEnabled())
|
||||
opts.InitConfig()
|
||||
backy.ReadConfig(opts)
|
||||
opts.Cron()
|
||||
|
@ -30,6 +30,8 @@ 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.
|
||||
//
|
||||
// Returns the output as a slice and an error, if any
|
||||
func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([]string, error) {
|
||||
|
||||
var (
|
||||
@ -53,9 +55,9 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
||||
command.Type = strings.TrimSpace(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 {
|
||||
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 {
|
||||
@ -165,7 +167,7 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
||||
outScanner := bufio.NewScanner(&cmdOutBuf)
|
||||
for outScanner.Scan() {
|
||||
outMap := make(map[string]interface{})
|
||||
outMap["cmd"] = cmd
|
||||
outMap["cmd"] = command.Name
|
||||
outMap["output"] = outScanner.Text()
|
||||
if str, ok := outMap["output"].(string); ok {
|
||||
outputArr = append(outputArr, str)
|
||||
@ -178,7 +180,7 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
||||
outScanner := bufio.NewScanner(&cmdOutBuf)
|
||||
for outScanner.Scan() {
|
||||
outMap := make(map[string]interface{})
|
||||
outMap["cmd"] = cmd
|
||||
outMap["cmd"] = command.Name
|
||||
outMap["output"] = outScanner.Text()
|
||||
if str, ok := outMap["output"].(string); ok {
|
||||
outputArr = append(outputArr, str)
|
||||
@ -288,7 +290,7 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
||||
outScanner := bufio.NewScanner(&cmdOutBuf)
|
||||
for outScanner.Scan() {
|
||||
outMap := make(map[string]interface{})
|
||||
outMap["cmd"] = cmd
|
||||
outMap["cmd"] = command.Name
|
||||
outMap["output"] = outScanner.Text()
|
||||
if str, ok := outMap["output"].(string); ok {
|
||||
outputArr = append(outputArr, str)
|
||||
@ -297,14 +299,14 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
} else {
|
||||
|
||||
var err error
|
||||
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)
|
||||
|
||||
@ -330,7 +332,7 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
||||
|
||||
for outScanner.Scan() {
|
||||
outMap := make(map[string]interface{})
|
||||
outMap["cmd"] = command.Cmd
|
||||
outMap["cmd"] = command.Name
|
||||
outMap["output"] = outScanner.Text()
|
||||
if str, ok := outMap["output"].(string); ok {
|
||||
outputArr = append(outputArr, str)
|
||||
@ -339,13 +341,13 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
||||
}
|
||||
|
||||
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, 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...)
|
||||
|
||||
@ -379,7 +381,7 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
||||
cmdCtxLogger.Info().Fields(outMap).Send()
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -388,9 +390,9 @@ func (command *Command) RunCmd(cmdCtxLogger zerolog.Logger, opts *ConfigOpts) ([
|
||||
|
||||
// cmdListWorker
|
||||
func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<- string, opts *ConfigOpts) {
|
||||
|
||||
// iterate over list to run
|
||||
for list := range jobs {
|
||||
res := CmdListResults{}
|
||||
fieldsMap := make(map[string]interface{})
|
||||
fieldsMap["list"] = list.Name
|
||||
|
||||
@ -401,9 +403,10 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<-
|
||||
var outStructArr []outStruct // stores output messages
|
||||
|
||||
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]
|
||||
cmdLog.Fields(fieldsMap).Send()
|
||||
|
||||
@ -418,12 +421,13 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<-
|
||||
}
|
||||
|
||||
outputArr, runOutErr := cmdToRun.RunCmd(cmdLogger, opts)
|
||||
|
||||
if list.NotifyConfig != nil {
|
||||
|
||||
// check if the command output should be included
|
||||
if cmdToRun.GetOutput || list.GetOutput {
|
||||
outputStruct := outStruct{
|
||||
CmdName: cmd,
|
||||
CmdName: cmdToRun.Name,
|
||||
CmdExecuted: currentCmd,
|
||||
Output: outputArr,
|
||||
}
|
||||
@ -434,6 +438,7 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<-
|
||||
}
|
||||
count++
|
||||
if runOutErr != nil {
|
||||
res.ErrCmd = cmd
|
||||
if list.NotifyConfig != nil {
|
||||
var errMsg bytes.Buffer
|
||||
errStruct := make(map[string]interface{})
|
||||
@ -466,8 +471,9 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<-
|
||||
break
|
||||
} else {
|
||||
|
||||
cmdsRan = append(cmdsRan, cmd)
|
||||
|
||||
if count == len(list.Order) {
|
||||
cmdsRan = append(cmdsRan, cmd)
|
||||
var successMsg bytes.Buffer
|
||||
|
||||
// if notification config is not nil, and NotifyOnSuccess is true or GetOuput is true,
|
||||
@ -487,19 +493,17 @@ func cmdListWorker(msgTemps *msgTemplates, jobs <-chan *CmdList, results chan<-
|
||||
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 {
|
||||
opts.Logger.Err(err).Send()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cmdsRan = append(cmdsRan, cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results <- "done"
|
||||
results <- res.ErrCmd
|
||||
}
|
||||
|
||||
}
|
||||
@ -534,8 +538,20 @@ func (opts *ConfigOpts) RunListConfig(cron string) {
|
||||
}
|
||||
close(listChan)
|
||||
|
||||
for a := 1; a <= configListsLen; a++ {
|
||||
<-results
|
||||
for a := 0; a <= configListsLen; a++ {
|
||||
l := <-results
|
||||
|
||||
opts.Logger.Debug().Msg(l)
|
||||
|
||||
if l != "" {
|
||||
// execute error hooks
|
||||
opts.Logger.Debug().Msg("hooks are working")
|
||||
} else {
|
||||
// execute success hooks
|
||||
|
||||
}
|
||||
// execute final hooks
|
||||
|
||||
}
|
||||
|
||||
opts.closeHostConnections()
|
||||
@ -550,7 +566,14 @@ func (config *ConfigOpts) ExecuteCmds(opts *ConfigOpts) {
|
||||
_, runErr := cmdToRun.RunCmd(cmdLogger, opts)
|
||||
if runErr != nil {
|
||||
opts.Logger.Err(runErr).Send()
|
||||
|
||||
ExecuteHooks(*cmdToRun, "error", opts)
|
||||
} else {
|
||||
|
||||
ExecuteHooks(*cmdToRun, "success", opts)
|
||||
}
|
||||
|
||||
ExecuteHooks(*cmdToRun, "final", opts)
|
||||
}
|
||||
|
||||
opts.closeHostConnections()
|
||||
@ -593,3 +616,17 @@ func (c *ConfigOpts) closeHostConnections() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ExecuteHooks(cmd Command, hookType string, opts *ConfigOpts) {
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -245,6 +245,7 @@ func ReadConfig(opts *ConfigOpts) *ConfigOpts {
|
||||
|
||||
cmdListFilePath := path.Clean(opts.CmdListFile)
|
||||
|
||||
// if path is not absolute, check config directory
|
||||
if !strings.HasPrefix(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)
|
||||
}
|
||||
|
||||
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
|
||||
for cmdListName, cmdList := range opts.CmdConfigLists {
|
||||
if opts.useCron {
|
||||
if opts.cronEnabled {
|
||||
cron := strings.TrimSpace(cmdList.Cron)
|
||||
if cron == "" {
|
||||
delete(opts.CmdConfigLists, cmdListName)
|
||||
@ -291,21 +292,18 @@ func ReadConfig(opts *ConfigOpts) *ConfigOpts {
|
||||
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)
|
||||
}
|
||||
|
||||
for c := range opts.Cmds {
|
||||
if opts.executeCmds != nil && !contains(opts.executeCmds, c) {
|
||||
delete(opts.Cmds, c)
|
||||
}
|
||||
// process commands
|
||||
if err := processCmds(opts); err != nil {
|
||||
log.Panic().Err(err).Send()
|
||||
}
|
||||
|
||||
if len(opts.executeLists) > 0 {
|
||||
for l := range opts.CmdConfigLists {
|
||||
if !contains(opts.executeLists, l) {
|
||||
delete(opts.CmdConfigLists, l)
|
||||
}
|
||||
for l := range opts.CmdConfigLists {
|
||||
if !contains(opts.executeLists, l) {
|
||||
delete(opts.CmdConfigLists, l)
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,23 +315,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()
|
||||
|
||||
if err := opts.setupVault(); err != nil {
|
||||
log.Err(err).Send()
|
||||
}
|
||||
@ -460,3 +443,94 @@ func GetVaultKey(str string, opts *ConfigOpts, log zerolog.Logger) string {
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func processCmds(opts *ConfigOpts) error {
|
||||
// process commands
|
||||
for cmdName, cmd := range opts.Cmds {
|
||||
cmd.hookRefs = map[string]map[string]*Command{}
|
||||
cmd.hookRefs["error"] = map[string]*Command{}
|
||||
cmd.hookRefs["success"] = map[string]*Command{}
|
||||
|
||||
if cmd.Name == "" {
|
||||
cmd.Name = cmdName
|
||||
}
|
||||
// println("Cmd.Name = " + cmd.Name)
|
||||
hooks := cmd.Hooks
|
||||
// resolve hooks
|
||||
if hooks != nil {
|
||||
opts.Logger.Debug().Msg("Hooks found")
|
||||
|
||||
errHook, hookRefs, processHookErr := processHooks(hooks.Error, opts.Cmds, "error")
|
||||
if !processHookErr {
|
||||
return fmt.Errorf("error in command %s hook list: hook command %s not found", cmd.Name, errHook)
|
||||
}
|
||||
cmd.hookRefs["error"] = hookRefs
|
||||
|
||||
successHook, SuccessHookRefs, processHookSuccess := processHooks(hooks.Error, opts.Cmds, "error")
|
||||
if !processHookSuccess {
|
||||
return fmt.Errorf("error in command %s hook list: hook command %s not found", cmd.Name, successHook)
|
||||
}
|
||||
cmd.hookRefs["success"] = SuccessHookRefs
|
||||
}
|
||||
|
||||
// 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:
|
||||
//
|
||||
// 1. command string
|
||||
// 2. each hook type's command map
|
||||
// 2. a bool which determines if the command is valid
|
||||
func processHooks(hooks []string, cmds map[string]*Command, hookType string) (hook string, hookRefs map[string]*Command, hookCmdFound bool) {
|
||||
// fmt.Printf("%v\n", hooks)
|
||||
// for _, v := range cmds {
|
||||
|
||||
// fmt.Printf("CmdName=%v\n", v.Name)
|
||||
// fmt.Printf("Cmd=%v\n", v.Cmd)
|
||||
// }
|
||||
// initialize hook type
|
||||
hookRefs = make(map[string]*Command)
|
||||
// hookRefs[hookType] = map[string]*Command{}
|
||||
for _, hook = range hooks {
|
||||
var hookCmd *Command
|
||||
// TODO: match by Command.Name
|
||||
|
||||
hookCmd, hookCmdFound = cmds[hook]
|
||||
|
||||
if !hookCmdFound {
|
||||
return
|
||||
}
|
||||
hookRefs[hook] = hookCmd
|
||||
|
||||
// Recursive, decide if this is good
|
||||
// if hookCmd.hookRefs == nil {
|
||||
// }
|
||||
// hookRef[hookType][h] = hookCmd
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -43,17 +43,24 @@ type (
|
||||
}
|
||||
|
||||
Command struct {
|
||||
Name string `yaml:"name,omitempty"`
|
||||
|
||||
// command to run
|
||||
Cmd string `yaml:"cmd"`
|
||||
|
||||
// Possible values: script, scriptFile
|
||||
// If blank, it is regualar command.
|
||||
Type string `yaml:"type"`
|
||||
// If blank, it is regular command.
|
||||
Type string `yaml:"type,omitempty"`
|
||||
|
||||
// host on which to run cmd
|
||||
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.
|
||||
Not applicable when host is defined.
|
||||
@ -123,7 +130,7 @@ type (
|
||||
CmdListFile string
|
||||
|
||||
// use command lists using cron
|
||||
useCron bool
|
||||
cronEnabled bool
|
||||
// Holds commands to execute for the exec command
|
||||
executeCmds []string
|
||||
// Holds lists to execute for the backup command
|
||||
@ -188,4 +195,17 @@ type (
|
||||
Commands []string
|
||||
Hosts []string
|
||||
}
|
||||
|
||||
Hooks struct {
|
||||
Error []string `yaml:"error,omitempty"`
|
||||
SuccessHooks []string `yaml:"success,omitempty"`
|
||||
FinalHooks []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
|
||||
func UseCron() BackyOptionFunc {
|
||||
// cronEnabled enables the execution of command lists at specified times
|
||||
func CronEnabled() BackyOptionFunc {
|
||||
return func(bco *ConfigOpts) {
|
||||
bco.useCron = true
|
||||
bco.cronEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user