Documentation
¶
Overview ¶
Package dockerhub is the Docker Hub RegistrySource implementation. It collects per-repo pull counts and total tag counts via the unauthenticated Docker Hub /v2/ API, handling wildcard owner expansion and severe-degradation detection.
Contract boundaries:
- URL shapes (https://hub.docker.com/v2/repositories/{owner}/...) are unchanged; httpx.DockerGitHubRedirectPolicy (wired on the shared *http.Client in main.go) still enforces the SSRF allowlist.
- The tag count comes from the tags listing's own top-level "count" field, read with a single page_size=1 request per repo — the registry's exact total at any tag cardinality, replacing the old full pagination of per-tag metadata whose only consumer was the slice length.
- The owner-listing page cap (10 pages, 100 items per page) and the "hit cap → warn log" signal are preserved so dashboards that alert on truncation still see the same key set.
The package exposes a *Client (for composition-root wiring via api.RegistrySource) plus the exported Degraded predicate (a pure function retained because its input-shape is what the legacy TestDockerHubDegraded matrix asserts against). All collection behavior is reached through *Client methods; there are no free-function shims.
Index ¶
Constants ¶
const ( MaxOwnerPages = 10 PageSize = 100 )
Pagination bounds for the owner listing. MaxOwnerPages is chosen well above realistic usage (1000 repos/owner) so normal traffic never hits it; hitting the cap is a signal that behaviour changed and the warn log below surfaces it.
Variables ¶
This section is empty.
Functions ¶
func Degraded ¶
func Degraded(results []model.RegistryEntry, attempted int) bool
Degraded reports whether a Docker Hub collection result is severely degraded: zero results with at least one attempt, or more than half of attempts failed. Kept as an exported free function because its pure-input shape is what the legacy TestDockerHubDegraded case matrix asserts against.
func ParseRepoListPage ¶
func ParseRepoListPage(data []byte, owner string) (next string, repos []model.RegistryEntry, err error)
ParseRepoListPage parses one page of the Docker Hub owner-listing response. It returns the "next" page token plus the page's repos with Owner set to the requested owner and Repo to the listed name (TagCount left 0 for the caller to fill). Pure parse core behind listRepos, exported for parse-only tests and fuzzing.
func ParseRepoMeta ¶
ParseRepoMeta parses a single Docker Hub repo metadata response, returning the pull count. It is the pure parse core behind Collect's explicit-ref path, exported so parse-only tests and fuzzing can drive it without standing up an HTTP server.
func ParseTagCount ¶ added in v2.2.0
ParseTagCount parses the Docker Hub tags-listing response's top-level "count" field — the registry's own total tag count for the repo. A response without a non-negative count is an error so a malformed or reshaped response can never flow into the image_tags gauge as a bogus value. Pure parse core behind the per-repo tag-count fetch, exported for parse-only tests and fuzzing.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client implements api.RegistrySource for Docker Hub. Construct via NewClient; the zero value is not usable.
func NewClient ¶
func NewClient(client *http.Client, retryOpts []httpx.GetOption, pageCap int, logger *slog.Logger) *Client
NewClient returns a Client that uses the provided *http.Client for all outbound requests, applying retryOpts to each call via httpx.GetBytes. A nil logger falls back to slog.Default. pageCap of 0 means "use the package-default owner-listing cap"; any non-zero value overrides it (used by tests to force the cap).
func (*Client) Collect ¶
func (c *Client) Collect( ctx context.Context, refs []model.RepoRef, ) (entries []model.RegistryEntry, attempted int, healthy bool)
Collect gathers pull counts and total tag counts for every ref in refs. Returns the per-repo entries plus the attempted count (including failures) and a healthy flag. healthy is false when the collection is severely degraded (see Degraded) OR when a wildcard owner-listing wholly failed — a non-nil listing error that yielded zero usable repos. The listing-failure signal is distinct because a wholesale listing outage leaves attempted == 0, which Degraded alone reads as healthy and would therefore mask a total Docker Hub outage.
A repo whose tag-count fetch fails still contributes its entry (pulls intact) with TagCount 0, so the caller emits no image_tags series for it that cycle rather than a wrong value — the same skip-don't-zero rule the GHCR source applies to failed scrapes.
func (*Client) Name ¶
Name identifies this source in logs and in the per-source health ratio. Matches the "dockerhub" const used on the HTTP API surface.
func (*Client) Source ¶
func (c *Client) Source() model.RegistrySource
Source returns the typed model.RegistrySource the orchestrator uses to route entries without a string compare. model.SourceDockerHub.String() must stay equal to Name() — both read as "dockerhub" on the wire.