fix: probe Angor IPv4 health endpoint inside the actual image
This commit is contained in:
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
## Unreleased
|
## 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.
|
- 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.
|
- Added a backed-up migration for the recognized legacy Nginx Proxy Manager tunnel/LND port conflict in both OTA and ISO startup paths.
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ app:
|
|||||||
path: /
|
path: /
|
||||||
health_check:
|
health_check:
|
||||||
type: http
|
type: http
|
||||||
endpoint: http://localhost:8080
|
endpoint: http://127.0.0.1:8080
|
||||||
path: /health
|
path: /health
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 8s
|
timeout: 8s
|
||||||
|
|||||||
@@ -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
|
container IDs/start times were unchanged. This supersedes the initial short
|
||||||
restart-only acceptance recorded above. The generic backend fix is committed
|
restart-only acceptance recorded above. The generic backend fix is committed
|
||||||
for release, while the live node uses the equivalent internal NPM health check.
|
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.
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Opt-in disposable rootless Angor gateway integration checks. No native app changes."""
|
"""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':
|
if os.environ.get('ARCHY_ALLOW_DISPOSABLE_CONTAINERS') != '1':
|
||||||
raise SystemExit('Set ARCHY_ALLOW_DISPOSABLE_CONTAINERS=1 to run isolated test containers')
|
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]
|
run_id=uuid.uuid4().hex[:12]
|
||||||
net='archy-angor-test-'+run_id;backend='angor-test-backend-'+run_id;gateway='angor-test-gateway-'+run_id
|
net='archy-angor-test-'+run_id;backend='angor-test-backend-'+run_id;gateway='angor-test-gateway-'+run_id
|
||||||
def run(*a):
|
def run(*a):
|
||||||
@@ -28,8 +32,11 @@ assert subprocess.run(['podman','network','exists',net]).returncode==1
|
|||||||
run('podman','network','create',net)
|
run('podman','network','create',net)
|
||||||
try:
|
try:
|
||||||
start_backend()
|
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()
|
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']:
|
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'})
|
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
|
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
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ class ServiceMetadata(unittest.TestCase):
|
|||||||
self.assertEqual(app['ports'][0]['bind'], '127.0.0.1')
|
self.assertEqual(app['ports'][0]['bind'], '127.0.0.1')
|
||||||
self.assertEqual(app['security']['capabilities'], [])
|
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):
|
def test_host_local_api_never_opens_mesh_port(self):
|
||||||
app = {'interfaces': {'main': {'type': 'api', 'port': 8999}},
|
app = {'interfaces': {'main': {'type': 'api', 'port': 8999}},
|
||||||
'ports': [{'host': 8999, 'auth': 'local'}],
|
'ports': [{'host': 8999, 'auth': 'local'}],
|
||||||
|
|||||||
Reference in New Issue
Block a user