Closes #386: Add ephemeral port support to generated apps - #399
Conversation
| """Write service port mappings for tools that cannot query Docker directly.""" | ||
| service_ports = {} | ||
|
|
||
| for _ in range(4): |
There was a problem hiding this comment.
What's the purpose of trying multiple times? In case the services haven't come up yet?
There was a problem hiding this comment.
yeah; it's functionally identical to the corresponding function in in the nautobot core. I've updated the docstring to also match the one used by the core, which is more explicit.
gsnider2195
left a comment
There was a problem hiding this comment.
I just have the one question but otherwise this looks good! Thanks
| except (json.decoder.JSONDecodeError, AttributeError, IndexError, KeyError): | ||
| continue | ||
|
|
||
| if set(["nautobot", "worker"]).issubset(service_ports.keys()): |
There was a problem hiding this comment.
Is this the correct list of expected services to be exposed by default? I added these changes to one of my dev environments and I saw this output:
Running docker compose command "ps --format json"
Running docker compose command "ps --format json"
Running docker compose command "ps --format json"
Running docker compose command "ps --format json"
There was a problem hiding this comment.
@nrnvgh this still needs changed. We don't expose the worker port by default, so this causes this loop to run all 4 times regardless. The docs service is enabled by default, but regardless I think we shouldn't expect any service except nautobot to be up to end this loop.
There was a problem hiding this comment.
Dag nabbit. Good catch; fixed.
Before
% time invoke start
Starting all services in detached mode...
Running docker compose command "up --detach"
Network testing-app_default Creating
[...]
Container testing-app-beat-1 Started
invoke start 0.68s user 0.34s system 2% cpu 37.277 total
After
Starting all services in detached mode...
Running docker compose command "up --detach"
Network testing-app_default Creating
Container testing-app-worker-1 Started
[...]
invoke start 0.37s user 0.17s system 3% cpu 16.770 total
| service_ports = {} | ||
|
|
||
| for _ in range(4): | ||
| result = docker_compose(context, "ps --format json", hide=True) |
There was a problem hiding this comment.
Based on my previous comment, it looks like we need to actually make hide=True work as it did not hide the print statements.
There was a problem hiding this comment.
Easy enough. Would you rather I rolled that into this PR or submitted as its own?
There was a problem hiding this comment.
It looks like just that one print statement, so I'd say roll it into this one.
There was a problem hiding this comment.
Added. Command output:
Before
% pwd
/<redacted>/cookiecutter-app-test-multioutput-bug/nautobot-app-testing-app
% time invoke start -s db
Starting db in detached mode...
Running docker compose command "up --detach"
Network testing-app_default Creating
Network testing-app_default Created
Container testing-app-db-1 Creating
Container testing-app-db-1 Created
Container testing-app-db-1 Starting
Container testing-app-db-1 Started
Running docker compose command "ps --format json"
Running docker compose command "ps --format json"
Running docker compose command "ps --format json"
Running docker compose command "ps --format json"
invoke start -s db 0.56s user 0.24s system 3% cpu 21.093 total
After
% pwd
/<redacted>/cookiecutter-app-test-multioutput-bugfixed/nautobot-app-testing-app
% time invoke start -s db
Starting db in detached mode...
Running docker compose command "up --detach"
Network testing-app_default Creating
Network testing-app_default Created
Container testing-app-db-1 Creating
Container testing-app-db-1 Created
Container testing-app-db-1 Starting
Container testing-app-db-1 Started
invoke start -s db 0.57s user 0.25s system 3% cpu 21.129 total
| nautobot_ver: "{{ min_nautobot_version }}" | ||
| local: false | ||
| python_ver: "3.12" | ||
| # ephemeral_ports: false |
There was a problem hiding this comment.
I assume this option will not work if the "default" example is to have a list of compose files that is different than the ORIGINAL_COMPOSE_FILES (same as mysql) so we should either drop it as a suggestion or add a comment here that explains when it will work.
There was a problem hiding this comment.
Done. I also tweaked the dev_environment.md file to clarify the behavior there.
|
FYI, the |
|
I ran into another issue. By default, the cookiecutter repo brings up the The quick fix for this patch is to update things so that the port override will be applied to 8080 rather than 8001, thusly: --- a/nautobot-app/{{ cookiecutter.project_slug }}/development/docker-compose.ephemeral-ports.yml
+++ b/nautobot-app/{{ cookiecutter.project_slug }}/development/docker-compose.ephemeral-ports.yml
@@ -6,7 +6,7 @@ services:
- "8080"
docs:
ports: !override
- - "8001"
+ - "8080"That said, I think a better solution would be to update things so that both core and the cookiecutter code use the same ports. I can certainly think of reasons why that might not be acceptable, or wouldn't be acceptable in
Thoughts? |
Drop the misleading `ephemeral_ports` suggestion and add a comment to the invoke configuration examples that use a customized compose_files list.
| docs: | ||
| ports: !override | ||
| - "8001" |
There was a problem hiding this comment.
This is incorrect. cookiecutter-based apps used 8080 as the internal port, so the for ephemeral ports, 8001 should be changed to 8080...if we want to keep the docs container listening on 8080. Alternatively, we can change it to 8001, in line with the nautobot core, and leave this file as-is.
There was a problem hiding this comment.
@nrnvgh thanks for all the PRs and fixes! Our usual process is to first test any changes via PR to https://github.com/nautobot/nautobot-app-dev-example and once it is working and merged there, backport it into this repo as template changes.
As this PR is starting to have quite a few moving parts and testing surface, I will ask that we test it out in dev-example before merging, so that we discover any issues before these changes are propagated to 30+ repos via our drift management tooling.
On the topic of the docs container internal port, way too many years have passed and I don't think it makes much of a difference what it is since we override it anyway. If it makes it simpler, we should align it to 8001 (same as configured in mkdocs.yml too) and make sure it works as expected in dev-example.
|
I agree that we should align to |
The docs container served mkdocs on 8080 and published it as 8001:8080, so the ephemeral-ports override (which publishes container port 8001) left docs unreachable on its assigned host port. Serve and publish on 8001 instead, matching mkdocs.yml's dev_addr and Nautobot core. Also replace the duplicated chatops ephemeral-ports override with a symlink to the base template, consistent with every other chatops compose file, so the two copies cannot drift apart.
Un-wrap the compose_command_tokens.append() call, which fits within the 120 column limit, so `invoke ruff --fix` has nothing to collapse in a freshly baked cookie.
Drop the leading slash from the .service_ports.json gitignore entry so the file is ignored at any depth, matching core. Raise the port discovery retry sleep from 5 to 15 seconds, also matching core.
I updated this repo submitted nautobot/nautobot-app-dev-example#180 with the same changes (modulo some unrelated differences between this repo and that one). In the future, what would my workflow for changes to the cookiecutter repo be? Or, put another way, is that workflow documented somewhere I can see it? For example, if I submit a PR to dev-example, once it's merged do you have processes which will handle the backport to this repo or should I submit my own PR here as well? |
Closes #386
What's Changed
Added ephemeral port support to apps built using this cookiecutter repo. The basic logic is a replication of ephemeral support in the core as done in nautobot/nautobot#6896, nautobot/nautobot#7717, and possibly others I failed to find.
Summary
ephemeral_portsInvoke setting for generated app development stacks, matching Nautobot core's default-compose guard behavior.invoke.ymland environment variables, ignore.service_ports.json, and update sample Invoke configs for custom compose lists.Validation
Rebaked all four generated app variants with
cookiecutter --overwrite-if-existsbefore running the matrix below.Static Ports Disabled
All four generated apps started successfully with
ephemeral_ports: false, reported fixed host ports ininvoke ps, wrote matching.service_ports.json, and stopped cleanly withinvoke stop.docsnautobot8001 -> 80808080 -> 80808001 -> 80808080 -> 80808001 -> 80808080 -> 80808001 -> 80808080 -> 8080Raw output
final-static-full-stack.txt
Ephemeral Ports Enabled
Each generated app was validated twice: once with
ephemeral_ports: trueininvoke.yml, and once with the correspondingINVOKE_*_EPHEMERAL_PORTS=1environment variable. In all cases,invoke psshowed dynamic host ports fordocsandnautobot,.service_ports.jsonmatched those mappings, and cleanup usedinvoke stop.docsnautobotinvoke.yml50321 -> 800150335 -> 808050442 -> 800150477 -> 8080invoke.yml62307 -> 800162335 -> 808062451 -> 800162469 -> 8080invoke.yml64499 -> 800164533 -> 808064631 -> 800164651 -> 8080invoke.yml62224 -> 800162273 -> 808062354 -> 800162377 -> 8080Full outputs
testing-app
commercial-app
chatops-testing-app
ssot-testing-app
ChatOps Mattermost Custom Compose
Validated ChatOps Mattermost with an explicit custom
compose_fileslist containing both ephemeral override files:docker-compose.ephemeral-ports.ymlmattermost/docker-compose.ephemeral-ports.ymlinvoke psshowed dynamic host ports for all published services,.service_ports.jsonincluded all three mappings, and cleanup usedinvoke stop.docs63871 -> 8001mattermost63872 -> 8065nautobot63902 -> 8080Full output
chatops-mattermost
Other tests
All stacks were tested with both with and without ephemeral ports to ensure that a stack brought up with
invoke debugwould be properly torn down if^Cwas entered in the terminal. All passed this test with the exception of the chatops cookie, however it failed for the same reason as running it under debug ondevelop:To Do