pve-go/task.go
2021-11-07 11:57:25 +01:00

103 lines
2 KiB
Go

// Copyright (C) 2020 Marius Schellenberger
package pve
import (
"context"
"errors"
"fmt"
"strings"
"time"
)
const (
TaskTimeout = 300
TaskStatusCheckInterval = 2
TaskExitStatusOK = "OK"
TaskStatusRunning = "running"
TaskStatusStopped = "stopped"
DummyTaskID = "dummy"
)
var DummyTask = Task{ID: DummyTaskID}
type Task struct {
ID string `json:"upid"`
Type string `json:"type"`
Status string `json:"status"`
Exitstatus string `json:"exitstatus"`
}
type TaskClient struct {
client *Client
}
func nodeFromTaskID(taskid string) (string, error) {
a := strings.SplitN(taskid, ":", 3)
if len(a) < 2 {
return "", errors.New("error parsing taskid")
}
return a[1], nil
}
func (c *TaskClient) MustGet(ctx context.Context, taskid string) (t *Task) {
t = &Task{ID: taskid}
task, err := c.Get(ctx, taskid)
if err == nil {
t = task
}
return
}
func (c *TaskClient) Get(ctx context.Context, taskid string) (t *Task, err error) {
node, err := nodeFromTaskID(taskid)
if err != nil {
return
}
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("/nodes/%s/tasks/%s/status", node, taskid), nil)
if err != nil {
return
}
t = &Task{ID: taskid}
_, err = c.client.Do(req, t)
return
}
type OnTaskChange func(t *Task)
func (c *TaskClient) Wait(ctx context.Context, t *Task, f OnTaskChange) error {
if t.ID == DummyTaskID {
return nil
}
if f != nil && t.Status != "" {
f(t)
}
if t.Status == TaskStatusStopped {
if t.Exitstatus == TaskExitStatusOK {
return nil
}
return errors.New(t.Exitstatus)
}
waited := 0
for waited < TaskTimeout {
task, err := c.Get(ctx, t.ID)
if err != nil {
return err
}
if task.Status != t.Status {
if f != nil {
f(task)
}
if task.Status == TaskStatusStopped {
if task.Exitstatus == TaskExitStatusOK {
return nil
}
return errors.New(task.Exitstatus)
}
}
time.Sleep(TaskStatusCheckInterval * time.Second)
waited += TaskStatusCheckInterval
}
return errors.New("task wait timeout for: " + t.ID)
}