Skip to content

feat: add Image and ResolvedImage fields to SwarmOpts#392

Open
tsivaprasad wants to merge 8 commits into
mainfrom
PLAT-596-add-image-version-fields-to-database-spec
Open

feat: add Image and ResolvedImage fields to SwarmOpts#392
tsivaprasad wants to merge 8 commits into
mainfrom
PLAT-596-add-image-version-fields-to-database-spec

Conversation

@tsivaprasad
Copy link
Copy Markdown
Contributor

@tsivaprasad tsivaprasad commented May 26, 2026

Summary

This PR adds Image and ResolvedImage fields to SwarmOpts and implements precedence-based image resolution in the Swarm orchestrator. This provides the foundation for user-controlled image overrides and stable image pinning.

Changes

  • Added Image (user override, never managed by CP) and ResolvedImage (CP-managed) fields to SwarmOpts in server/internal/database/spec.go, serialized under orchestrator_opts.docker.
  • Updated SwarmOpts.Clone() to correctly copy both new fields.
  • Extracted resolveInstanceImages() in the Swarm orchestrator to implement precedence-based image resolution: ImageResolvedImage → manifest lookup (lazy backfill).
  • When Image is explicitly set, the manifest is bypassed entirely, allowing unknown or custom versions to work through user overrides.

Testing

Verification:

  • Created cluster
  • Created DB using create_db.json
  • Confirm Docker service resolved the correct manifest image
docker service ls
ID             NAME                              MODE         REPLICAS   IMAGE                                                       PORTS
l2837hwwvoy8   postgres-storefront-n1-9ptayhma   replicated   1/1        ghcr.io/pgedge/pgedge-postgres:17.9-spock5.0.6-standard-2   
c6wg777c5rig   postgres-storefront-n1-689qacsi   replicated   1/1        ghcr.io/pgedge/pgedge-postgres:17.9-spock5.0.6-standard-2   
seysxqetlp0s   postgres-storefront-n1-ant97dj4   replicated   1/1        ghcr.io/pgedge/pgedge-postgres:17.9-spock5.0.6-standard-2 

Checklist

  • Tests added or updated

PLAT-596

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Image and ResolvedImage to SwarmOpts (copied by Clone), implements resolveInstanceImages with precedence (Image → ResolvedImage → manifest fetch + lazy backfill), integrates resolution into instanceResources and reconciliation, updates DB/service hooks and systemd stub, and adds tests plus a version-manifest.json.

Changes

Image Resolution and SwarmOpts Enhancement

Layer / File(s) Summary
SwarmOpts data model and cloning
server/internal/database/spec.go, server/internal/database/spec_test.go
SwarmOpts gains Image (user override) and ResolvedImage (control-plane managed) fields with JSON tags. Clone() copies both new fields. TestSwarmOptsClone validates cloning behavior, independence after mutation, and nil receiver handling.
Image resolution orchestrator logic
server/internal/orchestrator/swarm/orchestrator.go
New resolveInstanceImages helper applies image precedence (user Image → stored ResolvedImage → manifest fetch with lazy backfill). It initializes nil OrchestratorOpts/SwarmOpts when needed. ReconcileInstanceSpec clears ResolvedImage on version change and then resolves images. instanceResources now uses this helper.
Image resolution test coverage
server/internal/orchestrator/swarm/resolve_instance_images_test.go
TestResolveInstanceImages exercises explicit overrides, precedence ordering, using stored ResolvedImage without mutation, lazy backfill with nil struct initialization, error handling for unknown versions, and ensures manifest cache/results are not mutated by backfill.
Version manifest
server/internal/orchestrator/swarm/version-manifest.json
Adds pinned image tags, stability flags, and default markers for postgres, postgrest, mcp, and rag used by Versions.GetImages.
DB orchestrator hook and service integration
server/internal/database/orchestrator.go, server/internal/database/service.go
Adds ReconcileInstanceSpec(old, new *InstanceSpec) error to database.Orchestrator and calls it from Service.ReconcileInstanceSpec for both existing and new instances before persistence.
Systemd orchestrator stub
server/internal/orchestrator/systemd/orchestrator.go
Adds a no-op ReconcileInstanceSpec implementation returning nil to satisfy the updated orchestrator interface.

Poem

🐰 I nibbled the manifest root,

New image fields snug and bright,
User first then stored delight,
Backfill writes when tags run dry,
SwarmOpts clones hop safe and light.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding Image and ResolvedImage fields to SwarmOpts, which is the primary structural change in the pull request.
Description check ✅ Passed The description includes Summary, Changes, Testing, and Checklist sections per the template. However, Documentation and Breaking Changes sections are missing, and Changelog entry is not mentioned as added.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch PLAT-596-add-image-version-fields-to-database-spec

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented May 26, 2026

Up to standards ✅

🟢 Issues 1 medium

Results:
1 new issue

Category Results
Complexity 1 medium

View in Codacy

🟢 Metrics 62 complexity · 2 duplication

Metric Results
Complexity 62
Duplication 2

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

Comment thread server/internal/orchestrator/swarm/orchestrator.go
Comment thread server/internal/orchestrator/swarm/orchestrator.go
@tsivaprasad tsivaprasad force-pushed the PLAT-596-add-image-version-fields-to-database-spec branch from 44c4a96 to 02de9bd Compare June 3, 2026 06:03
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
server/internal/orchestrator/swarm/orchestrator.go (1)

214-221: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Clear ResolvedImage for nil↔explicit version changes too.

Line 214 only invalidates the cached image when both specs have a non-nil PgEdgeVersion. An update from nil -> 17.x or 17.x -> nil leaves ResolvedImage intact, and Line 221 will then reuse that stale value instead of resolving against the new effective version. That can deploy the wrong Postgres image after a version change.

Suggested fix
 func (o *Orchestrator) ReconcileInstanceSpec(old, new *database.InstanceSpec) error {
+	versionChanged := false
+
 	// If the Postgres version changed, the previously resolved image no longer
 	// matches — clear it so resolveInstanceImages fetches the correct one from
 	// the manifest.
-	if old != nil && old.PgEdgeVersion != nil && new.PgEdgeVersion != nil {
-		if !old.PgEdgeVersion.Equals(new.PgEdgeVersion) {
-			if new.OrchestratorOpts != nil && new.OrchestratorOpts.Swarm != nil {
-				new.OrchestratorOpts.Swarm.ResolvedImage = ""
-			}
-		}
+	if old != nil {
+		switch {
+		case old.PgEdgeVersion == nil && new.PgEdgeVersion == nil:
+			versionChanged = false
+		case old.PgEdgeVersion == nil || new.PgEdgeVersion == nil:
+			versionChanged = true
+		default:
+			versionChanged = !old.PgEdgeVersion.Equals(new.PgEdgeVersion)
+		}
+	}
+
+	if versionChanged && new.OrchestratorOpts != nil && new.OrchestratorOpts.Swarm != nil {
+		new.OrchestratorOpts.Swarm.ResolvedImage = ""
 	}
 	_, err := o.resolveInstanceImages(new)
 	return err
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/internal/orchestrator/swarm/orchestrator.go` around lines 214 - 221,
The cache invalidation only checks when both old.PgEdgeVersion and
new.PgEdgeVersion are non-nil; change the condition before calling
o.resolveInstanceImages(new) to detect any version change including nil↔non-nil
transitions (i.e., old==nil && new!=nil, old!=nil && new==nil, or
!old.Equals(new)) and when true, set new.OrchestratorOpts.Swarm.ResolvedImage =
"" (guarded by new.OrchestratorOpts != nil && new.OrchestratorOpts.Swarm != nil)
so resolveInstanceImages(new) cannot reuse a stale ResolvedImage; update the
logic around variables old, new, PgEdgeVersion,
OrchestratorOpts.Swarm.ResolvedImage and the subsequent call to
resolveInstanceImages to implement this.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@server/internal/orchestrator/swarm/orchestrator.go`:
- Around line 214-221: The cache invalidation only checks when both
old.PgEdgeVersion and new.PgEdgeVersion are non-nil; change the condition before
calling o.resolveInstanceImages(new) to detect any version change including
nil↔non-nil transitions (i.e., old==nil && new!=nil, old!=nil && new==nil, or
!old.Equals(new)) and when true, set new.OrchestratorOpts.Swarm.ResolvedImage =
"" (guarded by new.OrchestratorOpts != nil && new.OrchestratorOpts.Swarm != nil)
so resolveInstanceImages(new) cannot reuse a stale ResolvedImage; update the
logic around variables old, new, PgEdgeVersion,
OrchestratorOpts.Swarm.ResolvedImage and the subsequent call to
resolveInstanceImages to implement this.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4dbfec80-c34f-4855-98c9-eb20bd943510

📥 Commits

Reviewing files that changed from the base of the PR and between 02de9bd and 38303f5.

📒 Files selected for processing (4)
  • server/internal/database/orchestrator.go
  • server/internal/database/service.go
  • server/internal/orchestrator/swarm/orchestrator.go
  • server/internal/orchestrator/systemd/orchestrator.go

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
Makefile (1)

158-158: ⚡ Quick win

Add explanatory comment for the new exclusion.

The comment block at lines 149-151 documents why dependencies are excluded from NOTICE.txt generation. Following this pattern, add a comment explaining that dario.cat/mergo is manually handled in NOTICE.txt.tmpl.

📝 Proposed addition to comment block
 # Exclude some dependencies from NOTICE.txt generation
 # - github.com/pgEdge/control-plane is our own code
 # - github.com/eclipse/paho.golang is licensed under EDL-1.0 explicitly in # NOTICES.txt.tmpl
+# - dario.cat/mergo is licensed under BSD-3-Clause explicitly in NOTICE.txt.tmpl
 .PHONY: licenses
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` at line 158, Add a brief explanatory comment above the new Makefile
exclusion flag for "dario.cat/mergo" documenting that this dependency is
intentionally excluded because it is handled manually in NOTICE.txt.tmpl; update
the existing comment block that explains why dependencies are excluded (the
block around the --ignore flags) to mention "dario.cat/mergo is manually
maintained in NOTICE.txt.tmpl" so future maintainers understand the exception.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@Makefile`:
- Line 158: Add a brief explanatory comment above the new Makefile exclusion
flag for "dario.cat/mergo" documenting that this dependency is intentionally
excluded because it is handled manually in NOTICE.txt.tmpl; update the existing
comment block that explains why dependencies are excluded (the block around the
--ignore flags) to mention "dario.cat/mergo is manually maintained in
NOTICE.txt.tmpl" so future maintainers understand the exception.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 84f6954e-3a43-41cb-aa08-40510574b650

📥 Commits

Reviewing files that changed from the base of the PR and between 38303f5 and 9d7afa9.

📒 Files selected for processing (3)
  • Makefile
  • NOTICE.txt
  • NOTICE.txt.tmpl
✅ Files skipped from review due to trivial changes (1)
  • NOTICE.txt

@tsivaprasad tsivaprasad force-pushed the PLAT-596-add-image-version-fields-to-database-spec branch 3 times, most recently from d09cff8 to b66c3f9 Compare June 4, 2026 11:15
@tsivaprasad tsivaprasad force-pushed the PLAT-596-add-image-version-fields-to-database-spec branch from b66c3f9 to 94d6615 Compare June 4, 2026 11:27
Copy link
Copy Markdown
Member

@jason-lynch jason-lynch left a comment

Choose a reason for hiding this comment

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

Awesome! I was little confused for a second because it looks like the ManifestLoader PR got merged into this one, but I can see that it's still unused.

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.

2 participants