1
0
Fork 0
mirror of https://github.com/postmannen/ctrl.git synced 2025-03-31 01:24:31 +00:00

For the Linux and Darwin operating system we allow to automatically detect shell interpreter, so the user don't have to type "bash", "-c" as the first two arguments of the methodArgs.

This commit is contained in:
postmannen 2024-12-21 23:30:50 +01:00
parent 8ce651793c
commit c89983c489
3 changed files with 61 additions and 16 deletions

View file

@ -2,9 +2,12 @@ package ctrl
import (
"flag"
"fmt"
"log"
"os"
"os/exec"
"strconv"
"strings"
"github.com/joho/godotenv"
)
@ -16,6 +19,8 @@ import (
// an if check should be added to the checkConfigValues function
// to set default values when reading from config file.
type Configuration struct {
// Shell on the operating system to use when executing cliCommands
ShellOnNode string
// ConfigFolder, the location for the configuration folder on disk
ConfigFolder string `comment:"ConfigFolder, the location for the configuration folder on disk"`
// The folder where the socket file should live
@ -152,6 +157,7 @@ func NewConfiguration() *Configuration {
}
//flag.StringVar(&c.ConfigFolder, "configFolder", fc.ConfigFolder, "Defaults to ./usr/local/ctrl/etc/. *NB* This flag is not used, if your config file are located somwhere else than default set the location in an env variable named CONFIGFOLDER")
flag.StringVar(&c.ShellOnNode, "shellOnNode", CheckEnv("SHELL_ON_NODE", c.ShellOnNode).(string), "set a value to override the default shell used as interpreter for running cliCommand's on node.")
flag.StringVar(&c.SocketFolder, "socketFolder", CheckEnv("SOCKET_FOLDER", c.SocketFolder).(string), "folder who contains the socket file. Defaults to ./tmp/. If other folder is used this flag must be specified at startup.")
flag.StringVar(&c.ReadFolder, "readFolder", CheckEnv("READ_FOLDER", c.ReadFolder).(string), "folder who contains the readfolder. Defaults to ./readfolder/. If other folder is used this flag must be specified at startup.")
flag.StringVar(&c.TCPListener, "tcpListener", CheckEnv("TCP_LISTENER", c.TCPListener).(string), "start up a TCP listener in addition to the Unix Socket, to give messages to the system. e.g. localhost:8888. No value means not to start the listener, which is default. NB: You probably don't want to start this on any other interface than localhost")
@ -220,14 +226,30 @@ func NewConfiguration() *Configuration {
log.Fatalf("error: the centralNodeName config option or flag cannot be empty, check -help\n")
}
c.ShellOnNode = getShell()
fmt.Printf("\n******** DETECTED SHELL: %v\n\n", c.ShellOnNode)
flag.Parse()
return &c
}
func getShell() string {
out, err := exec.Command("echo", os.ExpandEnv("$SHELL")).Output()
if err != nil {
log.Fatalf("error: unable to detect shell: %v\n", err)
}
shell := string(out)
shell = strings.TrimSuffix(shell, "\n")
return string(shell)
}
// Get a Configuration struct with the default values set.
func newConfigurationDefaults() Configuration {
c := Configuration{
ShellOnNode: "",
ConfigFolder: "./etc/",
SocketFolder: "./tmp",
ReadFolder: "./readfolder",

View file

@ -5,6 +5,7 @@ import (
"bytes"
"fmt"
"os/exec"
"runtime"
"strings"
"time"
)
@ -27,8 +28,6 @@ func methodCliCommand(proc process, message Message, node string) ([]byte, error
go func() {
defer proc.processes.wg.Done()
var a []string
switch {
case len(message.MethodArgs) < 1:
er := fmt.Errorf("error: methodCliCommand: got <1 number methodArgs")
@ -36,12 +35,8 @@ func methodCliCommand(proc process, message Message, node string) ([]byte, error
newReplyMessage(proc, msgForErrors, []byte(er.Error()))
return
case len(message.MethodArgs) >= 0:
a = message.MethodArgs[1:]
}
c := message.MethodArgs[0]
// Get a context with the timeout specified in message.MethodTimeout.
ctx, cancel := getContextForMethodTimeout(proc.ctx, message)
@ -70,7 +65,24 @@ func methodCliCommand(proc process, message Message, node string) ([]byte, error
}
}
cmd := exec.CommandContext(ctx, c, a...)
var cmd *exec.Cmd
// For the Linux and Darwin operating system we allow to automatically detect
// shell interpreter, so the user don't have to type "bash", "-c" as the first
// two arguments of the methodArgs.
// We use the shell defined in the ShellOnNode variable as interpreter. Since
// it expects a "-c" directly after in the command we prefix it to the args.
if proc.configuration.ShellOnNode != "" {
switch runtime.GOOS {
case "linux", "darwin":
args := []string{"-c"}
args = append(args, message.MethodArgs...)
cmd = exec.CommandContext(ctx, proc.configuration.ShellOnNode, args...)
default:
cmd = exec.CommandContext(ctx, message.MethodArgs[0], message.MethodArgs...)
}
}
// Check for the use of env variable for CTRL_DATA, and set env if found.
if foundEnvData {
@ -149,8 +161,6 @@ func methodCliCommandCont(proc process, message Message, node string) ([]byte, e
// fmt.Printf(" * DONE *\n")
}()
var a []string
switch {
case len(message.MethodArgs) < 1:
er := fmt.Errorf("error: methodCliCommand: got <1 number methodArgs")
@ -158,12 +168,8 @@ func methodCliCommandCont(proc process, message Message, node string) ([]byte, e
newReplyMessage(proc, msgForErrors, []byte(er.Error()))
return
case len(message.MethodArgs) >= 0:
a = message.MethodArgs[1:]
}
c := message.MethodArgs[0]
// Get a context with the timeout specified in message.MethodTimeout.
ctx, cancel := getContextForMethodTimeout(proc.ctx, message)
// deadline, _ := ctx.Deadline()
@ -176,7 +182,24 @@ func methodCliCommandCont(proc process, message Message, node string) ([]byte, e
go func() {
defer proc.processes.wg.Done()
cmd := exec.CommandContext(ctx, c, a...)
var cmd *exec.Cmd
// For the Linux and Darwin operating system we allow to automatically detect
// shell interpreter, so the user don't have to type "bash", "-c" as the first
// two arguments of the methodArgs.
// We use the shell defined in the ShellOnNode variable as interpreter. Since
// it expects a "-c" directly after in the command we prefix it to the args.
if proc.configuration.ShellOnNode != "" {
switch runtime.GOOS {
case "linux", "darwin":
args := []string{"-c"}
args = append(args, message.MethodArgs...)
cmd = exec.CommandContext(ctx, proc.configuration.ShellOnNode, args...)
default:
cmd = exec.CommandContext(ctx, message.MethodArgs[0], message.MethodArgs...)
}
}
// Using cmd.StdoutPipe here so we are continuosly
// able to read the out put of the command.

View file

@ -61,7 +61,7 @@ func methodOpProcessStart(proc process, message Message, node string) ([]byte, e
method := Method(m)
tmpH := mt.getHandler(Method(method))
if tmpH == nil {
er := fmt.Errorf("error: OpProcessStart: no such request type defined: %v" + m)
er := fmt.Errorf("error: OpProcessStart: no such request type defined: %v", m)
proc.errorKernel.errSend(proc, message, er, logWarning)
return
}
@ -119,7 +119,7 @@ func methodOpProcessStop(proc process, message Message, node string) ([]byte, er
method := Method(methodString)
tmpH := mt.getHandler(Method(method))
if tmpH == nil {
er := fmt.Errorf("error: OpProcessStop: no such request type defined: %v, check that the methodArgs are correct: " + methodString)
er := fmt.Errorf("error: OpProcessStop: no such request type defined: %v, check that the methodArgs are correct: ", methodString)
proc.errorKernel.errSend(proc, message, er, logWarning)
return
}