easshy

package module
v0.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 1, 2023 License: MIT Imports: 13 Imported by: 0

README

easshy - easy ssh client

Overview

easshy is a thread-safe SSH client written in Golang.

The aim of this package is to provide a simple API for executing multiple commands in a single SSH session, preserving the context from previous commands. Using this package allows you to analyze the output of each command separately, just as you would when using a shell interactively.

⚠ WARNING ⚠

This package works by parsing the default prompt for a given system's shell and has only been tested for two Linux distributions (Ubuntu and Alpine) in a limited range of use-cases. It is possible that it may not work for your use-case, so do not treat this as a production-ready package. If you encounter any problem using this package or feel that it lacks an useful feature, you can contribute by creating a new issue or submitting a pull request.

Quick start

import (
    "context"
    "time"

    "github.com/patrulek/easshy"
)

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
    defer cancel()

    // connect to remote host
    client, err := easshy.NewClient(ctx, easshy.Config{
        URL:      "ssh://root@yourhost",
        KeyPath:  "./yourkey",
        Insecure: true,
    })
    if err != nil {
        return nil, err
    }

    defer client.Close(context.Background())

    // start new shell session
    if err := client.StartSession(context.Background()); err != nil {
        return nil, err
    }
 
    var cmds []string // your cmds to call

    for _, cmd := range cmds {
        // execute a single command
        output, err := client.Execute(context.Background(), cmd)
        if err != nil {
            // handle error
        }

        // handle command output
    }
}

API

easshy provides two ways of executing commands on a remote host:

  • Pseudo-interactive single calls
  • Non-interactive batch calls

The pseudo-interactive mode was presented in the Quick start section. It works by creating a client, starting a new shell session within this connection, and executing the defined commands one by one. This mode allows you to process a command's output before executing the next command. In this mode, you have control over the client's lifetime.

The non-interactive mode works by sending a batch of commands to the remote host and waiting for the call to finish. There are three different ways to make batch calls, and during these calls, a new client is created at the beginning and closed at the end of each call:

  • Serial: A blocking call that executes commands sequentially in a single session and returns after the last command finishes its execution.
  • Stream: A non-blocking call that executes commands sequentially in a single session and yields a reader object that lets you read command outputs as soon as they finish their execution.
  • Parallel: A blocking call that executes commands concurrently in separate sessions and returns after all commands finish their execution.

Commands may have an additional option that allows ignoring the error of a given command to prevent stopping the entire batch call. It's also possible to set context to specific command or a whole batch call with ContextCmd struct or WithShellContext option appropriately.

Examples of each call can be seen in the test file.

Changelog

  • v0.1.3 - 01.05.2023: Fixed ContextCmd for Serial and Stream calls

  • v0.1.2 - 01.05.2023: Improved error handling

  • v0.1.1 - 01.05.2023: Added ShellContext construct for a batch calls

  • v0.1.0 - 27.04.2023: Initial version

-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Go                               5            181             71            730
YAML                             3             16              1            148
Markdown                         2             36              0             80
BASH                             2              8              7             19
-------------------------------------------------------------------------------
TOTAL                           12            241             79            977
-------------------------------------------------------------------------------

Documentation

Overview

easshy is a package that provides simple API over standard ssh package. This package allows to execute multiple commands in a single ssh session and read output of each command separately.

Client supports only pubkey authentication method.

Index

Constants

This section is empty.

Variables

View Source
var (

	// ErrUnsupportedProtocol is return when trying to connect with non-ssh protocol scheme.
	ErrUnsupportedProtocol = errors.New("unsupported protocol")

	// ErrNoSession is returned when trying to execute command without shell session.
	ErrNoSession = errors.New("no session")

	// ErrExecuting is returned when trying to execute command, despite another one is currently executing.
	ErrExecuting = errors.New("executing")

	// ErrClosed is returned when trying to perform any operation on closed connection.
	ErrClosed = errors.New("connection closed")
)
View Source
var (
	// ErrBufferOverflow is returned when command output is greater than buffer.
	ErrBufferOverflow = errors.New("buffer overflow")

	// ErrUnsupportedPrompt is returned when remote shell's prompt doesn't end with space.
	ErrUnsupportedPrompt = errors.New("unsupported prompt")
)

Functions

func Parallel

func Parallel(ctx context.Context, cfg Config, cmds []ICmd, opts ...Option) ([]string, error)

Parallel is a convenience wrapper that establishes multiple shell sessions on a given host and executes each command in a separate session concurrently. The function returns when all commands finish execution or when any error occurs. If no error is returned, the result will contain separate output for each of the provided commands. In case of an error, the result will include separate output for all successfully executed commands, and an empty output for the ones that did not complete their execution.

func Serial

func Serial(ctx context.Context, cfg Config, cmds []ICmd, opts ...Option) ([]string, error)

Serial is a convenience wrapper that establishes a single shell session on a given host and executes the provided commands sequentially. The function returns when the last command finishes execution or when an error occurs. If no error is returned, the result will contain separate output for each of the provided commands. In case of an error, the result will include separate output for all successfully executed commands prior to the error.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a ssh.Client wrapper that allows for executing multiple command in a single session and read output of each command separately.

func NewClient

func NewClient(ctx context.Context, cfg Config) (*Client, error)

NewClient connects to remote host and returns *Shell object. It is required to call StartSession before trying to execute commands. Returns error if cannot connect to remote host or context has no or invalid deadline.

func (*Client) Close

func (this *Client) Close(ctx context.Context) error

Close waits for current command to end its execution and then immediately closes current connection. After this call all other calls will return ErrClosed.

func (*Client) Execute

func (this *Client) Execute(ctx context.Context, cmd string) (output string, err error)

Execute attempts to execute the given command on the remote host, then waits for an output of the executed command. A call to StartSession must be made prior to using Execute, otherwise ErrNoSession will be returned. The connection must be active when calling this function, otherwise ErrClosed will be returned. If another command or Close is currently processing, ErrExecuting will be returned.

func (*Client) StartSession

func (this *Client) StartSession(ctx context.Context, opts ...Option) error

StartSession initiates a new shell session for the current connection. Invalidates previous session, if such exist. Allows to pass additional Option functions that will be called on a fresh session. Returns ErrClosed if the connection has already been closed.

type Cmd

type Cmd string

Cmd is a command which error, if occured, will not be ignored in a batch call.

func (Cmd) Ctx added in v0.1.1

func (this Cmd) Ctx() ShellContext

func (Cmd) IgnoreError

func (this Cmd) IgnoreError() bool

func (Cmd) String

func (this Cmd) String() string

type Config

type Config struct {
	URL            string // Remote host, should be in format: [scheme][username]@<host>[:port]
	KeyPath        string // Path to private key used for authentication.
	PassPath       string // Path to password for a given key. Should be empty if key does not require password.
	KnownHostsPath string // Path to known hosts file. Required to authenticate remote host if Insecure is false.
	Insecure       bool   // If true, remote host will be not validated.
}

Config represents data needed for connection to remote host.

type ContextCmd added in v0.1.1

type ContextCmd struct {
	Cmd      string
	Optional bool
	Path     string
	Env      map[string]string
}

ContextCmd is a command that let you specify shell context that will be set before calling actual command. Errors returned during context setting will not be ignored regardless of IgnoreError result.

func (ContextCmd) Ctx added in v0.1.1

func (this ContextCmd) Ctx() ShellContext

func (ContextCmd) IgnoreError added in v0.1.1

func (this ContextCmd) IgnoreError() bool

func (ContextCmd) String added in v0.1.1

func (this ContextCmd) String() string

type ICmd

type ICmd interface {
	String() string
	IgnoreError() bool
	Ctx() ShellContext
}

ICmd represents command interface that can be executed in a batch call.

type Option added in v0.1.1

type Option func(context.Context, *shell) error

Option let you start shell session with additional properties.

func WithShellContext added in v0.1.1

func WithShellContext(shCtx ShellContext) Option

WithShellContext will set given shell context to session or command.

type OptionalCmd

type OptionalCmd string

OptionalCmd is a command which error, if occured, will be ignored to not stop whole batch call. Will not ignore context errors.

func (OptionalCmd) Ctx added in v0.1.1

func (this OptionalCmd) Ctx() ShellContext

func (OptionalCmd) IgnoreError

func (this OptionalCmd) IgnoreError() bool

func (OptionalCmd) String

func (this OptionalCmd) String() string

type ShellContext added in v0.1.1

type ShellContext struct {
	Path string
	Env  map[string]string
}

ShellContext represents context that will be used to call a command.

type StreamReader

type StreamReader struct {
	// contains filtered or unexported fields
}

StreamReader allows for reading commands output from a Stream call as soon as output arrives.

func Stream

func Stream(ctx context.Context, cfg Config, cmds []ICmd, opts ...Option) (*StreamReader, error)

Stream is a convenience wrapper that establishes a single shell session on a given host and executes the provided commands sequentially. The function returns a *StreamReader that allows reading the output of the commands as soon as they finish execution. If no error occurs during command execution, the Reader will return separate outputs for all provided commands, and will return EOF when attempting to read more outputs. In case of an command error, the Reader will return that error instead.

func (*StreamReader) Read

func (this *StreamReader) Read() (output string, err error)

Read waits for data from the Stream call. When the stream finishes execution (the last command returns), all subsequent calls to Read will return io.EOF. If any command in the stream fails in the middle of the stream, the given error will be returned for all subsequent calls. When Read function is called after stream's context cancels and before reading any error from stream, all subsequent calls to Read will return io.ErrClosedPipe.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL