Public source validation / validate (push) Failing after 3m8s
74 lines
2.4 KiB
Go
74 lines
2.4 KiB
Go
package unraid
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/itworx/pulse/internal/share"
|
|
)
|
|
|
|
// ShareSource maps Unraid's bounded, read-only shares query. Share usage is reported
|
|
// by Unraid in KiB; Pulse's domain contract consistently uses bytes. The API does not
|
|
// expose a complete placement scan in this selection, so no placement is inferred.
|
|
type ShareSource struct {
|
|
Client *Client
|
|
Now func() time.Time
|
|
}
|
|
|
|
func (s ShareSource) Snapshot(ctx context.Context) (share.RawSnapshot, error) {
|
|
if s.Client == nil {
|
|
return share.RawSnapshot{}, errors.New("Unraid client is required")
|
|
}
|
|
payload, err := s.Client.Query(ctx, "shares")
|
|
if err != nil {
|
|
return share.RawSnapshot{}, err
|
|
}
|
|
var response struct {
|
|
Shares []struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Used json.RawMessage `json:"used"`
|
|
Size json.RawMessage `json:"size"`
|
|
Include []string `json:"include"`
|
|
Exclude []string `json:"exclude"`
|
|
Cache bool `json:"cache"`
|
|
Allocator string `json:"allocator"`
|
|
} `json:"shares"`
|
|
}
|
|
if err := json.Unmarshal(payload, &response); err != nil {
|
|
return share.RawSnapshot{}, errors.New("decode Unraid shares response")
|
|
}
|
|
if len(response.Shares) > 1000 {
|
|
return share.RawSnapshot{}, errors.New("Unraid share response exceeds bounds")
|
|
}
|
|
now := time.Now().UTC()
|
|
if s.Now != nil {
|
|
now = s.Now().UTC()
|
|
}
|
|
items := make([]share.RawShare, 0, len(response.Shares))
|
|
for _, item := range response.Shares {
|
|
used, err := rawUint(item.Used)
|
|
if err != nil || strings.TrimSpace(item.ID) == "" || strings.TrimSpace(item.Name) == "" {
|
|
return share.RawSnapshot{}, errors.New("Unraid share identity or usage is invalid")
|
|
}
|
|
// `cache` is a boolean in this API version. Preserve exactly that fact instead
|
|
// of inventing a legacy mover policy or a primary/secondary placement.
|
|
cachePolicy := "disabled"
|
|
if item.Cache {
|
|
cachePolicy = "enabled"
|
|
}
|
|
items = append(items, share.RawShare{
|
|
ID: item.ID,
|
|
Name: item.Name,
|
|
StoragePolicy: share.StoragePolicy{Allocation: strings.TrimSpace(item.Allocator), CachePolicy: cachePolicy},
|
|
UsedBytes: kilobytes(used),
|
|
SizeObservedAt: now,
|
|
SizeState: share.SizeAvailable,
|
|
})
|
|
}
|
|
return share.RawSnapshot{Source: share.Source{ID: "unraid", Type: "unraid"}, Shares: items, ObservedAt: now, ReceivedAt: now}, nil
|
|
}
|