Documentation
¶
Overview ¶
Package client provides an exec.Command and ssh like interface for cpu sessions. It attempts to cleave as much as possible to the original. The choice between options and environment variables mirrors this effort. For example, the nonce for the mount protocol back is an environment variable. command name and arguments are passed in os.Args The only required parameter for Command() is a host name; if os.Args is empty, the remote server reads SHELL and starts a shell. Similarly, because the root for the client namespace is known only to the client. it is settable in the Cmd struct.
This is a bit of an odd experiment. For the union, we build a unionfs, and a cpiofs. But a cpiofs, most of the time, says "can't do that." Hence the cpiofs is the "default" case for file operations, and this system mounts "in front of" the cpio. Rather than having the cpio fail anything looking like a write, we embed a struct in the fs that performs those operations on the mounts. Still an experiment, and whether the simplification of having one, not two, file systems is worth the increased complexity is an open question.
Index ¶
- Constants
- Variables
- func GetHostName(host string) string
- func GetHostUser(n string) (host, user string)
- func GetKeyFile(host, kf string) string
- func GetPort(host, port string) (string, error)
- func JoinFSTab(tables ...string) string
- func NewNullAuthHandler(l net.Listener, fs billy.Filesystem, nonce string) nfs.Handler
- func NewOSFS(r string) billy.Filesystem
- func NewfsCPIO(c string, mounts ...MountPoint) (*fsCPIO, error)
- func ParseBinds(s string) (string, error)
- func SetVerbose(f func(string, ...interface{}))
- func SrvNFS(cl *Cmd, n string, dir string) (func() error, string, error)
- type COS
- type CPIO9P
- type CPIO9PFID
- func (l *CPIO9PFID) Create(name string, mode p9.OpenFlags, permissions p9.FileMode, _ p9.UID, _ p9.GID) (p9.File, p9.QID, uint32, error)
- func (l *CPIO9PFID) Flush() error
- func (l *CPIO9PFID) GetAttr(req p9.AttrMask) (p9.QID, p9.AttrMask, p9.Attr, error)
- func (l *CPIO9PFID) Link(target p9.File, newname string) error
- func (*CPIO9PFID) Lock(pid int, locktype p9.LockType, flags p9.LockFlags, start, length uint64, ...) (p9.LockStatus, error)
- func (l *CPIO9PFID) Mkdir(name string, permissions p9.FileMode, _ p9.UID, _ p9.GID) (p9.QID, error)
- func (*CPIO9PFID) Mknod(name string, mode p9.FileMode, major uint32, minor uint32, _ p9.UID, _ p9.GID) (p9.QID, error)
- func (l *CPIO9PFID) Open(mode p9.OpenFlags) (p9.QID, uint32, error)
- func (l *CPIO9PFID) ReadAt(p []byte, offset int64) (int, error)
- func (l *CPIO9PFID) Readdir(offset uint64, count uint32) (p9.Dirents, error)
- func (l *CPIO9PFID) Readlink() (string, error)
- func (*CPIO9PFID) Rename(directory p9.File, name string) error
- func (l *CPIO9PFID) RenameAt(oldName string, newDir p9.File, newName string) error
- func (l *CPIO9PFID) SetAttr(mask p9.SetAttrMask, attr p9.SetAttr) error
- func (*CPIO9PFID) StatFS() (p9.FSStat, error)
- func (l *CPIO9PFID) Symlink(oldname string, newname string, _ p9.UID, _ p9.GID) (p9.QID, error)
- func (l *CPIO9PFID) UnlinkAt(name string, flags uint32) error
- func (l *CPIO9PFID) Walk(names []string) ([]p9.QID, p9.File, error)
- func (l *CPIO9PFID) WriteAt(p []byte, offset int64) (int, error)
- type CPU9P
- func (l *CPU9P) Attach() (p9.File, error)
- func (l *CPU9P) Close() error
- func (l *CPU9P) Create(name string, mode p9.OpenFlags, permissions p9.FileMode, _ p9.UID, _ p9.GID) (p9.File, p9.QID, uint32, error)
- func (l *CPU9P) FSync() error
- func (l *CPU9P) Flush() error
- func (l *CPU9P) GetAttr(req p9.AttrMask) (p9.QID, p9.AttrMask, p9.Attr, error)
- func (l *CPU9P) GetXattr(attr string) ([]byte, error)
- func (l *CPU9P) Link(target p9.File, newname string) error
- func (l *CPU9P) ListXattrs() ([]string, error)
- func (l *CPU9P) Lock(pid int, locktype p9.LockType, flags p9.LockFlags, start, length uint64, ...) (p9.LockStatus, error)
- func (l *CPU9P) Mkdir(name string, permissions p9.FileMode, _ p9.UID, _ p9.GID) (p9.QID, error)
- func (*CPU9P) Mknod(name string, mode p9.FileMode, major uint32, minor uint32, _ p9.UID, _ p9.GID) (p9.QID, error)
- func (l *CPU9P) Open(mode p9.OpenFlags) (p9.QID, uint32, error)
- func (l *CPU9P) ReadAt(p []byte, offset int64) (int, error)
- func (l *CPU9P) Readdir(offset uint64, count uint32) (p9.Dirents, error)
- func (l *CPU9P) Readlink() (string, error)
- func (l *CPU9P) Remove() error
- func (l *CPU9P) RemoveXattr(attr string) error
- func (*CPU9P) Rename(directory p9.File, name string) error
- func (l *CPU9P) RenameAt(oldName string, newDir p9.File, newName string) error
- func (l *CPU9P) Renamed(parent p9.File, newName string)
- func (l *CPU9P) SetAttr(mask p9.SetAttrMask, attr p9.SetAttr) error
- func (l *CPU9P) SetXattr(attr string, data []byte, flags p9.XattrFlags) error
- func (*CPU9P) StatFS() (p9.FSStat, error)
- func (l *CPU9P) Symlink(oldname string, newname string, _ p9.UID, _ p9.GID) (p9.QID, error)
- func (l *CPU9P) UnlinkAt(name string, flags uint32) error
- func (l *CPU9P) Walk(names []string) ([]p9.QID, p9.File, error)
- func (l *CPU9P) WriteAt(p []byte, offset int64) (int, error)
- type Cmd
- func (c *Cmd) Close() error
- func (c *Cmd) Dial() error
- func (c *Cmd) HostKeyConfig(hostKeyFile string) error
- func (c *Cmd) Listen(n, addr string) (net.Listener, error)
- func (c *Cmd) Outputs() ([]bytes.Buffer, error)
- func (c *Cmd) Run() error
- func (c *Cmd) SSHStdin(w io.WriteCloser, r io.Reader)
- func (c *Cmd) SetEnv(envs ...string) error
- func (c *Cmd) SetOptions(opts ...Set) error
- func (c *Cmd) SetupInteractive() error
- func (c *Cmd) Signal(s ssh.Signal) error
- func (c *Cmd) Start() error
- func (c *Cmd) TTYIn(s *ssh.Session, w io.WriteCloser, r io.Reader)
- func (c *Cmd) UserKeyConfig() error
- func (c *Cmd) Wait() error
- type MountPoint
- type NullAuthHandler
- func (h *NullAuthHandler) Change(fs billy.Filesystem) billy.Change
- func (h *NullAuthHandler) FSStat(ctx context.Context, f billy.Filesystem, s *nfs.FSStat) error
- func (h *NullAuthHandler) FromHandle([]byte) (billy.Filesystem, []string, error)
- func (h *NullAuthHandler) HandleLimit() int
- func (c *NullAuthHandler) InvalidateHandle(billy.Filesystem, []byte) error
- func (h *NullAuthHandler) Mount(ctx context.Context, conn net.Conn, req nfs.MountRequest) (status nfs.MountStatus, hndl billy.Filesystem, auths []nfs.AuthFlavor)
- func (h *NullAuthHandler) ToHandle(f billy.Filesystem, s []string) []byte
- type Set
- func With9P(p9 bool) Set
- func WithDisablePrivateKey(disable bool) Set
- func WithFSTab(fstab string) Set
- func WithHostKeyFile(key string) Set
- func WithNameSpace(ns string) Set
- func WithNetwork(network string) Set
- func WithPort(port string) Set
- func WithPrivateKeyFile(key string) Set
- func WithRoot(root string) Set
- func WithServer(a p9.Attacher) Set
- func WithTimeout(timeout string) Set
- type Union9P
- type UnionMount
Constants ¶
const ( // DefaultNameSpace is the default used if the user does not request // something else. DefaultNameSpace = "/lib:/lib64:/usr:/bin:/etc:/home" )
const (
// DefaultPort is the default cpu port.
DefaultPort = "17010"
)
Variables ¶
var ( // DefaultKeyFile is the default key for cpu users. DefaultKeyFile = filepath.Join(os.Getenv("HOME"), ".ssh/cpu_rsa") // Debug9p enables 9p debugging. Debug9p bool // Dump9p enables dumping 9p packets. Dump9p bool // DumpWriter is an io.Writer to which dump packets are written. DumpWriter io.Writer = os.Stderr )
Functions ¶
func GetHostName ¶
GetHostName reads the host name from the ssh config file, if needed. If it is not found, the host name is returned.
func GetHostUser ¶
GetHostUser gets the user and host name. In ssh syntax, these can be in one string, or defined in .ssh/config, or (for user), as $USER. Given that just about anything can be valid, and errors will be caught in other places, it does not return an error. Also, experimentally, in the name@host form, name overrides any use name that might be in .ssh/config. Host, on the other hand, is always determined from .ssh/config. The host name is also pulled from .ssh/config; calls to GetHostName can be replaced as needed, but that's for the future.
func GetKeyFile ¶
GetKeyFile picks a keyfile if none has been set. It will use ssh config, else use a default.
func GetPort ¶
GetPort gets a port. It verifies that the port fits in 16-bit space. The rules here are messy, since config.Get will return "22" if there is no entry in .ssh/config.
func JoinFSTab ¶
JoinFSTab joins an arbitrary number of fstab-style strings. The intent is to deal with strings that may not be well formatted as provided by users, e.g. too many newlines, not enough, and so on.
func NewNullAuthHandler ¶
NewNullAuthHandler creates a handler for the provided filesystem TODO: see if the newer NFS can supply this.
func NewOSFS ¶
func NewOSFS(r string) billy.Filesystem
NewOSFS returns a billy.FileSystem for a path.
func NewfsCPIO ¶
func NewfsCPIO(c string, mounts ...MountPoint) (*fsCPIO, error)
NewfsCPIO returns a fsCPIO, properly initialized. c is a string, referencing a CPIO file. If it is non-zero length, the CPIO file becomes the "backing root" for the namespace. This allows the use of flattened docker containers, so that one does not always need to run docker to use a docker container.
func ParseBinds ¶
ParseBinds parses a CPU_NAMESPACE-style string to a an fstab format string.
func SetVerbose ¶
func SetVerbose(f func(string, ...interface{}))
SetVerbose sets the verbose printing function. e.g., one might call SetVerbose(log.Printf)
Types ¶
type COS ¶
type COS struct {
billy.Filesystem
}
COS or OSFS + Change wraps a billy.FS to not fail the `Change` interface.
type CPIO9P ¶
type CPIO9P struct { p9.DefaultWalkGetAttr // contains filtered or unexported fields }
CPIO9P is a p9.Attacher.
func NewCPIO9PReaderAt ¶
NewCPIO9PReaderAt returns a CPIO9P, properly initialized, from an io.ReaderAt.
type CPIO9PFID ¶
type CPIO9PFID struct { p9.DefaultWalkGetAttr templatefs.XattrUnimplemented templatefs.NilCloser templatefs.NilSyncer templatefs.NoopRenamed // contains filtered or unexported fields }
CPIO9PFID defines a FID. It kind of sucks because it has a pointer for every FID. Luckily they go away when clunked.
func (*CPIO9PFID) Create ¶
func (l *CPIO9PFID) Create(name string, mode p9.OpenFlags, permissions p9.FileMode, _ p9.UID, _ p9.GID) (p9.File, p9.QID, uint32, error)
Create implements p9.File.Create.
func (*CPIO9PFID) Lock ¶
func (*CPIO9PFID) Lock(pid int, locktype p9.LockType, flags p9.LockFlags, start, length uint64, client string) (p9.LockStatus, error)
Lock implements lock by doing nothing.
func (*CPIO9PFID) Mknod ¶
func (*CPIO9PFID) Mknod(name string, mode p9.FileMode, major uint32, minor uint32, _ p9.UID, _ p9.GID) (p9.QID, error)
Mknod implements p9.File.Mknod.
func (*CPIO9PFID) Readdir ¶
Readdir implements p9.File.Readdir. This is a bit of a mess in cpio, but the good news is that files will be in some sort of order ...
func (*CPIO9PFID) RenameAt ¶
RenameAt implements p9.File.RenameAt. There is no guarantee that there is not a zipslip issue.
type CPU9P ¶
type CPU9P struct { p9.DefaultWalkGetAttr // contains filtered or unexported fields }
CPU9P is a p9.Attacher.
func (*CPU9P) Create ¶
func (l *CPU9P) Create(name string, mode p9.OpenFlags, permissions p9.FileMode, _ p9.UID, _ p9.GID) (p9.File, p9.QID, uint32, error)
Create implements p9.File.Create.
func (*CPU9P) ListXattrs ¶
ListXattrs implements p9.File.ListXattrs
func (*CPU9P) Lock ¶
func (l *CPU9P) Lock(pid int, locktype p9.LockType, flags p9.LockFlags, start, length uint64, client string) (p9.LockStatus, error)
Lock implements p9.File.Lock.
func (*CPU9P) Mknod ¶
func (*CPU9P) Mknod(name string, mode p9.FileMode, major uint32, minor uint32, _ p9.UID, _ p9.GID) (p9.QID, error)
Mknod implements p9.File.Mknod.
func (*CPU9P) RemoveXattr ¶
RemoveXattr implements p9.File.RemoveXattr
func (*CPU9P) RenameAt ¶
RenameAt implements p9.File.RenameAt. There is no guarantee that there is not a zipslip issue.
func (*CPU9P) UnlinkAt ¶
UnlinkAt implements p9.File.UnlinkAt. The flags docs are not very clear, but we always block on the unlink anyway.
func (*CPU9P) WriteAt ¶
WriteAt implements p9.File.WriteAt. There is a very rare case where O_APPEND files are written more than once, and we get an error. That error is generated by the Go runtime, after checking the open flag in the os.File struct. I.e. the error is not generated by a system call, so it is very cheap to try the WriteAt, check the error, and call Write if it is the rare case of a second write to an append-only file..
type Cmd ¶
type Cmd struct { // CPU-specific options. // As in exec.Command, these controls are exposed and can // be set directly. Host string // HostName as found in .ssh/config; set to Host if not found HostName string Args []string Root string HostKeyFile string PrivateKeyFile string DisablePrivateKey bool Port string Timeout time.Duration Env []string SessionIn io.WriteCloser SessionOut io.Reader SessionErr io.Reader Stdin io.Reader Stdout io.Writer Stderr io.Writer Row int Col int // NameSpace is a string as defined in the cpu documentation. NameSpace string // FSTab is an fstab(5)-format string FSTab string // Ninep determines if client will run a 9P server Ninep bool // contains filtered or unexported fields }
Cmd is a cpu client. It implements as much of exec.Command as makes sense.
func Command ¶
Command implements exec.Command. The required parameter is a host. The args arg args to $SHELL. If there are no args, then starting $SHELL is assumed.
func (*Cmd) Dial ¶
Dial implements ssh.Dial for cpu. Additionaly, if Cmd.Root is not "", it starts up a server for 9p requests. Note that any bind parsing is deferred until this point, to avoid callers getting ordering of setting variables in the Cmd wrong.
func (*Cmd) HostKeyConfig ¶
HostKeyConfig sets the host key. It is optional.
func (*Cmd) Outputs ¶
Outputs returns a slice of bytes.Buffer for stdout and stderr, and an error if either had trouble being read.
func (*Cmd) SSHStdin ¶
func (c *Cmd) SSHStdin(w io.WriteCloser, r io.Reader)
SSHStdin implements an ssh-like reader, honoring ~ commands.
func (*Cmd) SetEnv ¶
SetEnv sets zero or more environment variables for a Session. If envs is nil or a zero length slice, no variables are set.
func (*Cmd) SetOptions ¶
SetOptions sets various options into the Command.
func (*Cmd) SetupInteractive ¶
SetupInteractive sets up a cpu client for interactive access. It adds a function to c.Closers to clean up the terminal.
func (*Cmd) UserKeyConfig ¶
UserKeyConfig sets up authentication for a User Key. It is required in almost all cases.
type MountPoint ¶
type MountPoint struct {
// contains filtered or unexported fields
}
MountPoint is a mountpoint in an fsCPIO
func WithMount ¶
func WithMount(n string, fs billy.Filesystem) MountPoint
WithMount allows the addition of mounts to an fsCPIO, as part of a NewfsCPIO call.
type NullAuthHandler ¶
type NullAuthHandler struct {
// contains filtered or unexported fields
}
NullAuthHandler returns a NFS backing that exposes a given file system in response to all mount requests.
func (*NullAuthHandler) Change ¶
func (h *NullAuthHandler) Change(fs billy.Filesystem) billy.Change
Change provides an interface for updating file attributes.
func (*NullAuthHandler) FromHandle ¶
func (h *NullAuthHandler) FromHandle([]byte) (billy.Filesystem, []string, error)
FromHandle is handled by CachingHandler
func (*NullAuthHandler) HandleLimit ¶
func (h *NullAuthHandler) HandleLimit() int
HandleLimit is handled by cachingHandler
func (*NullAuthHandler) InvalidateHandle ¶
func (c *NullAuthHandler) InvalidateHandle(billy.Filesystem, []byte) error
InvalidateHandle is handled by cachingHandler
func (*NullAuthHandler) Mount ¶
func (h *NullAuthHandler) Mount(ctx context.Context, conn net.Conn, req nfs.MountRequest) (status nfs.MountStatus, hndl billy.Filesystem, auths []nfs.AuthFlavor)
Mount backs Mount RPC Requests, allowing for access control policies.
func (*NullAuthHandler) ToHandle ¶
func (h *NullAuthHandler) ToHandle(f billy.Filesystem, s []string) []byte
ToHandle is handled by CachingHandler
type Set ¶
Set is the type of function used to set options in SetOptions.
func WithDisablePrivateKey ¶
WithDisablePrivateKey disables using private keys to encrypt the SSH connection.
func WithHostKeyFile ¶
WithHostKeyFile adds a host key to a Cmd
func WithNameSpace ¶
WithNameSpace sets the namespace to Cmd.There is no default: having some default violates the principle of least surprise for package users.
func WithNetwork ¶
WithNetwork sets the network. This almost never needs to be set, save for vsock.
func WithPort ¶
WithPort sets the port in the Cmd. It calls GetPort with the passed-in port before assigning it.
func WithPrivateKeyFile ¶
WithPrivateKeyFile adds a private key file to a Cmd
func WithServer ¶
WithServer allows setting custom 9P servers. One use: should users wish to serve from a flattened docker container saved as a cpio or tar.
type Union9P ¶
type Union9P struct {
// contains filtered or unexported fields
}
Union9P is a p9.Attacher.
func NewUnion9P ¶
func NewUnion9P(mounts []UnionMount) (*Union9P, error)
NewUnion9P returns a Union9P, properly initialized, from a []UnionMount. Each UnionMount has a []string that defines a walk path. The []string argument is matched to each walk path in the []UnionMount in turn. As in Plan 9, the first match is used; if the walk to that server fails, the code returns the error; it does not go any further.
I.e., if /home and /home/rminnich are in the table, they need to be in the order /home/rminnich /home in the case that the second mount does not include /home/rminnich. (it could be from a different 9p server, for example). Having a UnionMount with an empty []string is allowed; this will match any walk []string and hence acts as a default.
For example, in Sidecore, the code looks like this: home, err := NewCPU9P(...) container, err := NewCPIO9(...) m1 := NewUnionMount([]string{"/home"}, home) m2 := NewUnionMount([]string{}, container) u := NewUnion9P([]UnionMount{home, container}) This ensures /home matches first, and the container CPIO matches the rest.
If a default is not desired, callers should only use Union Mount structs with non-empty []string. Only one Mount with an empty walk slice should be used, as the search will always stop there. It is allowed to have multiple Mounts for a single p9.File. E.g, give a p9.File, f, once can: m1 := NewUnionMount([]string{"/etc", f) m2 := NewUnionMount([]string{"/bin", f) u := NewUnion9P([]UnionMount{m1, m2}) and no matter what other directories exist in f, only /etc and /bin will match.
Again, to add a default case, using, e.g., another p9.File, one might have m1 := NewUnionMount([]string{"/etc}", f) m2 := NewUnionMount([]string{"/bin}", f) mdefault := NewUnionMount([]string{""}, fi2) u := NewUnion9P([]UnionMount{m1, m2, mdefault})
type UnionMount ¶
type UnionMount struct {
// contains filtered or unexported fields
}
Bind is a single bind For a given Twalk, the walk []string will be compared to the string slice in the Twalk. If there is match, the mount is called with the complete Twalk []string.
func NewUnionMount ¶
func NewUnionMount(w []string, m p9.File) UnionMount
NewUnionMount creates a new Union Mount from a []string and a p9.File.