summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/config/common.go27
-rw-r--r--internal/io/run/run.go26
-rw-r--r--internal/server/handlers/runcommand.go95
-rw-r--r--samples/dtail.json.sample1
4 files changed, 88 insertions, 61 deletions
diff --git a/internal/config/common.go b/internal/config/common.go
index 8c07710..f0f1a94 100644
--- a/internal/config/common.go
+++ b/internal/config/common.go
@@ -2,27 +2,19 @@ package config
// CommonConfig stores configuration keys shared by DTail server and client.
type CommonConfig struct {
- // The SSH server port number.
- SSHPort int
- // Enable experimental features.
+ SSHPort int
ExperimentalFeaturesEnable bool `json:",omitempty"`
- // Enable extra debug logging (used for deevlopment or debugging purpes only).
- DebugEnable bool `json:",omitempty"`
- // Enable extra trace logging (used for deevlopment or debugging purpes only).
- TraceEnable bool `json:",omitempty"`
+ DebugEnable bool `json:",omitempty"`
+ TraceEnable bool `json:",omitempty"`
// The log strategy to use, one of
// stdout: only log to stdout (useful when used with systemd)
// daily: create a log file for every day
- LogStrategy string
- // The log directory
- LogDir string
- // The cache directory
- CacheDir string
- // Do we want to enable pperf http server?
- PProfEnable bool `json:",omitempty"`
- // The HTTP port used by PProf
- PProfPort int `json:",omitempty"`
- // The PProf HTTP server bind address
+ LogStrategy string
+ LogDir string
+ CacheDir string
+ TmpDir string `json:",omitempty"`
+ PProfEnable bool `json:",omitempty"`
+ PProfPort int `json:",omitempty"`
PProfBindAddress string `json:",omitempty"`
}
@@ -35,6 +27,7 @@ func newDefaultCommonConfig() *CommonConfig {
ExperimentalFeaturesEnable: false,
LogDir: "log",
CacheDir: "cache",
+ TmpDir: "/tmp",
PProfEnable: false,
PProfPort: 6060,
PProfBindAddress: "0.0.0.0",
diff --git a/internal/io/run/run.go b/internal/io/run/run.go
index 3cf7935..5951cde 100644
--- a/internal/io/run/run.go
+++ b/internal/io/run/run.go
@@ -14,16 +14,16 @@ import (
// Run is for execute a command.
type Run struct {
- commandPath string
- args []string
- cmd *exec.Cmd
+ command string
+ args []string
+ cmd *exec.Cmd
}
// New returns a new command runner.
-func New(commandPath string, args []string) Run {
+func New(command string, args []string) Run {
return Run{
- commandPath: commandPath,
- args: args,
+ command: command,
+ args: args,
}
}
@@ -36,11 +36,11 @@ func (r Run) Start(ctx context.Context, lines chan<- line.Line) (pid int, ec int
pid = -1
if len(r.args) > 0 {
- logger.Debug(r.commandPath, r.args, " ")
- r.cmd = exec.CommandContext(ctx, r.commandPath, r.args...)
+ logger.Debug(r.command, r.args, " ")
+ r.cmd = exec.CommandContext(ctx, r.command, r.args...)
} else {
- logger.Debug(r.commandPath)
- r.cmd = exec.CommandContext(ctx, r.commandPath)
+ logger.Debug(r.command)
+ r.cmd = exec.CommandContext(ctx, r.command)
}
stdoutPipe, myErr := r.cmd.StdoutPipe()
@@ -60,8 +60,10 @@ func (r Run) Start(ctx context.Context, lines chan<- line.Line) (pid int, ec int
return
}
- pid = r.cmd.Process.Pid
- ec = 0
+ if r.cmd.Process != nil {
+ pid = r.cmd.Process.Pid
+ ec = 0
+ }
var wg sync.WaitGroup
wg.Add(2)
diff --git a/internal/server/handlers/runcommand.go b/internal/server/handlers/runcommand.go
index b7fbb8b..9dc878f 100644
--- a/internal/server/handlers/runcommand.go
+++ b/internal/server/handlers/runcommand.go
@@ -3,9 +3,13 @@ package handlers
import (
"context"
"fmt"
+ "io/ioutil"
+ "os"
"os/exec"
"strings"
+ "time"
+ "github.com/mimecast/dtail/internal/config"
"github.com/mimecast/dtail/internal/io/logger"
"github.com/mimecast/dtail/internal/io/run"
)
@@ -26,39 +30,66 @@ func (r runCommand) Start(ctx context.Context, argc int, args []string) {
r.server.sendServerMessage(logger.Warn(r.server.user, commandParseWarning, args, argc))
return
}
- commands := strings.Split(strings.Join(args[1:], " "), ";")
- r.start(ctx, commands)
+
+ command := strings.Join(args[1:], " ")
+ if strings.Contains(command, ";") {
+ r.startScript(ctx, command)
+ return
+ }
+
+ r.start(ctx, strings.TrimSpace(command))
}
-func (r runCommand) start(ctx context.Context, commands []string) {
- for _, command := range commands {
- command = strings.TrimSpace(command)
- if len(command) == 0 {
- continue
- }
- splitted := strings.Split(command, " ")
- path := splitted[0]
- args := splitted[1:]
-
- qualifiedPath, err := exec.LookPath(path)
- if err != nil {
- logger.Error(r.server.user, err)
- r.server.sendServerMessage(logger.Error(r.server.user, "Unable to execute command(s), check server logs"))
- r.server.sendServerMessage(".run exitstatus 255")
- return
- }
-
- if !r.server.user.HasFilePermission(qualifiedPath, "runcommands") {
- logger.Error(r.server.user, "No permission to execute path", qualifiedPath)
- r.server.sendServerMessage(logger.Error(r.server.user, "Unable to execute command(s), check server logs"))
- r.server.sendServerMessage(".run exitstatus 255")
- return
- }
-
- r.run = run.New(qualifiedPath, args)
- pid, ec, _ := r.run.Start(ctx, r.server.lines)
-
- r.server.sendServerMessage(fmt.Sprintf(".run exitstatus %d", ec))
- r.server.sendServerMessage(logger.Info(fmt.Sprintf("Process %d exited with status %d", pid, ec)))
+func (r runCommand) startScript(ctx context.Context, script string) {
+ if _, err := os.Stat(config.Common.TmpDir); os.IsNotExist(err) {
+ logger.Error(r.server.user, err)
+ r.server.sendServerMessage(logger.Error(r.server.user, "Unable to execute command(s), check server logs"))
+ return
+ }
+
+ timestamp := time.Now().UnixNano()
+ scriptPath := fmt.Sprintf("%s/%s_%v.sh", config.Common.TmpDir, r.server.user.Name, timestamp)
+
+ // TODO: On dserver startup delete all previously written scripts (there might be left overs due to a crash or so)
+ logger.Debug(r.server.user, "Writing temp script", scriptPath)
+
+ script = fmt.Sprintf("#!/bin/sh\n%s", script)
+ if err := ioutil.WriteFile(scriptPath, []byte(script), 0700); err != nil {
+ logger.Error(r.server.user, err)
+ r.server.sendServerMessage(logger.Error(r.server.user, "Unable to execute command(s), check server logs"))
+ return
}
+
+ r.start(ctx, scriptPath)
+ os.Remove(scriptPath)
+}
+
+func (r runCommand) start(ctx context.Context, command string) {
+ if len(command) == 0 {
+ return
+ }
+ splitted := strings.Split(command, " ")
+ path := splitted[0]
+ args := splitted[1:]
+
+ qualifiedPath, err := exec.LookPath(path)
+ if err != nil {
+ logger.Error(r.server.user, err)
+ r.server.sendServerMessage(logger.Error(r.server.user, "Unable to execute command(s), check server logs"))
+ r.server.sendServerMessage(".run exitstatus 255")
+ return
+ }
+
+ if !r.server.user.HasFilePermission(qualifiedPath, "runcommands") {
+ logger.Error(r.server.user, "No permission to execute path", qualifiedPath)
+ r.server.sendServerMessage(logger.Error(r.server.user, "Unable to execute command(s), check server logs"))
+ r.server.sendServerMessage(".run exitstatus 255")
+ return
+ }
+
+ r.run = run.New(qualifiedPath, args)
+ pid, ec, _ := r.run.Start(ctx, r.server.lines)
+
+ r.server.sendServerMessage(fmt.Sprintf(".run exitstatus %d", ec))
+ r.server.sendServerMessage(logger.Info(fmt.Sprintf("Process %d exited with status %d", pid, ec)))
}
diff --git a/samples/dtail.json.sample b/samples/dtail.json.sample
index 83925c6..4f672e9 100644
--- a/samples/dtail.json.sample
+++ b/samples/dtail.json.sample
@@ -29,6 +29,7 @@
"Common": {
"LogDir" : "log",
"CacheDir" : "cache",
+ "TmpDir" : "tmp",
"LogStrategy": "stdout",
"SSHPort": 2222,
"DebugEnable": false,