Skip to content

Multi-instance Tentacle with cross-platform service host

Placeholder ppxd requested to merge tentacle-multi-instance into main

Adds Octopus-style multi-instance support and a generic service host abstraction so the binary + systemd/launchd/WinService flow actually works end-to-end across all platforms.

Core architecture:

  • PlatformPaths: unified per-OS config dir resolution (Linux /etc, macOS /Library/Application Support, Windows %ProgramData%) with user-scope fallback when running unprivileged.
  • InstanceRegistry: cross-platform JSON-backed instance registry at instances.json, replacing the Windows Registry / Linux JSON split that Octopus inherited. Supports case-insensitive lookup, schema versioning, auto-created Default instance.
  • TentacleConfigFile: persistent per-instance JSON config that IConfigurationBuilder consumes natively. Merge-based updates skip empty values so partial overrides don't wipe existing keys. Unix permissions locked to 600.
  • IServiceHost: OS-agnostic service-manager abstraction with SystemdServiceHost (complete) plus WindowsServiceHost / LaunchdServiceHost placeholders. ServiceHostFactory uses a registry pattern so adding a new platform is a one-line change.

Fixes the critical register -> systemd gap:

  • register now persists effective settings to the instance config file after a successful registration. systemd's "run --instance NAME" can then start the agent with no other arguments.
  • service install generates units with the correct ExecStart (Environment.ProcessPath, not the broken "dotnet *.dll" fallback) and passes --instance NAME when not Default.
  • service install returns non-zero when systemctl fails, no longer falsely reports success on Docker/WSL1 without systemd.

New commands:

  • create-instance --instance NAME [--config PATH]
  • list-instances
  • delete-instance --instance NAME
  • --instance NAME flag now honoured by register / run / show-* / new-certificate / service install.

Server-side:

  • Squid.Api.Program ConfigureKestrel uses SelfCert.Base64 so port 7078 (API) and 10943 (Halibut) present the same thumbprint. Fixes the TLS pinning mismatch where UI-displayed ServerThumbprint (SelfCert) disagreed with what Kestrel actually served (dev-cert).

install-tentacle.sh:

  • Auto-installs libicu + ca-certificates across apt/dnf/yum/apk. .NET 9 globalization can't start without libicu; prior behaviour aborted with SIGABRT.
  • Supports both v-prefixed and plain version tags.
  • Creates /etc/squid-tentacle with mode 700.
  • Makes Squid.Calamari executable (Tentacle spawns it at runtime).
  • Verification uses the "help" subcommand instead of --help (which was routed to RunCommand).

Modernisation:

  • RuntimeInformation.IsOSPlatform(...) replaced with OperatingSystem.IsLinux()/IsWindows()/IsMacOS() throughout.
  • CommandResolver extracted for unit-testable command routing.

Tests: +38 new tests covering config file round-trips, instance registry persistence, platform path conventions, systemd unit generation, and factory dispatch. All 3992 unit tests and integration tests pass; 782/782 Tentacle tests (excluding pre-existing metrics flakiness) pass.

Merge request reports

Loading