summaryrefslogtreecommitdiff
path: root/internal/server
diff options
context:
space:
mode:
Diffstat (limited to 'internal/server')
-rw-r--r--internal/server/scheduler.go78
-rw-r--r--internal/server/server.go19
-rw-r--r--internal/server/stats.go2
3 files changed, 93 insertions, 6 deletions
diff --git a/internal/server/scheduler.go b/internal/server/scheduler.go
new file mode 100644
index 0000000..3cf55ce
--- /dev/null
+++ b/internal/server/scheduler.go
@@ -0,0 +1,78 @@
+package server
+
+import (
+ "context"
+ "fmt"
+ "math/rand"
+ "time"
+
+ "github.com/mimecast/dtail/internal/clients"
+ "github.com/mimecast/dtail/internal/config"
+ "github.com/mimecast/dtail/internal/io/logger"
+ "github.com/mimecast/dtail/internal/omode"
+
+ gossh "golang.org/x/crypto/ssh"
+)
+
+const authLength = 64
+const authCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@£$%^&*()_+[]"
+
+type scheduler struct {
+ authPayload string
+}
+
+func newScheduler() *scheduler {
+ seededRand := rand.New(rand.NewSource(time.Now().UnixNano()))
+
+ b := make([]byte, authLength)
+ for i := range b {
+ b[i] = authCharset[seededRand.Intn(len(authCharset))]
+ }
+
+ return &scheduler{
+ authPayload: string(b),
+ }
+}
+
+func (s *scheduler) start(ctx context.Context) {
+ for {
+ select {
+ case <-time.After(time.Second * 10):
+ s.runJobs(ctx)
+ return
+ case <-time.After(time.Minute):
+ s.runJobs(ctx)
+ case <-ctx.Done():
+ return
+ }
+ }
+}
+
+func (s *scheduler) runJobs(ctx context.Context) {
+ for _, scheduled := range config.Server.Schedule {
+ args := clients.Args{
+ ConnectionsPerCPU: scheduled.ConnectionsPerCPU,
+ Discovery: scheduled.Discovery,
+ ServersStr: scheduled.Servers,
+ What: scheduled.Files,
+ Mode: omode.MapClient,
+ UserName: config.ScheduledUser,
+ }
+ args.SSHAuthMethods = append(args.SSHAuthMethods, gossh.Password(s.authPayload))
+
+ client, err := clients.NewMaprClient(args, scheduled.Query)
+ if err != nil {
+ logger.Error(fmt.Sprintf("Unable to create scheduled job %s", scheduled.Name), err)
+ continue
+ }
+
+ logger.Info(fmt.Sprintf("Starting scheduled job %s", scheduled.Name))
+ status := client.Start(ctx)
+ logMessage := fmt.Sprintf("Scheduled job %s exited with status %d", scheduled.Name, status)
+ if status != 0 {
+ logger.Warn(logMessage)
+ continue
+ }
+ logger.Info(logMessage)
+ }
+}
diff --git a/internal/server/server.go b/internal/server/server.go
index 42eb74c..5c46147 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -27,6 +27,8 @@ type Server struct {
catLimiterCh chan struct{}
// To control the max amount of concurrent tails
tailLimiterCh chan struct{}
+ // To run scheduled tasks (if configured)
+ sched *scheduler
}
// New returns a new server.
@@ -37,9 +39,10 @@ func New() *Server {
sshServerConfig: &gossh.ServerConfig{},
catLimiterCh: make(chan struct{}, config.Server.MaxConcurrentCats),
tailLimiterCh: make(chan struct{}, config.Server.MaxConcurrentTails),
+ sched: newScheduler(),
}
- s.sshServerConfig.PasswordCallback = s.controlUserCallback
+ s.sshServerConfig.PasswordCallback = s.backgroundUserCallback
s.sshServerConfig.PublicKeyCallback = server.PublicKeyCallback
private, err := gossh.ParsePrivateKey(server.PrivateHostKey())
@@ -62,7 +65,8 @@ func (s *Server) Start(ctx context.Context) int {
logger.FatalExit("Failed to open listening TCP socket", err)
}
- go s.stats.periodicLogServerStats(ctx)
+ go s.stats.start(ctx)
+ go s.sched.start(ctx)
for {
conn, err := listener.Accept() // Blocking
@@ -192,13 +196,18 @@ func (s *Server) handleRequests(ctx context.Context, sshConn gossh.Conn, in <-ch
return nil
}
-func (*Server) controlUserCallback(c gossh.ConnMetadata, authPayload []byte) (*gossh.Permissions, error) {
+func (s *Server) backgroundUserCallback(c gossh.ConnMetadata, authPayload []byte) (*gossh.Permissions, error) {
user := user.New(c.User(), c.RemoteAddr().String())
if user.Name == config.ControlUser && string(authPayload) == config.ControlUser {
- logger.Debug(user, "Initiating master control program")
+ logger.Debug(user, "Granting permissions to control user")
return nil, nil
}
- return nil, fmt.Errorf("Not authorized")
+ if user.Name == config.ScheduledUser && string(authPayload) == s.sched.authPayload {
+ logger.Debug(user, "Granting permissions to schedule user")
+ return nil, nil
+ }
+
+ return nil, fmt.Errorf("user %s not authorized", user)
}
diff --git a/internal/server/stats.go b/internal/server/stats.go
index 4d661f7..ac579ad 100644
--- a/internal/server/stats.go
+++ b/internal/server/stats.go
@@ -67,7 +67,7 @@ func (s *stats) serverLimitExceeded() error {
return nil
}
-func (s *stats) periodicLogServerStats(ctx context.Context) {
+func (s *stats) start(ctx context.Context) {
for {
select {
case <-time.NewTimer(time.Second * 10).C: