vssh: github.com/yahoo/vssh Index | Examples | Files

package vssh

import "github.com/yahoo/vssh"

Package vssh is a Go library to handle tens of thousands SSH connections and execute the command with higher-level API for building network device / server automation.

run(ctx, command, timeout)
runWithLabel(ctx, command, timeout, "OS == Ubuntu && POP == LAX")

By calling the run method vssh sends the given command to all available clients or based on your query it runs the command on the specific clients and the results of the ran command can be received in two options, streaming or final result.In streaming you can get line by line from command’s stdout / stderr in real time or in case of non-real time you can get the whole of the lines together.

This example demonstrates integration vSSH with AWS EC2

Code:

vs := vssh.New().Start()
config, _ := vssh.GetConfigPEM("ubuntu", "aws.pem")

// AWS EC2 Golang SDK
// Please check their website for more information
// https://docs.aws.amazon.com/sdk-for-go/
awsConfig := &aws.Config{
    Region:      aws.String("us-west-1"),
    Credentials: credentials.NewStaticCredentials("YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY", ""),
}
sess, err := session.NewSession(awsConfig)
if err != nil {
    fmt.Println("error creating new session:", err.Error())
    log.Fatal(err)
}
ec2svc := ec2.New(sess)
params := &ec2.DescribeInstancesInput{
    // filter running instances at us-west-1
    Filters: []*ec2.Filter{
        {
            Name:   aws.String("instance-state-name"),
            Values: []*string{aws.String("running")},
        },
    },
}
resp, err := ec2svc.DescribeInstances(params)
if err != nil {
    fmt.Println("there was an error listing instances in", err.Error())
    log.Fatal(err.Error())
}

// iterate over the EC2 running instances and add to vssh
for idx := range resp.Reservations {
    for _, inst := range resp.Reservations[idx].Instances {
        labels := make(map[string]string)
        for _, tag := range inst.Tags {
            labels[*tag.Key] = *tag.Value
        }
        addr := net.JoinHostPort(*inst.PublicIpAddress, "22")
        vs.AddClient(addr, config, vssh.SetLabels(labels))
    }
}

vs.Wait()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

cmd := "uname -a"
timeout, _ := time.ParseDuration("5s")
respChan := vs.Run(ctx, cmd, timeout)

for resp := range respChan {
    // in case of the connectivity issue to client
    if err := resp.Err(); err != nil {
        log.Println(err)
        continue
    }

    // get the returned data from client
    outTxt, errTxt, err := resp.GetText(vs)

    // check the error like timeout but still
    // we can have data on outTxt and errTxt
    if err != nil {
        log.Println(err)
    }

    // print command's stdout
    fmt.Println(outTxt)

    // print command's stderr
    fmt.Println(errTxt)

    // print exit status of the remote command
    fmt.Println(resp.ExitStatus())
}

Index

Examples

Package Files

client.go client_mem.go helper.go query.go vssh.go

func GetConfigPEM Uses

func GetConfigPEM(user, keyFile string) (*ssh.ClientConfig, error)

GetConfigPEM returns SSH configuration that uses the given private key. the keyfile should be unencrypted PEM-encoded private key file.

func GetConfigUserPass Uses

func GetConfigUserPass(user, password string) *ssh.ClientConfig

GetConfigUserPass returns SSH configuration that uses the given username and password.

func SetClientsShardNumber Uses

func SetClientsShardNumber(n int)

SetClientsShardNumber sets the clients shard number.

vSSH uses map data structure to keep the clients data in the memory. Sharding helps to have better performance on write/read with mutex. This setting can be tuned if needed.

type ClientOption Uses

type ClientOption func(c *clientAttr)

ClientOption represents client optional parameters.

func DisableRequestPty Uses

func DisableRequestPty() ClientOption

DisableRequestPty disables the pty.

func RequestPty Uses

func RequestPty(term string, h, w uint, modes ssh.TerminalModes) ClientOption

RequestPty sets the pty parameters.

func SetLabels Uses

func SetLabels(labels map[string]string) ClientOption

SetLabels sets labels for a client.

func SetMaxSessions Uses

func SetMaxSessions(n int) ClientOption

SetMaxSessions sets maximum sessions for given client.

type MaxSessionsError Uses

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

MaxSessionsError represents max sessions error.

type Response Uses

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

Response represents the response for given session.

This example demonstrates the use of GetText() for two hosts.

Code:

// construct and start the vssh
vs := vssh.New().Start()

// create ssh configuration with user/pass
// you can create this configuration by golang ssh package
config := vssh.GetConfigUserPass("vssh", "vssh")

// add clients to vssh with one option: max session
// there are other options that you can add to this method
for _, addr := range []string{"54.193.17.197:22", "192.168.2.19:22"} {
    vs.AddClient(addr, config, vssh.SetMaxSessions(4))
}

// wait until vssh connected to all the clients
vs.Wait()

// create a context with cancel
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// send the ping command to clients with 6 seconds timeout
cmd := "ping -c 4 192.168.55.10"
timeout, _ := time.ParseDuration("6s")
respChan := vs.Run(ctx, cmd, timeout)

// get the resp channel for each client
for resp := range respChan {
    // in case of the connectivity issue to client
    if err := resp.Err(); err != nil {
        log.Println(err)
        continue
    }

    // get the returned data from client
    outTxt, errTxt, err := resp.GetText(vs)

    // check the error like timeout but still
    // we can have data on outTxt and errTxt
    if err != nil {
        log.Println(err)
    }

    // print command's stdout
    fmt.Println(outTxt)

    // print command's stderr
    fmt.Println(errTxt)

    // print exit status of the remote command
    fmt.Println(resp.ExitStatus())
}

func (*Response) Err Uses

func (r *Response) Err() error

Err returns response error.

func (*Response) ExitStatus Uses

func (r *Response) ExitStatus() int

ExitStatus returns the exit status of the remote command.

func (*Response) GetStream Uses

func (r *Response) GetStream() *Stream

GetStream constructs a new stream from a response.

func (*Response) GetText Uses

func (r *Response) GetText(v *VSSH) (string, string, error)

GetText gets the final result of the given response.

func (*Response) ID Uses

func (r *Response) ID() string

ID returns response identification.

type RunOption Uses

type RunOption func(q *query)

RunOption represents run optional parameters.

func SetLimitReaderStderr Uses

func SetLimitReaderStderr(n int64) RunOption

SetLimitReaderStderr sets limit for stderr reader.

func SetLimitReaderStdout Uses

func SetLimitReaderStdout(n int64) RunOption

SetLimitReaderStdout sets limit for stdout reader.

respChan := vs.Run(ctx, cmd, timeout, vssh.SetLimitReaderStdout(1024))

This example demonstrates how to set limit the amount of returned data

Code:


// construct and start the vssh
vs := vssh.New().Start()

// create ssh configuration
// you can create this configuration by golang ssh package
config, _ := vssh.GetConfigPEM("ubuntu", "aws.pem")

// add client to vssh with one option: max-sessions
// there are other options that you can add to this method
vs.AddClient("54.215.209.152:22", config, vssh.SetMaxSessions(2))

// wait until vssh connected to the client
vs.Wait()

// create a context with cancel
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

timeout, _ := time.ParseDuration("6s")

// run dmesg command with limit the amounth of returned data to 512 bytes
respChan := vs.Run(ctx, "dmesg", timeout, vssh.SetLimitReaderStdout(1024))

// get the resp
resp := <-respChan
// in case of the connectivity issue to client
if err := resp.Err(); err != nil {
    log.Fatal(err)
}

outTxt, errTxt, err := resp.GetText(vs)
// check the error like timeout but still
// we can have data on outTxt and errTxt
if err != nil {
    log.Println(err)
}

fmt.Println(outTxt)
fmt.Println(errTxt)

type Stream Uses

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

Stream represents data stream for given response. It provides convenient interfaces to get the returned data real-time.

This example demonstrates the use of stream

Code:

vs := vssh.New().Start()
config, _ := vssh.GetConfigPEM("ubuntu", "aws.pem")
vs.AddClient("54.193.17.197:22", config, vssh.SetMaxSessions(4))
vs.Wait()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

cmd := "uname -a"
timeout, _ := time.ParseDuration("5s")
respChan := vs.Run(ctx, cmd, timeout)

resp := <-respChan
if err := resp.Err(); err != nil {
    log.Fatal(err)
}

stream := resp.GetStream()
defer stream.Close()

for stream.ScanStdout() {
    txt := stream.TextStdout()
    fmt.Println(txt)
}

if err := stream.Err(); err != nil {
    log.Fatal(err)
}

func (*Stream) BytesStderr Uses

func (s *Stream) BytesStderr() []byte

BytesStderr returns the most recent data scanned by ScanStderr as bytes.

func (*Stream) BytesStdout Uses

func (s *Stream) BytesStdout() []byte

BytesStdout returns the most recent data scanned by ScanStdout as bytes.

func (*Stream) Close Uses

func (s *Stream) Close() error

Close cleans up the stream's response.

func (*Stream) Err Uses

func (s *Stream) Err() error

Err returns stream response error.

func (*Stream) Input Uses

func (s *Stream) Input(in io.Reader)

Input writes the given reader to remote command's standard input when the command starts.

func (*Stream) ScanStderr Uses

func (s *Stream) ScanStderr() bool

ScanStderr provides a convenient interface for reading stderr which it connected to remote host. It reads a line and buffers it. The TextStdout() or BytesStdout() methods return the buffer in string or bytes.

func (*Stream) ScanStdout Uses

func (s *Stream) ScanStdout() bool

ScanStdout provides a convenient interface for reading stdout which it connected to remote host. It reads a line and buffers it. The TextStdout() or BytesStdout() methods return the buffer in string or bytes.

func (*Stream) Signal Uses

func (s *Stream) Signal(sig ssh.Signal)

Signal sends the given signal to remote process.

func (*Stream) TextStderr Uses

func (s *Stream) TextStderr() string

TextStderr returns the most recent data scanned by ScanStderr as string.

func (*Stream) TextStdout Uses

func (s *Stream) TextStdout() string

TextStdout returns the most recent data scanned by ScanStdout as string.

type TimeoutError Uses

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

TimeoutError represents timeout error.

type VSSH Uses

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

VSSH represents VSSH instance.

func New Uses

func New() *VSSH

New constructs a new VSSH instance.

func (*VSSH) AddClient Uses

func (v *VSSH) AddClient(addr string, config *ssh.ClientConfig, opts ...ClientOption) error

AddClient adds a new SSH client to VSSH.

func (*VSSH) CurrentProc Uses

func (v *VSSH) CurrentProc() uint64

CurrentProc returns number of running processes / workers.

func (*VSSH) DecreaseProc Uses

func (v *VSSH) DecreaseProc(n ...int)

DecreaseProc destroys the idle processes / workers.

func (*VSSH) ForceReConn Uses

func (v *VSSH) ForceReConn(addr string) error

ForceReConn reconnects the client immediately.

func (*VSSH) IncreaseProc Uses

func (v *VSSH) IncreaseProc(n ...int)

IncreaseProc adds more processes / workers.

func (*VSSH) OnDemand Uses

func (v *VSSH) OnDemand() *VSSH

OnDemand changes VSSH connection behavior. By default VSSH connects to all of the clients before any run request and it maintains the authenticated SSH connection to all clients. We can call this "persistent SSH connection" but with OnDemand it tries to connect to clients once the run requested and it closes the appropriate connection once the response data returned.

func (*VSSH) Run Uses

func (v *VSSH) Run(ctx context.Context, cmd string, timeout time.Duration, opts ...RunOption) chan *Response

Run sends a new run query with given context, command and timeout.

timeout allows you to set a limit on the length of time the command will run for. You can cancel the running command by context.WithCancel.

func (*VSSH) RunWithLabel Uses

func (v *VSSH) RunWithLabel(ctx context.Context, cmd, queryStmt string, timeout time.Duration, opts ...RunOption) (chan *Response, error)

RunWithLabel runs the command on the specific clients which they matched with given query statement.

	labels := map[string]string {
 	"POP" : "LAX",
 	"OS" : "JUNOS",
	}
	// sets labels to a client
	vs.AddClient(addr, config, vssh.SetLabels(labels))
	// run the command with label
	vs.RunWithLabel(ctx, cmd, timeout, "POP == LAX || POP == DCA) && OS == JUNOS")

func (*VSSH) SetInitNumProc Uses

func (v *VSSH) SetInitNumProc(n int)

SetInitNumProc sets the initial number of processes / workers.

You need to set this number right after creating vssh.

vs := vssh.New()
vs.SetInitNumProc(200)
vs.Start()

There are two other methods in case you need to change the settings in the middle of your code.

IncreaseProc(n int)
DecreaseProc(n int)

func (*VSSH) SetLogger Uses

func (v *VSSH) SetLogger(l *log.Logger)

SetLogger sets external logger.

func (*VSSH) Start Uses

func (v *VSSH) Start() *VSSH

Start starts vSSH, including action queue and re-connect procedures. You can construct and start the vssh like below:

vs := vssh.New().Start()

func (*VSSH) StartWithContext Uses

func (v *VSSH) StartWithContext(ctx context.Context) *VSSH

StartWithContext is same as Run but it accepts external context.

func (*VSSH) Wait Uses

func (v *VSSH) Wait(p ...int) (float64, error)

Wait stands by until percentage of the clients have been processed. An optional percentage can be passed as an argument - otherwise the default value of 100% is used.

Package vssh imports 18 packages (graph). Updated 2020-07-30. Refresh now. Tools for package owners.