diff --git a/backup.go b/backup.go index 80ca6ba..db08c8c 100644 --- a/backup.go +++ b/backup.go @@ -13,47 +13,75 @@ import ( "git.andrewnw.xyz/CyberShell/backy/pkg/backy" "github.com/kevinburke/ssh_config" + "github.com/spf13/viper" "golang.org/x/crypto/ssh" ) +// const logFile = "backy.log" + type backupCommand struct { // command to run - cmd string + Cmd string // host on which to run cmd - host string + Host string // Shell specifies which shell to run the command in, if any // Not applicable when host is not local - shell string - // path to the command - - path string + Shell string // cmdArgs is an array that holds the arguments to cmd - cmdArgs []string + CmdArgs []string } -var remoteHost *backy.Host +// type config struct { +// Commands struct { +// backupCommand `mapstructure:",squash"` +// } +// } +var testCmd = &backupCommand{ + Cmd: "hostname", + Shell: "bash", + CmdArgs: []string{}, +} + +var remoteHost backy.Host func main() { + var test = true + + if test { + + readConfigFile() + + } else { + + remoteHost.User = "root" + testCmd.runCmd() + // shutdownEmailSvr.runCmd() + // backupEmailSvrRestic.runCmd() + // backupEmailSvrRsync.runCmd() + // startEmailSvr.runCmd() + + } } func (command *backupCommand) runCmd() { var cmdArgsStr string - for _, v := range command.cmdArgs { + for _, v := range command.CmdArgs { cmdArgsStr += fmt.Sprintf(" %s", v) } - fmt.Printf("\n\nRunning command: " + command.cmd + " " + cmdArgsStr + " on host " + command.host + "...\n\n") - if command.host != "local" { + + fmt.Printf("\n\nRunning command: " + command.Cmd + " " + cmdArgsStr + " on host " + command.Host + "...\n\n") + if command.Host != "local" { remoteHost.Port = 22 - remoteHost.Host = command.host + remoteHost.Host = command.Host - sshc, err := connectToSSHHost(remoteHost) + sshc, err := connectToSSHHost(&remoteHost) if err != nil { panic(fmt.Errorf("ssh dial: %w", err)) } @@ -64,8 +92,8 @@ func (command *backupCommand) runCmd() { } defer s.Close() - cmd := command.cmd - for _, a := range command.cmdArgs { + cmd := command.Cmd + for _, a := range command.CmdArgs { cmd += " " + a } @@ -76,31 +104,31 @@ func (command *backupCommand) runCmd() { if err != nil { panic(fmt.Errorf("error when running cmd " + cmd + "\n Error: " + err.Error())) } - // fmt.Printf("Output: %s\n", string(output)) } else { // shell := "/bin/bash" var err error - if command.shell != "" { - cmdArgsStr = fmt.Sprintf("%s %s", command.cmd, cmdArgsStr) - localCMD := exec.Command(command.shell, "-c", cmdArgsStr) + if command.Shell != "" { + cmdArgsStr = fmt.Sprintf("%s %s", command.Cmd, cmdArgsStr) + localCMD := exec.Command(command.Shell, "-c", cmdArgsStr) var stdoutBuf, stderrBuf bytes.Buffer localCMD.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf) localCMD.Stderr = io.MultiWriter(os.Stderr, &stderrBuf) err = localCMD.Run() if err != nil { - panic(fmt.Errorf("error when running cmd: %s: %w", command.cmd, err)) + panic(fmt.Errorf("error when running cmd: %s: %w", command.Cmd, err)) } + return } - // localCMD := exec.Command(command.cmd, command.args...) + localCMD := exec.Command(command.Cmd, command.CmdArgs...) - // var stdoutBuf, stderrBuf bytes.Buffer - // localCMD.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf) - // localCMD.Stderr = io.MultiWriter(os.Stderr, &stderrBuf) - // err = localCMD.Run() + var stdoutBuf, stderrBuf bytes.Buffer + localCMD.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf) + localCMD.Stderr = io.MultiWriter(os.Stderr, &stderrBuf) + err = localCMD.Run() if err != nil { - panic(fmt.Errorf("error when running cmd: %s: %w", command.cmd, err)) + panic(fmt.Errorf("error when running cmd: %s: %w", command.Cmd, err)) } // fmt.Printf("%s\n", string(output)) } @@ -147,7 +175,7 @@ func connectToSSHHost(remoteConfig *backy.Host) (*ssh.Client, error) { panic(fmt.Errorf("parse private key: %w", err)) } sshConfig := &ssh.ClientConfig{ - User: "root", + User: remoteHost.User, Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), } @@ -158,3 +186,91 @@ func connectToSSHHost(remoteConfig *backy.Host) (*ssh.Client, error) { } return sshc, connectErr } + +func readConfigFile() { + viper.SetConfigName("backy") // name of config file (without extension) + viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name + viper.AddConfigPath("$HOME/.config/backy") // call multiple times to add many search paths + viper.AddConfigPath(".") // optionally look for config in the working directory + err := viper.ReadInConfig() // Find and read the config file + if err != nil { // Handle errors reading the config file + panic(fmt.Errorf("fatal error config file: %w", err)) + } + // if err := viper.ReadInConfig(); err != nil { + // if _, ok := err.(viper.ConfigFileNotFoundError); ok { + // // Config file not found; ignore error if desired + // } else { + // // Config file was found but another error was produced + // } + // } + + // Config file found and successfully parsed + + // viper.WriteConfig() // writes current config to predefined path set by 'viper.AddConfigPath()' and 'viper.SetConfigName' + + // err = viper.Unmarshal(&C) + // if err != nil { + // panic(fmt.Errorf("unable to decode into struct, %v", err)) + // } + commandsMap := viper.GetStringMapString("commands") + var cmdNames []string + for k := range commandsMap { + cmdNames = append(cmdNames, k) + } + var cmdStructs []backupCommand + for _, cmdName := range cmdNames { + var backupCmdStruct backupCommand + println(cmdName) + subCmd := viper.Sub(getNestedConfig("commands", cmdName)) + + hostSet := subCmd.IsSet("host") + host := subCmd.GetString("host") + + cmdSet := subCmd.IsSet("cmd") + cmd := subCmd.GetString("cmd") + cmdArgsSet := subCmd.IsSet("cmdargs") + cmdArgs := subCmd.GetStringSlice("cmdargs") + + if hostSet { + println("Host:") + println(host) + backupCmdStruct.Host = host + } else { + println("Host is not set") + } + if cmdSet { + println("Cmd:") + println(cmd) + backupCmdStruct.Cmd = cmd + } else { + println("Cmd is not set") + } + if cmdArgsSet { + println("CmdArgs:") + for _, arg := range cmdArgs { + println(arg) + } + backupCmdStruct.CmdArgs = cmdArgs + } else { + println("CmdArgs is not set") + } + cmdStructs = append(cmdStructs, backupCmdStruct) + for _, cmd := range cmdStructs { + fmt.Printf("Cmd is %s\n", cmd.Cmd) + fmt.Printf("Host is %s\n", cmd.Host) + } + } + cmdOrder := viper.GetStringMapStringSlice("cmd-order") + for cmd, orderSlice := range cmdOrder { + println("Cmd name: ", cmd) + println("Cmd order: ") + for _, v := range orderSlice { + println(v) + + } + } +} + +func getNestedConfig(nestedConfig, key string) string { + return fmt.Sprintf("%s.%s", nestedConfig, key) +} diff --git a/mail.go b/mail.go deleted file mode 100644 index 80ca6ba..0000000 --- a/mail.go +++ /dev/null @@ -1,160 +0,0 @@ -package main - -import ( - "bytes" - "fmt" - "io" - "os" - "path/filepath" - "strings" - - "os/exec" - "os/user" - - "git.andrewnw.xyz/CyberShell/backy/pkg/backy" - "github.com/kevinburke/ssh_config" - "golang.org/x/crypto/ssh" -) - -type backupCommand struct { - - // command to run - cmd string - - // host on which to run cmd - host string - - // Shell specifies which shell to run the command in, if any - // Not applicable when host is not local - shell string - // path to the command - - path string - - // cmdArgs is an array that holds the arguments to cmd - cmdArgs []string -} - -var remoteHost *backy.Host - -func main() { - -} - -func (command *backupCommand) runCmd() { - - var cmdArgsStr string - for _, v := range command.cmdArgs { - cmdArgsStr += fmt.Sprintf(" %s", v) - } - fmt.Printf("\n\nRunning command: " + command.cmd + " " + cmdArgsStr + " on host " + command.host + "...\n\n") - if command.host != "local" { - - remoteHost.Port = 22 - remoteHost.Host = command.host - - sshc, err := connectToSSHHost(remoteHost) - if err != nil { - panic(fmt.Errorf("ssh dial: %w", err)) - } - defer sshc.Close() - s, err := sshc.NewSession() - if err != nil { - panic(fmt.Errorf("new ssh session: %w", err)) - } - defer s.Close() - - cmd := command.cmd - for _, a := range command.cmdArgs { - cmd += " " + a - } - - var stdoutBuf, stderrBuf bytes.Buffer - s.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf) - s.Stderr = io.MultiWriter(os.Stderr, &stderrBuf) - err = s.Run(cmd) - if err != nil { - panic(fmt.Errorf("error when running cmd " + cmd + "\n Error: " + err.Error())) - } - // fmt.Printf("Output: %s\n", string(output)) - } else { - // shell := "/bin/bash" - var err error - if command.shell != "" { - cmdArgsStr = fmt.Sprintf("%s %s", command.cmd, cmdArgsStr) - localCMD := exec.Command(command.shell, "-c", cmdArgsStr) - - var stdoutBuf, stderrBuf bytes.Buffer - localCMD.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf) - localCMD.Stderr = io.MultiWriter(os.Stderr, &stderrBuf) - err = localCMD.Run() - if err != nil { - panic(fmt.Errorf("error when running cmd: %s: %w", command.cmd, err)) - } - } - // localCMD := exec.Command(command.cmd, command.args...) - - // var stdoutBuf, stderrBuf bytes.Buffer - // localCMD.Stdout = io.MultiWriter(os.Stdout, &stdoutBuf) - // localCMD.Stderr = io.MultiWriter(os.Stderr, &stderrBuf) - // err = localCMD.Run() - - if err != nil { - panic(fmt.Errorf("error when running cmd: %s: %w", command.cmd, err)) - } - // fmt.Printf("%s\n", string(output)) - } -} - -func connectToSSHHost(remoteConfig *backy.Host) (*ssh.Client, error) { - var sshc *ssh.Client - var connectErr error - - f, _ := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "config")) - cfg, _ := ssh_config.Decode(f) - for _, host := range cfg.Hosts { - if host.Matches(remoteConfig.Host) { - var identityFile string - if remoteConfig.PrivateKeyPath == "" { - identityFile, _ = cfg.Get(remoteConfig.Host, "IdentityFile") - usr, _ := user.Current() - dir := usr.HomeDir - if identityFile == "~" { - // In case of "~", which won't be caught by the "else if" - identityFile = dir - } else if strings.HasPrefix(identityFile, "~/") { - // Use strings.HasPrefix so we don't match paths like - // "/something/~/something/" - identityFile = filepath.Join(dir, identityFile[2:]) - } - remoteConfig.PrivateKeyPath = filepath.Join(identityFile) - } - remoteConfig.HostName, _ = cfg.Get(remoteConfig.Host, "HostName") - if remoteConfig.HostName == "" { - remoteConfig.HostName = remoteConfig.Host - } - port, _ := cfg.Get(remoteConfig.Host, "Port") - if port == "" { - port = "22" - } - privateKey, err := os.ReadFile(remoteConfig.PrivateKeyPath) - remoteConfig.HostName = remoteConfig.HostName + ":" + port - if err != nil { - panic(fmt.Errorf("read private key: %w", err)) - } - signer, err := ssh.ParsePrivateKey(privateKey) - if err != nil { - panic(fmt.Errorf("parse private key: %w", err)) - } - sshConfig := &ssh.ClientConfig{ - User: "root", - Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)}, - HostKeyCallback: ssh.InsecureIgnoreHostKey(), - } - sshc, connectErr = ssh.Dial("tcp", remoteConfig.HostName, sshConfig) - break - } - - } - return sshc, connectErr -}