feat: add custom Docker labels for supporting services#284
Conversation
Add `orchestrator_opts` to `ServiceSpec`, enabling users to apply custom Docker Swarm labels (e.g., for Traefik routing) to supporting services like MCP. This mirrors the existing `extra_labels` support on Postgres containers. Also adds API validation rejecting `pgedge.*`-prefixed labels across all three `orchestrator_opts` locations (database spec, node, and service) to prevent accidental overwrite of system labels.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds orchestrator options to ServiceSpec across API and database layers, validates reserved Swarm extra label prefixes, propagates options through conversion functions, merges user-provided Swarm extra labels into generated swarm service specs, and updates tests and CI lint output. Changes
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
server/internal/api/apiv1/convert.go (2)
981-993:⚠️ Potential issue | 🟠 MajorSame nil pointer dereference issue in
orchestratorOptsToAPI.If
optsis non-nil butopts.Swarmis nil, this function will panic when accessingopts.Swarm.ExtraVolumes,opts.Swarm.ExtraNetworks, andopts.Swarm.ExtraLabelson lines 987-989.🐛 Proposed fix to add nil check for Swarm
func orchestratorOptsToAPI(opts *database.OrchestratorOpts) *api.OrchestratorOpts { if opts == nil { return nil } + if opts.Swarm == nil { + return &api.OrchestratorOpts{} + } return &api.OrchestratorOpts{ Swarm: &api.SwarmOpts{ ExtraVolumes: extraVolumesToAPI(opts.Swarm.ExtraVolumes), ExtraNetworks: extraNetworksToAPI(opts.Swarm.ExtraNetworks), ExtraLabels: maps.Clone(opts.Swarm.ExtraLabels), }, } - }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@server/internal/api/apiv1/convert.go` around lines 981 - 993, The function orchestratorOptsToAPI dereferences opts.Swarm without checking for nil, which can panic; update orchestratorOptsToAPI to check if opts.Swarm is nil and only populate the returned api.OrchestratorOpts.Swarm when present—otherwise set Swarm to nil (or return nil) to avoid the dereference; use extraVolumesToAPI(opts.Swarm.ExtraVolumes), extraNetworksToAPI(opts.Swarm.ExtraNetworks) and maps.Clone(opts.Swarm.ExtraLabels) only after verifying opts.Swarm != nil.
968-979:⚠️ Potential issue | 🟠 MajorPotential nil pointer dereference when
opts.Swarmis nil.If
optsis non-nil butopts.Swarmis nil, this function will panic when accessingopts.Swarm.ExtraVolumes,opts.Swarm.ExtraNetworks, andopts.Swarm.ExtraLabelson lines 974-976.🐛 Proposed fix to add nil check for Swarm
func orchestratorOptsToDatabase(opts *api.OrchestratorOpts) *database.OrchestratorOpts { if opts == nil { return nil } + if opts.Swarm == nil { + return &database.OrchestratorOpts{} + } return &database.OrchestratorOpts{ Swarm: &database.SwarmOpts{ ExtraVolumes: extraVolumesToDatabase(opts.Swarm.ExtraVolumes), ExtraNetworks: extraNetworksToDatabase(opts.Swarm.ExtraNetworks), ExtraLabels: maps.Clone(opts.Swarm.ExtraLabels), }, } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@server/internal/api/apiv1/convert.go` around lines 968 - 979, The function orchestratorOptsToDatabase dereferences opts.Swarm without checking for nil; update orchestratorOptsToDatabase to first handle a nil opts.Swarm (when opts != nil) and avoid accessing opts.Swarm.ExtraVolumes/ExtraNetworks/ExtraLabels if Swarm is nil — e.g., if opts.Swarm == nil return &database.OrchestratorOpts{Swarm: nil} or construct a database.SwarmOpts with nil/empty fields accordingly; ensure you still call extraVolumesToDatabase and extraNetworksToDatabase only when the corresponding Swarm slices are present and use maps.Clone on ExtraLabels only when ExtraLabels is non-nil to prevent panics.
🧹 Nitpick comments (1)
server/internal/orchestrator/swarm/service_spec_test.go (1)
453-456: Minor style suggestion from static analysis (optional).The static analysis tool suggests that
got.Annotations.Labelscould be simplified togot.LabelssinceAnnotationsis an embedded field inswarm.ServiceSpec. However, the explicit form is clearer and this is a test file, so leaving it as-is is fine for readability.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@server/internal/orchestrator/swarm/service_spec_test.go` around lines 453 - 456, The test currently accesses labels via got.Annotations.Labels; simplify this by using the embedded field directly (got.Labels) to match static analysis suggestion—update the two occurrences in the test where tt.checkLabels is invoked (the calls that reference got.TaskTemplate.ContainerSpec.Labels and got.Annotations.Labels) to use got.Labels for the service-level labels while keeping ContainerSpec label checks unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@server/internal/api/apiv1/convert.go`:
- Around line 981-993: The function orchestratorOptsToAPI dereferences
opts.Swarm without checking for nil, which can panic; update
orchestratorOptsToAPI to check if opts.Swarm is nil and only populate the
returned api.OrchestratorOpts.Swarm when present—otherwise set Swarm to nil (or
return nil) to avoid the dereference; use
extraVolumesToAPI(opts.Swarm.ExtraVolumes),
extraNetworksToAPI(opts.Swarm.ExtraNetworks) and
maps.Clone(opts.Swarm.ExtraLabels) only after verifying opts.Swarm != nil.
- Around line 968-979: The function orchestratorOptsToDatabase dereferences
opts.Swarm without checking for nil; update orchestratorOptsToDatabase to first
handle a nil opts.Swarm (when opts != nil) and avoid accessing
opts.Swarm.ExtraVolumes/ExtraNetworks/ExtraLabels if Swarm is nil — e.g., if
opts.Swarm == nil return &database.OrchestratorOpts{Swarm: nil} or construct a
database.SwarmOpts with nil/empty fields accordingly; ensure you still call
extraVolumesToDatabase and extraNetworksToDatabase only when the corresponding
Swarm slices are present and use maps.Clone on ExtraLabels only when ExtraLabels
is non-nil to prevent panics.
---
Nitpick comments:
In `@server/internal/orchestrator/swarm/service_spec_test.go`:
- Around line 453-456: The test currently accesses labels via
got.Annotations.Labels; simplify this by using the embedded field directly
(got.Labels) to match static analysis suggestion—update the two occurrences in
the test where tt.checkLabels is invoked (the calls that reference
got.TaskTemplate.ContainerSpec.Labels and got.Annotations.Labels) to use
got.Labels for the service-level labels while keeping ContainerSpec label checks
unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2630658c-e924-4fc9-9075-624feef73574
⛔ Files ignored due to path filters (9)
api/apiv1/gen/control_plane/service.gois excluded by!**/gen/**api/apiv1/gen/http/control_plane/client/encode_decode.gois excluded by!**/gen/**api/apiv1/gen/http/control_plane/client/types.gois excluded by!**/gen/**api/apiv1/gen/http/control_plane/server/encode_decode.gois excluded by!**/gen/**api/apiv1/gen/http/control_plane/server/types.gois excluded by!**/gen/**api/apiv1/gen/http/openapi.jsonis excluded by!**/gen/**api/apiv1/gen/http/openapi.yamlis excluded by!**/gen/**api/apiv1/gen/http/openapi3.jsonis excluded by!**/gen/**api/apiv1/gen/http/openapi3.yamlis excluded by!**/gen/**
📒 Files selected for processing (7)
api/apiv1/design/database.goserver/internal/api/apiv1/convert.goserver/internal/api/apiv1/validate.goserver/internal/api/apiv1/validate_test.goserver/internal/database/spec.goserver/internal/orchestrator/swarm/service_spec.goserver/internal/orchestrator/swarm/service_spec_test.go
This should cause any errors to appear in the build log, while --output.junit-xml.path still writes the XML. Without --output.text, specifying --output.junit-xml.path causes golangci-lint v2 to only emit XML.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Makefile`:
- Line 59: Update the CI golangci-lint invocation in the Makefile where the
conditional uses "$(if $(filter true,$(CI)),--output.text
--output.junit-xml.path $@-results.xml)" to replace the invalid flag with the
correct form for v2.5.0: use "--output.text.path stdout" instead of
"--output.text"; ensure the conditional emits "--output.text.path stdout
--output.junit-xml.path $@-results.xml" so CI linting uses the valid flags.
|
|
||
| golangci-lint=$(gobin)/golangci-lint \ | ||
| $(if $(filter true,$(CI)),--output.text --output.junit-xml.path $@-results.xml) | ||
| $(if $(filter true,$(CI)),--output.text.path stdout --output.junit-xml.path $@-results.xml) |
There was a problem hiding this comment.
Just FYI in case you haven't seen it, CircleCI consumes these files and makes the results available in a dedicated Tests tab. I can see why you'd also want them in the text output, so I'm OK with adding this.
Summary
orchestrator_optstoServiceSpec, enabling custom Docker Swarm labels (e.g., for Traefik routing) on supporting services like MCPextra_labelssupport on Postgres containerspgedge.*-prefixed labels across all threeorchestrator_optslocations (database spec, node, and service) to prevent accidental overwrite of system labelsLinter improvement
--output.text.path stdoutto linter so the actual errors show up in the CircleCI output nowTest plan
ServiceContainerSpecwith extra labels and nil backward compatvalidateOrchestratorOpts(nil, empty, valid, reserved prefix)TestValidateServiceSpec(valid labels, rejectedpgedge.*labels)orchestrator_opts.swarm.extra_labelsand verify withdocker service inspectSample config
PLAT-455