Documentation ¶
Overview ¶
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.
Example (Cloud) ¶
This example demonstrates integration vSSH with AWS EC2
package main import ( "context" "fmt" "log" "net" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/ec2" "github.com/yahoo/vssh" ) func main() { 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()) } }
Output:
Example (Stream) ¶
package main import ( "context" "fmt" "log" "sync" "time" "github.com/yahoo/vssh" ) func main() { var wg sync.WaitGroup vs := vssh.New().Start() config, err := vssh.GetConfigPEM("ubuntu", "myaws.pem") if err != nil { log.Fatal(err) } for _, addr := range []string{"3.101.78.17:22", "13.57.12.15:22"} { vs.AddClient(addr, config, vssh.SetMaxSessions(4)) } vs.Wait() ctx, cancel := context.WithCancel(context.Background()) defer cancel() cmd := "uname -a" timeout, _ := time.ParseDuration("6s") respChan := vs.Run(ctx, cmd, timeout) for resp := range respChan { if err := resp.Err(); err != nil { log.Println("error", err) continue } wg.Add(1) go func(resp *vssh.Response) { defer wg.Done() handler(resp) }(resp) } wg.Wait() } func handler(resp *vssh.Response) { stream := resp.GetStream() defer stream.Close() for stream.ScanStdout() { txt := stream.TextStdout() fmt.Println(resp.ID(), txt) } if err := stream.Err(); err != nil { log.Println("error", err) } }
Output:
Index ¶
- func GetConfigPEM(user, keyFile string) (*ssh.ClientConfig, error)
- func GetConfigUserPass(user, password string) *ssh.ClientConfig
- func SetClientsShardNumber(n int)
- type ClientOption
- type MaxSessionsError
- type Response
- type RunOption
- type Stream
- func (s *Stream) BytesStderr() []byte
- func (s *Stream) BytesStdout() []byte
- func (s *Stream) Close() error
- func (s *Stream) Err() error
- func (s *Stream) Input(in io.Reader)
- func (s *Stream) ScanStderr() bool
- func (s *Stream) ScanStdout() bool
- func (s *Stream) Signal(sig ssh.Signal)
- func (s *Stream) TextStderr() string
- func (s *Stream) TextStdout() string
- type TimeoutError
- type VSSH
- func (v *VSSH) AddClient(addr string, config *ssh.ClientConfig, opts ...ClientOption) error
- func (v *VSSH) CurrentProc() uint64
- func (v *VSSH) DecreaseProc(n ...int)
- func (v *VSSH) ForceReConn(addr string) error
- func (v *VSSH) IncreaseProc(n ...int)
- func (v *VSSH) OnDemand() *VSSH
- func (v *VSSH) Run(ctx context.Context, cmd string, timeout time.Duration, opts ...RunOption) chan *Response
- func (v *VSSH) RunWithLabel(ctx context.Context, cmd, queryStmt string, timeout time.Duration, ...) (chan *Response, error)
- func (v *VSSH) SetInitNumProc(n int)
- func (v *VSSH) SetLogger(l *log.Logger)
- func (v *VSSH) Start() *VSSH
- func (v *VSSH) StartWithContext(ctx context.Context) *VSSH
- func (v *VSSH) Wait(p ...int) (float64, error)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GetConfigPEM ¶
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 ¶
func GetConfigUserPass(user, password string) *ssh.ClientConfig
GetConfigUserPass returns SSH configuration that uses the given username and password.
func SetClientsShardNumber ¶
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.
Types ¶
type ClientOption ¶
type ClientOption func(c *clientAttr)
ClientOption represents client optional parameters.
func RequestPty ¶
func RequestPty(term string, h, w uint, modes ssh.TerminalModes) ClientOption
RequestPty sets the pty parameters.
func SetLabels ¶
func SetLabels(labels map[string]string) ClientOption
SetLabels sets labels for a client.
func SetMaxSessions ¶
func SetMaxSessions(n int) ClientOption
SetMaxSessions sets maximum sessions for given client.
type MaxSessionsError ¶
type MaxSessionsError struct {
// contains filtered or unexported fields
}
MaxSessionsError represents max sessions error.
type Response ¶
type Response struct {
// contains filtered or unexported fields
}
Response represents the response for given session.
Example ¶
This example demonstrates the use of GetText() for two hosts.
package main import ( "context" "fmt" "log" "time" "github.com/yahoo/vssh" ) func main() { // 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()) } }
Output:
func (*Response) ExitStatus ¶
ExitStatus returns the exit status of the remote command.
type RunOption ¶
type RunOption func(q *query)
RunOption represents run optional parameters.
func SetLimitReaderStderr ¶
SetLimitReaderStderr sets limit for stderr reader.
func SetLimitReaderStdout ¶
SetLimitReaderStdout sets limit for stdout reader.
respChan := vs.Run(ctx, cmd, timeout, vssh.SetLimitReaderStdout(1024))
Example ¶
This example demonstrates how to set limit the amount of returned data
package main import ( "context" "fmt" "log" "time" "github.com/yahoo/vssh" ) func main() { // 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) }
Output:
type Stream ¶
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.
Example ¶
This example demonstrates the use of stream
package main import ( "context" "fmt" "log" "time" "github.com/yahoo/vssh" ) func main() { 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) } }
Output:
func (*Stream) BytesStderr ¶
BytesStderr returns the most recent data scanned by ScanStderr as bytes.
func (*Stream) BytesStdout ¶
BytesStdout returns the most recent data scanned by ScanStdout as bytes.
func (*Stream) Input ¶
Input writes the given reader to remote command's standard input when the command starts.
func (*Stream) ScanStderr ¶
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 ¶
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) TextStderr ¶
TextStderr returns the most recent data scanned by ScanStderr as string.
func (*Stream) TextStdout ¶
TextStdout returns the most recent data scanned by ScanStdout as string.
type TimeoutError ¶
type TimeoutError struct {
// contains filtered or unexported fields
}
TimeoutError represents timeout error.
type VSSH ¶
type VSSH struct {
// contains filtered or unexported fields
}
VSSH represents VSSH instance.
func (*VSSH) AddClient ¶
func (v *VSSH) AddClient(addr string, config *ssh.ClientConfig, opts ...ClientOption) error
AddClient adds a new SSH client to VSSH.
func (*VSSH) CurrentProc ¶
CurrentProc returns number of running processes / workers.
func (*VSSH) DecreaseProc ¶
DecreaseProc destroys the idle processes / workers.
func (*VSSH) ForceReConn ¶
ForceReConn reconnects the client immediately.
func (*VSSH) IncreaseProc ¶
IncreaseProc adds more processes / workers.
func (*VSSH) OnDemand ¶
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 ¶
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 ¶
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 ¶
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) Start ¶
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 ¶
StartWithContext is same as Run but it accepts external context.