remotes: add mirrorlist for round-robin + failover across mirrors (rpm/deb/apk) #121
Reference in New Issue
Block a user
Delete Branch "benvin/multi-baseurl-core"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
OS package remotes (rpm/deb/apk) fetch many small files and benefit from spreading upstream load across mirrors and surviving a mirror outage. A remote may now set a
mirrorlistof additional upstream base URLs. The effective upstream pool is[base_url] + mirrorlist, which the shared proxy engine load-balances round-robin and, on a network error/timeout/5xx, fails over to the next mirror before returning an error. Selection happens in the engine, so it works for every provider that reaches upstream.Backward compatible:
base_urlstays a plain string (providers read it unchanged), and a remote with no mirrorlist behaves exactly as today (single attempt, same error path).How
models.Remote.Mirrorlist([]string,json:"mirrorlist,omitempty") +UpstreamPool()=[base_url] + mirrorlist.ValidateMirrorlist: a non-empty mirrorlist is allowed only whenrepo_type==remoteandpackage_type ∈ {rpm, deb, alpine}; each entry must be an http/https URL. Enforced in the v2 create/update handlers (400 otherwise);base_urlstays required for remotes.mirrorlist TEXT[]column (remoteCols/scanRemote/CreateRemote/UpdateRemote); thebase_urlcolumn is unchanged.Scope
Round-robin + failover only, restricted to remote rpm/deb/apk repos. Least-connections and a per-remote strategy selector are a follow-up PR.
Tests
make test(go test -race) green.e2e-docker,dockere2etag, wired intodocker-e2e.sh): round-robin distribution across two mock upstreams, failover past a dead primary, no-mirrorlist regression, and a realdnfmakecache + install through a two-mirror rpm remote whosebase_urlis dead. All four pass locally.OS package remotes (rpm/deb/apk) fetch many small files and benefit from spreading upstream load across mirrors and surviving a mirror outage. A remote may now set a `mirrorlist` of additional upstream base URLs; the effective upstream pool is [base_url] + mirrorlist, which the shared proxy engine load-balances round-robin and, on a network error/timeout/5xx, fails over to the next mirror before returning an error. Because selection happens in the engine, it works for every provider that reaches upstream. Backward compatible: `base_url` stays a plain string that providers read unchanged, and a remote with no mirrorlist behaves exactly as today (single attempt, same error path). - add models.Remote.Mirrorlist ([]string, json "mirrorlist,omitempty") and UpstreamPool() = [base_url] + mirrorlist; ValidateMirrorlist enforces remote repo_type + package_type in {rpm, deb, alpine} and http/https URLs - v2 create/update: reject a mirrorlist on any other repo (400); base_url remains required for remotes - persist mirrorlist in a new additive `mirrorlist TEXT[]` column (remoteCols/scanRemote/CreateRemote/UpdateRemote); base_url column unchanged - engine: per-remote round-robin cursor over the pool; wrap the fetch/head/revalidate upstream calls in a failover loop that narrows the remote to one selected mirror per attempt; only network errors and 5xx fail over (404/403/... return as-is); circuit breaker stays keyed per remote and trips only after all mirrors fail - tests: model JSON round-trip + validation gating, engine round-robin/failover/no-mirrorlist-unchanged, DB mirrorlist round-trip, and a docker acceptance suite (round-robin across two mock upstreams, failover past a dead primary, no-mirrorlist regression, and a real dnf makecache+install through a two-mirror rpm remote whose base_url is dead) Least-connections and a per-remote strategy selector are a follow-up PR.68a1f14e17toac8be0a105remotes: support multiple base_urls with round-robin + failoverto remotes: add mirrorlist for round-robin + failover across mirrors (rpm/deb/apk)