Skip to content

Migration: route execution and validation through the SSH tunnel for tunnelled connections #573

Open

Description

@KIvanow

Problem

Raised by @jamby77 on #572. Migration execution (all three modes) and validation build their clients from connectionRegistry.getConfig(), which returns the stored host and port:

  • apps/api/src/migration/execution/client-factory.ts passes config.host / config.port to iovalkey for command mode and for validation.
  • apps/api/src/migration/execution/toml-builder.ts writes the same host and port into the RedisShake TOML for redis_shake and redis_shake_sync.

For a connection with sshTunnel set, the registry's own adapter talks to 127.0.0.1:<localPort> opened by SshTunnelService, but the migration clients dial the remote address directly. If the BetterDB host cannot reach that address (the usual reason for a tunnel), execution and validation fail to connect while analysis, which goes through the adapter, works. assertLiveMigrationPair in live-connections.ts does not reject the case, so the user gets a connection error at run time rather than a clear message up front.

Docs now state the limitation (#572). This issue is the fix for the tunnel half.

Proposal

  • Add a helper, e.g. resolveMigrationEndpoint(connectionId) on the registry or a small service, that returns { host, port, tls, username, password } for migration use: for a tunnelled connection, ensure the tunnel is up via SshTunnelService and return 127.0.0.1 plus its localPort; otherwise return the stored values.
  • Use it in migration-execution.service.ts (both the TOML builders and runCommandMode) and in migration-validation.service.ts instead of getConfig() for host and port. Credentials and TLS still come from the stored config.
  • Keep the tunnel alive for the life of the job. The tunnel service may close idle tunnels; the execution job should hold a reference (or ping through it) until the job is terminal, and release it in the existing finally cleanup.
  • Cluster sources through a tunnel remain unsupported for the RedisShake modes and for the per-master fan-out in command mode, for the same reason as the monitoring limitation in the README: nodes advertise their own addresses. Reject that combination in assertLiveMigrationPair with a message saying so, instead of failing mid-run.
  • TLS: RedisShake and iovalkey will connect to 127.0.0.1 with tls = true and the certificate will not match. Either pass servername through for iovalkey and check what RedisShake supports, or document that tunnelled TLS sources need the tunnel to terminate TLS.

Out of scope

Agent connections (host === 'agent'). The agent carries commands over a WebSocket and has no TCP endpoint, so RedisShake cannot use it. command mode could in principle run through the agent adapter instead of a raw iovalkey client, but that is a different change. For now assertLiveMigrationPair should reject agent connections for execution with a clear message, which can be done in this issue since it is one line.

Tests

  • Unit test for the endpoint resolver with and without sshTunnel.
  • A migration e2e variant that puts the source behind a local SSH container (the sentinel e2e compose already has the pattern for a jump host, if not, linuxserver/openssh-server is enough).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions