From f992780957cc69d05156867c6503b09820af2804 Mon Sep 17 00:00:00 2001 From: archipelago Date: Wed, 30 Sep 2026 16:40:16 -0400 Subject: [PATCH] fix: probe Angor IPv4 health endpoint inside the actual image --- CHANGELOG.md | 2 ++ apps/angor-indexer/manifest.yml | 2 +- docs/next-release-20260930.md | 11 +++++++++++ tests/lifecycle/angor-proxy-check.py | 11 +++++++++-- tests/regression/angor-service-metadata.py | 5 +++++ 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90fd6359..d0b19bf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- Fixed Angor Indexer health checks choosing IPv6 localhost for an IPv4 listener and unnecessarily restarting the working service. + - Prevented false app restarts by probing each published port at its actual bind address; Nginx Proxy Manager now checks its internal admin API. - Added a backed-up migration for the recognized legacy Nginx Proxy Manager tunnel/LND port conflict in both OTA and ISO startup paths. diff --git a/apps/angor-indexer/manifest.yml b/apps/angor-indexer/manifest.yml index d28c96a2..0601c5c0 100644 --- a/apps/angor-indexer/manifest.yml +++ b/apps/angor-indexer/manifest.yml @@ -48,7 +48,7 @@ app: path: / health_check: type: http - endpoint: http://localhost:8080 + endpoint: http://127.0.0.1:8080 path: /health interval: 30s timeout: 8s diff --git a/docs/next-release-20260930.md b/docs/next-release-20260930.md index ce957829..584449ae 100644 --- a/docs/next-release-20260930.md +++ b/docs/next-release-20260930.md @@ -302,3 +302,14 @@ ID/start time, every API probe returned success, and Bitcoin/LND/production-site container IDs/start times were unchanged. This supersedes the initial short restart-only acceptance recorded above. The generic backend fix is committed for release, while the live node uses the equivalent internal NPM health check. + +### Final-gate Angor health-check correction + +Final release observation found the adapter healthy over IPv4 but marked +unhealthy by its in-container BusyBox wget: `localhost` resolved to `::1`, where +nginx does not listen. Its manifest now explicitly probes `127.0.0.1`. The live +managed service was refreshed and its real Podman health check passed. The +rootless gateway integration now runs the manifest's health check inside the +actual image, in addition to endpoint/security/outage/DNS recovery assertions; +all passed. A metadata regression covers the address-family requirement. Test +containers and their network were removed by the fixture cleanup. diff --git a/tests/lifecycle/angor-proxy-check.py b/tests/lifecycle/angor-proxy-check.py index c3cf1d9a..3f1ce778 100644 --- a/tests/lifecycle/angor-proxy-check.py +++ b/tests/lifecycle/angor-proxy-check.py @@ -1,8 +1,12 @@ #!/usr/bin/env python3 """Opt-in disposable rootless Angor gateway integration checks. No native app changes.""" -import subprocess,pathlib,json,urllib.request,urllib.error,time,tempfile,os,uuid +import subprocess,pathlib,json,urllib.request,urllib.error,time,tempfile,os,uuid,shlex +import yaml if os.environ.get('ARCHY_ALLOW_DISPOSABLE_CONTAINERS') != '1': raise SystemExit('Set ARCHY_ALLOW_DISPOSABLE_CONTAINERS=1 to run isolated test containers') +manifest=yaml.safe_load((pathlib.Path(__file__).resolve().parents[2]/'apps/angor-indexer/manifest.yml').read_text())['app'] +health=manifest['health_check'] +health_url=health['endpoint'].rstrip('/')+health.get('path','/') run_id=uuid.uuid4().hex[:12] net='archy-angor-test-'+run_id;backend='angor-test-backend-'+run_id;gateway='angor-test-gateway-'+run_id def run(*a): @@ -28,8 +32,11 @@ assert subprocess.run(['podman','network','exists',net]).returncode==1 run('podman','network','create',net) try: start_backend() - run('podman','run','-d','--name',gateway,'--network',net,'--read-only','--cap-drop=all','--security-opt=no-new-privileges','--memory','128m','-p','127.0.0.1:19098:8080','source.archipelago-foundation.org/chaum/angor-indexer:1.0.1') + run('podman','run','-d','--name',gateway,'--network',net,'--read-only','--cap-drop=all','--security-opt=no-new-privileges','--memory','128m','--health-cmd','wget -q -T 5 -O /dev/null '+shlex.quote(health_url),'--health-interval','5s','--health-retries','2','-p','127.0.0.1:19098:8080','source.archipelago-foundation.org/chaum/angor-indexer:1.0.1') ready() + run('podman','healthcheck','run',gateway) + assert json.loads(run('podman','inspect',gateway))[0]['State']['Health']['Status']=='healthy' + print('PASS manifest health check inside actual image (including localhost address family)',flush=True) for path in ['/api/v1/address/bc1fixture/txs?after_txid=abc','/api/v1/fees/recommended','/api/tx/fixture/hex']: status,headers,body=req(path,headers={'Cookie':'node-secret=do-not-forward','Authorization':'Bearer do-not-forward'}) result=json.loads(body);assert status==200 and result['url']==(path if path.startswith('/api/v1/') else path.replace('/api/','/api/v1/',1)) and result['cookie'] is None and result['auth'] is None diff --git a/tests/regression/angor-service-metadata.py b/tests/regression/angor-service-metadata.py index 6c6ed0ff..7f118a7f 100644 --- a/tests/regression/angor-service-metadata.py +++ b/tests/regression/angor-service-metadata.py @@ -19,6 +19,11 @@ class ServiceMetadata(unittest.TestCase): self.assertEqual(app['ports'][0]['bind'], '127.0.0.1') self.assertEqual(app['security']['capabilities'], []) + def test_indexer_health_targets_ipv4_listener(self): + app = yaml.safe_load((ROOT / 'apps/angor-indexer/manifest.yml').read_text())['app'] + self.assertEqual(app['health_check']['endpoint'], 'http://127.0.0.1:8080') + self.assertEqual(app['health_check']['path'], '/health') + def test_host_local_api_never_opens_mesh_port(self): app = {'interfaces': {'main': {'type': 'api', 'port': 8999}}, 'ports': [{'host': 8999, 'auth': 'local'}],