Skip to content

Fix Portainer stack discovery and update environment handling - #137

Merged
fnyaker merged 2 commits into
mainfrom
claude/gracious-lovelace-9nqm1s
Oct 15, 2026
Merged

fnyaker merged 2 commits into
mainfrom
claude/gracious-lovelace-9nqm1s

Conversation

@fnyaker

@fnyaker fnyaker commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Summary

This PR fixes critical defects in Docker stack management that prevented Portainer stacks from being recognized and caused their environment variables to be erased during updates. The changes refactor stack discovery and update logic into a new dedicated module while fixing the underlying issues.

Key Changes

  • New module fleet_stacks.py: Extracted and rewrote stack discovery and update logic from fleet_docker.py. This module now:

    • Correctly identifies Portainer stacks by their deployment directory (/data/compose/<id>) rather than a non-existent label
    • Distinguishes stack ownership (compose vs. Portainer vs. Engine-only)
    • Implements three update strategies: through compose files, through Portainer's API, or by recreating containers through the Engine
    • Preserves container configuration (environment, volumes, networks) during updates
  • Fixed Portainer stack recognition: Portainer does not write io.portainer.stack.name labels on containers. Stacks are now correctly identified by their working directory path matching the pattern /data/compose/<id>, with the numeric ID extracted for exact matching against Portainer's records.

  • Fixed environment preservation: When updating a Portainer stack through Portainer's API, the stack's environment (stored in Portainer's database) is now handed back on redeploy rather than being lost.

  • Refactored Docker panel UI: Replaced card-based layout with tabbed navigation (Stacks, Containers, Images, Volumes & Networks, Portainer) for better organization and scalability.

  • Improved operation handling: Separated fast Docker reads from slow operations (pulls, updates, deploys) with independent concurrency limits, allowing the UI to remain responsive while long operations run.

  • Updated fleet_docker.py: Removed stack-specific logic, keeping only Engine API operations. Removed unused labels (LABEL_CONFIG, LABEL_WORKDIR, LABEL_PORTAINER).

  • Enhanced testing: Added comprehensive test suite in test_fleet_stacks.py covering:

    • Stack discovery from container labels
    • Portainer stack identification
    • File accessibility validation
    • Update strategy selection
    • Environment and configuration preservation

Notable Implementation Details

  • Stack discovery reads only from running containers; no database is consulted
  • Compose files are validated for readability before attempting updates
  • Three fallback update strategies ensure stacks can be updated even without compose or Portainer access
  • Long-running operations (pulls, updates) use a polling mechanism with 2-second intervals and 30-minute timeout
  • All operator input (names, paths, image references) is validated against charsets and bounds before reaching sockets or APIs
  • Concurrency is bounded per peer: 4 total Docker operations, with 2 reserved for slow operations

https://claude.ai/code/session_018DwLKZQBnKWkWwTCQ2RKCW

…pdates that keep what runs

Stacks are recovered from what the machine runs and each gets an owner:
Portainer (known by its /data/compose/<id> directory — Portainer writes no
label of its own) or compose. Update is the owner's own act: Portainer's API
(environment and stored git credentials handed back, deployment waited out),
compose pull + up -d with the recorded files, or, with neither, a pull and an
Engine-level recreation of each container that keeps its settings, volumes
and aliases and puts the old one back if the new one does not stay up.

A Portainer on the machine is found from its container; connecting it reads
and pins its certificate. Check for updates compares registry digests through
the daemon. The panel is rewritten: summary, stacks with what Update will do,
containers, images, volumes and networks, Portainer.

Fixed on the way (BUGSVULNS 110-113): Portainer stacks never recognised; a
Portainer redeploy erased the stack's environment; a stack update reported
failed after 25 s; the Docker and Logs panels never loaded on open; a token
accepted over plain HTTP to any host; compose assumed from a docker binary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018DwLKZQBnKWkWwTCQ2RKCW
Keeps main's BUGSVULNS 110-116 and renumbers this branch's entries 117-120,
with the references to them; version 0.4.116, one step past main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018DwLKZQBnKWkWwTCQ2RKCW
@fnyaker
fnyaker merged commit 0d07807 into main Oct 15, 2026
14 checks passed
@fnyaker
fnyaker deleted the claude/gracious-lovelace-9nqm1s branch October 15, 2026 12:35
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