[ISSUE-99] Deploy portainer-automation service #137
No reviewers
Labels
No Label
architect:complete
blocked-by:#139
blocks:#140
bug
CI/CD
complexity:low
complexity:medium
complexity:medium
config
depends-on:#124
docker
docs
effort:l
effort:s
effort:xs
epic/development
lead:complete
needs-decision
performance
priority:critical
priority:high
priority:low
priority:medium
security
spike
story-points:1
story-points:3
story-points:5
story-points:8
tech-debt
test
user-story
architect:complete
complexity:high
complexity:low
complexity:medium
cross-repo
cross-repo-dev
dev:in-progress
effort:l
effort:m
effort:s
effort:xl
effort:xs
epic
analytics
epic
development
epic
devops
epic
infra
epic
observability
epic
platform
epic
product
lead:complete
needs-decision
pipeline-complete
pipeline-error
pipeline-running
priority
later
priority
next
priority
now
start-pipeline
status
acceptance
status
blocked
status
done
status
in progress
status
in review
status
in testing
status
ready
status
refine
status
triage
subtask
type
analysis
type
bug
type
hygiene
type
mantainence
type
story
user-story
No Milestone
No project
No Assignees
4 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Hithomelabs/CFTunnels#137
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "Dave/CFTunnels:ISSUE-99"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Deploy the portainer-automation service as a separate Portainer stack (Option B). This service provides a
POST /api/deploy/{stackId}endpoint that CI workflows call to trigger Portainer stack redeploys after pushing new container images.Files Created
portainer-automation/Dockerfileportainer-automation/docker-compose.yamlportainer-automation/src/main/resources/application-prod.propertiesportainer-automation/src/main/resources/application-ci.propertiesportainer-automation/.env.exampleportainer-automation/PORTAINER_STACK.md.gitea/workflows/portainer_automation_build_push.ymltestFiles Modified
docker-compose.yamlportainer-automationservice alongsideappandpostgresArchitecture
Environment Variables
PORTAINER_API_KEYPORTAINER_SERVICE_API_KEYSPRING_PROFILES_ACTIVEENVTesting
./gradlew :portainer-automation:buildcurl -X POST -H "X-API-Key: <key>" http://localhost:8081/api/deploy/<stack-id>Issues
@ -0,0 +3,4 @@COPY gradlew settings.gradle build.gradle ./COPY gradle ./gradleCOPY common ./commonCOPY cftunnels-service ./cftunnels-service@Dave do we need to copy this for portainer-automation to function ?
PR Review: [ISSUE-99] Deploy portainer-automation service
Overview
This PR implements Option B — deploying the portainer-automation service as a separate Portainer stack. It adds 8 files (CI workflow, Dockerfile, standalone compose, profile configs, docs, and modifies the root compose). The implementation reuses the existing
common:portainerclient library for Portainer API interactions.✅ Strengths
commonlibraryDeployControllerTest(4: valid key, invalid key, missing key, service failure) andDeployServiceTest(4: with env, null env, resource not found, connection error, redeploy failure)PORTAINER_STACK.mdis excellent — includes architecture diagram, env var tables, deployment steps, CI trigger examples, troubleshootinglocal/ci/prodprofiles properly isolate environments; trust-all SSL for local/Cloudflare Tunnel makes senseDeployServicefetches existing env vars before redeploying, preventing them from being overwrittenpa-{version}), separate from CFTunnels tags⚠️ Concerns & Recommendations
DeployController.javaline 37 catchesException ePortainerConnectionException,PortainerResourceNotFoundException, etc.) and map to appropriate HTTP status codes (502, 404) instead of blanket 500Loggerand log deployment attempts (with stack ID), auth failures, and errors before returning responses — critical for debugging production issuescftunnels-service/— The portainer-automation module only depends on:common, but the Dockerfile copies the entirecftunnels-service/treesettings.gradle, removing the copy may cause build failures. Either removecftunnels-servicefromsettings.gradlefor this Docker build (via a different Gradle settings file) or add a.dockerignoreto exclude itsecrets.TOKEN— Generic secret name for registry passwordsecrets.REGISTRY_TOKENorsecrets.GITEA_REGISTRY_TOKENfor clarity (but keep consistent with other workflows if they useTOKEN)stack.envin compose files — Both compose files referencestack.envviaenv_fileenv_filedirective and set all vars viaenvironmentblockGET /api/health→{"status":"UP"}endpoint to enable Portainer health checks and easier debugging192.168.0.100:9442. In the docs, dev usesdevdocker.hithomelabs.com(local profile) and prod uses:9443. Ensure the default profile is never used accidentally in production🔒 Security Review
localprofile acceptable (behind Cloudflare Tunnel);produses standard SSL validation🧪 Testing Assessment
integration_test.yamlworkflow tests the main CFTunnels app, not PA. Recommend adding PA-specific integration tests in a follow-up📋 Implementation Checklist
POST /api/deploy/{stackId})Approval Status
REVIEW COMPLETE — APPROVED ✅
This is a well-crafted PR with clean code, thorough testing, and comprehensive documentation. The concerns noted are non-blocking recommendations for improvement. The implementation correctly follows the Option B architecture (separate Portainer stack) and integrates properly with the existing
commonlibrary and CI infrastructure.Please address items #1 (specific exception handling), #2 (logging), and consider #6 (health endpoint) before or after merge as time permits.
@hitanshu — great question. Here's the analysis:
Short answer: Yes, we need this line for the Docker build to succeed.
Why it's required:
settings.gradledeclares:Even though
portainer-automation/build.gradleonly directly depends on:common(not:cftunnels-service), Gradle's configuration phase parsessettings.gradleand attempts to resolve all included projects before building the task graph. If thecftunnels-service/directory is missing from the Docker build context, Gradle will fail during project configuration with an error like:The task
:portainer-automation:bootJaritself doesn't compilecftunnels-service, but Gradle still requires the project declaration insettings.gradleto be resolvable.Options to remove the copy:
settings-docker.gradlethat excludescftunnels-service, then use--settings-file settings-docker.gradlein the DockerfileRUNcommandcftunnels-service/build.gradlecftunnels-service/to.dockerignoreMy recommendation: Stick with option 1 (keep the
COPY). Thecftunnels-service/source tree adds negligible overhead to a multi-stage Docker build since it's only in thebuildstage and isn't compiled. If we ever want to optimize, option 2 (separate settings file) is the cleanest approach, but it's a low-priority improvement.Referencing Linus's review concern #3 as well — agreed this can be deferred.
Addressed the lead's review recommendations from PR #137:
Specific exception handling —
DeployControllernow catchesPortainerConnectionException(→ 502),PortainerResourceNotFoundException(→ 404),PortainerAuthenticationException(→ 401),PortainerDeploymentException(→ 502), andRuntimeException(→ 500 catch-all) instead of blanketException.SLF4J logging — Added
Loggerto bothDeployControllerandDeployService. Logs deployment attempts/results with stack ID, auth failures, and errors with full stack traces on unexpected exceptions.Health endpoint — Added
GET /api/health→{"status":"UP"}to the controller for Portainer health checks and debugging.stack.env — No action needed (as decided).
Build passes (
./gradlew :portainer-automation:build), all existing tests remain green.══════════════════════════════════════════════════════════
PM AGENT COMPLETED ✓
══════════════════════════════════════════════════════════
Addressed the request to extend the workflow beyond
testand parameterize it.Milestone: Portainer Automation — Production & Parameterization — #5
Created 2 user stories in Hithomelabs/CFTunnels:
• #139: Parameterize portainer-automation build workflow for multi-environment reuse — 5pts — priority:high
• #140: Add main-branch deployment workflow for portainer-automation production — 5pts — priority:high
Total Story Points: 10
Priority Distribution: critical[0] high[2] medium[0] low[0]
Critical Path:
#139 → #140 → #136 (wire CI deploy triggers)
Dependencies:
• #139 blocks #140
• #140 blocked by #139
What was created:
portainer_automation_build_push.ymlinto a parameterized workflow (reusableworkflow_callorworkflow_dispatchwith inputs) so both test and prod use the same logic without YAML duplication.prod,latest,pa-<version>), and pushes images for production consumption. Depends on #139.Next: #139 should be implemented first, then #140, then #136 (already open for wiring the deploy trigger).
══════════════════════════════════════════════════════════