Documentation
¶
Overview ¶
Package remotepc runs eta on another machine over SSH and forwards it to a local port, so that machine can be browsed as an ordinary peer.
Almost nothing here is implemented. The system `ssh` binary connects (as VS Code Remote-SSH and Ansible both do, rather than a Go SSH library — so this works exactly when the user's own `ssh <dest>` works). `go install` fetches, builds, pins the version, and verifies integrity against the checksum database. `ssh -L` reaches it, so ssh auth is the only auth and nothing is exposed remotely. --exit-on-stdin-close stops it, so there is no daemon to manage. GOPATH and GOCACHE live in ~/.eta so cleanup is one directory.
What's left is glue: an argv, two ports, two one-line commands, a marker scanner, a health poll.
Full rationale and citations: temp/remote-bootstrap-design.md.
Index ¶
- Variables
- func Cleanup(ctx context.Context, destination string) error
- type Manager
- func (m *Manager) Connect(ctx context.Context, opts Options) (*Session, error)
- func (m *Manager) ConnectAsync(opts Options) error
- func (m *Manager) Disconnect(destination string)
- func (m *Manager) Get(destination string) (*Session, bool)
- func (m *Manager) LastFailure(destination string) (error, bool)
- func (m *Manager) Pending(destination string) (*Session, bool)
- func (m *Manager) SetSessionForTest(destination, url string)
- func (m *Manager) Starting(destination string) bool
- func (m *Manager) StopAll()
- type Options
- type Phase
- type Session
- func (s *Session) Adopted() bool
- func (s *Session) Destination() string
- func (s *Session) Err() error
- func (s *Session) Phase() Phase
- func (s *Session) Recent() []string
- func (s *Session) Stop()
- func (s *Session) URL() string
- func (s *Session) Wait() error
- func (s *Session) WaitReady(ctx context.Context) error
Constants ¶
This section is empty.
Variables ¶
var ErrAdopted = errors.New("eta on that PC was already running and was not installed from here, so there is nothing here to remove")
ErrAdopted reports an action that only makes sense for an eta this computer installed, attempted on one that was already running.
Functions ¶
Types ¶
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager keeps one session per destination. Without it, double-clicking twice starts a second remote eta that fails to bind, for no reason the user could act on.
func NewManager ¶
func NewManager() *Manager
func (*Manager) ConnectAsync ¶
ConnectAsync starts a connection and returns straight away. The caller polls Get for progress. Used by the HTTP layer, where a first connect can take minutes and holding a request open for it is not an option.
func (*Manager) Disconnect ¶
Disconnect stops one session.
func (*Manager) LastFailure ¶
LastFailure returns the memoized Begin-time error for a destination, if one exists. The status handler renders it as a failed setup rather than as a disconnected one, so a user who hit "Go not installed" or "Windows cmd.exe" actually sees that — the wording is the only thing the install path can say, and it used to be lost.
func (*Manager) Pending ¶
Pending reports a session that exists but is not ready yet, so status can distinguish "still working" from "never started".
func (*Manager) SetSessionForTest ¶
SetSessionForTest inserts a ready Session into m.sessions for a destination, for handler tests that need to drive the status / identity-probe path without going through a real SSH install. The production path is Manager.Connect. The exited channel is pre-closed because a synthetic session has no real process to wait on, and StopAll in t.Cleanup would otherwise block on the unread channel.
func (*Manager) Starting ¶
Starting reports whether a connect attempt is in progress for a destination but has not yet produced a session. The status handler answers "connecting" for this case, since a poll that lands a few hundred ms after the POST — before Begin's adopt-probe/detectShell completes — would otherwise see no session and report "disconnected" even though a connection is on its way.
type Options ¶
type Options struct {
// Passed to ssh verbatim: hostname, user@host, or a ~/.ssh/config alias.
Destination string
// Default to this binary's own, so a remote never runs a different
// version than the machine that started it.
Module string
Version string
// Port to look for an eta already running on that PC. Zero means
// eta's own default. Set in tests so they never probe -- or adopt --
// a real instance the developer is running on this machine.
RemotePort int
// Host is the local address the ssh forward binds to and the host
// that ends up in the peer's URL. Empty means loopback (127.0.0.1),
// which only works for a browser on the same machine as the
// coordinator; the handler passes the request Host so the same
// forward is reachable from the browser wherever it is.
Host string
// AccessHash is the encoded PBKDF2 verifier the coordinator has
// already derived, forwarded to the remote so the freshly installed
// eta on that PC has the same access password as the coordinator.
// Empty means the coordinator has no password configured and the
// remote is left without one — matching the no-password case the
// coordinator itself is in.
AccessHash string
// RepoURL is the git repository URL used for shallow clone + build
// instead of `go install`. Empty means use the legacy `go install`
// path for backward compatibility.
RepoURL string
}
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session is one running remote eta, reachable at URL while alive.
func Begin ¶
Begin connects to a PC, returning as soon as the ssh process is spawned — before it is ready. Callers reporting progress need the session while it converges: a first install compiles from source and can take minutes, and a session that only exists once it works cannot be observed getting there.
An eta already running on that PC is adopted rather than replaced. That is checked first, and if it answers, nothing is installed and nothing is started — see adopt.
func Start ¶
Start is Begin plus WaitReady: convenient when the caller has nothing to do until the session works.
func (*Session) Adopted ¶
Adopted reports that this session attached to an eta that was already running on that PC, rather than installing and starting one. An adopted eta is not ours: nothing was installed for it, and ending the session leaves it running.
func (*Session) Destination ¶
Destination is the stable identity: unchanged between sessions.
func (*Session) Err ¶
Err is why the session failed, or nil. Unlike Wait it does not block, so a status request can report a failure without waiting for one.
func (*Session) Stop ¶
func (s *Session) Stop()
Stop closes stdin (the leash, which stops the remote eta) and kills ssh as a backstop. The kill is explicit because OS parent-death is Linux-only: docker/cli's own pdeathsig_nolinux.go is an empty func.
func (*Session) URL ¶
URL is a forwarded loopback address, valid only while this session lives — so a saved peer must be keyed by Destination, never by this.
func (*Session) WaitReady ¶
WaitReady polls until the forwarded port serves eta. Decided locally, not by a remote marker or a remote curl: it checks the thing that matters (reachable from here) and the remote needs no HTTP client. Gives up the moment ssh dies rather than waiting out its own timeout.
Safe to call more than once, and returns immediately once ready, so several callers can wait on the same converging session.