Skip to content

Commit fffc85b

Browse files
XoreCI-fix lane
andauthored
fix(arkime): un-shadow db.pl, and make #3346's translation actually run (#3343) (#3392)
* fix(arkime): un-shadow db.pl and make the translation actually run (#3343) into composable ones, and left the refusal it could not get past open: Elasticsearch refuses to create a legacy template whose patterns match an existing composable one, and single-node-replica-default matches "*", so db.pl could never install or refresh any of Arkime's templates again. On an Arkime version bump that needed a template upgrade, arkime-init's db.pl would fail under `set -e`, the done-marker would not be written, and capture and viewer would wait on it forever. It was worse than that. arkime-init's command is a YAML `>` folded block scalar, and a folded scalar joins every run of adjacent non-empty lines with a single space. The node invocation sat directly under its comment with no blank line between, so the whole thing rendered as one `fi` line with a trailing comment: fi # #3343: translate ... See arkime/composable-templates.js. /opt/arkime/bin/node /opt/arkime/composable-templates.js composable-templates.js had therefore never once run, and #3346's fix was inert while still reading as correct in the YAML. bash -n accepts the result either way and nothing else exercised the rendering. composable-templates.js gains a `shadow` subcommand, run before db.pl and restored after: it deletes every composable template that covers an Arkime index family, stashing each body first, so db.pl has nothing to collide with. Coverage is decided by Elasticsearch's own simpleMatch glob semantics rather than by name, so a renamed or second catch-all is shadowed too -- the previous approach of testing one invented probe name missed even arkime_sessions3-2*, which overlaps arkime_sessions3-* just as hard. The restore runs in a `finally`, because the shadowed set includes the replicas catch-all for every template-less index family in the stack and leaving it deleted would turn one failure into a yellow cluster. compose.yml wraps db.pl in a bounded three-attempt retry, which covers the one race a shadow cannot: a template created *while* db.pl runs, by elasticsearch-setup's catch-all landing mid-run. Both db.pl verbs are safe to re-run, and the loop exits non-zero without writing the done marker rather than wedging the deploy permanently. elasticsearch-setup.sh's comment claimed the catch-all "explicitly excluded" Arkime, which was never true -- composable templates have no exclusion syntax, so the "-arkime_..." entries were literal index names matching nothing. The inert entries are gone and the comment now names the mechanism that actually works. Its 60s wait for Arkime's legacy template is kept: it is the common case and needs no shadow/restore cycle, but it is no longer load-bearing. Refs #3343 * fix(arkime): keep the template stash out of world-readable /tmp (#3343) CodeQL flagged js/insecure-temp-file on the shadow file: it was written to a fixed path directly in /tmp, so anything on the host could have pre-created it as a symlink or read the stash. The stash holds the full body of every Arkime template this script deletes from the cluster, so that is worth closing. The path stays fixed because the shadow and generate passes are separate processes that must share it -- a fresh mkdtemp per process would hand each one its own empty stash and the generate pass would have nothing to restore. The fix is the permissions instead: the parent directory is created 0700 and the file 0600, and neither is widened on rewrite. os.tmpdir() honours TMPDIR and SHADOW_FILE still overrides the location outright. Asserted in tests/docs/test_3343_fix.py so a later change cannot quietly drop the modes back to the mkdir/write defaults. * test(arkime): teach the #3343 stub the routes #3283 added to generate() Conflict resolution follow-up for the rebase onto main. #3391 (the #3283 retention work) landed in composable-templates.js between this branch being cut and the rebase, and it widened the contract generate() has with Elasticsearch: it now installs _ilm/policy/arkime-sessions-30d immediately before the template that names it, verifies index.lifecycle.name through _simulate_index, and adopts the arkime_sessions3-* indices already on disk. The #3343 suite drives the real script against a stub Elasticsearch, so two of its tests failed on the rebase with an AssertionError naming an "unexpected" PUT /_ilm/policy/arkime-sessions-30d. No assertion changed -- the stub is what was stale, and it is what had to learn the new routes. Its _simulate_index answer changes from a canned {"number_of_replicas": "0"} to a composition of the templates the script really PUT, which is what Elasticsearch does and what the script's own post-install verification depends on. That is strictly stronger than what it replaces: the canned reply reported 0 replicas whatever the script installed, so a generated template that dropped number_of_replicas would still have passed. Composed, it fails. Dropping the retention line from build() now fails 18 tests across both suites rather than passing silently. The adoption routes answer with an empty index list, so the #3343 assertions stay about templates and the shadow; the adoption contract itself remains asserted in tests/docs/test_3283_fix.py, which owns it. Refs #3343, #3283 * test(arkime): drive #3283's adoption from the #3343 stub, and pin the ordering Follow-up to 7a80c9c, which taught this stub the routes #3283 added. That commit answered them, but answered _cat/indices with an empty list and _settings with a constant, so the adoption branch was never actually entered from this suite -- the routes were registered and dead. tests/docs/ test_3283_fix.py owns the adoption contract and pins it properly; this change is about the *combined* run, which is what this suite owns. The stub now models the one field the script reads: a name maps to whatever index.lifecycle.name it carries, or None for unmanaged. _stubbed() seeds one unmanaged sessions index, so the functional tests drive the real path, and put_ilm_policies records the body so the ordering can be asserted rather than assumed. New test: the run that restores the catch-all is the same run that installs arkime-sessions-30d and adopts what predates it, and the policy is installed before the template that names it. That ordering is the part that breaks silently -- an index template naming an ILM policy that does not exist yet fails index creation outright, and Elasticsearch validates it at index creation rather than here, so nothing upstream would report it. Non-vacuous, checked by mutating the script and reverting: * moving ensurePolicy after the template PUT fails the new test ("the policy was installed after the template naming it") * deleting the adoption loop fails it ("arkime_sessions3-2026.09.01 was not adopted onto the policy: None") Local: pytest tests/docs/ 521 passed, 1 xfailed (main: 497 passed, same xfail); test_3343 + test_3283 together 46 passed. scripts/tests unchanged from main: the same 2 pre-existing test_compose_drift_watch_sweep failures that fail on a pristine main checkout on this host. --------- Co-authored-by: CI-fix lane <ci-fix@users.noreply.github.com>
1 parent 81e9ae8 commit fffc85b

4 files changed

Lines changed: 1120 additions & 91 deletions

File tree

‎arcane/home/honeypot-init/analysis/elasticsearch-setup.sh‎

Lines changed: 52 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,48 +1556,46 @@ curl -fsS -X PUT "$es_url/_all/_settings?expand_wildcards=all" \
15561556
# number_of_replicas explicitly and outranks this one on priority, so this
15571557
# only ever applies to an index nothing more specific already covers.
15581558
#
1559-
# EXCEPT arkime_sessions3-*/arkime_history_v1-*, explicitly excluded below.
1560-
# Elasticsearch's own documented precedence rule: when ANY composable index
1561-
# template (the modern _index_template API, what this whole script and
1562-
# every "priority": N template above uses) matches an index, EVERY legacy
1563-
# template (the old _template API) is ignored outright for that index, not
1564-
# merged -- even a priority-1 catch-all like this one wins outright over a
1565-
# legacy template with no priority concept at all. Arkime's own db.pl
1566-
# still creates its real field-typing templates (arkime_sessions3_template/
1567-
# _ecs_template, arkime_history_v1_template) via that legacy API, and this
1568-
# catch-all's original "*" pattern silently shadowed them completely --
1569-
# confirmed live: every arkime_sessions3-* index's source.ip/destination.ip
1570-
# fell through to Elasticsearch's own dynamic string default (text +
1571-
# .keyword) instead of a real `ip`-typed field, breaking session-detail
1572-
# lookups outright ("TypeError: Cannot create property 'keyword' on
1573-
# string" in Arkime's own viewer, since it assumes an object-typed IP
1574-
# field it can attach a .keyword accessor to). Both excluded index
1575-
# families already set their own number_of_replicas: 0 in their real
1576-
# legacy templates, so excluding them here doesn't reintroduce the
1577-
# yellow-cluster problem this template exists to prevent -- it only lets
1578-
# their own already-correct settings apply uncontested again. Every OTHER
1579-
# arkime_* index (dstats, files, stats, users, etc) has no legacy template
1580-
# of its own and still needs this catch-all, so the exclusion is scoped to
1581-
# exactly these two, not arkime_* broadly.
1582-
# Wait for Arkime's own legacy template before adding ANY composable template that overlaps it.
1583-
# Elasticsearch allows a composable template to overlap an existing legacy one
1584-
# (it only warns), but REFUSES the reverse:
1559+
# #3343: the "EXCEPT arkime_sessions3-*/arkime_history_v1-*, explicitly
1560+
# excluded below" claim that used to stand here was simply false. Composable
1561+
# index templates have no exclusion syntax, so the "-arkime_..." entries this
1562+
# template carried matched nothing but literal index names -- the "*" really
1563+
# did match every arkime_sessions3-* index. The inert entries are gone, and so
1564+
# is any pretence that this catch-all leaves Arkime alone. It does not.
1565+
#
1566+
# That is not only a mapping wart, it is why Arkime could not be installed at
1567+
# all. Elasticsearch applies NO legacy template to an index once ANY
1568+
# composable template matches it (even a priority-1 catch-all like this one
1569+
# wins outright over a legacy template, which has no priority concept at all),
1570+
# and it refuses the reverse direction outright:
15851571
#
15861572
# illegal_argument_exception: legacy template [arkime_sessions3_template] has
15871573
# index patterns [arkime_sessions3-*] matching patterns from existing
1588-
# composable templates [arkime-sessions3-ip-fix, ...] -- use composable
1574+
# composable templates [single-node-replica-default, ...] -- use composable
15891575
# templates (/_index_template) instead
15901576
#
1591-
# arkime-init and elasticsearch-setup are both honeypot-init one-shots with no
1592-
# depends_on between them, so they race. On the 2026-09-04 rebuild this script
1593-
# won, and `db.pl init` then failed with the above and exited 255 -- Arkime got
1594-
# no session indices at all, while hp-arkime-capture and -viewer both looked
1595-
# healthy. Ordering the composable templates behind it makes Arkime win deterministically,
1596-
# without coupling the whole of this script to arkime-init succeeding (a hard
1597-
# depends_on would let one Arkime failure block every template here).
1577+
# `db.pl init` DELETEs and re-creates all three of Arkime's legacy templates,
1578+
# so against this catch-all it fails and exits 255, and Arkime ends up with no
1579+
# session indices at all while hp-arkime-capture and -viewer both look healthy.
1580+
#
1581+
# arkime-init now owns Arkime's mappings properly: it deletes this catch-all
1582+
# for the duration of db.pl, puts it straight back afterwards, and translates
1583+
# Arkime's own legacy templates into full composable equivalents at priority 11
1584+
# -- above this priority-1 one -- so the real field typing wins. See
1585+
# arkime/composable-templates.js. That is what replaced the
1586+
# arkime-sessions3-ip-fix fragment which used to stand below: it decided every
1587+
# sessions index alone (firstPacket long, no wordSplit analyzer, 1 replica) and
1588+
# left source.ip/destination.ip as text + .keyword, breaking session-detail
1589+
# lookups outright ("TypeError: Cannot create property 'keyword' on string" in
1590+
# Arkime's own viewer, since it assumes an object-typed IP field it can attach
1591+
# a .keyword accessor to).
15981592
#
1599-
# Bounded, and non-fatal on timeout: a deployment with arkime-init disabled
1600-
# entirely should still get this mapping fix rather than hang.
1593+
# Waiting for Arkime's own legacy template before adding this catch-all is
1594+
# still worth doing -- it is the common case and needs no shadow/restore cycle
1595+
# at all -- but it is no longer load-bearing, since arkime-init now handles
1596+
# either order itself. It stays bounded and non-fatal: this script must not
1597+
# depend on arkime-init succeeding, or one Arkime failure would block every
1598+
# template here.
16011599
arkime_legacy_wait=60
16021600
while (( arkime_legacy_wait > 0 )); do
16031601
if curl -fsS -o /dev/null "$es_url/_template/arkime_sessions3_template" 2>/dev/null; then
@@ -1609,38 +1607,31 @@ while (( arkime_legacy_wait > 0 )); do
16091607
done
16101608
if (( arkime_legacy_wait <= 0 )); then
16111609
echo "elasticsearch-setup: Arkime legacy template did not appear within 60s --" \
1612-
"adding the composable templates anyway (arkime-init may be disabled; if it" \
1613-
"runs later it will fail its own template creation, see #2961)"
1610+
"adding the composable catch-all anyway (arkime-init may be disabled; if it" \
1611+
"runs later it shadows this template and regenerates Arkime's own, so the" \
1612+
"worst case is a needless shadow/restore cycle, not a failure -- #3343)"
16141613
fi
16151614

16161615
curl -fsS -X PUT "$es_url/_index_template/single-node-replica-default" \
16171616
-H 'Content-Type: application/json' \
1618-
--data-binary '{"index_patterns":["*","-arkime_sessions3-*","-arkime_history_v1-*"],"priority":1,"template":{"settings":{"index.number_of_replicas":0}}}' >/dev/null
1617+
--data-binary '{"index_patterns":["*"],"priority":1,"template":{"settings":{"index.number_of_replicas":0}}}' >/dev/null
16191618

1620-
# #3343: no Arkime template is created here any more. What the comment that
1621-
# used to stand here called "under-documented legacy-template merge behavior"
1622-
# was plain shadowing: Elasticsearch applies NO legacy template to an index
1623-
# once any composable template matches it, and single-node-replica-default
1624-
# above matches "*" (composable templates have no exclusion syntax -- the
1625-
# "-arkime_..." entries are literal names). So neither of Arkime's legacy
1626-
# templates ever applied, and the arkime-sessions3-ip-fix fragment that stood
1627-
# here decided every sessions index alone (firstPacket long, no analyzer, 1
1628-
# replica). arkime-init now translates Arkime's legacy templates into full
1629-
# composable ones right after db.pl (arkime/composable-templates.js) and
1630-
# deletes arkime-sessions3-ip-fix.
1631-
#
16321619
# #3283: arkime_sessions3-*'s retention is NOT here, with the other twelve
16331620
# policies, and that placement is the fix rather than an omission. This
1634-
# script's own catch-all cannot reach that family (it is excluded above, and
1635-
# the generated composable template is what creates the indices), and an
1636-
# index template naming an ILM policy that does not exist yet fails index
1637-
# creation outright. This job and arkime-init are independent one-shots that
1638-
# race -- the wait above exists because of exactly that -- and arkime-capture
1639-
# waits only on arkime-init.done, so a policy created here could not be
1640-
# relied on to exist before the first sessions index is created.
1641-
# composable-templates.js therefore installs arkime-sessions-30d immediately
1642-
# before the template that names it, and adopts the indices already on disk
1643-
# in the same run. One definition, one owner, an ordering that cannot lose.
1621+
# script's own catch-all cannot reach that family: since #3343 its pattern is
1622+
# a bare "*", so it really does match arkime_sessions3-* -- what keeps it off
1623+
# that family is that the composable template arkime-init generates for it
1624+
# outranks this one on priority, and composable templates replace rather than
1625+
# merge, so nothing set here would survive to govern an index. The generated
1626+
# template is also what creates those indices. An index template naming an
1627+
# ILM policy that does not exist yet fails index creation outright. This job
1628+
# and arkime-init are independent one-shots that race -- the wait above exists
1629+
# because of exactly that -- and arkime-capture waits only on arkime-init.done,
1630+
# so a policy created here could not be relied on to exist before the first
1631+
# sessions index is created. composable-templates.js therefore installs
1632+
# arkime-sessions-30d immediately before the template that names it, and
1633+
# adopts the indices already on disk in the same run. One definition, one
1634+
# owner, an ordering that cannot lose.
16441635

16451636
echo
16461637
echo "elasticsearch-setup: GeoIP, retention policies, and event templates installed"

0 commit comments

Comments
 (0)