Skip to content

Push custom project config api at start of Up#13958

Open
nicksieger wants to merge 6 commits into
docker:mainfrom
nicksieger:project-config-api
Open

Push custom project config api at start of Up#13958
nicksieger wants to merge 6 commits into
docker:mainfrom
nicksieger:project-config-api

Conversation

@nicksieger

@nicksieger nicksieger commented Jul 21, 2026

Copy link
Copy Markdown
Member

What I did

POST /v{version}/compose/project is a new custom api to be sent over the engine connection at the start of compose up that sends the full project configuration to the server to allow pre-populating caches and service maps. An engine marks that it can receive the config api by putting a com.docker.compose.project.config key in the context metadata with value bool true or string "true".

  • version-gated behind new apiVersionComposeProjectConfig constant
  • skipped in dry-run
  • non-fatal: warn and continue on request or engine error

Related issue

(not mandatory) A picture of a cute animal, if possible in relation to what you did

IMG_0074

Detect the `com.docker.compose.project.config` context metadata key (bool
true or string "true"); when set, POST the full project config to the
coordinator at `/v{version}/compose/project` over the engine socket dialer
at the start of `compose up`, before any other Docker API call.

- version-gated behind new apiVersionComposeProjectConfig constant
- skipped in dry-run
- non-fatal: warn and continue on request or engine error

Signed-off-by: Nick Sieger <nick@nicksieger.com>
@nicksieger
nicksieger requested review from a team as code owners July 21, 2026 20:37
@nicksieger
nicksieger requested review from glours and ndeloof July 21, 2026 20:37

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 No issues found — LGTM! View logs.

@glours glours left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The project-config push is coordinator-specific integration code, and pkg/compose isn't the right home for it. pkg/ is Compose's reusable, general-purpose surface, tool-specific integrations should stay under internal/, the way Docker Desktop integration lives entirely in internal/desktop (endpoint detection, HTTP client, feature gating) with pkg/compose only calling into it.

Could we move this into a dedicated internal/coordinator package following that same pattern? The detection (the com.docker.compose.project.config context-metadata check), the HTTP client over the engine dialer, the versioned URL and the outcome handling would all live there, and pkg/compose would keep just a thin call-site in up.go.

Besides keeping the core library clean, this gives us a natural home as more coordinator-specific features land, rather than scattering them across pkg/compose.

Separate concern - the request needs a timeout. The http.Client has no Timeout and the Up context has no deadline; since this runs before s.create, a coordinator that accepts the connection but never responds would hang up indefinitely, so the "non-fatal, warn and continue" guarantee doesn't hold. This should be bounded (I'll leave the exact approach up to you).

@codecov

codecov Bot commented Jul 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 87.87879% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/coordinator/coordinator.go 92.30% 2 Missing and 2 partials ⚠️
pkg/compose/up.go 71.42% 3 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Relocate the coordinator-specific project-config push out of pkg/compose,
which is Compose's reusable surface, into a dedicated internal/coordinator
package mirroring internal/desktop. Detection, the engine-dialer HTTP
client, the versioned URL and outcome handling now live there; up.go keeps
a thin call-site.

Bound the push with an http.Client timeout so a coordinator that accepts
the connection but never responds cannot hang "compose up", preserving the
non-fatal warn-and-continue guarantee.

Signed-off-by: Nick Sieger <nick@nicksieger.com>

@docker-agent docker-agent left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assessment: 🟡 NEEDS ATTENTION

Lower-confidence findings (not posted inline)

  • [medium] internal/coordinator/coordinator.go:80 — PushEnabled type-switch lacks *map[string]any arm — contexts stored via testStoreCfg factory may silently return false (confidence: weak 52/100)

    The testStoreCfg uses a factory returning &map[string]any{}. If the Docker CLI context store calls this factory to allocate a deserialization target, round-tripped metadata of type map[string]any would arrive as *map[string]any. The type-switch in PushEnabled only handles command.DockerContext and map[string]any — a *map[string]any falls to the default branch and returns false, silently disabling the project-config push for any such context. If this matters in production (contexts backed by generic map metadata), adding a case *map[string]any: arm is the fix.

Comment thread internal/coordinator/coordinator.go
http.Transport is allocated per call and discarded; without
CloseIdleConnections its persistConn goroutines linger until
IdleConnTimeout. Tear them down eagerly in the deferred cleanup.

Signed-off-by: Nick Sieger <nick@nicksieger.com>

@glours glours left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 last small change to ensure the warning message will be properly displayed by the ttyWriter

Comment thread pkg/compose/up.go Outdated
Comment thread internal/coordinator/coordinator.go Outdated
Comment thread internal/coordinator/coordinator.go Outdated
nicksieger and others added 3 commits July 23, 2026 10:38
Co-authored-by: Guillaume Lours <705411+glours@users.noreply.github.com>
Signed-off-by: Nick Sieger <nick@nicksieger.com>
"compose up" with no service arguments and no profiles applied resolves
the whole project; naming services narrows it to a subset (+ dependency
closure), and an applied profile disables the services outside it.
Advertise which one the coordinator received via a new
X-Compose-Project-Complete header so it can merge partial pushes with
stored config instead of treating every push as authoritative.

- mark complete only when the service selection is empty and no profile
  is active; blank profile entries (compose-go's no-profile sentinel) are
  ignored via hasActiveProfiles
- set the header explicitly (true/false); absent means older client and
  must be read as "false" so no prune is ever triggered on its behalf

Signed-off-by: Nick Sieger <nick@nicksieger.com>
Use the metadata to indicate coordinator presense, not just capable of accepting
the push project config api.

Signed-off-by: Nick Sieger <nick@nicksieger.com>
@nicksieger
nicksieger force-pushed the project-config-api branch from 8ec96b4 to 95d5383 Compare July 23, 2026 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants