Skip to content

Commit

Permalink
Merge pull request #12 from FMotalleb/rehaul
Browse files Browse the repository at this point in the history
Rehaul
  • Loading branch information
FMotalleb authored Jun 10, 2024
2 parents 42dadc1 + 9173743 commit ed22ee6
Show file tree
Hide file tree
Showing 21 changed files with 582 additions and 356 deletions.
4 changes: 2 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ linters-settings:
locale: US
nolintlint:
allow-unused: false # report any unused nolint directives

require-explanation: true # require an explanation for nolint directives
require-specific: false # don't require nolint directives to be specific about which linter is being skipped
revive:
Expand All @@ -35,7 +34,7 @@ linters:
# - revive
- rowserrcheck
- goprintffuncname
- gosec
# - gosec
- gosimple
- govet
- ineffassign
Expand All @@ -51,6 +50,7 @@ linters:
- unparam
- unused
- whitespace
- copyloopvar

issues:
# enable issues excluded by default
Expand Down
14 changes: 14 additions & 0 deletions abstraction/cmd_connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package abstraction

import (
"context"

"github.com/FMotalleb/crontab-go/config"
)

type CmdConnection interface {
Prepare(context.Context, *config.Task) error
Connect() error
Execute() ([]byte, error)
Disconnect() error
}
4 changes: 3 additions & 1 deletion abstraction/executable.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Package abstraction must contain only interfaces and abstract layers of modules
package abstraction

import "context"
import (
"context"
)

// Executable is an object that can be executed using a execute method and stopped using cancel method
type Executable interface {
Expand Down
15 changes: 12 additions & 3 deletions config.doc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ jobs:
# Description is reserved for the future
description: Sample of a single job
# Jobs can be disabled explicitly instead of commenting/removing the job
# disabled: true
disabled: true
# Concurrency level of this job, indicates how many tasks can run simultaneously
concurrency: 5
tasks:
# This line specifies the actual command to be executed.
- command: echo $(whoami)
# This setting determines the number of times the task will be retried if it fails
# This setting determines the number of times the task will be retried if it fails, defaults to zero
# A failure is defined by either a non-zero exit code for commands or a status code of 400 or higher for HTTP requests.
retries: 3
# This specifies the delay between retries.
Expand All @@ -21,8 +23,15 @@ jobs:
# If the task exceeds 15 seconds, it will be considered failed and stopped (command) or canceled (http requests)
timeout: 15s
user: root
# # This defines the working directory for the command.
# This defines the working directory for the command.
working-dir: /home/user
# This tasks will be executed if current task is done (exit-code: 0, or http response code: <400)
on-done:
- command: echo ok

# This tasks will be executed if current task is failed (exit-code: 1, or http response code: >=400)
on-fail:
- command: echo fail
# This section allows you to set environment variables that will be available to the command during execution.
# `SHELL` and `SHELL_ARGS` can be used to change this commands shell environment
env:
Expand Down
7 changes: 3 additions & 4 deletions config.local.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
jobs:
- name: Test Job
tasks:
- command: ip a
env:
SHELL: C:\WINDOWS\System32\OpenSSH\ssh.exe
SHELL_ARGS: "-i;C:/Users/Motalleb/.xpipe/storage/data/id_rsa_old;[email protected];-p;9011"
- command: ip a -pt
retries: 5
retry-delay: 5s
schedulers:
- on-init: true
- interval: 10m10s
62 changes: 0 additions & 62 deletions config/compiler/compiler.go

This file was deleted.

34 changes: 34 additions & 0 deletions config/compiler/scheduler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package cfgcompiler

import (
"github.com/robfig/cron/v3"
"github.com/sirupsen/logrus"

"github.com/FMotalleb/crontab-go/abstraction"
"github.com/FMotalleb/crontab-go/config"
"github.com/FMotalleb/crontab-go/core/schedule"
)

func CompileScheduler(sh *config.JobScheduler, cr *cron.Cron, logger *logrus.Entry) abstraction.Scheduler {
switch {
case sh.Cron != "":
scheduler := schedule.NewCron(
sh.Cron,
cr,
logger,
)
return &scheduler
case sh.Interval != 0:
scheduler := schedule.NewInterval(
sh.Interval,
logger,
)
return &scheduler

case sh.OnInit:
scheduler := schedule.Init{}
return &scheduler
}

return nil
}
36 changes: 36 additions & 0 deletions config/compiler/task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package cfgcompiler

import (
"github.com/sirupsen/logrus"

"github.com/FMotalleb/crontab-go/abstraction"
"github.com/FMotalleb/crontab-go/config"
"github.com/FMotalleb/crontab-go/core/task"
)

func CompileTask(t *config.Task, logger *logrus.Entry) abstraction.Executable {
var exe abstraction.Executable
switch {
case t.Command != "":
exe = task.NewCommand(t, logger)
case t.Get != "":
exe = task.NewGet(t, logger)
case t.Post != "":
exe = task.NewPost(t, logger)
default:
logger.Fatalln("cannot handle given task config", t)
}

onDone := []abstraction.Executable{}
for _, d := range t.OnDone {
onDone = append(onDone, CompileTask(&d, logger))
}
exe.SetDoneHooks(onDone)
onFail := []abstraction.Executable{}
for _, d := range t.OnFail {
onFail = append(onFail, CompileTask(&d, logger))
}
exe.SetFailHooks(onFail)

return exe
}
30 changes: 19 additions & 11 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,30 @@ type (
}

Task struct {
Post string `mapstructure:"post" json:"post,omitempty"`
Get string `mapstructure:"get" json:"get,omitempty"`
// Http Requests
Post string `mapstructure:"post" json:"post,omitempty"`
Get string `mapstructure:"get" json:"get,omitempty"`
Headers map[string]string `mapstructure:"headers" json:"headers,omitempty"`
Data any `mapstructure:"data" json:"data,omitempty"`

// Command params
Command string `mapstructure:"command" json:"command,omitempty"`
WorkingDirectory string `mapstructure:"working-dir" json:"working_directory,omitempty"`
Headers map[string]string `mapstructure:"headers" json:"headers,omitempty"`
Data any `mapstructure:"data" json:"data,omitempty"`

UserName string `mapstructure:"user" json:"user,omitempty"`
GroupName string `mapstructure:"group" json:"group,omitempty"`
UserName string `mapstructure:"user" json:"user,omitempty"`
GroupName string `mapstructure:"group" json:"group,omitempty"`
Env map[string]string `mapstructure:"env" json:"env,omitempty"`
Connections []TaskConnection `mapstructure:"connections" json:"connections,omitempty"`

Retries uint `mapstructure:"retries" json:"retries,omitempty"`
RetryDelay time.Duration `mapstructure:"retry-delay" json:"retry_delay,omitempty"`
Timeout time.Duration `mapstructure:"timeout" json:"timeout,omitempty"`
Env map[string]string `mapstructure:"env" json:"env,omitempty"`
// Retry & Timeout config
Retries uint `mapstructure:"retries" json:"retries,omitempty"`
RetryDelay time.Duration `mapstructure:"retry-delay" json:"retry_delay,omitempty"`
Timeout time.Duration `mapstructure:"timeout" json:"timeout,omitempty"`

// Hooks
OnDone []Task `mapstructure:"on-done" json:"on_done,omitempty"`
OnFail []Task `mapstructure:"on-fail" json:"on_fail,omitempty"`
}
TaskConnection struct {
Local bool
}
)
18 changes: 18 additions & 0 deletions core/cmd_connection/compiler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package connection

import (
"log"

"github.com/sirupsen/logrus"

"github.com/FMotalleb/crontab-go/abstraction"
"github.com/FMotalleb/crontab-go/config"
)

func CompileConnection(conn *config.TaskConnection, logger *logrus.Entry) abstraction.CmdConnection {
if conn.Local {
return NewLocalCMDConn(logger)
}
log.Fatalln("cannot compile given taskConnection", conn)
return nil
}
100 changes: 100 additions & 0 deletions core/cmd_connection/local.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package connection

import (
"bytes"
"context"
"fmt"
"os"
"os/exec"
"strings"

"github.com/sirupsen/logrus"

"github.com/FMotalleb/crontab-go/abstraction"
"github.com/FMotalleb/crontab-go/cmd"
"github.com/FMotalleb/crontab-go/config"
credential "github.com/FMotalleb/crontab-go/core/os_credential"
)

type Local struct {
log *logrus.Entry
cmd *exec.Cmd
}

func NewLocalCMDConn(log *logrus.Entry) abstraction.CmdConnection {
return &Local{
log: log.WithField(
"connection", "local",
),
}
}

// Prepare implements abstraction.CmdConnection.
func (l *Local) Prepare(ctx context.Context, task *config.Task) error {
shell := cmd.CFG.Shell
shellArgs := cmd.CFG.ShellArgs
env := os.Environ()
for key, val := range task.Env {
env = append(env, fmt.Sprintf("%s=%s", key, val))
switch strings.ToLower(key) {
case "shell":
l.log.Info("you've used `SHELL` env variable in command environments, overriding the global shell with:", val)
shell = val
case "shell_args":
l.log.Info("you've used `SHELL_ARGS` env variable in command environments, overriding the global shell_args with: ", val)
shellArgs = strings.Split(val, ";")
}
}
workingDir := task.WorkingDirectory
if workingDir == "" {
var e error
workingDir, e = os.Getwd()
if e != nil {
return fmt.Errorf("cannot get current working directory: %s", e)
}
}
l.cmd = exec.CommandContext(
ctx,
shell,
append(shellArgs, task.Command)...,
)
l.log = l.log.WithFields(
logrus.Fields{
"working_directory": workingDir,
"shell": shell,
"shell_args": shellArgs,
},
)
credential.SetUser(l.log, l.cmd, task.UserName, task.GroupName)
l.cmd.Env = env
l.cmd.Dir = workingDir

return nil
}

// Connect implements abstraction.CmdConnection.
func (l *Local) Connect() error {
return nil
}

// Disconnect implements abstraction.CmdConnection.
func (l *Local) Disconnect() error {
return nil
}

// Execute implements abstraction.CmdConnection.
func (l *Local) Execute() ([]byte, error) {
var res bytes.Buffer
l.cmd.Stdout = &res
l.cmd.Stderr = &res
if err := l.cmd.Start(); err != nil {
l.log.Warn("failed to start the command ", err)
return []byte{}, err
} else if err := l.cmd.Wait(); err != nil {
l.log.Warnf("command failed with answer: %s", strings.TrimSpace(res.String()))
l.log.Warn("failed to execute the command", err)
return res.Bytes(), err
} else {
return res.Bytes(), nil
}
}
Loading

0 comments on commit ed22ee6

Please sign in to comment.