Documentation
¶
Index ¶
- Constants
- Variables
- func AwaitCondition(ctx context.Context, cond func() (bool, error), interval time.Duration) error
- func AwaitContainerInspect(ctx context.Context, docker ContainerInspector, id string, ...) (container.InspectResponse, error)
- func AwaitLinkByIndex(ctx context.Context, handle *netlink.Handle, index int, interval time.Duration) (netlink.Link, error)
- func AwaitNetNS(ctx context.Context, path string, interval time.Duration) (netns.NsHandle, error)
- func ErrToStatus(err error) int
- func JSONErrResponse(w http.ResponseWriter, err error, statusCode int)
- func JSONResponse(w http.ResponseWriter, v interface{}, statusCode int)
- func ParseJSONOrErrorResponse(v interface{}, w http.ResponseWriter, r *http.Request) error
- func WriteAccessLog(w io.Writer, params handlers.LogFormatterParams)
- type ContainerInspector
Constants ¶
const (
OptionsKeyGeneric = "com.docker.network.generic"
)
Variables ¶
var ( // ErrIPAM indicates an unsupported IPAM driver was used ErrIPAM = errors.New("only the null IPAM driver is supported") // ErrBridgeRequired indicates a network bridge was not provided for network creation ErrBridgeRequired = errors.New("bridge required (mode=bridge)") // ErrNotBridge indicates that the provided network interface is not a bridge ErrNotBridge = errors.New("network interface is not a bridge") // ErrBridgeUsed indicates that a bridge is already in use ErrBridgeUsed = errors.New("bridge already in use by Docker") // ErrInvalidMode indicates an unsupported value was passed for the `mode` option ErrInvalidMode = errors.New("invalid mode (must be 'bridge' or 'macvlan')") // ErrParentRequired indicates `parent` was not provided when mode=macvlan ErrParentRequired = errors.New("parent required (mode=macvlan)") // ErrParentInvalid indicates the parent interface cannot host macvlan children ErrParentInvalid = errors.New("parent interface is unsuitable for macvlan (bridge or macvlan)") // ErrParentDown indicates the parent interface is administratively down ErrParentDown = errors.New("parent interface is down") // ErrModeMismatch indicates an option that doesn't apply to the chosen mode was set ErrModeMismatch = errors.New("option does not apply to selected mode") // ErrMACAddress indicates an invalid MAC address ErrMACAddress = errors.New("invalid MAC address") // ErrNoLease indicates a DHCP lease was not obtained from dhcpcd ErrNoLease = errors.New("dhcpcd did not output a lease") // ErrNoHint indicates missing state from the CreateEndpoint stage in Join ErrNoHint = errors.New("missing CreateEndpoint hints") // ErrNotVEth indicates a host link was unexpectedly not a veth interface ErrNotVEth = errors.New("host link is not a veth interface") // ErrNoContainer indicates a container was unexpectedly not found ErrNoContainer = errors.New("couldn't find container by endpoint on the network") // ErrNoSandbox indicates missing state from the Join stage ErrNoSandbox = errors.New("missing joined endpoint state") )
Functions ¶
func AwaitCondition ¶
AwaitCondition polls cond every interval until it returns ok=true, an error, or ctx is cancelled. The poll runs synchronously in the caller's goroutine: a previous async-poller form leaked a goroutine on every ctx-cancel because it kept calling cond forever (typically Docker NetworkInspect, ~10/s/leaked-goroutine). cond is expected to be reasonably fast or to honor ctx itself; we don't try to interrupt it.
func AwaitContainerInspect ¶
func AwaitContainerInspect(ctx context.Context, docker ContainerInspector, id string, interval time.Duration) (container.InspectResponse, error)
AwaitContainerInspect polls docker.ContainerInspect until it succeeds, ctx is cancelled, or interval-paced retries exhaust. Synchronous for the same reason as AwaitNetNS — the previous async form leaked a poller goroutine on ctx-cancel that kept hitting the Docker API forever.
"No such container" ends the wait immediately instead of being retried. Polling for a container that has been removed can only ever end in the deadline, and callers then read that deadline as "the daemon was slow" when what actually happened is "the container is gone". Those need opposite responses: one is a fault worth counting, the other is an ordinary short-lived container. Retrying an absence spent the whole budget converting the second into the first — nine to twelve times per integration run (#401).
A NotFound arriving here means removed, not "not yet": every caller resolves the container ID from the daemon first, so it existed moments ago. The error is returned with its chain intact so callers can classify with cerrdefs.IsNotFound.
Other errors are still retried, and the last one is reported alongside the deadline — the same contract AwaitNetNS and AwaitLinkByIndex already keep. Discarding it here was why a Join timeout said only "context deadline exceeded" while its sibling failures named a missing file.
func AwaitLinkByIndex ¶
func AwaitLinkByIndex(ctx context.Context, handle *netlink.Handle, index int, interval time.Duration) (netlink.Link, error)
AwaitLinkByIndex polls for a netlink Link by index until it appears, ctx is cancelled, or interval-paced retries exhaust. Synchronous for the same reason as AwaitNetNS; surfaces the last attempt's error for the same reason too.
func AwaitNetNS ¶
AwaitNetNS polls for a netns at path until it appears, ctx is cancelled, or interval-paced retries exhaust. Synchronous to avoid leaking a poller goroutine on ctx-cancel (the previous form did, and each leaked goroutine kept hammering netns.GetFromPath forever).
On ctx expiry the returned error wraps ctx.Err() (so errors.Is against context.DeadlineExceeded keeps working) and carries the last attempt's underlying error. A bare "context deadline exceeded" hid a persistent EACCES for weeks in production — the netns open needs ptrace access to the target process, and a permission failure retried to the deadline is indistinguishable from a startup race without this (#317).
func ErrToStatus ¶
ErrToStatus maps a sentinel error to its HTTP status. Validation errors (caller-supplied bad input) produce 400. Upstream-DHCP and retryable Docker-state-transition errors produce 502 / 503 / 409 so the wire shape is meaningful to non-libnetwork consumers; the libnetwork integration treats all 5xx the same so this is purely a clarity win for direct API users / logs / dashboards.
Anything not enumerated here falls through to 500 — those are either internal plumbing failures (netlink, fs) or unexpected daemon errors, where 500 is the honest answer.
func JSONErrResponse ¶
func JSONErrResponse(w http.ResponseWriter, err error, statusCode int)
JSONErrResponse Sends an `error` as a JSON object with a `message` property. Logs at a level matching the HTTP status:
- 5xx -> Error (we did something wrong)
- 4xx -> Warn (caller did something wrong; not actionable for us)
- other -> Info
A torrent of 4xx from a misconfigured client used to land at ERROR, drowning real failures (I-12 in the 2026-05-05 review).
func JSONResponse ¶
func JSONResponse(w http.ResponseWriter, v interface{}, statusCode int)
JSONResponse Sends a JSON payload in response to a HTTP request. The payload is encoded into a buffer first so that, on encoding failure, we can still send a clean HTTP 500 instead of a garbled response with a half-flushed body and a no-op second WriteHeader call.
func ParseJSONOrErrorResponse ¶
func ParseJSONOrErrorResponse(v interface{}, w http.ResponseWriter, r *http.Request) error
ParseJSONOrErrorResponse decodes the request body as JSON into v. On failure it ALSO writes a 400 JSON error response to w; the caller is expected to early-return on a non-nil error and not touch w again. The verbose name is deliberate: the prior name (ParseJSONBody) read as a pure parse, but the function quietly took over response writing — a future caller writing the obvious-looking
if err := ParseJSONBody(&req, w, r); err != nil {
JSONErrResponse(w, err, ...); return
}
would double-write headers. This name makes the response-writing side-effect impossible to overlook at the call site.
func WriteAccessLog ¶
func WriteAccessLog(w io.Writer, params handlers.LogFormatterParams)
Types ¶
type ContainerInspector ¶
type ContainerInspector interface {
ContainerInspect(ctx context.Context, id string) (container.InspectResponse, error)
}
ContainerInspector is the one Docker-client method AwaitContainerInspect needs. Taking an interface (not the concrete *client.Client) lets callers inject a fake in tests; the real client satisfies it as-is.