279 lines
7.2 KiB
Go
279 lines
7.2 KiB
Go
package grouptasks
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"janex/admin-dashboard-backend/modules/cache"
|
|
"janex/admin-dashboard-backend/modules/database"
|
|
"janex/admin-dashboard-backend/modules/structs"
|
|
"janex/admin-dashboard-backend/modules/utils"
|
|
"janex/admin-dashboard-backend/socketclients"
|
|
"os"
|
|
"os/exec"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
var root = "./groupTasks/groups/"
|
|
|
|
func LoadGroups(category string) {
|
|
entries, err := os.ReadDir(root)
|
|
|
|
if err != nil {
|
|
log.Error().Msg("Failed to read groups directory, error: " + err.Error())
|
|
return
|
|
}
|
|
|
|
if category != "" {
|
|
cache.RemoveAllCategoryGroupsByCategory(category)
|
|
}
|
|
|
|
var updatedGroups []structs.Group
|
|
|
|
for _, entry := range entries {
|
|
files, err := os.ReadDir(root + entry.Name())
|
|
|
|
if err != nil {
|
|
log.Error().Msg("Failed to read groups directory files, error: " + err.Error())
|
|
return
|
|
}
|
|
|
|
for _, file := range files {
|
|
if file.Name() == "index.json" {
|
|
content, err := os.ReadFile(root + entry.Name() + "/index.json")
|
|
|
|
if err != nil {
|
|
log.Error().Msg("Failed to read file content, error: " + err.Error())
|
|
return
|
|
}
|
|
|
|
var group structs.Group
|
|
|
|
json.Unmarshal(content, &group)
|
|
|
|
group.Id = entry.Name()
|
|
|
|
if category == "" || group.Category == category {
|
|
cache.AddCategoryGroup(group)
|
|
|
|
updatedGroups = append(updatedGroups, group)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if category != "" {
|
|
socketclients.BroadcastMessage(structs.SendSocketMessage{
|
|
Cmd: utils.SentCmdGroupTasksReloaded,
|
|
Body: struct {
|
|
Category string
|
|
UpdatedGroups []structs.Group
|
|
}{
|
|
Category: category,
|
|
UpdatedGroups: updatedGroups,
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
const (
|
|
RunGroupTaskStartTypeNormal = 0
|
|
RunGroupTaskStartTypeTryAgain = 1
|
|
)
|
|
|
|
type RunGroupTaskArgs struct {
|
|
StartType uint8
|
|
GroupTaskId string
|
|
Category string
|
|
GroupId string
|
|
Step uint8
|
|
TaskStepId string
|
|
GlobalInputs string
|
|
TaskInputs string
|
|
}
|
|
|
|
type InputParameters struct {
|
|
ParameterName string `json:"parameterName"`
|
|
Value string `json:"value"`
|
|
}
|
|
|
|
func RunGroupTask(args RunGroupTaskArgs) {
|
|
categoryGroup := GetCategoryGroupTaskByCategoryAndGroupId(args.Category, args.GroupId)
|
|
|
|
groupTaskStep := structs.GroupTaskSteps{
|
|
GroupTasksId: args.GroupTaskId,
|
|
Step: args.Step,
|
|
Status: structs.GroupTasksStatusRunning,
|
|
Inputs: args.TaskInputs,
|
|
StartedAt: time.Now(),
|
|
}
|
|
|
|
// task type
|
|
if args.StartType == RunGroupTaskStartTypeNormal {
|
|
groupTaskStep.Id = uuid.New().String()
|
|
|
|
database.DB.Create(&groupTaskStep)
|
|
|
|
socketclients.BroadcastMessage(structs.SendSocketMessage{
|
|
Cmd: utils.SentCmdNewGroupTaskStep,
|
|
Body: groupTaskStep,
|
|
})
|
|
} else if args.StartType == RunGroupTaskStartTypeTryAgain {
|
|
groupTaskStep.Id = args.TaskStepId
|
|
|
|
updateGroupTaskSteps(groupTaskStep)
|
|
}
|
|
|
|
// set group task to running
|
|
dbGroupTask := updateGroupTask(groupTaskStep.GroupTasksId, structs.GroupTasks{
|
|
Status: structs.GroupTasksStatusRunning,
|
|
})
|
|
|
|
// global inputs
|
|
var globalInputParameters []InputParameters
|
|
|
|
if len(args.GlobalInputs) > 0 { // global inputs given in args because the group task was just created
|
|
if err := json.Unmarshal([]byte(args.GlobalInputs), &globalInputParameters); err != nil {
|
|
log.Error().Msgf("err unmarshalling global inputs %s", err.Error())
|
|
}
|
|
} else { // global inputs not given in args - fetch it from the database
|
|
if err := json.Unmarshal([]byte(dbGroupTask.GlobalInputs), &globalInputParameters); err != nil {
|
|
log.Error().Msgf("err unmarshalling global inputs %s", err.Error())
|
|
}
|
|
}
|
|
|
|
// task parameters
|
|
commandArgs := []string{root + categoryGroup.Id + "/" + categoryGroup.Tasks[args.Step-1].ScriptPath}
|
|
|
|
if len(categoryGroup.Tasks[args.Step-1].Parameters) != 0 && len(args.TaskInputs) == 0 {
|
|
updateGroupTask(groupTaskStep.GroupTasksId, structs.GroupTasks{
|
|
Status: structs.GroupTasksStatusInputRequired,
|
|
})
|
|
|
|
groupTaskStep.Status = structs.GroupTasksStatusInputRequired
|
|
|
|
updateGroupTaskSteps(groupTaskStep)
|
|
return
|
|
} else if len(args.TaskInputs) > 0 {
|
|
var taskParameterInputs []InputParameters
|
|
|
|
if err := json.Unmarshal([]byte(args.TaskInputs), &taskParameterInputs); err != nil {
|
|
log.Error().Msgf("err unmarshalling task parameter inputs %s", err.Error())
|
|
}
|
|
|
|
for _, taskParameterInput := range taskParameterInputs {
|
|
commandArgs = append(commandArgs, taskParameterInput.Value)
|
|
}
|
|
}
|
|
|
|
// execute script
|
|
cmd, err := exec.Command("python3", commandArgs...).Output()
|
|
|
|
cmdLog := string(cmd)
|
|
|
|
if err != nil {
|
|
if exitErr, ok := err.(*exec.ExitError); ok {
|
|
exitCode := exitErr.ExitCode()
|
|
log.Error().Msgf("exit code %d", exitCode)
|
|
cmdLog += fmt.Sprintf("\nExit code: %v", exitCode)
|
|
}
|
|
|
|
log.Error().Msgf("error exec command %s", err.Error())
|
|
groupTaskStep.Status = structs.GroupTasksStatusFailed
|
|
} else {
|
|
groupTaskStep.Status = structs.GroupTasksStatusFinished
|
|
}
|
|
|
|
fmt.Println(cmdLog)
|
|
|
|
groupTaskStep.Log = cmdLog
|
|
groupTaskStep.EndedAt = time.Now()
|
|
|
|
updateGroupTaskSteps(groupTaskStep)
|
|
|
|
if int(args.Step) < len(categoryGroup.Tasks) {
|
|
if groupTaskStep.Status == structs.GroupTasksStatusFailed {
|
|
// set group task to failed
|
|
updateGroupTask(groupTaskStep.GroupTasksId, structs.GroupTasks{
|
|
Status: structs.GroupTasksStatusFailed,
|
|
})
|
|
} else {
|
|
args.StartType = RunGroupTaskStartTypeNormal
|
|
args.Step = args.Step + 1
|
|
|
|
updateGroupTask(groupTaskStep.GroupTasksId, structs.GroupTasks{
|
|
CurrentTasksStep: args.Step,
|
|
})
|
|
|
|
// clear task parameters, because otherwise the next task would have the parameters from the previous task
|
|
args.TaskInputs = ""
|
|
|
|
RunGroupTask(args)
|
|
}
|
|
} else {
|
|
// set group task to finished
|
|
updateGroupTask(groupTaskStep.GroupTasksId, structs.GroupTasks{
|
|
Status: structs.GroupTasksStatusFinished,
|
|
EndedAt: time.Now(),
|
|
})
|
|
}
|
|
}
|
|
|
|
// Updates group task and send it to websocket users
|
|
func updateGroupTask(groupTasksId string, updates structs.GroupTasks) structs.GroupTasks {
|
|
database.DB.Model(&structs.GroupTasks{}).Where("id = ?", groupTasksId).Updates(updates)
|
|
|
|
var dbGroupTask structs.GroupTasks
|
|
|
|
database.DB.First(&dbGroupTask, "id = ?", groupTasksId)
|
|
|
|
socketclients.BroadcastMessage(structs.SendSocketMessage{
|
|
Cmd: utils.SentCmdUpdateGroupTask,
|
|
Body: dbGroupTask,
|
|
})
|
|
|
|
return dbGroupTask
|
|
}
|
|
|
|
// Updates group task steps and send it to websocket users
|
|
func updateGroupTaskSteps(groupTaskStep structs.GroupTaskSteps) {
|
|
database.DB.Model(&structs.GroupTaskSteps{}).Where("id = ?", groupTaskStep.Id).Updates(groupTaskStep)
|
|
|
|
socketclients.BroadcastMessage(structs.SendSocketMessage{
|
|
Cmd: utils.SentCmdUpdateGroupTaskStep,
|
|
Body: groupTaskStep,
|
|
})
|
|
}
|
|
|
|
func GetAllGroupTasks() []structs.GroupTasks {
|
|
var groupTasks []structs.GroupTasks
|
|
|
|
database.DB.Find(&groupTasks)
|
|
|
|
return groupTasks
|
|
}
|
|
|
|
func GetAllGroupTasksSteps() []structs.GroupTaskSteps {
|
|
var groupTaskStepsLogs []structs.GroupTaskSteps
|
|
|
|
database.DB.Find(&groupTaskStepsLogs)
|
|
|
|
return groupTaskStepsLogs
|
|
}
|
|
|
|
func GetCategoryGroupTaskByCategoryAndGroupId(category string, groupId string) structs.Group {
|
|
for _, categoryGroup := range cache.GetCategoryGroups() {
|
|
if categoryGroup.Category == category {
|
|
for _, group := range categoryGroup.Groups {
|
|
if group.Id == groupId {
|
|
return group
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return structs.Group{}
|
|
}
|