Compare commits
21 Commits
a16ac8f627
...
main
Author | SHA1 | Date | |
---|---|---|---|
4a79011793 | |||
0b62ac9ecd | |||
c9b14730ad | |||
2ee8a95a90 | |||
8bc1759dcb | |||
e60b9f62f1 | |||
5d241e9ade | |||
b8c8da9e31 | |||
55a05a5571 | |||
2bfe4161b2 | |||
0b1d9907a7 | |||
c78761fe20 | |||
2e8ec1735a | |||
29d0d25a3b | |||
3f01074e3f | |||
532cda72d3 | |||
0e545e56de | |||
92b9c356b8 | |||
c86165f88c | |||
b2eb9d3116 | |||
79d66e4b6b |
@@ -11,7 +11,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/mycelium_client"
|
||||
"git.threefold.info/herocode/heroagent/pkg/mycelium_client"
|
||||
)
|
||||
|
||||
type config struct {
|
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/mycelium_client"
|
||||
"git.threefold.info/herocode/heroagent/pkg/mycelium_client"
|
||||
)
|
||||
|
||||
func main() {
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.threefold.info/herocode/heroagent/pkg/system/stats"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
@@ -3,7 +3,7 @@ package api
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/sal/executor"
|
||||
"git.threefold.info/herocode/heroagent/pkg/sal/executor"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
@@ -7,9 +7,9 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"git.threefold.info/herocode/heroagent/pkg/processmanager"
|
||||
"git.threefold.info/herocode/heroagent/pkg/processmanager/interfaces"
|
||||
"git.threefold.info/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
@@ -12,16 +12,16 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroagent/api"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroagent/handlers"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroagent/pages"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/sal/executor"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/servers/redisserver"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroagent/api"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroagent/handlers"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroagent/pages"
|
||||
"git.threefold.info/herocode/heroagent/pkg/processmanager"
|
||||
"git.threefold.info/herocode/heroagent/pkg/sal/executor"
|
||||
"git.threefold.info/herocode/heroagent/pkg/servers/redisserver"
|
||||
"git.threefold.info/herocode/heroagent/pkg/system/stats"
|
||||
|
||||
// "github.com/freeflowuniverse/heroagent/pkg/vfs/interfaces"
|
||||
// "github.com/freeflowuniverse/heroagent/pkg/vfs/interfaces/mock"
|
||||
// "git.threefold.info/herocode/heroagent/pkg/vfs/interfaces"
|
||||
// "git.threefold.info/herocode/heroagent/pkg/vfs/interfaces/mock"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
@@ -239,7 +239,7 @@ func (hl *HeroLauncher) GetUptime() string {
|
||||
func (hl *HeroLauncher) startProcessManager() error {
|
||||
_, filename, _, _ := runtime.Caller(0)
|
||||
projectRoot := filepath.Join(filepath.Dir(filename), "../..")
|
||||
processManagerPath := filepath.Join(projectRoot, "cmd/processmanager/main.go")
|
||||
processManagerPath := filepath.Join(projectRoot, "pkg/processmanager/examples/openrpc/main.go")
|
||||
|
||||
log.Printf("Starting process manager from: %s", processManagerPath)
|
||||
|
@@ -3,40 +3,40 @@ package handlers
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv" // Added strconv for JobID parsing
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/herojobs"
|
||||
"git.threefold.info/herocode/heroagent/pkg/herojobs"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// HeroJobsClientInterface defines the interface for the HeroJobs client
|
||||
type HeroJobsClientInterface interface {
|
||||
Connect() error
|
||||
Close() error
|
||||
SubmitJob(job *herojobs.Job) (*herojobs.Job, error)
|
||||
GetJob(jobID string) (*herojobs.Job, error)
|
||||
DeleteJob(jobID string) error
|
||||
ListJobs(circleID, topic string) ([]string, error)
|
||||
// RedisClientInterface defines the methods JobHandler needs from a HeroJobs Redis client.
|
||||
type RedisClientInterface interface {
|
||||
StoreJob(job *herojobs.Job) error
|
||||
EnqueueJob(job *herojobs.Job) error
|
||||
GetJob(jobID interface{}) (*herojobs.Job, error) // Changed jobID type to interface{}
|
||||
ListJobs(circleID, topic string) ([]uint32, error)
|
||||
QueueSize(circleID, topic string) (int64, error)
|
||||
QueueEmpty(circleID, topic string) error
|
||||
QueueGet(circleID, topic string) (*herojobs.Job, error)
|
||||
CreateJob(circleID, topic, sessionKey, heroScript, rhaiScript string) (*herojobs.Job, error)
|
||||
// herojobs.Job also has Load() and Save() methods, but those are on the Job object itself,
|
||||
// not typically part of the client interface unless the client is a facade for all job operations.
|
||||
}
|
||||
|
||||
// JobHandler handles job-related routes
|
||||
type JobHandler struct {
|
||||
client HeroJobsClientInterface
|
||||
client RedisClientInterface // Changed to use the interface
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
// NewJobHandler creates a new JobHandler
|
||||
func NewJobHandler(socketPath string, logger *log.Logger) (*JobHandler, error) {
|
||||
client, err := herojobs.NewClient(socketPath)
|
||||
func NewJobHandler(redisAddr string, logger *log.Logger) (*JobHandler, error) {
|
||||
redisClient, err := herojobs.NewRedisClient(redisAddr, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create HeroJobs client: %w", err)
|
||||
return nil, fmt.Errorf("failed to create HeroJobs Redis client: %w", err)
|
||||
}
|
||||
|
||||
// *herojobs.RedisClient must implement RedisClientInterface.
|
||||
// This assignment is valid if *herojobs.RedisClient has all methods of RedisClientInterface.
|
||||
return &JobHandler{
|
||||
client: client,
|
||||
client: redisClient,
|
||||
logger: logger,
|
||||
}, nil
|
||||
}
|
||||
@@ -76,14 +76,6 @@ func (h *JobHandler) RegisterRoutes(app *fiber.App) {
|
||||
// @Router /api/jobs/submit [post]
|
||||
// @Router /admin/jobs/submit [post]
|
||||
func (h *JobHandler) submitJob(c *fiber.Ctx) error {
|
||||
// Connect to the HeroJobs server
|
||||
if err := h.client.Connect(); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to connect to HeroJobs server: %v", err),
|
||||
})
|
||||
}
|
||||
defer h.client.Close()
|
||||
|
||||
// Parse job from request body
|
||||
var job herojobs.Job
|
||||
if err := c.BodyParser(&job); err != nil {
|
||||
@@ -92,15 +84,32 @@ func (h *JobHandler) submitJob(c *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
// Submit job
|
||||
submittedJob, err := h.client.SubmitJob(&job)
|
||||
if err != nil {
|
||||
// Save job to OurDB (this assigns/confirms JobID)
|
||||
if err := job.Save(); err != nil {
|
||||
h.logger.Printf("Failed to save job to OurDB: %v", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to submit job: %v", err),
|
||||
"error": fmt.Sprintf("Failed to save job: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(submittedJob)
|
||||
// Store job in Redis
|
||||
if err := h.client.StoreJob(&job); err != nil {
|
||||
h.logger.Printf("Failed to store job in Redis: %v", err)
|
||||
// Attempt to roll back or log, but proceed to enqueue if critical
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to store job in Redis: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
// Enqueue job in Redis
|
||||
if err := h.client.EnqueueJob(&job); err != nil {
|
||||
h.logger.Printf("Failed to enqueue job in Redis: %v", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to enqueue job: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(job)
|
||||
}
|
||||
|
||||
// @Summary Get a job
|
||||
@@ -114,29 +123,37 @@ func (h *JobHandler) submitJob(c *fiber.Ctx) error {
|
||||
// @Router /api/jobs/get/{id} [get]
|
||||
// @Router /admin/jobs/get/{id} [get]
|
||||
func (h *JobHandler) getJob(c *fiber.Ctx) error {
|
||||
// Connect to the HeroJobs server
|
||||
if err := h.client.Connect(); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to connect to HeroJobs server: %v", err),
|
||||
})
|
||||
}
|
||||
defer h.client.Close()
|
||||
|
||||
// Get job ID from path parameter
|
||||
jobID := c.Params("id")
|
||||
if jobID == "" {
|
||||
jobIDStr := c.Params("id")
|
||||
if jobIDStr == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"error": "Job ID is required",
|
||||
})
|
||||
}
|
||||
|
||||
// Get job
|
||||
// Convert jobID string to uint32
|
||||
jobID64, err := strconv.ParseUint(jobIDStr, 10, 32)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Invalid Job ID format: %s. %v", jobIDStr, err),
|
||||
})
|
||||
}
|
||||
jobID := uint32(jobID64)
|
||||
|
||||
// Get job from Redis first
|
||||
job, err := h.client.GetJob(jobID)
|
||||
if err != nil {
|
||||
// If not found in Redis (e.g. redis.Nil or other error), try OurDB
|
||||
h.logger.Printf("Job %d not found in Redis or error: %v. Trying OurDB.", jobID, err)
|
||||
retrievedJob := &herojobs.Job{JobID: jobID}
|
||||
if loadErr := retrievedJob.Load(); loadErr != nil {
|
||||
h.logger.Printf("Failed to load job %d from OurDB: %v", jobID, loadErr)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to get job: %v", err),
|
||||
"error": fmt.Sprintf("Failed to get job %d: %v / %v", jobID, err, loadErr),
|
||||
})
|
||||
}
|
||||
job = retrievedJob // Use the job loaded from OurDB
|
||||
}
|
||||
|
||||
return c.JSON(job)
|
||||
}
|
||||
@@ -152,32 +169,22 @@ func (h *JobHandler) getJob(c *fiber.Ctx) error {
|
||||
// @Router /api/jobs/delete/{id} [delete]
|
||||
// @Router /admin/jobs/delete/{id} [delete]
|
||||
func (h *JobHandler) deleteJob(c *fiber.Ctx) error {
|
||||
// Connect to the HeroJobs server
|
||||
if err := h.client.Connect(); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to connect to HeroJobs server: %v", err),
|
||||
})
|
||||
}
|
||||
defer h.client.Close()
|
||||
|
||||
// Get job ID from path parameter
|
||||
jobID := c.Params("id")
|
||||
if jobID == "" {
|
||||
jobIDStr := c.Params("id")
|
||||
if jobIDStr == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"error": "Job ID is required",
|
||||
})
|
||||
}
|
||||
|
||||
// Delete job
|
||||
if err := h.client.DeleteJob(jobID); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to delete job: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"status": "success",
|
||||
"message": fmt.Sprintf("Job %s deleted successfully", jobID),
|
||||
// Deleting jobs requires removing from OurDB and Redis.
|
||||
// This functionality is not directly provided by RedisClient.DeleteJob
|
||||
// and OurDB job deletion is not specified in README.
|
||||
// For now, returning not implemented.
|
||||
h.logger.Printf("Attempt to delete job %s - not implemented", jobIDStr)
|
||||
return c.Status(fiber.StatusNotImplemented).JSON(fiber.Map{
|
||||
"error": "Job deletion is not implemented",
|
||||
"message": fmt.Sprintf("Job %s deletion requested but not implemented.", jobIDStr),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -193,14 +200,6 @@ func (h *JobHandler) deleteJob(c *fiber.Ctx) error {
|
||||
// @Router /api/jobs/list [get]
|
||||
// @Router /admin/jobs/list [get]
|
||||
func (h *JobHandler) listJobs(c *fiber.Ctx) error {
|
||||
// Connect to the HeroJobs server
|
||||
if err := h.client.Connect(); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to connect to HeroJobs server: %v", err),
|
||||
})
|
||||
}
|
||||
defer h.client.Close()
|
||||
|
||||
// Get parameters from query
|
||||
circleID := c.Query("circleid")
|
||||
if circleID == "" {
|
||||
@@ -242,14 +241,6 @@ func (h *JobHandler) listJobs(c *fiber.Ctx) error {
|
||||
// @Router /api/jobs/queue/size [get]
|
||||
// @Router /admin/jobs/queue/size [get]
|
||||
func (h *JobHandler) queueSize(c *fiber.Ctx) error {
|
||||
// Connect to the HeroJobs server
|
||||
if err := h.client.Connect(); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to connect to HeroJobs server: %v", err),
|
||||
})
|
||||
}
|
||||
defer h.client.Close()
|
||||
|
||||
// Get parameters from query
|
||||
circleID := c.Query("circleid")
|
||||
if circleID == "" {
|
||||
@@ -291,14 +282,6 @@ func (h *JobHandler) queueSize(c *fiber.Ctx) error {
|
||||
// @Router /api/jobs/queue/empty [post]
|
||||
// @Router /admin/jobs/queue/empty [post]
|
||||
func (h *JobHandler) queueEmpty(c *fiber.Ctx) error {
|
||||
// Connect to the HeroJobs server
|
||||
if err := h.client.Connect(); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to connect to HeroJobs server: %v", err),
|
||||
})
|
||||
}
|
||||
defer h.client.Close()
|
||||
|
||||
// Parse parameters from request body
|
||||
var params struct {
|
||||
CircleID string `json:"circleid"`
|
||||
@@ -347,14 +330,6 @@ func (h *JobHandler) queueEmpty(c *fiber.Ctx) error {
|
||||
// @Router /api/jobs/queue/get [get]
|
||||
// @Router /admin/jobs/queue/get [get]
|
||||
func (h *JobHandler) queueGet(c *fiber.Ctx) error {
|
||||
// Connect to the HeroJobs server
|
||||
if err := h.client.Connect(); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to connect to HeroJobs server: %v", err),
|
||||
})
|
||||
}
|
||||
defer h.client.Close()
|
||||
|
||||
// Get parameters from query
|
||||
circleID := c.Query("circleid")
|
||||
if circleID == "" {
|
||||
@@ -370,14 +345,40 @@ func (h *JobHandler) queueGet(c *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
// Get job from queue
|
||||
job, err := h.client.QueueGet(circleID, topic)
|
||||
// Get list of job IDs (uint32) from the queue (non-destructive)
|
||||
jobIDs, err := h.client.ListJobs(circleID, topic)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to get job from queue: %v", err),
|
||||
"error": fmt.Sprintf("Failed to list jobs in queue: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
if len(jobIDs) == 0 {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
|
||||
"error": "Queue is empty or no jobs found",
|
||||
})
|
||||
}
|
||||
|
||||
// Take the first job ID from the list (it's already uint32)
|
||||
jobIDToFetch := jobIDs[0]
|
||||
|
||||
// Get the actual job details using the ID
|
||||
job, err := h.client.GetJob(jobIDToFetch)
|
||||
if err != nil {
|
||||
// If not found in Redis (e.g. redis.Nil or other error), try OurDB
|
||||
h.logger.Printf("Job %d (from queue list) not found in Redis or error: %v. Trying OurDB.", jobIDToFetch, err)
|
||||
retrievedJob := &herojobs.Job{JobID: jobIDToFetch} // Ensure CircleID and Topic are set if Load needs them
|
||||
retrievedJob.CircleID = circleID // Needed for Load if path depends on it
|
||||
retrievedJob.Topic = topic // Needed for Load if path depends on it
|
||||
if loadErr := retrievedJob.Load(); loadErr != nil {
|
||||
h.logger.Printf("Failed to load job %d from OurDB: %v", jobIDToFetch, loadErr)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to get job %d from queue (Redis err: %v / OurDB err: %v)", jobIDToFetch, err, loadErr),
|
||||
})
|
||||
}
|
||||
job = retrievedJob // Use the job loaded from OurDB
|
||||
}
|
||||
|
||||
return c.JSON(job)
|
||||
}
|
||||
|
||||
@@ -393,51 +394,92 @@ func (h *JobHandler) queueGet(c *fiber.Ctx) error {
|
||||
// @Router /api/jobs/create [post]
|
||||
// @Router /admin/jobs/create [post]
|
||||
func (h *JobHandler) createJob(c *fiber.Ctx) error {
|
||||
// Connect to the HeroJobs server
|
||||
if err := h.client.Connect(); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to connect to HeroJobs server: %v", err),
|
||||
})
|
||||
}
|
||||
defer h.client.Close()
|
||||
|
||||
// Parse parameters from request body
|
||||
var params struct {
|
||||
var reqBody struct {
|
||||
CircleID string `json:"circleid"`
|
||||
Topic string `json:"topic"`
|
||||
SessionKey string `json:"sessionkey"`
|
||||
HeroScript string `json:"heroscript"`
|
||||
RhaiScript string `json:"rhaiscript"`
|
||||
Params string `json:"params"`
|
||||
ParamsType string `json:"paramstype"`
|
||||
Timeout int64 `json:"timeout"` // Optional: allow timeout override
|
||||
Log bool `json:"log"` // Optional: allow log enabling
|
||||
}
|
||||
if err := c.BodyParser(¶ms); err != nil {
|
||||
if err := c.BodyParser(&reqBody); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to parse parameters: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
if params.CircleID == "" {
|
||||
if reqBody.CircleID == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"error": "Circle ID is required",
|
||||
})
|
||||
}
|
||||
|
||||
if params.Topic == "" {
|
||||
if reqBody.Topic == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"error": "Topic is required",
|
||||
})
|
||||
}
|
||||
if reqBody.Params == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"error": "Params are required",
|
||||
})
|
||||
}
|
||||
if reqBody.ParamsType == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"error": "ParamsType is required",
|
||||
})
|
||||
}
|
||||
|
||||
// Create job
|
||||
job, err := h.client.CreateJob(
|
||||
params.CircleID,
|
||||
params.Topic,
|
||||
params.SessionKey,
|
||||
params.HeroScript,
|
||||
params.RhaiScript,
|
||||
)
|
||||
if err != nil {
|
||||
// Create a new job instance
|
||||
job := herojobs.NewJob() // Initializes with defaults
|
||||
job.CircleID = reqBody.CircleID
|
||||
job.Topic = reqBody.Topic
|
||||
job.SessionKey = reqBody.SessionKey
|
||||
job.Params = reqBody.Params
|
||||
|
||||
// Convert ParamsType string to herojobs.ParamsType
|
||||
switch herojobs.ParamsType(reqBody.ParamsType) {
|
||||
case herojobs.ParamsTypeHeroScript:
|
||||
job.ParamsType = herojobs.ParamsTypeHeroScript
|
||||
case herojobs.ParamsTypeRhaiScript:
|
||||
job.ParamsType = herojobs.ParamsTypeRhaiScript
|
||||
case herojobs.ParamsTypeOpenRPC:
|
||||
job.ParamsType = herojobs.ParamsTypeOpenRPC
|
||||
case herojobs.ParamsTypeAI:
|
||||
job.ParamsType = herojobs.ParamsTypeAI
|
||||
default:
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Invalid ParamsType: %s", reqBody.ParamsType),
|
||||
})
|
||||
}
|
||||
|
||||
if reqBody.Timeout > 0 {
|
||||
job.Timeout = reqBody.Timeout
|
||||
}
|
||||
job.Log = reqBody.Log
|
||||
|
||||
// Save job to OurDB (this assigns JobID)
|
||||
if err := job.Save(); err != nil {
|
||||
h.logger.Printf("Failed to save new job to OurDB: %v", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to create job: %v", err),
|
||||
"error": fmt.Sprintf("Failed to save new job: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
// Store job in Redis
|
||||
if err := h.client.StoreJob(job); err != nil {
|
||||
h.logger.Printf("Failed to store new job in Redis: %v", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to store new job in Redis: %v", err),
|
||||
})
|
||||
}
|
||||
|
||||
// Enqueue job in Redis
|
||||
if err := h.client.EnqueueJob(job); err != nil {
|
||||
h.logger.Printf("Failed to enqueue new job in Redis: %v", err)
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"error": fmt.Sprintf("Failed to enqueue new job: %v", err),
|
||||
})
|
||||
}
|
||||
|
572
_pkg2_dont_use/heroagent/handlers/job_handlers_test.go
Normal file
572
_pkg2_dont_use/heroagent/handlers/job_handlers_test.go
Normal file
@@ -0,0 +1,572 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"git.threefold.info/herocode/heroagent/pkg/herojobs"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// MockRedisClient is a mock implementation of the RedisClientInterface
|
||||
type MockRedisClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// StoreJob mocks the StoreJob method
|
||||
func (m *MockRedisClient) StoreJob(job *herojobs.Job) error {
|
||||
args := m.Called(job)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// EnqueueJob mocks the EnqueueJob method
|
||||
func (m *MockRedisClient) EnqueueJob(job *herojobs.Job) error {
|
||||
args := m.Called(job)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// GetJob mocks the GetJob method
|
||||
func (m *MockRedisClient) GetJob(jobID interface{}) (*herojobs.Job, error) { // jobID is interface{}
|
||||
args := m.Called(jobID)
|
||||
if args.Get(0) == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
return args.Get(0).(*herojobs.Job), args.Error(1)
|
||||
}
|
||||
|
||||
// ListJobs mocks the ListJobs method
|
||||
func (m *MockRedisClient) ListJobs(circleID, topic string) ([]uint32, error) { // Returns []uint32
|
||||
args := m.Called(circleID, topic)
|
||||
if args.Get(0) == nil {
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
return args.Get(0).([]uint32), args.Error(1)
|
||||
}
|
||||
|
||||
// QueueSize mocks the QueueSize method
|
||||
func (m *MockRedisClient) QueueSize(circleID, topic string) (int64, error) {
|
||||
args := m.Called(circleID, topic)
|
||||
// Ensure Get(0) is not nil before type assertion if it can be nil in some error cases
|
||||
if args.Get(0) == nil && args.Error(1) != nil { // If error is set, result might be nil
|
||||
return 0, args.Error(1)
|
||||
}
|
||||
return args.Get(0).(int64), args.Error(1)
|
||||
}
|
||||
|
||||
// QueueEmpty mocks the QueueEmpty method
|
||||
func (m *MockRedisClient) QueueEmpty(circleID, topic string) error {
|
||||
args := m.Called(circleID, topic)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
// setupTest initializes a test environment with a mock client
|
||||
func setupTest() (*JobHandler, *MockRedisClient, *fiber.App) {
|
||||
mockClient := new(MockRedisClient)
|
||||
handler := &JobHandler{
|
||||
client: mockClient, // Assign the mock that implements RedisClientInterface
|
||||
}
|
||||
|
||||
app := fiber.New()
|
||||
|
||||
// Register routes (ensure these match the actual routes in job_handlers.go)
|
||||
apiJobs := app.Group("/api/jobs") // Assuming routes are under /api/jobs
|
||||
apiJobs.Post("/submit", handler.submitJob)
|
||||
apiJobs.Get("/get/:id", handler.getJob) // :id as per job_handlers.go
|
||||
apiJobs.Delete("/delete/:id", handler.deleteJob) // :id as per job_handlers.go
|
||||
apiJobs.Get("/list", handler.listJobs)
|
||||
apiJobs.Get("/queue/size", handler.queueSize)
|
||||
apiJobs.Post("/queue/empty", handler.queueEmpty)
|
||||
apiJobs.Get("/queue/get", handler.queueGet)
|
||||
apiJobs.Post("/create", handler.createJob)
|
||||
|
||||
// If admin routes are also tested, they need to be registered here too
|
||||
// adminJobs := app.Group("/admin/jobs")
|
||||
// jobRoutes(adminJobs) // if using the same handler instance
|
||||
|
||||
return handler, mockClient, app
|
||||
}
|
||||
|
||||
// createTestRequest creates a test request with the given method, path, and body
|
||||
func createTestRequest(method, path string, body io.Reader) (*http.Request, error) {
|
||||
req := httptest.NewRequest(method, path, body)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// TestQueueEmpty tests the queueEmpty handler
|
||||
func TestQueueEmpty(t *testing.T) {
|
||||
// Test cases
|
||||
tests := []struct {
|
||||
name string
|
||||
circleID string
|
||||
topic string
|
||||
emptyError error
|
||||
expectedStatus int
|
||||
expectedBody string
|
||||
}{
|
||||
{
|
||||
name: "Success",
|
||||
circleID: "test-circle",
|
||||
topic: "test-topic",
|
||||
emptyError: nil,
|
||||
expectedStatus: fiber.StatusOK,
|
||||
expectedBody: `{"status":"success","message":"Queue for circle test-circle and topic test-topic emptied successfully"}`,
|
||||
},
|
||||
// Removed "Connection Error" test case as Connect is no longer directly called per op
|
||||
{
|
||||
name: "Empty Error",
|
||||
circleID: "test-circle",
|
||||
topic: "test-topic",
|
||||
emptyError: errors.New("empty error"),
|
||||
expectedStatus: fiber.StatusInternalServerError,
|
||||
expectedBody: `{"error":"Failed to empty queue: empty error"}`,
|
||||
},
|
||||
{
|
||||
name: "Empty Circle ID",
|
||||
circleID: "",
|
||||
topic: "test-topic",
|
||||
emptyError: nil,
|
||||
expectedStatus: fiber.StatusBadRequest,
|
||||
expectedBody: `{"error":"Circle ID is required"}`,
|
||||
},
|
||||
{
|
||||
name: "Empty Topic",
|
||||
circleID: "test-circle",
|
||||
topic: "",
|
||||
emptyError: nil,
|
||||
expectedStatus: fiber.StatusBadRequest,
|
||||
expectedBody: `{"error":"Topic is required"}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Create a new mock client for each test and setup app
|
||||
_, mockClient, app := setupTest() // Use setupTest to get handler with mock
|
||||
|
||||
// Setup mock expectations
|
||||
if tc.circleID != "" && tc.topic != "" { // Only expect call if params are valid
|
||||
mockClient.On("QueueEmpty", tc.circleID, tc.topic).Return(tc.emptyError)
|
||||
}
|
||||
|
||||
// Create request body
|
||||
reqBody := map[string]string{
|
||||
"circleid": tc.circleID,
|
||||
"topic": tc.topic,
|
||||
}
|
||||
reqBodyBytes, err := json.Marshal(reqBody)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Create test request
|
||||
req, err := createTestRequest(http.MethodPost, "/api/jobs/queue/empty", bytes.NewReader(reqBodyBytes))
|
||||
assert.NoError(t, err)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Perform the request
|
||||
resp, err := app.Test(req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check status code
|
||||
assert.Equal(t, tc.expectedStatus, resp.StatusCode)
|
||||
|
||||
// Check response body
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.JSONEq(t, tc.expectedBody, string(body))
|
||||
|
||||
// Verify that all expectations were met
|
||||
mockClient.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestQueueGet tests the queueGet handler
|
||||
func TestQueueGet(t *testing.T) {
|
||||
// Create a test job
|
||||
testJob := herojobs.NewJob()
|
||||
testJob.JobID = 10 // This will be a number in JSON
|
||||
testJob.CircleID = "test-circle"
|
||||
testJob.Topic = "test-topic"
|
||||
testJob.Params = "some script"
|
||||
testJob.ParamsType = herojobs.ParamsTypeHeroScript
|
||||
testJob.Status = herojobs.JobStatusNew
|
||||
|
||||
// Test cases
|
||||
tests := []struct {
|
||||
name string
|
||||
circleID string
|
||||
topic string
|
||||
listJobsError error
|
||||
listJobsResp []uint32
|
||||
getJobError error
|
||||
getJobResp *herojobs.Job
|
||||
expectedStatus int
|
||||
expectedBody string // This will need to be updated to match the actual job structure
|
||||
}{
|
||||
{
|
||||
name: "Success",
|
||||
circleID: "test-circle",
|
||||
topic: "test-topic",
|
||||
listJobsError: nil,
|
||||
listJobsResp: []uint32{10},
|
||||
getJobError: nil,
|
||||
getJobResp: testJob,
|
||||
expectedStatus: fiber.StatusOK,
|
||||
expectedBody: `{"jobid":10,"circleid":"test-circle","topic":"test-topic","params":"some script","paramstype":"HeroScript","status":"new","sessionkey":"","result":"","error":"","timeout":60,"log":false,"timescheduled":0,"timestart":0,"timeend":0}`,
|
||||
},
|
||||
// Removed "Connection Error"
|
||||
{
|
||||
name: "ListJobs Error",
|
||||
circleID: "test-circle",
|
||||
topic: "test-topic",
|
||||
listJobsError: errors.New("list error"),
|
||||
listJobsResp: nil,
|
||||
getJobError: nil, // Not reached
|
||||
getJobResp: nil, // Not reached
|
||||
expectedStatus: fiber.StatusInternalServerError,
|
||||
expectedBody: `{"error":"Failed to list jobs in queue: list error"}`,
|
||||
},
|
||||
{
|
||||
name: "GetJob Error after ListJobs success",
|
||||
circleID: "test-circle",
|
||||
topic: "test-topic",
|
||||
listJobsError: nil,
|
||||
listJobsResp: []uint32{10},
|
||||
getJobError: errors.New("get error"),
|
||||
getJobResp: nil,
|
||||
expectedStatus: fiber.StatusInternalServerError, // Or based on how GetJob error is handled (e.g. fallback to OurDB)
|
||||
// The error message might be more complex if OurDB load is also attempted and fails
|
||||
expectedBody: `{"error":"Failed to get job 10 from queue (Redis err: get error / OurDB err: record not found)"}`, // Adjusted expected error
|
||||
},
|
||||
{
|
||||
name: "Queue Empty (ListJobs returns empty)",
|
||||
circleID: "test-circle",
|
||||
topic: "test-topic",
|
||||
listJobsError: nil,
|
||||
listJobsResp: []uint32{}, // Empty list
|
||||
getJobError: nil,
|
||||
getJobResp: nil,
|
||||
expectedStatus: fiber.StatusNotFound,
|
||||
expectedBody: `{"error":"Queue is empty or no jobs found"}`,
|
||||
},
|
||||
{
|
||||
name: "Empty Circle ID",
|
||||
circleID: "",
|
||||
topic: "test-topic",
|
||||
listJobsError: nil,
|
||||
listJobsResp: nil,
|
||||
getJobError: nil,
|
||||
getJobResp: nil,
|
||||
expectedStatus: fiber.StatusBadRequest,
|
||||
expectedBody: `{"error":"Circle ID is required"}`,
|
||||
},
|
||||
{
|
||||
name: "Empty Topic",
|
||||
circleID: "test-circle",
|
||||
topic: "",
|
||||
listJobsError: nil,
|
||||
listJobsResp: nil,
|
||||
getJobError: nil,
|
||||
getJobResp: nil,
|
||||
expectedStatus: fiber.StatusBadRequest,
|
||||
expectedBody: `{"error":"Topic is required"}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Create a new mock client for each test and setup app
|
||||
_, mockClient, app := setupTest()
|
||||
|
||||
// Setup mock expectations
|
||||
if tc.circleID != "" && tc.topic != "" {
|
||||
mockClient.On("ListJobs", tc.circleID, tc.topic).Return(tc.listJobsResp, tc.listJobsError)
|
||||
if tc.listJobsError == nil && len(tc.listJobsResp) > 0 {
|
||||
// Expect GetJob to be called with the first ID from listJobsResp
|
||||
// The handler passes uint32 to client.GetJob, which matches interface{}
|
||||
mockClient.On("GetJob", tc.listJobsResp[0]).Return(tc.getJobResp, tc.getJobError).Maybe()
|
||||
// If GetJob from Redis fails, a Load from OurDB is attempted.
|
||||
// We are not mocking job.Load() here as it's on the job object.
|
||||
// The error message in the test case reflects this potential dual failure.
|
||||
}
|
||||
}
|
||||
|
||||
// Create test request
|
||||
path := fmt.Sprintf("/api/jobs/queue/get?circleid=%s&topic=%s", tc.circleID, tc.topic)
|
||||
req, err := createTestRequest(http.MethodGet, path, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Perform the request
|
||||
resp, err := app.Test(req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check status code
|
||||
assert.Equal(t, tc.expectedStatus, resp.StatusCode)
|
||||
|
||||
// Check response body
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.JSONEq(t, tc.expectedBody, string(body))
|
||||
|
||||
// Verify that all expectations were met
|
||||
mockClient.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateJob tests the createJob handler
|
||||
func TestCreateJob(t *testing.T) {
|
||||
// Test cases
|
||||
createdJob := herojobs.NewJob()
|
||||
createdJob.JobID = 10 // Assuming Save will populate this; for mock, we set it
|
||||
createdJob.CircleID = "test-circle"
|
||||
createdJob.Topic = "test-topic"
|
||||
createdJob.SessionKey = "test-key"
|
||||
createdJob.Params = "test-params"
|
||||
createdJob.ParamsType = herojobs.ParamsTypeHeroScript // Match "HeroScript" string
|
||||
createdJob.Status = herojobs.JobStatusNew // Default status after NewJob and Save
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
reqBody map[string]interface{} // Use map for flexibility
|
||||
storeError error
|
||||
enqueueError error
|
||||
expectedStatus int
|
||||
expectedBody string // Will be the createdJob marshaled
|
||||
}{
|
||||
{
|
||||
name: "Success",
|
||||
reqBody: map[string]interface{}{
|
||||
"circleid": "test-circle",
|
||||
"topic": "test-topic",
|
||||
"sessionkey": "test-key",
|
||||
"params": "test-params",
|
||||
"paramstype": "HeroScript",
|
||||
"timeout": 30,
|
||||
"log": true,
|
||||
},
|
||||
storeError: nil,
|
||||
enqueueError: nil,
|
||||
expectedStatus: fiber.StatusOK,
|
||||
// Expected body should match the 'createdJob' structure after Save, Store, Enqueue
|
||||
// JobID is assigned by Save(), which we are not mocking here.
|
||||
// The handler returns the job object.
|
||||
// For the test, we assume Save() works and populates JobID if it were a real DB.
|
||||
// The mock will return the job passed to it.
|
||||
expectedBody: `{"jobid":0,"circleid":"test-circle","topic":"test-topic","params":"test-params","paramstype":"HeroScript","status":"new","sessionkey":"test-key","result":"","error":"","timeout":30,"log":true,"timescheduled":0,"timestart":0,"timeend":0}`,
|
||||
},
|
||||
// Removed "Connection Error"
|
||||
{
|
||||
name: "StoreJob Error",
|
||||
reqBody: map[string]interface{}{
|
||||
"circleid": "test-circle", "topic": "test-topic", "params": "p", "paramstype": "HeroScript",
|
||||
},
|
||||
storeError: errors.New("store error"),
|
||||
enqueueError: nil,
|
||||
expectedStatus: fiber.StatusInternalServerError,
|
||||
expectedBody: `{"error":"Failed to store new job in Redis: store error"}`,
|
||||
},
|
||||
{
|
||||
name: "EnqueueJob Error",
|
||||
reqBody: map[string]interface{}{
|
||||
"circleid": "test-circle", "topic": "test-topic", "params": "p", "paramstype": "HeroScript",
|
||||
},
|
||||
storeError: nil,
|
||||
enqueueError: errors.New("enqueue error"),
|
||||
expectedStatus: fiber.StatusInternalServerError,
|
||||
expectedBody: `{"error":"Failed to enqueue new job in Redis: enqueue error"}`,
|
||||
},
|
||||
{
|
||||
name: "Empty Circle ID",
|
||||
reqBody: map[string]interface{}{
|
||||
"circleid": "", "topic": "test-topic", "params": "p", "paramstype": "HeroScript",
|
||||
},
|
||||
expectedStatus: fiber.StatusBadRequest,
|
||||
expectedBody: `{"error":"Circle ID is required"}`,
|
||||
},
|
||||
{
|
||||
name: "Empty Topic",
|
||||
reqBody: map[string]interface{}{
|
||||
"circleid": "c", "topic": "", "params": "p", "paramstype": "HeroScript",
|
||||
},
|
||||
expectedStatus: fiber.StatusBadRequest,
|
||||
expectedBody: `{"error":"Topic is required"}`,
|
||||
},
|
||||
{
|
||||
name: "Empty Params",
|
||||
reqBody: map[string]interface{}{
|
||||
"circleid": "c", "topic": "t", "params": "", "paramstype": "HeroScript",
|
||||
},
|
||||
expectedStatus: fiber.StatusBadRequest,
|
||||
expectedBody: `{"error":"Params are required"}`,
|
||||
},
|
||||
{
|
||||
name: "Empty ParamsType",
|
||||
reqBody: map[string]interface{}{
|
||||
"circleid": "c", "topic": "t", "params": "p", "paramstype": "",
|
||||
},
|
||||
expectedStatus: fiber.StatusBadRequest,
|
||||
expectedBody: `{"error":"ParamsType is required"}`,
|
||||
},
|
||||
{
|
||||
name: "Invalid ParamsType",
|
||||
reqBody: map[string]interface{}{
|
||||
"circleid": "c", "topic": "t", "params": "p", "paramstype": "InvalidType",
|
||||
},
|
||||
expectedStatus: fiber.StatusBadRequest,
|
||||
expectedBody: `{"error":"Invalid ParamsType: InvalidType"}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
_, mockClient, app := setupTest()
|
||||
|
||||
// Setup mock expectations
|
||||
// job.Save() is called before client interactions. We assume it succeeds for these tests.
|
||||
// The mock will be called with a job object. We use mock.AnythingOfType for the job
|
||||
// because the JobID might be populated by Save() in a real scenario, making exact match hard.
|
||||
if tc.reqBody["circleid"] != "" && tc.reqBody["topic"] != "" &&
|
||||
tc.reqBody["params"] != "" && tc.reqBody["paramstype"] != "" &&
|
||||
herojobs.ParamsType(tc.reqBody["paramstype"].(string)) != "" { // Basic validation check
|
||||
|
||||
// We expect StoreJob to be called with a *herojobs.Job.
|
||||
// The actual JobID is set by job.Save() which is not mocked here.
|
||||
// So we use mock.AnythingOfType to match the argument.
|
||||
mockClient.On("StoreJob", mock.AnythingOfType("*herojobs.Job")).Return(tc.storeError).Once().Maybe()
|
||||
|
||||
if tc.storeError == nil {
|
||||
mockClient.On("EnqueueJob", mock.AnythingOfType("*herojobs.Job")).Return(tc.enqueueError).Once().Maybe()
|
||||
}
|
||||
}
|
||||
|
||||
reqBodyBytes, err := json.Marshal(tc.reqBody)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req, err := createTestRequest(http.MethodPost, "/api/jobs/create", bytes.NewReader(reqBodyBytes)) // Use /api/jobs/create
|
||||
assert.NoError(t, err)
|
||||
// Content-Type is set by createTestRequest
|
||||
|
||||
// Perform the request
|
||||
resp, err := app.Test(req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check status code
|
||||
assert.Equal(t, tc.expectedStatus, resp.StatusCode)
|
||||
|
||||
// Check response body
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.JSONEq(t, tc.expectedBody, string(body))
|
||||
|
||||
// Verify that all expectations were met
|
||||
mockClient.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestSubmitJob tests the submitJob handler
|
||||
func TestSubmitJob(t *testing.T) {
|
||||
// Test cases
|
||||
submittedJob := herojobs.NewJob()
|
||||
submittedJob.JobID = 10 // Assume Save populates this
|
||||
submittedJob.CircleID = "test-circle"
|
||||
submittedJob.Topic = "test-topic"
|
||||
submittedJob.Params = "submitted params"
|
||||
submittedJob.ParamsType = herojobs.ParamsTypeHeroScript
|
||||
submittedJob.Status = herojobs.JobStatusNew
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
jobToSubmit *herojobs.Job // This is the job in the request body
|
||||
storeError error
|
||||
enqueueError error
|
||||
expectedStatus int
|
||||
expectedBody string // Will be the jobToSubmit marshaled (after potential Save)
|
||||
}{
|
||||
{
|
||||
name: "Success",
|
||||
jobToSubmit: submittedJob,
|
||||
storeError: nil,
|
||||
enqueueError: nil,
|
||||
expectedStatus: fiber.StatusOK,
|
||||
// The handler returns the job object from the request after Save(), Store(), Enqueue()
|
||||
// For the mock, the JobID from jobToSubmit will be used.
|
||||
expectedBody: `{"jobid":10,"circleid":"test-circle","topic":"test-topic","params":"submitted params","paramstype":"HeroScript","status":"new","sessionkey":"","result":"","error":"","timeout":60,"log":false,"timescheduled":0,"timestart":0,"timeend":0}`,
|
||||
},
|
||||
// Removed "Connection Error"
|
||||
{
|
||||
name: "StoreJob Error",
|
||||
jobToSubmit: submittedJob,
|
||||
storeError: errors.New("store error"),
|
||||
enqueueError: nil,
|
||||
expectedStatus: fiber.StatusInternalServerError,
|
||||
expectedBody: `{"error":"Failed to store job in Redis: store error"}`,
|
||||
},
|
||||
{
|
||||
name: "EnqueueJob Error",
|
||||
jobToSubmit: submittedJob,
|
||||
storeError: nil,
|
||||
enqueueError: errors.New("enqueue error"),
|
||||
expectedStatus: fiber.StatusInternalServerError,
|
||||
expectedBody: `{"error":"Failed to enqueue job: enqueue error"}`,
|
||||
},
|
||||
{
|
||||
name: "Empty Job in request (parsing error)",
|
||||
jobToSubmit: nil, // Simulates empty or malformed request body
|
||||
expectedStatus: fiber.StatusBadRequest,
|
||||
expectedBody: `{"error":"Failed to parse job data: unexpected end of JSON input"}`, // Or similar based on actual parsing
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
_, mockClient, app := setupTest()
|
||||
|
||||
// Setup mock expectations
|
||||
// job.Save() is called before client interactions.
|
||||
if tc.jobToSubmit != nil { // If job is parsable from request
|
||||
// We expect StoreJob to be called with the job from the request.
|
||||
// The JobID might be modified by Save() in a real scenario.
|
||||
mockClient.On("StoreJob", tc.jobToSubmit).Return(tc.storeError).Once().Maybe()
|
||||
if tc.storeError == nil {
|
||||
mockClient.On("EnqueueJob", tc.jobToSubmit).Return(tc.enqueueError).Once().Maybe()
|
||||
}
|
||||
}
|
||||
|
||||
var reqBodyBytes []byte
|
||||
var err error
|
||||
if tc.jobToSubmit != nil {
|
||||
reqBodyBytes, err = json.Marshal(tc.jobToSubmit)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
req, err := createTestRequest(http.MethodPost, "/api/jobs/submit", bytes.NewReader(reqBodyBytes)) // Use /api/jobs/submit
|
||||
assert.NoError(t, err)
|
||||
// Content-Type is set by createTestRequest
|
||||
|
||||
// Perform the request
|
||||
resp, err := app.Test(req)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check status code
|
||||
assert.Equal(t, tc.expectedStatus, resp.StatusCode)
|
||||
|
||||
// Check response body
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
assert.JSONEq(t, tc.expectedBody, string(body))
|
||||
|
||||
// Verify that all expectations were met
|
||||
mockClient.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/logger"
|
||||
"git.threefold.info/herocode/heroagent/pkg/logger"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
@@ -156,7 +156,6 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// Calculate total pages
|
||||
totalLogs := len(logs)
|
||||
totalPages := (totalLogs + itemsPerPage - 1) / itemsPerPage
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.threefold.info/herocode/heroagent/pkg/system/stats"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
@@ -201,5 +201,3 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error {
|
||||
// Return only the table HTML content directly to be injected into the processes-table-content div
|
||||
return c.Render("admin/system/processes_data", templateData)
|
||||
}
|
||||
|
||||
|
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"git.threefold.info/herocode/heroagent/pkg/processmanager/interfaces"
|
||||
"git.threefold.info/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.threefold.info/herocode/heroagent/pkg/system/stats"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
)
|
@@ -7,8 +7,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroagent/handlers"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroagent/handlers"
|
||||
"git.threefold.info/herocode/heroagent/pkg/system/stats"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/shirou/gopsutil/v3/host"
|
||||
)
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/herojobs"
|
||||
"git.threefold.info/herocode/heroagent/pkg/herojobs"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
@@ -15,8 +15,8 @@ type JobDisplayInfo struct {
|
||||
Topic string `json:"topic"`
|
||||
Status string `json:"status"`
|
||||
SessionKey string `json:"sessionkey"`
|
||||
HeroScript string `json:"heroscript"`
|
||||
RhaiScript string `json:"rhaiscript"`
|
||||
Params string `json:"params"`
|
||||
ParamsType string `json:"paramstype"`
|
||||
Result string `json:"result"`
|
||||
Error string `json:"error"`
|
||||
TimeScheduled int64 `json:"time_scheduled"`
|
||||
@@ -27,15 +27,17 @@ type JobDisplayInfo struct {
|
||||
|
||||
// JobHandler handles job-related page routes
|
||||
type JobHandler struct {
|
||||
client *herojobs.Client
|
||||
client *herojobs.RedisClient
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
// NewJobHandler creates a new job handler with the provided socket path
|
||||
func NewJobHandler(socketPath string, logger *log.Logger) (*JobHandler, error) {
|
||||
client, err := herojobs.NewClient(socketPath)
|
||||
func NewJobHandler(redisAddr string, logger *log.Logger) (*JobHandler, error) {
|
||||
// Assuming SSL is false as per README example herojobs.NewRedisClient("localhost:6379", false)
|
||||
// This might need to be configurable later.
|
||||
client, err := herojobs.NewRedisClient(redisAddr, false)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create HeroJobs client: %w", err)
|
||||
return nil, fmt.Errorf("failed to create HeroJobs Redis client: %w", err)
|
||||
}
|
||||
|
||||
return &JobHandler{
|
||||
@@ -59,18 +61,13 @@ func (h *JobHandler) RegisterRoutes(app *fiber.App) {
|
||||
|
||||
// getJobsPage renders the jobs page
|
||||
func (h *JobHandler) getJobsPage(c *fiber.Ctx) error {
|
||||
// Check if we can connect to the HeroJobs server
|
||||
var warning string
|
||||
if err := h.client.Connect(); err != nil {
|
||||
warning = "Could not connect to HeroJobs server: " + err.Error()
|
||||
h.logger.Printf("Warning: %s", warning)
|
||||
} else {
|
||||
h.client.Close()
|
||||
}
|
||||
|
||||
// Assuming h.client (RedisClient) is valid if NewJobHandler succeeded.
|
||||
// The client is connected on creation. A Ping method could be used here for a health check if available.
|
||||
// The previous connect/close logic per-request is removed.
|
||||
var warning string // This will be empty unless a new check (e.g., Ping) sets it.
|
||||
return c.Render("admin/jobs", fiber.Map{
|
||||
"title": "Jobs",
|
||||
"warning": warning,
|
||||
"warning": warning, // warning will be empty for now
|
||||
"error": "",
|
||||
})
|
||||
}
|
||||
@@ -100,11 +97,9 @@ func (h *JobHandler) getJobsList(c *fiber.Ctx) error {
|
||||
|
||||
// getJobsData gets job data from the HeroJobs server
|
||||
func (h *JobHandler) getJobsData(circleID, topic string) ([]JobDisplayInfo, error) {
|
||||
// Connect to the HeroJobs server
|
||||
if err := h.client.Connect(); err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to HeroJobs server: %w", err)
|
||||
}
|
||||
defer h.client.Close()
|
||||
// Assuming h.client (RedisClient) is already connected (established by NewJobHandler).
|
||||
// It should not be closed here as it's a long-lived client.
|
||||
// Connect() and Close() calls per-request are removed.
|
||||
|
||||
// If circleID and topic are not provided, try to list all jobs
|
||||
if circleID == "" && topic == "" {
|
||||
@@ -131,13 +126,13 @@ func (h *JobHandler) getJobsData(circleID, topic string) ([]JobDisplayInfo, erro
|
||||
}
|
||||
|
||||
allJobs = append(allJobs, JobDisplayInfo{
|
||||
JobID: job.JobID,
|
||||
JobID: fmt.Sprintf("%d", job.JobID),
|
||||
CircleID: job.CircleID,
|
||||
Topic: job.Topic,
|
||||
Status: string(job.Status),
|
||||
SessionKey: job.SessionKey,
|
||||
HeroScript: job.HeroScript,
|
||||
RhaiScript: job.RhaiScript,
|
||||
Params: job.Params,
|
||||
ParamsType: string(job.ParamsType),
|
||||
Result: job.Result,
|
||||
Error: job.Error,
|
||||
TimeScheduled: job.TimeScheduled,
|
||||
@@ -171,13 +166,13 @@ func (h *JobHandler) getJobsData(circleID, topic string) ([]JobDisplayInfo, erro
|
||||
}
|
||||
|
||||
jobInfo := JobDisplayInfo{
|
||||
JobID: job.JobID,
|
||||
JobID: fmt.Sprintf("%d", job.JobID),
|
||||
CircleID: job.CircleID,
|
||||
Topic: job.Topic,
|
||||
Status: string(job.Status),
|
||||
SessionKey: job.SessionKey,
|
||||
HeroScript: job.HeroScript,
|
||||
RhaiScript: job.RhaiScript,
|
||||
Params: job.Params,
|
||||
ParamsType: string(job.ParamsType),
|
||||
Result: job.Result,
|
||||
Error: job.Error,
|
||||
TimeScheduled: job.TimeScheduled,
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"git.threefold.info/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
|
||||
"git.threefold.info/herocode/heroagent/pkg/processmanager"
|
||||
)
|
||||
|
||||
// ProcessDisplayInfo represents information about a process for display purposes
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 844 B After Width: | Height: | Size: 844 B |
@@ -35,7 +35,7 @@ Key features:
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
// Create a new playbook from HeroScript text
|
@@ -7,7 +7,7 @@ import (
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory/herohandler"
|
||||
"git.threefold.info/herocode/heroagent/pkg/handlerfactory/herohandler"
|
||||
)
|
||||
|
||||
func main() {
|
@@ -8,7 +8,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
func main() {
|
@@ -3,8 +3,8 @@ package internal
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlers"
|
||||
"git.threefold.info/herocode/heroagent/pkg/handlerfactory"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/handlers"
|
||||
)
|
||||
|
||||
// ExampleHandler handles example actions
|
@@ -7,7 +7,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/cmd/herohandler/internal"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/cmd/herohandler/internal"
|
||||
)
|
||||
|
||||
func main() {
|
@@ -10,7 +10,7 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory/herohandler"
|
||||
"git.threefold.info/herocode/heroagent/pkg/handlerfactory/herohandler"
|
||||
)
|
||||
|
||||
func main() {
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
const exampleScript = `
|
@@ -16,7 +16,7 @@ The VM handler example shows how to:
|
||||
To run the example:
|
||||
|
||||
```bash
|
||||
cd ~/code/github/freeflowuniverse/heroagent/pkg/handlerfactory/cmd/vmhandler
|
||||
cd ~/code/github/freeflowuniverse/herocode/heroagent/pkg/handlerfactory/cmd/vmhandler
|
||||
go run . tutorial
|
||||
#to run just the server do
|
||||
go run .
|
@@ -6,7 +6,7 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory"
|
||||
"git.threefold.info/herocode/heroagent/pkg/handlerfactory"
|
||||
)
|
||||
|
||||
// runTutorial runs an interactive tutorial demonstrating the VM handler
|
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory"
|
||||
"git.threefold.info/herocode/heroagent/pkg/handlerfactory"
|
||||
)
|
||||
|
||||
// VMHandler handles VM-related actions
|
@@ -8,7 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory"
|
||||
"git.threefold.info/herocode/heroagent/pkg/handlerfactory"
|
||||
)
|
||||
|
||||
// The tutorial functions are defined in tutorial.go
|
@@ -30,7 +30,7 @@ The Handler Factory exposes two interfaces for communication:
|
||||
to get started
|
||||
|
||||
```bash
|
||||
cd /root/code/github/freeflowuniverse/heroagent/pkg/handlerfactory/herohandler/cmd
|
||||
cd /root/code/github/freeflowuniverse/herocode/heroagent/pkg/handlerfactory/herohandler/cmd
|
||||
go run .
|
||||
```
|
||||
|
@@ -5,8 +5,8 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/paramsparser"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/paramsparser"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
// Handler interface defines methods that all handlers must implement
|
@@ -5,7 +5,7 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
// HandlerFactory manages a collection of handlers
|
@@ -12,7 +12,7 @@ import (
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
// ANSI color codes for terminal output
|
||||
@@ -466,8 +466,6 @@ func (ts *TelnetServer) addJsonFormat(script string) string {
|
||||
return strings.Join(lines, "\n")
|
||||
}
|
||||
|
||||
|
||||
|
||||
// formatHeroscript formats heroscript with colors for console output only
|
||||
// This is not used for telnet responses, only for server-side logging
|
||||
func formatHeroscript(script string) string {
|
@@ -3,7 +3,7 @@ package handlers
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
)
|
||||
|
||||
// AuthHandler handles authentication actions
|
@@ -5,9 +5,9 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/paramsparser"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/paramsparser"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
// BaseHandler provides common functionality for all handlers
|
@@ -4,8 +4,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
// HandlerFactory manages a collection of handlers for processing HeroScript commands
|
@@ -1,7 +1,7 @@
|
||||
package herohandler
|
||||
|
||||
import (
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
)
|
||||
|
||||
// GetFactory returns the handler factory
|
@@ -4,7 +4,7 @@ import (
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory/herohandler"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/handlerfactory/herohandler"
|
||||
)
|
||||
|
||||
func main() {
|
@@ -4,10 +4,10 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
|
||||
// "github.com/freeflowuniverse/heroagent/pkg/handlerfactory/heroscript/handlerfactory/fakehandler"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/processmanagerhandler"
|
||||
// "git.threefold.info/herocode/heroagent/pkg/handlerfactory/heroscript/handlerfactory/fakehandler"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/handlerfactory/processmanagerhandler"
|
||||
)
|
||||
|
||||
// HeroHandler is the main handler factory that manages all registered handlers
|
@@ -2,10 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/playbook"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -15,26 +13,26 @@ func main() {
|
||||
pb := playbook.New()
|
||||
|
||||
// Start a simple process
|
||||
startAction := pb.NewAction(1, "start", "process", 0, playbook.ActionTypeUnknown)
|
||||
startAction := pb.NewAction("1", "start", "process", 0, playbook.ActionTypeUnknown)
|
||||
startAction.Params.Set("name", "example_process")
|
||||
startAction.Params.Set("command", "ping -c 60 localhost")
|
||||
startAction.Params.Set("log", "true")
|
||||
|
||||
// List all processes
|
||||
listAction := pb.NewAction(2, "list", "process", 0, playbook.ActionTypeUnknown)
|
||||
listAction := pb.NewAction("2", "list", "process", 0, playbook.ActionTypeUnknown)
|
||||
listAction.Params.Set("format", "table")
|
||||
|
||||
// Get status of a specific process
|
||||
statusAction := pb.NewAction(3, "status", "process", 0, playbook.ActionTypeUnknown)
|
||||
statusAction := pb.NewAction("3", "status", "process", 0, playbook.ActionTypeUnknown)
|
||||
statusAction.Params.Set("name", "example_process")
|
||||
|
||||
// Get logs of a specific process
|
||||
logsAction := pb.NewAction(4, "logs", "process", 0, playbook.ActionTypeUnknown)
|
||||
logsAction := pb.NewAction("4", "logs", "process", 0, playbook.ActionTypeUnknown)
|
||||
logsAction.Params.Set("name", "example_process")
|
||||
logsAction.Params.Set("lines", "10")
|
||||
|
||||
// Stop a process
|
||||
stopAction := pb.NewAction(5, "stop", "process", 0, playbook.ActionTypeUnknown)
|
||||
stopAction := pb.NewAction("5", "stop", "process", 0, playbook.ActionTypeUnknown)
|
||||
stopAction.Params.Set("name", "example_process")
|
||||
|
||||
// Generate the heroscript
|
@@ -3,8 +3,8 @@ package processmanagerhandler
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
|
||||
"git.threefold.info/herocode/heroagent/pkg/heroscript/handlerfactory/core"
|
||||
"git.threefold.info/herocode/heroagent/pkg/processmanager"
|
||||
)
|
||||
|
||||
// ProcessManagerHandler handles process manager-related actions
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user