slice 8C Phase B.2 + C.1/C.2: retire disk subsystem + rewire disk mgmt to agent
Retired (~12.3k LOC): internal/storage/* (scan/format/attach/migrate/safety), backup restic/crossdrive/restore_drives/disk_layout/local_infra/restore_scan/ paths + restore_app, report/infra_backup*/infra_pull, setup/scanner, monitor/watchdog+pinger, web/storage_handlers+handler_restore. Surgically split backup.Manager to app-data only (DB dumps + volume tars + app restore; dropped restic + cross-drive + snapshot history). Fixed router/main/web wiring. Added agent-backed disk API (web/agent_disk_handlers.go): /api/disks list/ assign/eject/format proxying agentapi; data-bearing format refusal -> HTTP 409 'operator authorization required'. report/config_pull.go keeps the setup fresh-install config download. go build + go test green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
package report
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config-pull error types for setup-wizard UI display.
|
||||
//
|
||||
// These (and PullConfig) were previously part of infra_pull.go alongside the
|
||||
// disk-tier DR-recovery (PullRecovery / infra-backup) client. Disk recovery moved
|
||||
// to the host agent in slice 8C; only the fresh-install config download survives
|
||||
// here, so it lives in this slimmed file.
|
||||
var (
|
||||
ErrHubUnreachable = errors.New("hub unreachable")
|
||||
ErrAuthFailed = errors.New("authentication failed")
|
||||
ErrNotFound = errors.New("customer not found")
|
||||
ErrHubError = errors.New("hub error")
|
||||
)
|
||||
|
||||
// PullConfig fetches a generated controller.yaml from the Hub config endpoint.
|
||||
// Auth: X-Retrieval-Password header. Used by the setup wizard's fresh-install flow.
|
||||
func PullConfig(hubURL, customerID, retrievalPassword string) (string, error) {
|
||||
url := strings.TrimRight(hubURL, "/") + "/api/v1/config/" + customerID
|
||||
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: %v", ErrHubError, err)
|
||||
}
|
||||
req.Header.Set("X-Retrieval-Password", retrievalPassword)
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: %v", ErrHubUnreachable, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
switch resp.StatusCode {
|
||||
case http.StatusOK:
|
||||
// success
|
||||
case http.StatusUnauthorized:
|
||||
return "", ErrAuthFailed
|
||||
case http.StatusNotFound:
|
||||
return "", ErrNotFound
|
||||
default:
|
||||
return "", fmt.Errorf("%w: HTTP %d", ErrHubError, resp.StatusCode)
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20)) // 1MB limit
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%w: reading response: %v", ErrHubError, err)
|
||||
}
|
||||
|
||||
return string(body), nil
|
||||
}
|
||||
Reference in New Issue
Block a user