Skip to content

Commit

Permalink
first release
Browse files Browse the repository at this point in the history
  • Loading branch information
SidorkinAlex committed Nov 24, 2024
1 parent b038580 commit 3f2729a
Show file tree
Hide file tree
Showing 13 changed files with 301 additions and 107 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
build:
go build -v ./cmd/CyclicCommandCheckerAndExecutive/CyclicCommandCheckerAndExecutive.go
$(eval NEW_VER:=$(shell cat version | cut -d '_' -f 2 ))
mkdir build
mkdir -p build
mv CyclicCommandCheckerAndExecutive ./build/CyclicCommandCheckerAndExecutive.$(NEW_VER)
104 changes: 104 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,54 @@
- **CLI Parameters**: Provides command-line options to start, stop, restart, or create jobs.
- **Logging**: Logs execution results and errors for debugging purposes.

## Setting up a command
to create a configuration file, use
```bash
nano /etc/CyclicCommandCheckerAndExecutive/config.json
```
Example of a configuration file:
```json
[
{
"checkingCommand": "cat /path/to/your/file.txt | tr -d '\n'",
"interval": 5,
"branchCommand": [
{
"resultExecution": "success",
"commands": [
"echo 'Command executed successfully.'",
"echo '' > /path/to/your/file.txt"
]
},
{
"resultExecution": "failure",
"commands": [
"bash command 1",
"bash command 2"
]
}
]
}
]
```

In this example, cat is used to display the contents of the specified file /path/to/your/file.txt . You should replace /path/to/your/file.txt to the actual path to the file you want to track.
```bash
cat /path/to/your/file.txt
```
interval: Sets the time interval (in seconds) between each execution of the checkingCommand command. In this case, the value is 5, which means that the command will be executed every 5 seconds.

branchCommand command: This section defines the actions to be performed based on the result of the checkingCommand command.

resultExecution - The first object in the array indicates the actions to be performed if the string success (resultExecution: "success") was in the file. Here it includes:

commands - the second object is an array of commands that will be executed if the result of executing the checkingCommand command matches the expected resultExecution

In this example, Command executed successfully will be output to the application logs. and the file /path/to/your/file.txt it will be overwritten with an empty string.

To use this configuration, save it in your configuration file (for example, /etc/CyclicCommandCheckerAndExecutive/config.json). The application will read this configuration and execute the cat command every 5 seconds, handling success and failure cases as defined.


#### Components
- **CliParamsParser**: Parses command-line arguments to determine the action to be performed.
- **Actions**: Contains functions for starting, stopping, restarting, and creating jobs.
Expand All @@ -22,8 +70,13 @@
- **FileUtils**: Utility functions for file operations.

#### Usage
#### sudo permissions are required to use the utility.

1. **Configuration**: Define your commands in `/etc/CyclicCommandCheckerAndExecutive/config.json`.
2. **Start the Application**: Use `-start` parameter to start the cyclic execution.
```bash
sudo ./build/CyclicCommandCheckerAndExecutive.0.0.1
```
3. **Stop the Application**: Use `-stop` parameter to stop the application.
4. **Restart the Application**: Use `-restart` parameter to restart the application.
5. **Create a Job**: Use `-create-job` parameter to create new job entries.
Expand All @@ -33,13 +86,64 @@
**CyclicCommandCheckerAndExecutive** — это приложение на языке Go, предназначенное для циклического выполнения команд и управления их выполнением на основе заранее заданных условий. Оно предоставляет функционал для запуска, остановки, перезапуска и создания заданий через параметры командной строки. Программа может работать в режиме демона, обеспечивая непрерывную работу и мониторинг.

#### Основные возможности
#### для использования утилиты требуются разрешения sudo
- **Циклическое выполнение команд**: Программа повторно выполняет команды, указанные в конфигурационном файле.
- **Логика ветвления**: Поддерживает условное выполнение команд на основе результатов ранее выполненных команд.
- **Режим демона**: Работает как фоновый сервис.
- **Настраиваемость**: Использует конфигурационный файл JSON для определения команд и интервалов выполнения.
- **Параметры командной строки**: Предоставляет опции командной строки для запуска, остановки, перезапуска или создания заданий.
- **Логирование**: Ведет журнал результатов выполнения и ошибок для целей отладки.

## Настройка комманд
для создания конфигурационного файла используйте
```bash
nano /etc/CyclicCommandCheckerAndExecutive/config.json
```
Пример конфигурационного файла:
```json
[
{
"checkingCommand": "cat /path/to/your/file.txt | tr -d '\n'",
"interval": 5,
"branchCommand": [
{
"resultExecution": "success",
"commands": [
"echo 'Command executed successfully.'",
"echo '' > /path/to/your/file.txt"
]
},
{
"resultExecution": "failure",
"commands": [
"log_error",
"send_alert"
]
}
]
}
]


```

В этом примере для отображения содержимого указанного файла используется cat /path/to/your/file.txt. Вам следует заменить /path/to/your/file.txt на фактический путь к файлу, который вы хотите отслеживать.
```bash
cat /path/to/your/file.txt
```
интервал: задает интервал времени (в секундах) между каждым выполнением команды checkingCommand. В данном случае значение равно 5, что означает, что команда будет выполняться каждые 5 секунд.

Команда branchCommand: В этом разделе определяются действия, которые необходимо выполнить на основе результата команды checkingCommand.

resultExecution - Первый объект в массиве указывает действия, которые необходимо выполнить в случае если в файле лежала строка success (resultExecution: "success"). Здесь он включает в себя:

commands - второй объект это массив команд, которые будут выполнены в случае если результат выполнения команды checkingCommand будет совпадать с ожидаемым resultExecution

В данном примере будет выведено в логи приложения Command executed successfully. и файл /path/to/your/file.txt будет перезаписан пустой строкой.

Чтобы использовать эту конфигурацию, сохраните ее в своем конфигурационном файле (например, /etc/CyclicCommandCheckerAndExecutive/config.json). Приложение будет считывать эту конфигурацию и выполнять команду cat каждые 5 секунд, обрабатывая случаи успешного выполнения и сбоя, как определено.


#### Компоненты
- **CliParamsParser**: Разбирает аргументы командной строки для определения действия, которое необходимо выполнить.
- **Actions**: Содержит функции для запуска, остановки, перезапуска и создания заданий.
Expand Down
22 changes: 22 additions & 0 deletions example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
{
"checkingCommand": "cat /path/to/your/file.txt | tr -d '\n'",
"interval": 5,
"branchCommand": [
{
"resultExecution": "success",
"commands": [
"echo 'Command executed successfully.'",
"echo '' > /path/to/your/file.txt"
]
},
{
"resultExecution": "failure",
"commands": [
"log_error",
"send_alert"
]
}
]
}
]
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
module github.com/SidorkinAlex/CyclicCommandCheckerAndExecutive

go 1.21.9

require github.com/sevlyar/go-daemon v0.1.6

require (
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
)
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/sevlyar/go-daemon v0.1.6 h1:EUh1MDjEM4BI109Jign0EaknA2izkOyi0LV3ro3QQGs=
github.com/sevlyar/go-daemon v0.1.6/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW3MebLDRKE=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
100 changes: 2 additions & 98 deletions internal/Actions/CreateJob.go
Original file line number Diff line number Diff line change
@@ -1,103 +1,7 @@
package Actions

import (
"bufio"
"encoding/json"
"fmt"
"github.com/SidorkinAlex/CyclicCommandCheckerAndExecutive/internal/Config"
"github.com/SidorkinAlex/CyclicCommandCheckerAndExecutive/internal/fileutils"
"os"
"strconv"
"strings"
)
import "fmt"

func CreateJob() {
configPath := Config.ConfigPath
config := Config.CreateConfig(configPath)

reader := bufio.NewReader(os.Stdin)

for {
fmt.Println("1. Create a new command for monitoring")
fmt.Println("2. Save changes and exit")
fmt.Print("Choose an option: ")
option, _ := reader.ReadString('\n')
option = strings.TrimSpace(option)

if option == "2" {
break
}

if option == "1" {
var newCommand Config.Command

fmt.Print("Enter the command for cyclic execution and monitoring: ")
command, _ := reader.ReadString('\n')
newCommand.Command = strings.TrimSpace(command)

fmt.Print("Enter the time interval in seconds for executing the above command: ")
intervalStr, _ := reader.ReadString('\n')
interval, err := strconv.Atoi(strings.TrimSpace(intervalStr))
if err != nil {
fmt.Println("Invalid interval. Please enter a number.")
continue
}
newCommand.Interval = interval

for {
fmt.Println("1. Add a new expected result")
fmt.Println("2. Finish configuration and proceed to save")
fmt.Print("Choose an option: ")
resultOption, _ := reader.ReadString('\n')
resultOption = strings.TrimSpace(resultOption)

if resultOption == "2" {
break
}

if resultOption == "1" {
var branch Config.BranchResultExecution

fmt.Print("Enter the expected result: ")
result, _ := reader.ReadString('\n')
branch.ResultExecution = strings.TrimSpace(result)

for {
fmt.Println("1. Enter a command to execute if the result matches")
fmt.Println("2. Create a new expected result")
fmt.Print("Choose an option: ")
commandOption, _ := reader.ReadString('\n')
commandOption = strings.TrimSpace(commandOption)

if commandOption == "2" {
break
}

if commandOption == "1" {
fmt.Print("Enter the command to execute if the result matches: ")
execCommand, _ := reader.ReadString('\n')
branch.Commands = append(branch.Commands, strings.TrimSpace(execCommand))
}
}

newCommand.BranchCommand = append(newCommand.BranchCommand, branch)
}
}

config = append(config, newCommand)
}
}

// Display and save the new configuration
configData, err := json.MarshalIndent(config, "", " ")
if err != nil {
fmt.Println("Error marshalling config:", err)
return
}

fmt.Println("New configuration:")
fmt.Println(string(configData))

fileutils.RewriteFile(string(configData), configPath)
fmt.Println("Configuration saved successfully.")
fmt.Println("this logic will appear in future versions")
}
4 changes: 3 additions & 1 deletion internal/Actions/Restart.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package Actions

func Restart() {
import "fmt"

func Restart() {
fmt.Println("this logic will appear in future versions")
}
67 changes: 65 additions & 2 deletions internal/Actions/Start.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,73 @@ package Actions

import (
"github.com/SidorkinAlex/CyclicCommandCheckerAndExecutive/internal/Config"
"github.com/SidorkinAlex/CyclicCommandCheckerAndExecutive/internal/RunController"
"github.com/SidorkinAlex/CyclicCommandCheckerAndExecutive/internal/fileutils"
"github.com/sevlyar/go-daemon"
"log"
"os/exec"
"time"
)

func Start() {
config := Config.CreateConfig("")
log.Print(config)
CommandConfig := Config.CreateConfig("")
//todo приложениие теряет контекст и аргументы , с которыми оно было запущено здесь дебажить конфиг и ключи
log.Println("CommandConfig = ")
log.Println(CommandConfig)

fileutils.CheckAndCreatDir(RunController.RunDirName)
fileutils.CheckAndCreatDir(RunController.LogDir)
cntxt := &daemon.Context{
PidFileName: RunController.RunDirName + RunController.PidFile,
PidFilePerm: 0644,
LogFileName: RunController.LogDir + ".sample.log",
LogFilePerm: 0640,
WorkDir: "/",
Umask: 027,
Args: []string{"[go-daemon CyclicCommandCheckerAndExecutive] -start"},
}

d, err := cntxt.Reborn()
if err != nil {
log.Fatal("Unable to run: ", err)
}
if d != nil {
return
}
defer cntxt.Release()

runCyclicCommand(CommandConfig)
}
func runCyclicCommand(CommandConfig Config.Config) {
for _, command := range CommandConfig {
//runCommand(command)
go runCommand(command)
}
RunController.RunningController()
}

func runCommand(command Config.Command) {
for {
commandResult, _ := exec.Command("/bin/sh", "-c", command.Command).Output()

log.Println("command from command`" + command.Command + "` result is `" + string(commandResult) + "`")
for _, branch := range command.BranchCommand {
log.Println("branch.ResultExecution=`" + branch.ResultExecution + "` commandResult=`" + string(commandResult) + "`")
if branch.ResultExecution == string(commandResult) {
executeCommands(branch.Commands)
}
}
if string(commandResult) == "" {
log.Fatalln("test")
}
log.Println(string(commandResult))
time.Sleep(time.Duration(command.Interval) * time.Second)
}
}

func executeCommands(commands []string) {
for _, cmd := range commands {
result, _ := exec.Command("/bin/sh", "-c", cmd).Output()
log.Println("command:" + cmd + "execute from result:" + string(result))
}
}
Loading

0 comments on commit 3f2729a

Please sign in to comment.