Skip to content

fix: service network not attached + complete service adapter conversions#525

Merged
CybotTM merged 8 commits intomainfrom
fix/roundtrip-tests
Mar 16, 2026
Merged

fix: service network not attached + complete service adapter conversions#525
CybotTM merged 8 commits intomainfrom
fix/roundtrip-tests

Conversation

@CybotTM
Copy link
Copy Markdown
Member

@CybotTM CybotTM commented Mar 16, 2026

Summary

Fixes #524job-service-run network attachment silently dropped, service never joins the specified network.

Root cause: convertToSwarmSpec() read networks from ServiceSpec.Networks, but buildService() writes to TaskTemplate.Networks. The domain/adapter refactor in 9cefcdf (2025-11-26) introduced this mismatch.

Bug fixes

  • convertToSwarmSpec network mapping: read networks from both ServiceSpec.Networks and TaskTemplate.Networks
  • convertFromSwarmService missing conversions: Mounts, RestartPolicy, Resources, Networks, Mode were silently lost when inspecting services

New conversions (previously dead domain types)

Placement, LogDriver, and EndpointSpec existed in the domain model but had no conversion code in either direction — silently dropped when set. Now fully wired:

  • TaskSpec.Placement (Constraints + Preferences with SpreadOver)
  • TaskSpec.LogDriver (Name + Options)
  • ServiceSpec.EndpointSpec (Mode + Ports with all PortConfig fields)

Refactoring

Extracted convertTaskTemplateToSwarm and convertTaskTemplateFromSwarm helpers to keep cyclomatic complexity below the gocyclo threshold.

Tests — 13 round-trip + 1 integration (TDD)

Test Verifies
ContainerSpec All 11 fields + Mounts + service Name/Labels
TaskTemplateNetworks Networks set on TaskTemplate (the #524 bug)
ServiceSpecNetworks Networks set on ServiceSpec level
RestartPolicy All 4 fields (on-failure condition)
RestartConditionNone Exact production values (condition=none, maxAttempts=1)
Resources Limits + Reservations (NanoCPUs, MemoryBytes)
ModeReplicated Replicated mode with replica count
ModeGlobal Global mode
Mounts Bind + Volume with ReadOnly
NilFields All optional fields nil/zero stay nil/zero
Placement Constraints + SpreadOver preferences
LogDriver Name + Options map
EndpointSpec VIP mode + TCP ports with all PortConfig fields

Plus 1 integration test verifying buildService() → domain spec has network.

Test plan

  • 13 round-trip tests — all written before fixes, verified failing (TDD)
  • 1 integration test for buildService network wiring
  • All existing tests unaffected
  • CHANGELOG updated
  • CI passes

Fix convertToSwarmSpec reading networks only from ServiceSpec.Networks,
ignoring TaskTemplate.Networks where buildService() actually writes them.
This caused job-service-run network attachments to be silently dropped
(closes #524).

Fix convertFromSwarmService missing conversions for Mounts, RestartPolicy,
Resources, Networks, and Mode — all were silently lost when inspecting
services.

Add comprehensive round-trip tests (domain→swarm→domain) that verify
every field survives the conversion cycle. All 8 round-trip tests were
written before the fixes and confirmed failing (TDD).

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Copilot AI review requested due to automatic review settings March 16, 2026 21:59
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical bug where Docker Swarm service network attachments were silently dropped due to a mismatch in how network configurations were read and written within the domain layer. It also significantly enhances the fromSwarm conversion logic to ensure a complete and accurate round-trip conversion of various service specifications, including mounts, restart policies, resource limits, and service modes, thereby improving the robustness and reliability of service management.

Highlights

  • Network Attachment Fix: Modified convertToSwarmSpec() to correctly read network configurations from both ServiceSpec.Networks and TaskTemplate.Networks, resolving an issue where network attachments were silently dropped.
  • Swarm Conversion Enhancements: Extended convertFromSwarmService() to include missing conversions for ContainerSpec Mounts, RestartPolicy, Resources (Limits and Reservations), TaskTemplate-level Networks, and Service Mode (Replicated and Global).
Changelog
  • core/adapters/docker/service.go
    • Updated convertToSwarmSpec to correctly process network configurations from both ServiceSpec.Networks and TaskTemplate.Networks.
    • Expanded convertFromSwarmService to include comprehensive conversions for ContainerSpec Mounts, RestartPolicy, Resources (Limits and Reservations), TaskTemplate-level Networks, and Service Mode (Replicated and Global).
  • core/adapters/docker/service_roundtrip_test.go
    • Added a new test file containing 8 round-trip tests to validate the correct conversion of various service specification fields between domain and Swarm types.
  • core/runservice_network_test.go
    • Added a new integration test to confirm that network attachments specified in RunServiceJob are correctly wired into the Docker Swarm service specification.
Activity
  • The author confirmed that 8 new round-trip tests, designed to expose the conversion bugs, were failing prior to the changes and now pass successfully.
  • All existing test suites were confirmed to be unaffected by these changes.
  • The continuous integration (CI) pipeline has passed, indicating no regressions were introduced.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 16, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

github-actions[bot]
github-actions Bot previously approved these changes Mar 16, 2026
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated approval for solo maintainer project

All CI checks passed. See SECURITY.md for compensating controls.

@github-actions
Copy link
Copy Markdown

✅ Mutation Testing Results

Mutation Score: 100.00% (threshold: 60%)

✨ Good job! Mutation score meets the threshold.

What is mutation testing?

Mutation testing measures test quality by introducing small changes (mutations) to the code and checking if tests detect them. A higher score means better test effectiveness.

  • Killed mutants: Tests caught the mutation (good!)
  • Survived mutants: Tests missed the mutation (needs improvement)

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

The pull request addresses several conversion bugs in core/adapters/docker/service.go. The convertToSwarmSpec function was updated to correctly aggregate network configurations from both service and task template levels. The convertFromSwarmService function was significantly enhanced to properly convert various service properties, including container mounts, restart policies, resource requirements (limits and reservations), network attachments, and service mode (replicated or global), from Docker Swarm's swarm.Service structure back to the internal domain.Service representation. These fixes are validated by new, comprehensive round-trip tests in service_roundtrip_test.go and a new test in runservice_network_test.go for network wiring. The review comments suggest optimizing slice allocations in convertFromSwarmService for Mounts and Networks by pre-allocating them, and updating outdated "BUG" comments and assertion messages in the new service_roundtrip_test.go file to reflect the resolved issues.

Comment thread core/adapters/docker/service.go
Comment thread core/adapters/docker/service.go Outdated
Comment thread core/adapters/docker/service_roundtrip_test.go Outdated
Comment thread core/adapters/docker/service_roundtrip_test.go Outdated
Comment thread core/adapters/docker/service_roundtrip_test.go Outdated
Comment thread core/adapters/docker/service_roundtrip_test.go Outdated
Comment thread core/adapters/docker/service_roundtrip_test.go Outdated
Comment thread core/adapters/docker/service_roundtrip_test.go Outdated
Comment thread core/adapters/docker/service_roundtrip_test.go Outdated
Comment thread core/adapters/docker/service_roundtrip_test.go Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes the Swarm service network attachment regression for job-service-run by ensuring the Docker adapter correctly converts network attachments from the domain model to the Swarm SDK model, and expands convertFromSwarmService() to round-trip additional service fields.

Changes:

  • Fix convertToSwarmSpec() to include networks provided via both ServiceSpec.Networks and TaskTemplate.Networks.
  • Implement missing convertFromSwarmService() conversions (mounts, restart policy, resources, networks, service mode).
  • Add unit tests covering round-trip conversions and a core-level test asserting RunServiceJob.Network is wired into the service spec.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
core/adapters/docker/service.go Fixes network conversion path and adds missing Swarm→domain conversions for service specs.
core/adapters/docker/service_roundtrip_test.go Adds round-trip coverage to validate the adapter conversions end-to-end.
core/runservice_network_test.go Adds a focused regression test to ensure RunServiceJob.Network is preserved into the created service spec.
Comments suppressed due to low confidence (1)

core/adapters/docker/service.go:249

  • convertToSwarmSpec currently merges ServiceSpec.Networks and TaskTemplate.Networks by simple concatenation. If both are set, the same network can be emitted twice, which may cause Docker to reject the spec or attach twice. Consider de-duplicating by Target (and possibly merging/unioning Aliases) and avoid potential slice aliasing by copying before append.
	// Convert networks from both ServiceSpec and TaskTemplate levels.
	// buildService() writes to TaskTemplate.Networks; both locations are valid.
	allNetworks := append(spec.Networks, spec.TaskTemplate.Networks...)
	for _, n := range allNetworks {
		swarmSpec.TaskTemplate.Networks = append(swarmSpec.TaskTemplate.Networks, swarm.NetworkAttachmentConfig{
			Target:  n.Target,
			Aliases: n.Aliases,
		})
	}

You can also share your feedback on Copilot code review. Take the survey.

Comment thread core/adapters/docker/service.go Outdated
Comment thread core/adapters/docker/service.go Outdated
Comment thread core/adapters/docker/service_roundtrip_test.go Outdated
Comment thread core/adapters/docker/service_roundtrip_test.go
Comment thread core/adapters/docker/service_roundtrip_test.go Outdated
Fix gocritic appendAssign lint by using separate loops for network
sources. Fix gci import ordering. Reword test comments/assertions
to describe expected behavior rather than fixed bugs.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
github-actions[bot]
github-actions Bot previously approved these changes Mar 16, 2026
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated approval for solo maintainer project

All CI checks passed. See SECURITY.md for compensating controls.

The project gci config uses prefix(github.com/netresearch/ofelia) as
a separate section, requiring blank line between external and project
imports.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
github-actions[bot]
github-actions Bot previously approved these changes Mar 16, 2026
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated approval for solo maintainer project

All CI checks passed. See SECURITY.md for compensating controls.

Add TestServiceSpec_RoundTrip_NilFields verifying that nil RestartPolicy,
Resources, Networks, Mounts, and Mode all remain nil/empty after round-trip.

Add TestServiceSpec_RoundTrip_RestartConditionNone testing the exact
values buildService() uses (Condition=none, MaxAttempts=1, nil Delay/Window).

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
github-actions[bot]
github-actions Bot previously approved these changes Mar 16, 2026
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated approval for solo maintainer project

All CI checks passed. See SECURITY.md for compensating controls.

Add toSwarm and fromSwarm conversion for three domain types that existed
in the model but were silently dropped during conversion:

- TaskSpec.Placement (Constraints + Preferences with SpreadOver)
- TaskSpec.LogDriver (Name + Options)
- ServiceSpec.EndpointSpec (Mode + Ports with all PortConfig fields)

Add 3 round-trip tests verifying full domain→swarm→domain fidelity.
Total round-trip tests: 13.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
github-actions[bot]
github-actions Bot previously approved these changes Mar 16, 2026
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated approval for solo maintainer project

All CI checks passed. See SECURITY.md for compensating controls.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
github-actions[bot]
github-actions Bot previously approved these changes Mar 16, 2026
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated approval for solo maintainer project

All CI checks passed. See SECURITY.md for compensating controls.

Split convertToSwarmSpec and convertFromSwarmService into smaller
functions (convertTaskTemplateToSwarm, convertTaskTemplateFromSwarm)
to bring cyclomatic complexity below the gocyclo threshold of 15.

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
github-actions[bot]
github-actions Bot previously approved these changes Mar 16, 2026
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated approval for solo maintainer project

All CI checks passed. See SECURITY.md for compensating controls.

@CybotTM CybotTM changed the title fix: service network not attached + missing fromSwarm conversions fix: service network not attached + complete service adapter conversions Mar 16, 2026
Distinguish the network bug fix and missing fromSwarm conversions (Fixed)
from the new Placement/LogDriver/EndpointSpec support (Added).

Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated approval for solo maintainer project

All CI checks passed. See SECURITY.md for compensating controls.

@CybotTM CybotTM added this pull request to the merge queue Mar 16, 2026
Merged via the queue into main with commit f3d3204 Mar 16, 2026
29 checks passed
@CybotTM CybotTM deleted the fix/roundtrip-tests branch March 16, 2026 23:51
@github-actions github-actions Bot added the released:v0.21.4 Included in v0.21.4 release label Mar 17, 2026
@github-actions
Copy link
Copy Markdown

🚀 Released in v0.21.4

Thank you for your contribution! 🙏

This is now available in the latest release. Please test and verify everything works as expected in your environment.

If you encounter any issues, please open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

released:v0.21.4 Included in v0.21.4 release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Job not getting added to network.

2 participants