conn.go

v0.6.1
Doc Versions Source
1
package legatus
2
3
import (
4
	"context"
5
	"io"
6
	"io/fs"
7
)
8
9
// FileMode is the permission mode used when writing remote files.
10
type FileMode = fs.FileMode
11
12
// Cmd is a remote command. Args are passed structurally: a transport must
13
// quote each element so the remote shell can never re-split or re-evaluate it.
14
type Cmd struct {
15
	Path  string
16
	Args  []string
17
	Env   map[string]string
18
	Sudo  bool
19
	Stdin io.Reader
20
21
	// Dir, when non-empty, is the working directory the command runs in. Empty
22
	// ⇒ the connection's default (login) directory, exactly as today. The
23
	// directory is quoted by the transport, so it never re-splits or re-evaluates
24
	// — the same guarantee Args carry.
25
	Dir string
26
}
27
28
// ExecResult is the outcome of a remote command.
29
type ExecResult struct {
30
	Stdout   []byte
31
	Stderr   []byte
32
	ExitCode int
33
}
34
35
// Combined returns stdout followed by stderr.
36
func (r ExecResult) Combined() []byte {
37
	out := make([]byte, 0, len(r.Stdout)+len(r.Stderr))
38
	out = append(out, r.Stdout...)
39
	out = append(out, r.Stderr...)
40
	return out
41
}
42
43
// PutOptions configures a file upload.
44
type PutOptions struct {
45
	Sudo  bool
46
	Owner string
47
}
48
49
// PutOption mutates PutOptions.
50
type PutOption func(*PutOptions)
51
52
// WithPutSudo stages the upload and moves it into place with sudo.
53
func WithPutSudo() PutOption { return func(o *PutOptions) { o.Sudo = true } }
54
55
// WithPutOwner chowns the uploaded file to owner.
56
func WithPutOwner(owner string) PutOption { return func(o *PutOptions) { o.Owner = owner } }
57
58
// Conn is a live connection to one host. Transports implement it; the core
59
// engine depends only on this interface and never imports SSH (IV1, PC1).
60
type Conn interface {
61
	// Exec runs cmd to completion. A command that runs is not an error even on a
62
	// non-zero exit: the status is reported via ExecResult.ExitCode and err is
63
	// nil. err is reserved for failures to run the command at all (no session,
64
	// IO error, context cancellation). Callers decide whether a non-zero exit is
65
	// a failure (a step's Apply) or a signal (a probe like `test -e`).
66
	Exec(ctx context.Context, cmd Cmd) (ExecResult, error)
67
	// ExecStream runs cmd like Exec but streams output: a non-nil stdout/stderr
68
	// writer receives that stream live and the matching ExecResult field is left
69
	// nil; a nil writer buffers that stream into ExecResult exactly as Exec does,
70
	// so a caller can stream one stream while capturing the other. The exit-code
71
	// contract is identical to Exec — a clean run with a non-zero exit returns
72
	// err==nil with ExecResult.ExitCode set; ctx cancellation tears down the
73
	// process and returns ctx.Err() with bytes-so-far already written to the sink.
74
	ExecStream(ctx context.Context, cmd Cmd, stdout, stderr io.Writer) (ExecResult, error)
75
	Put(ctx context.Context, content io.Reader, remote string, mode FileMode, opts ...PutOption) error
76
	Get(ctx context.Context, remote string, w io.Writer) error
77
	Close() error
78
}
79
80
// Dialer opens a Conn to a host. transport provides the SSH implementation.
81
type Dialer interface {
82
	Dial(ctx context.Context, h *Host) (Conn, error)
83
}
84

Source Files