Skip to content

Find the API node when TAILSCALE_HOSTNAME names the desk, not a number - #237

Open
david-hummingbot wants to merge 3 commits into
mainfrom
fix/tailnet-peer-custom-hostname
Open

david-hummingbot wants to merge 3 commits into
mainfrom
fix/tailnet-peer-custom-hostname

Conversation

@david-hummingbot

@david-hummingbot david-hummingbot commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor

tailnet_api_peers (added in #231) matched hummingbot-api plus a numeric suffix, because that is the only suffix Tailscale itself appends when a name is taken. But TAILSCALE_HOSTNAME is a setting, and naming the API per desk — hummingbot-api-cornell, hummingbot-api-eu — is the ordinary way to run more than one.

For those the search found nothing, and nothing is the branch that warns:

! No hummingbot-api node is visible on this tailnet yet.
→ Deploy it on that machine first (its setup joins the tailnet), or
→ enter the name/address it is reachable at.

…about a node sitting in plain sight in tailscale status, and then asks the operator to type the name it had just declined to recognise.

A lone match is not a confirmed match

Widening the suffix also widens what reaches the count == 1 branch, and that branch selected silently (thanks @greptile-apps for catching it). A stale node, a colleague's staging box, another desk's API — each is alone on a tailnet the intended machine has not joined yet, and each would be accepted and written into config.yml with only a ✓ Found it to show for it. The wrong node is very likely running the same software, so it answers, and the mistake arrives as 401 Incorrect username or password against a password that was never wrong — the exact failure #231 set out to stop.

So count == 1 splits:

found behaviour
hummingbot-api (unsuffixed) taken silently — it is the name hummingbot-api's own setup asks for, and there is nothing to choose between
hummingbot-api-cornell (suffixed) shown and confirmed, pre-filled so Enter accepts it

It costs one keystroke in the common case, and no name the operator never chose lands in config.yml unseen.

"Pick the one you just deployed" was wrong guidance

The multi-match message asserted:

→ Tailscale adds -1, -2 ... when a name is taken, so these are
→ different machines. Pick the one you just deployed.

Running several APIs on purpose — hummingbot-api-1, hummingbot-api-2 alongside the default — is an ordinary deployment, and there those suffixes are chosen names, not collision artifacts. That wording told such an operator their own naming was an accident. And "the one you just deployed" is the wrong instruction regardless when Condor is being pointed at an instance that has been up for weeks. Now:

! More than one hummingbot-api node on this tailnet:
      • hummingbot-api
      • hummingbot-api-1
      • hummingbot-api-2
→ These are separate machines -- deployments named on purpose, or
→ names Tailscale suffixed because one was already taken.
→ Pick the one this Condor should talk to.

Verification

Driven end to end through the real wizard in a container, against a tailnet whose only API node was hummingbot-api-cornell (tailscale stubbed, a stand-in API bound off-loopback so the localhost probe could not see it). Before:

! No hummingbot-api node is visible on this tailnet yet.
  hummingbot-api host [hummingbot-api]: hummingbot-api-cornell

After:

✓ Found one hummingbot-api node on your tailnet: hummingbot-api-cornell
→ That is not the default name, so it is worth a look before it
→ goes in config.yml. Press Enter to use it, or type another.
  hummingbot-api host [hummingbot-api-cornell]:

…and Enter is the whole answer. Both runs end with ✓ API reachable and credentials accepted and the same config.yml. All four branches were also rendered through the real decision block with stubbed prompts.

tests/test_setup_tailnet_peers.py adds 16 assertions over the helper. They source the real function out of setup-environment.sh with a stubbed tailscale ahead of it on PATH, rather than restating the regex in Python — a copy of the regex asserts only that the copy matches itself. Four of them fail against the old -[0-9]+, confirmed by reverting it. They cover the numeric fleet (hummingbot-api + -1 + -2, which must reach the pick-one branch and never auto-select), desk names, and the nodes that must not be claimed (condor-hackathon, condor1, hummingbot-apis, my-hummingbot-api).

Full suite: 5109 passed, 23 skipped.

(An earlier revision of this description claimed 13 stubbed assertions; they were ad-hoc and never committed. They are in the tree now.)

🤖 Generated with Claude Code

`tailnet_api_peers` matched `hummingbot-api` plus a numeric suffix, because
that is the only suffix Tailscale itself appends when a name is taken. But
TAILSCALE_HOSTNAME is a setting, and naming the API per desk --
`hummingbot-api-cornell`, `hummingbot-api-eu` -- is the ordinary way to run
more than one of these.

For those, the search found nothing. "Nothing" is the branch that warns

    ! No hummingbot-api node is visible on this tailnet yet.
    → Deploy it on that machine first (its setup joins the tailnet), or
    → enter the name/address it is reachable at.

about a node sitting in plain sight in `tailscale status`, and then asks the
operator to type the name it had just declined to recognise. Driven through
the wizard against a tailnet whose only API node was
`hummingbot-api-cornell`, the same run now reports

    ✓ Found it on your tailnet: hummingbot-api-cornell

and asks nothing. Widening the suffix cannot make the earlier silent-wrong-
node failure worse: more matches means the operator is shown the list and
picks, which is the one outcome that is never wrong.
@greptile-apps

greptile-apps Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium risk] Changes how the setup wizard finds the API node on the tailnet.

The PR appears safe to merge.

Summary

The PR expands Tailscale API-node discovery to recognize operator-defined suffixes and prevents a lone suffixed match from being selected without being shown to the operator.

  • Matches names such as hummingbot-api-cornell while retaining anchored filtering.
  • Prompts before accepting a lone suffixed candidate, with the discovered hostname pre-filled.
  • Clarifies guidance when multiple API nodes are visible.
  • Adds focused shell-backed tests for matching and exclusion behavior.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Tailscale peer names] --> B[Filter hummingbot-api or suffixed names]
  B --> C{Number of matches}
  C -->|None| D[Prompt for hostname]
  C -->|One unsuffixed| E[Use default API node]
  C -->|One suffixed| F[Display candidate and request confirmation]
  C -->|Multiple| G[Ask operator to select a node]
  D --> H[Probe and save API configuration]
  E --> H
  F --> H
  G --> H
Loading

Reviews (3) · Last reviewed commit: "Run black over the new test file"

Comment thread setup-environment.sh
david-hummingbot and others added 2 commits September 29, 2026 12:06
…isions

Two things the widened suffix in this branch exposed.

Greptile's point first: widening `-[0-9]+` to `-.+` widens what can reach
the count==1 branch, and that branch selects silently. A lone
`hummingbot-api-staging`, a node someone rebuilt, another desk's API --
each is alone on a tailnet where the intended one has not joined yet, and
each is now accepted and written into config.yml with only a "Found it"
to show for it. The wrong node is very likely running the same software,
so it answers, and the mistake arrives as "401 Incorrect username or
password" against a password that was never wrong -- the exact failure
#231 set out to stop. Being the only match is not evidence of being the
right match.

So count==1 splits. The unsuffixed `hummingbot-api` is still taken
silently: it is the name hummingbot-api's own setup asks for, and there is
nothing to choose between. A suffixed lone match is shown and confirmed,
pre-filled, so Enter accepts it when it is right -- which is the common
case and the whole point of the search. It costs a keystroke and it means
no name the operator never chose lands in config.yml unseen.

Second, the pick-one message asserted "Tailscale adds -1, -2 ... when a
name is taken, so these are different machines. Pick the one you just
deployed." Running several APIs on purpose -- hummingbot-api-1,
hummingbot-api-2 alongside the default -- is an ordinary deployment, and
there those suffixes are chosen names, not collision artifacts. The old
wording told that operator their own naming was an accident, and "the one
you just deployed" is the wrong instruction anyway when Condor is being
pointed at an instance that has been up for weeks. It now covers both
origins and asks which node this Condor should talk to.

Plus the assertions over the helper this branch described but never
committed: 16 of them, sourcing the real function out of the script with a
stubbed `tailscale` rather than restating the regex in Python (a copy of
the regex asserts only that the copy matches itself). Four fail against
the old `-[0-9]+`. Full suite 5109 passed, 23 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`black --check .` is a CI gate and the file I added in the previous commit
had not been through it. Formatting only; the 16 assertions are unchanged
and still pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant