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 }