Documentation
¶
Overview ¶
Package bootstrap is the exchange between `upterm host` and the daemon it spawns, over the connection the daemon inherits. The child reports and asks; the parent shows, answers and, once the command has started, leaves.
Index ¶
- Variables
- type Child
- func (c *Child) Claimed(m *api.Claimed) error
- func (c *Child) Close() error
- func (c *Child) Disarm()
- func (c *Child) Failed(msg string, nameInUse, abandoned bool)
- func (c *Child) Listening(socket string, hostKeys []string) error
- func (c *Child) Print(text string)
- func (c *Child) ReadSecret(prompt string) ([]byte, error)
- func (c *Child) Reader() io.Reader
- func (c *Child) SessionCreated(sess *api.GetSessionResponse) (api.Accept_Decision, error)
- func (c *Child) Started(sessionID, status string, joinState *api.JoinState) error
- func (c *Child) Writer() io.Writer
- type Conn
- type Handlers
- type NoAnswerError
- type Outcome
- type Parent
Constants ¶
This section is empty.
Variables ¶
var ErrDaemonGone = errors.New("the session daemon exited before reporting whether it started")
ErrDaemonGone: the daemon closed the channel before saying whether it started. Its log says why.
var ErrParentGone = errors.New("the process that started this session went away")
ErrParentGone: the process that started this session closed its end of the channel, or never answered.
Functions ¶
This section is empty.
Types ¶
type Child ¶
type Child struct {
// contains filtered or unexported fields
}
Child is the daemon's half of the exchange.
One goroutine reads the parent's messages for the Child's life. Replies go to whoever is waiting for one; the protocol is strictly request/reply, so at most one is ever outstanding. A read error — the parent closing its end, or dying — while the Child is armed calls onParentGone, once: that is parent-lifetime cancellation, and Disarm is what ends it.
func NewChild ¶
func NewChild(rw io.ReadWriteCloser, onParentGone func()) *Child
NewChild starts reading rw. It is armed: the parent leaving is abandonment until Disarm is called.
func (*Child) Close ¶
Close disarms and closes the connection. Disarming first: the close makes the reader return, and a return after Disarm is not abandonment.
func (*Child) Disarm ¶
func (c *Child) Disarm()
Disarm stops treating the parent's departure as abandonment. Call it the instant the command has started, before Started: a parent that exits the moment it is told the session is up must not be read as leaving it.
func (*Child) Failed ¶
Failed reports that the session did not start. Nothing is sent after Started: the parent has gone by then, and a session that started and then ended is an outcome the record carries, not a startup failure.
func (*Child) Print ¶
Print sends text for the parent's stderr. Best-effort: a parent that is gone will be noticed by the next thing that needs an answer.
func (*Child) ReadSecret ¶
ReadSecret asks the parent's terminal for a line that must not echo.
func (*Child) SessionCreated ¶
func (c *Child) SessionCreated(sess *api.GetSessionResponse) (api.Accept_Decision, error)
SessionCreated reports that the tunnel is up and the session registered, and gets the operator's decision in the same round trip: the parent shows the session and answers with it.
func (*Child) Started ¶
Started reports that the command is running and the session's record has been published. Disarm first.
status is what the session's record says at this moment, and joinState the join timeout as the daemon holds it, both of which the parent reports rather than assuming: see the Started message in startup.proto.
type Conn ¶
type Conn struct {
// contains filtered or unexported fields
}
Conn frames Startup messages over a byte stream, one varint-delimited protobuf per message. Send is safe for concurrent use; Recv is for one goroutine.
func NewConn ¶
func NewConn(rw io.ReadWriteCloser) *Conn
type Handlers ¶
type Handlers struct {
Claimed func(*api.Claimed)
SessionCreated func(*api.GetSessionResponse) api.Accept_Decision
Listening func(*api.Listening)
}
Handlers receives the child's reports. Each is called on Run's goroutine, between messages; SessionCreated blocks the exchange for as long as the operator takes, which is the point.
type NoAnswerError ¶
type NoAnswerError struct{ Reason string }
NoAnswerError: the parent could not answer a read, and says why — no terminal for a secret, EOF on its stdin. Callers that wrap it in their own message (the host-key callback does) keep the reason.
func (*NoAnswerError) Error ¶
func (e *NoAnswerError) Error() string
type Parent ¶
type Parent struct {
// contains filtered or unexported fields
}
Parent is `upterm host`'s half of the exchange.