Files
osmedeus/internal/distributed/task.go
T
j3ssie d5b5564149 feat: add queue system for delayed task execution
- Add QueuePoller for dual-source (DB + Redis) task polling with concurrent execution
- Add worker queue subcommands (list, new, run) for managing queued tasks
- Add uninstall command to safely remove Osmedeus installation
- Add input validation to prevent command injection via dangerous shell characters
- Add queue run support via --queue and --queue-run flags in osmedeus run
- Add queue polling to server with --no-queue-polling flag to disable it
- Support queuing tasks from both CLI and API with deduplication across sources
2026-02-15 18:13:57 +07:00

171 lines
5.7 KiB
Go

package distributed
import (
"encoding/json"
"time"
)
// TaskStatus represents the status of a distributed task
type TaskStatus string
const (
TaskStatusPending TaskStatus = "pending"
TaskStatusRunning TaskStatus = "running"
TaskStatusCompleted TaskStatus = "completed"
TaskStatusFailed TaskStatus = "failed"
)
// Task represents a distributed scan task
type Task struct {
ID string `json:"id"`
ScanID string `json:"scan_id,omitempty"`
WorkflowName string `json:"workflow_name"`
WorkflowKind string `json:"workflow_kind"` // "module" or "flow"
Target string `json:"target"`
Params map[string]interface{} `json:"params,omitempty"`
Status TaskStatus `json:"status"`
WorkerID string `json:"worker_id,omitempty"`
InputIsFile bool `json:"input_is_file,omitempty"`
InputFilePath string `json:"input_file_path,omitempty"`
CreatedAt time.Time `json:"created_at"`
StartedAt *time.Time `json:"started_at,omitempty"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
Error string `json:"error,omitempty"`
}
// TaskResult represents the result of a completed task
type TaskResult struct {
TaskID string `json:"task_id"`
Status TaskStatus `json:"status"`
Output string `json:"output,omitempty"`
Error string `json:"error,omitempty"`
Exports map[string]interface{} `json:"exports,omitempty"`
CompletedAt time.Time `json:"completed_at"`
}
// WorkerInfo represents information about a worker node
type WorkerInfo struct {
ID string `json:"id"`
Hostname string `json:"hostname"`
Status string `json:"status"` // "idle", "busy", "offline"
CurrentTaskID string `json:"current_task_id,omitempty"`
JoinedAt time.Time `json:"joined_at"`
LastHeartbeat time.Time `json:"last_heartbeat"`
TasksComplete int `json:"tasks_complete"`
TasksFailed int `json:"tasks_failed"`
IPAddress string `json:"ip_address,omitempty"`
PublicIP string `json:"public_ip,omitempty"`
SSHEnabled bool `json:"ssh_enabled,omitempty"`
SSHKeysPath string `json:"ssh_keys_path,omitempty"`
Alias string `json:"alias,omitempty"`
}
// NewTask creates a new task with the given parameters
func NewTask(id, workflowName, workflowKind, target string, params map[string]interface{}) *Task {
return &Task{
ID: id,
WorkflowName: workflowName,
WorkflowKind: workflowKind,
Target: target,
Params: params,
Status: TaskStatusPending,
CreatedAt: time.Now(),
}
}
// MarshalJSON serializes a task to JSON
func (t *Task) MarshalJSON() ([]byte, error) {
type Alias Task
return json.Marshal(&struct {
*Alias
}{
Alias: (*Alias)(t),
})
}
// UnmarshalTask deserializes a task from JSON
func UnmarshalTask(data []byte) (*Task, error) {
var task Task
if err := json.Unmarshal(data, &task); err != nil {
return nil, err
}
return &task, nil
}
// MarshalJSON serializes a task result to JSON
func (r *TaskResult) MarshalJSON() ([]byte, error) {
type Alias TaskResult
return json.Marshal(&struct {
*Alias
}{
Alias: (*Alias)(r),
})
}
// UnmarshalTaskResult deserializes a task result from JSON
func UnmarshalTaskResult(data []byte) (*TaskResult, error) {
var result TaskResult
if err := json.Unmarshal(data, &result); err != nil {
return nil, err
}
return &result, nil
}
// MarshalJSON serializes worker info to JSON
func (w *WorkerInfo) MarshalJSON() ([]byte, error) {
type Alias WorkerInfo
return json.Marshal(&struct {
*Alias
}{
Alias: (*Alias)(w),
})
}
// UnmarshalWorkerInfo deserializes worker info from JSON
func UnmarshalWorkerInfo(data []byte) (*WorkerInfo, error) {
var info WorkerInfo
if err := json.Unmarshal(data, &info); err != nil {
return nil, err
}
return &info, nil
}
// MarkRunning marks the task as running with the given worker
func (t *Task) MarkRunning(workerID string) {
t.Status = TaskStatusRunning
t.WorkerID = workerID
now := time.Now()
t.StartedAt = &now
}
// MarkCompleted marks the task as completed
func (t *Task) MarkCompleted() {
t.Status = TaskStatusCompleted
now := time.Now()
t.CompletedAt = &now
}
// ExecuteRequest represents a request from a worker to execute something on the master or another worker.
// ExecuteType "func" executes a utility function expression.
// ExecuteType "run" submits a workflow task to the pending queue.
// TargetRole controls where the request is executed: "master" or "worker".
type ExecuteRequest struct {
ExecuteType string `json:"execute_type"` // "func", "run", or "bash"
TargetRole string `json:"target_role"` // "master" or "worker"
Data string `json:"data,omitempty"` // function expression (for "func"), workflow name (for "run"), or command (for "bash")
Target string `json:"target,omitempty"` // target (for "run")
Params string `json:"params,omitempty"` // comma-separated key=value (for "run")
TargetScope string `json:"target_scope,omitempty"` // For worker-targeted: "all", alias, worker ID, or public IP
Action string `json:"action,omitempty"` // deprecated: use ExecuteType instead
Expr string `json:"expr,omitempty"` // deprecated: use Data instead
Workflow string `json:"workflow,omitempty"` // deprecated: use Data instead (for "run")
}
// MarkFailed marks the task as failed with an error message
func (t *Task) MarkFailed(err string) {
t.Status = TaskStatusFailed
t.Error = err
now := time.Now()
t.CompletedAt = &now
}