move weirder example code here

Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
Jeff Carr 2024-03-09 17:45:14 -06:00
parent 0a0f11d4f1
commit 2960a05ed3
7 changed files with 463 additions and 0 deletions

11
shell/example1/Makefile Normal file
View File

@ -0,0 +1,11 @@
all:
# go build
GO111MODULE="off" go run main.go
goimports:
goimports -w *.go
redomod:
rm -f go.*
GO111MODULE= go mod init
GO111MODULE= go mod tidy

43
shell/example1/main.go Normal file
View File

@ -0,0 +1,43 @@
package main
/*
import "log"
import "reflect"
*/
import "os"
// import "github.com/davecgh/go-spew/spew"
import "go.wit.com/lib/gui/shell"
func main() {
shell.Run("ls /tmp")
shell.Run("ping -c 3 localhost")
// slow down the polling to every 2 seconds
shell.SetDelayInMsec(2000)
shell.Run("ping -c 4 localhost")
// capture ping output into a file
fout, _ := os.Create("/tmp/example1.ping.stdout")
ferr, _ := os.Create("/tmp/example1.ping.stderr")
shell.SetStdout(fout)
shell.SetStderr(ferr)
shell.Run("ping -c 5 localhost")
// turn out process exit debugging
shell.SpewOn()
fout, _ = os.Create("/tmp/example1.fail.stdout")
ferr, _ = os.Create("/tmp/example1.fail.stderr")
shell.SetStdout(fout)
shell.SetStderr(ferr)
// TODO: this might not be working
// check error handling
shell.Run("ls /tmpthisisnothere")
}

3
shell/example2/Makefile Normal file
View File

@ -0,0 +1,3 @@
all:
# go build
GO111MODULE="off" go run main.go

11
shell/example2/main.go Normal file
View File

@ -0,0 +1,11 @@
package main
import "log"
// import "fmt"
import "go.wit.com/lib/gui/shell"
func main() {
err := shell.Run("cat /etc/issue")
log.Println("cat /etc/issue returned", err)
// fmt.Print(output)
}

27
shell/linux.go Normal file
View File

@ -0,0 +1,27 @@
//go:build linux && go1.7
// +build linux,go1.7
// put stuff in here that you only want compiled under linux
package shell
import (
"log"
"os"
"os/signal"
"syscall"
"github.com/wercker/journalhook"
)
var sigChan chan os.Signal
func handleSignal(err interface{}, ret int) {
log.Println("handleSignal() only should be compiled on linux")
sigChan = make(chan os.Signal, 3)
signal.Notify(sigChan, syscall.SIGUSR1)
}
func UseJournalctl() {
journalhook.Enable()
}

211
shell/run.go Normal file
View File

@ -0,0 +1,211 @@
package shell
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"os/exec"
"strings"
"time"
"github.com/svent/go-nbreader"
"go.wit.com/log"
)
func (cmd *OldShell) Run(cmdline string) string {
cmd.InitProcess(cmdline)
if cmd.Error != nil {
return ""
}
cmd.Exec(cmdline)
return Chomp(cmd.Buffer)
}
func (cmd *OldShell) InitProcess(cmdline string) {
log.Log(RUN, "shell.InitProcess() START "+cmdline)
cmd.Cmdline = Chomp(cmdline) // this is like 'chomp' in perl
cmdArgs := strings.Fields(cmd.Cmdline)
if len(cmdArgs) == 0 {
cmd.Error = fmt.Errorf("cmdline == ''")
cmd.Done = true
return
}
if cmdArgs[0] == "cd" {
if len(cmdArgs) > 1 {
log.Log(RUN, "os.Chdir()", cmd)
os.Chdir(cmdArgs[1])
}
handleError(nil, 0)
cmd.Done = true
return
}
cmd.Process = exec.Command(cmdArgs[0], cmdArgs[1:len(cmdArgs)]...)
}
func (cmd *OldShell) FileCreate(out string) {
var newfile File
var iof io.ReadCloser
if out == "STDOUT" {
iof, _ = cmd.Process.StdoutPipe()
} else {
iof, _ = cmd.Process.StderrPipe()
}
newfile.Fio = iof
newfile.Fbufio = bufio.NewReader(iof)
// newfile.Fnbreader = nbreader.NewNBReader(newfile.Fbufio, 1024)
if out == "STDOUT" {
cmd.STDOUT = &newfile
} else {
cmd.STDERR = &newfile
}
}
// NOTE: this might cause problems:
// always remove the newlines at the end ?
func (cmd *OldShell) Exec(cmdline string) {
log.Log(RUN, "shell.Run() START "+cmdline)
cmd.InitProcess(cmdline)
if cmd.Error != nil {
return
}
cmd.FileCreate("STDOUT")
cmd.FileCreate("STDERR")
cmd.Process.Start()
// TODO; 'goroutine' both of these
// and make your own wait that will make sure
// the process is then done and run process.Wait()
go cmd.Capture(cmd.STDERR)
cmd.Capture(cmd.STDOUT)
// wait until the process exists
// https://golang.org/pkg/os/exec/#Cmd.Wait
// What should happen here, before calling Wait()
// is checks to make sure the READERS() on STDOUT and STDERR are done
err := cmd.Process.Wait()
// time.Sleep(2 * time.Second) // putting this here doesn't help STDOUT flush()
if err != nil {
cmd.Fail = true
cmd.Error = err
log.Log(RUN, "process.Wait() END err =", err.Error())
} else {
log.Log(RUN, "process.Wait() END")
}
return
}
// nonblocking read until file errors
func (cmd *OldShell) Capture(f *File) {
log.Log(RUN, "nbrREADER() START")
if cmd.Buffer == nil {
cmd.Buffer = new(bytes.Buffer)
}
if cmd.Buffer == nil {
f.Dead = false
cmd.Error = fmt.Errorf("could not make buffer")
log.Error(cmd.Error, "f.Buffer == nil")
log.Error(cmd.Error, "SHOULD DIE HERE")
cmd.Done = true
}
f.Dead = false
// loop that keeps trying to read from f
for f.Dead == false {
time.Sleep(time.Duration(msecDelay) * time.Millisecond) // only check the buffer 500 times a second
// set to false so it keeps retrying reads
f.Empty = false
// tight loop that reads 1024 bytes at a time until buffer is empty
// 1024 is set in f.BufferSize
for f.Empty == false {
f.Empty = cmd.ReadToBuffer(f)
}
}
}
// returns true if filehandle buffer is empty
func (cmd *OldShell) ReadToBuffer(f *File) bool {
log.Log(RUN, "ReadToBuffer() START")
// nbr := f.Fnbreader
// newfile.Fnbreader = nbreader.NewNBReader(newfile.Fbufio, 1024)
nbr := nbreader.NewNBReader(f.Fbufio, 1024)
oneByte := make([]byte, 1024)
if nbr == nil {
// log.Debugln("ReadToBuffer() ERROR nbr is nil")
f.Dead = true
return true
}
count, err := nbr.Read(oneByte)
f.TotalCount += count
if err != nil {
// log.Debugln("ReadToBuffer() file has closed with", err)
// log.Debugln("ReadToBuffer() count = ", count, "err = ", err)
f.Dead = true
return true
}
if count == 0 {
// log.Debugln("ReadToBuffer() START count == 0 return true")
return true
}
// log.Debugln("ReadToBuffer() count = ", count)
// tmp := Chomp(oneByte)
// log.Debugln("ReadToBuffer() tmp = ", tmp)
io.WriteString(cmd.Buffer, strings.Trim(string(oneByte), "\x00"))
return false
}
// pass in two file handles (1 read, 1 write)
func nonBlockingReader(buffReader *bufio.Reader, writeFileHandle *os.File, stdout *bufio.Writer) {
// newreader := bufio.NewReader(readFileHandle)
// create a nonblocking GO reader
nbr := nbreader.NewNBReader(buffReader, 1024)
for {
// defer buffReader.Close()
// defer writeFileHandle.Flush()
defer writeFileHandle.Close()
totalCount := 0
for {
oneByte := make([]byte, 1024)
count, err := nbr.Read(oneByte)
if err != nil {
log.Log(INFO, "count, err =", count, err)
handleError(err, -1)
return
}
totalCount += count
if count == 0 {
time.Sleep(time.Duration(msecDelay) * time.Millisecond) // without this delay this will peg the CPU
if totalCount != 0 {
log.Log(INFO, "STDERR: totalCount = ", totalCount)
totalCount = 0
}
} else {
log.Log(INFO, "STDERR: count = ", count)
writeFileHandle.Write(oneByte[0:count])
if quiet == false {
stdout.Write(oneByte[0:count])
stdout.Flush()
}
}
}
}
}

157
shell/ssh.go Normal file
View File

@ -0,0 +1,157 @@
package shell
import (
"fmt"
"io/ioutil"
"time"
"github.com/tmc/scp"
"go.wit.com/log"
"golang.org/x/crypto/ssh"
)
var sshHostname string
var sshPort int
var sshUsername string
var sshPassword string
var sshKeyfile string
func SSHclientSet(hostname string, port int, username string, pass string, keyfile string) {
sshHostname = hostname
sshPort = port
sshUsername = username
sshPassword = pass
sshKeyfile = keyfile
}
func SSHclientSCP(localfile string, remotefile string) {
log.Log(SSH, "shell.SSHclientSCP() START")
log.Log(SSH, "shell.SSHclientSCP() \tlocalfile =", localfile)
log.Log(SSH, "shell.SSHclientSCP() \tremotefile =", remotefile)
sess := mySsh(sshHostname, sshPort, sshUsername, sshPassword, sshKeyfile)
err := scp.CopyPath(localfile, remotefile, sess)
sess.Close()
log.Log(SSH, "shell.SSHclientSCP() \tscp.CopyPath() err =", err)
log.Log(SSH, "shell.SSHclientSCP() END")
}
func SSHclientRun(cmd string) {
log.Log(SSH, "shell.SSHclientRun() START cmd =", cmd)
sess := mySsh(sshHostname, sshPort, sshUsername, sshPassword, sshKeyfile)
err := sess.Run(cmd)
sess.Close()
log.Log(SSH, "shell.SSHclientRun() END err =", err)
}
func mySsh(hostname string, port int, username string, pass string, keyfile string) *ssh.Session {
// get host public key
// hostKey := getHostKey(host)
// log.Log(SSH, "hostkey =", hostKey)
publicKey, err := PublicKeyFile(keyfile)
if err != nil {
log.Log(SSH, "PublicKeyFile() error =", err)
}
// ssh client config
config := ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.Password(pass),
publicKey,
},
// allow any host key to be used (non-prod)
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
// verify host public key
// HostKeyCallback: ssh.FixedHostKey(hostKey),
// optional host key algo list
HostKeyAlgorithms: []string{
ssh.KeyAlgoRSA,
ssh.KeyAlgoDSA,
ssh.KeyAlgoECDSA256,
ssh.KeyAlgoECDSA384,
ssh.KeyAlgoECDSA521,
ssh.KeyAlgoED25519,
},
// optional tcp connect timeout
Timeout: 5 * time.Second,
}
sport := fmt.Sprintf("%d", port)
// connect
client, err := ssh.Dial("tcp", hostname+":"+sport, &config)
if err != nil {
log.Error(err)
}
// defer client.Close()
// start session
sess, err := client.NewSession()
if err != nil {
log.Error(err)
}
// defer sess.Close()
return sess
}
func Scp(sess *ssh.Session, localfile string, remotefile string) {
err := scp.CopyPath(localfile, remotefile, sess)
log.Log(SSH, "scp.CopyPath() err =", err)
}
func PublicKeyFile(file string) (ssh.AuthMethod, error) {
buffer, err := ioutil.ReadFile(file)
log.Log(SSH, "buffer =", string(buffer))
if err != nil {
return nil, err
}
key, err := ssh.ParsePrivateKey(buffer)
if err != nil {
return nil, err
}
return ssh.PublicKeys(key), nil
}
// THIS doesn't work
/*
func getHostKey(host string) ssh.PublicKey {
// parse OpenSSH known_hosts file
// ssh or use ssh-keyscan to get initial key
file, err := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "known_hosts"))
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
var hostKey ssh.PublicKey
for scanner.Scan() {
fields := strings.Split(scanner.Text(), " ")
if len(fields) != 3 {
continue
}
if strings.Contains(fields[0], host) {
var err error
hostKey, _, _, _, err = ssh.ParseAuthorizedKey(scanner.Bytes())
if err != nil {
log.Fatalf("error parsing %q: %v", fields[2], err)
}
break
}
}
// 9enFJdMhb8eHN/6qfHSU/jww2Mo=|pcsWQCvAyve9QXBhjL+w/LhkcHU= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMQx8BJXxD+vk3wyjy7Irzw4FA6xxJvqUP7Hb+Z+ygpOuidYj9G8x6gHEXFUnABn5YirePrWh5tNsk4Rqs48VwU=
hostKey, _, _, _, err = ssh.ParseAuthorizedKey([]byte("9enFJdMhb8eHN/6qfHSU/jww2Mo=|pcsWQCvAyve9QXBhjL+w/LhkcHU= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMQx8BJXxD+vk3wyjy7Irzw4FA6xxJvqUP7Hb+Z+ygpOuidYj9G8x6gHEXFUnABn5YirePrWh5tNsk4Rqs48VwU="))
log.Log(SSH, "hostkey err =", err)
log.Log(SSH, "hostkey =", hostKey)
if hostKey == nil {
log.Log(SSH, "no hostkey found err =", err)
log.Fatalf("no hostkey found for %s", host)
}
return hostKey
}
*/