рд▓реЗрдЦ рдХрд┐рд╕ рдмрд╛рд░реЗ рдореЗрдВ рд╣реИ

рдЗрд╕ рдЕрдиреБрдЪреНрдЫреЗрдж рдореЗрдВ, рд╣рдо рдПрдХ рд╕рд░рд▓ рдЧреЛ рдХрд╛рд░реНрдпрдХреНрд░рдо (100 рд▓рд╛рдЗрдиреЛрдВ рдореЗрдВ) рд▓рд┐рдЦреЗрдВрдЧреЗ рдЬреЛ рд╕реИрдХрдбрд╝реЛрдВ рд╕рд░реНрд╡рд░реЛрдВ рдкрд░ рдПрд╕рдПрд╕рдПрдЪ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрдорд╛рдВрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдпрд╣ рдХрд╛рдлреА рдкреНрд░рднрд╛рд╡реА рдврдВрдЧ рд╕реЗ рдХрд░ рд░рд╣рд╛ рд╣реИред рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ
go.crypto / ssh - рдЧреЛ рдХреЗ рд▓реЗрдЦрдХреЛрдВ рджреНрд╡рд╛рд░рд╛ SSH рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рд▓рд┐рдЦреЗ рдЧрдП рдХрд╛рд░реНрдпрдХреНрд░рдо рдХрд╛ рдПрдХ рдФрд░ рдЕрдзрд┐рдХ "рдЙрдиреНрдирдд" рд╕рдВрд╕реНрдХрд░рдг рдПрдХ
рдЧреЛрдердм рдкрд░ рдЙрдкрд▓рдмреНрдз рд╣реИ рдЬрд┐рд╕реЗ
рдЧреЛрдПрд╕рдПрд╕рдПрдЪрдП (рдЧреЛ рдПрд╕рдПрд╕рдПрдЪ рдПрдЬреЗрдВрдЯ) рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред
рдкрд░рд┐рдЪрдп
рдЬрд┐рд╕ рдХрдВрдкрдиреА рдХреЗ рд▓рд┐рдП рдореИрдВ рдХрд╛рдо рдХрд░рддрд╛ рд╣реВрдВ, рдЙрд╕рдХреЗ рдкрд╛рд╕ 1 рд╕реЗ рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рд╕рд░реНрд╡рд░ рд╣реИ, рдФрд░ рдПрд╕рдПрд╕рдПрдЪ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╣рдорд╛рд░реЗ рд╕рд░реНрд╡рд░реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд╕рд╛рде рдкреНрд░рднрд╛рд╡реА рдврдВрдЧ рд╕реЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП,
libssh2 рдкрд░ рдЖрдзрд╛рд░рд┐рдд
рд▓рд┐рдмрд╕реНрдкрд░реНрд╢ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдерд╛ред рдпрд╣ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрдИ рд╕рд╛рд▓ рдкрд╣рд▓реЗ рд╕реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рдерд╛, рдФрд░ рдЕрднреА рднреА рдЕрдкрдирд╛ рдХрд╛рдо рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд░рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЗрд╕реЗ рдмрдирд╛рдП рд░рдЦрдирд╛ рдмрд╣реБрдд рдореБрд╢реНрдХрд┐рд▓ рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, Google рдХреА рдЧреЛ рднрд╛рд╖рд╛ рдиреЗ рд╣рдорд╛рд░реА рдХрдВрдкрдиреА рд╕рд╣рд┐рдд рд▓реЛрдХрдкреНрд░рд┐рдпрддрд╛ рд╣рд╛рд╕рд┐рд▓ рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░ рджрд┐рдпрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдЧреЛ рдХреЗ рд╕рд╛рде рд▓рд┐рдмрд╕реНрдкреИрд╢ рдХреЛ рдмрджрд▓рдиреЗ рдФрд░ рдЗрд╕рдХреЗ рдХреБрдЫ рдХрдорд┐рдпреЛрдВ рдХреЛ рдареАрдХ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛, рд╕рд╛рде рд╣реА рд╕рд╛рде рдХреЛрдб рдФрд░ рд╕рдорд░реНрдерди рдХреА рдЬрдЯрд┐рд▓рддрд╛ рдХреЛ рдмрд╣реБрдд рд╕рд░рд▓ рдХрд┐рдпрд╛ред
рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдПрдХ рдЧреЛ рд╕рдВрдХрд▓рдХ (
golang.org рдкрд░ рдбрд╛рдЙрдирд▓реЛрдб рдХреЗ рд▓рд┐рдП рдЙрдкрд▓рдмреНрдз) рдФрд░ "go get" рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ go.crypto / ssh рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдХрд╛рд░реНрдпрд╢реАрд▓ hg рдХрдорд╛рдВрдб рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рд╢реБрд░реБрдЖрдд рд╣реЛ рд░рд╣реА рд╣реИ
рдХреБрдЫ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ "main.go" рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ, рдЕрдзрд┐рдорд╛рдирддрдГ рдЦрд╛рд▓реАред рдЕрдм рд╣рдорд╛рд░реЗ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреА "рд░реВрдкрд░реЗрдЦрд╛" рд▓рд┐рдЦреЗрдВ, рдФрд░ рдлрд┐рд░ рд╣рдо рд▓реЗрдЦ рдХреЗ рджреМрд░рд╛рди рд▓рд╛рдкрддрд╛ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд░реЗрдВрдЧреЗ:
package main import ( "code.google.com/p/go.crypto/ssh"
рдЗрд╕ рддрдереНрдп рдХреЗ рдЕрд▓рд╛рд╡рд╛ рдХрд┐ рд╣рдореЗрдВ MakeKeyring () рдФрд░ executeCmd () рдлрд╝рдВрдХреНрд╢рди рд▓рд┐рдЦрдиреЗ рдХреА рдЬрд╝рд░реВрд░рдд рд╣реИ, рд╣рдорд╛рд░рд╛ рдХрд╛рд░реНрдпрдХреНрд░рдо рддреИрдпрд╛рд░ рд╣реИ! "рдЧреЛ рдореИрдЬрд┐рдХ" рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рд╣рдо рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рд╕рднреА рд╕рд░реНрд╡рд░реЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдХрдиреЗрдХреНрд╢рди рд╕реНрдерд╛рдкрд┐рдд рдХрд░реЗрдВрдЧреЗ рдФрд░ рдЙрди рдкрд░ рджреА рдЧрдИ рдХрдорд╛рдВрдб рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░реЗрдВрдЧреЗ, рдФрд░ рдХрд┐рд╕реА рднреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рд╕реНрдХреНрд░реАрди рдкрд░ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛрдиреЗ рд╡рд╛рд▓реЗ рд╕рднреА рд╕рд░реНрд╡рд░реЛрдВ рд╕реЗ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЛ рдкреНрд░рд┐рдВрдЯ рдХрд░рдХреЗ 5 рд╕реЗрдХрдВрдб рдореЗрдВ рд╕рдорд╛рдкреНрдд рд╣реЛрдЧрд╛ред рдЪреИрдирд▓реЛрдВ рдХреА рдЕрд╡рдзрд╛рд░рдгрд╛ рдФрд░ рдПрдХ рдЪреБрдирд┐рдВрджрд╛ рдирд┐рд░реНрдорд╛рдг рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рдХрд╛рд░рдг рдПрдХ рд╕рдорд╛рди рд╕рдордпрд╛рд╡рдзрд┐ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХрд╛ рдРрд╕рд╛ рд╕рд░рд▓ рддрд░реАрдХрд╛ рд╕рдВрднрд╡ рд╣реИ рдХрд┐ рдПрдХ рд╕рд╛рде рдХрдИ рдЪреИрдирд▓реЛрдВ рдХреЗ рдмреАрдЪ рд╕рдВрдЪрд╛рд░ рдХреА рдЕрдиреБрдорддрд┐ рдорд┐рд▓рддреА рд╣реИ: рдЬреИрд╕реЗ рд╣реА рдПрдХ рдорд╛рдорд▓реЗ рдореЗрдВ рдХрдо рд╕реЗ рдХрдо рдПрдХ рдирд┐рд░реНрдорд╛рдг рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЙрд╕реА рдХреЛрдб рдмреНрд▓реЙрдХ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
Go.crypto / ssh рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рд╕рдВрд░рдЪрдирд╛рдУрдВ рдХреА рд╢реБрд░реБрдЖрдд
рд╣рдордиреЗ рдЕрднреА рддрдХ MakeKeyring () рдФрд░ executeCmd () рдирд╣реАрдВ рд▓рд┐рдЦрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЛ рдпрд╣рд╛рдВ рдХреБрдЫ рднреА рдмрд╣реБрдд рджрд┐рд▓рдЪрд╕реНрдк рдирд╣реАрдВ рд▓рдЧреЗрдЧрд╛ред рд╣рдо рдХреЗрд╡рд▓ SSH рдХреБрдВрдЬреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдзрд┐рдХреГрдд рд╣реЛрдВрдЧреЗ, рдФрд░ рд╣рдо рдорд╛рди рд▓реЗрдВрдЧреЗ рдХрд┐ рдХреБрдВрдЬрд┐рдпрд╛рдБ .ssh / id_rsa рдпрд╛ .ssh / id_dsa рдореЗрдВ рд╕реНрдерд┐рдд рд╣реИрдВ:
type SignerContainer struct { signers []ssh.Signer } func (t *SignerContainer) Key(i int) (key ssh.PublicKey, err error) { if i >= len(t.signers) { return } key = t.signers[i].PublicKey() return } func (t *SignerContainer) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) { if i >= len(t.signers) { return } sig, err = t.signers[i].Sign(rand, data) return } func makeSigner(keyname string) (signer ssh.Signer, err error) { fp, err := os.Open(keyname) if err != nil { return } defer fp.Close() buf, _ := ioutil.ReadAll(fp) signer, _ = ssh.ParsePrivateKey(buf) return } func makeKeyring() ssh.ClientAuth { signers := []ssh.Signer{} keys := []string{os.Getenv("HOME") + "/.ssh/id_rsa", os.Getenv("HOME") + "/.ssh/id_dsa"} for _, keyname := range keys { signer, err := makeSigner(keyname) if err == nil { signers = append(signers, signer) } } return ssh.ClientAuthKeyring(&SignerContainer{signers}) }
рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд╣рдо ssh.ClientAuth рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд▓реМрдЯрд╛ рд░рд╣реЗ рд╣реИрдВ, рдЬрд┐рд╕рдореЗрдВ рд╕рд░реНрд╡рд░ рдкрд░ рдЕрдзрд┐рдХреГрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рддрд░реАрдХреЗ рд╣реИрдВред рд╕рдВрдХреНрд╖рд┐рдкреНрддрддрд╛ рдХреЗ рд▓рд┐рдП, рддреНрд░реБрдЯрд┐ рд╣реИрдВрдбрд▓рд┐рдВрдЧ рд▓рдЧрднрдЧ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрдиреБрдкрд╕реНрдерд┐рдд рд╣реИ, рдЙрддреНрдкрд╛рджрди рдореЛрдб рдореЗрдВ, рдХреЛрдб рдХреА рдорд╛рддреНрд░рд╛ 1.5 рдЧреБрдирд╛ рдмрдбрд╝реА рд╣реЛрдЧреАред
рд╕рд░реНрд╡рд░ рдкрд░ рдХрдорд╛рдВрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдХреЛрдб рднреА рдмрд╣реБрдд рддреБрдЪреНрдЫ рд╣реИ (рддреНрд░реБрдЯрд┐ рд╣реИрдВрдбрд▓рд┐рдВрдЧ рд╕рдВрдХреНрд╖рд┐рдкреНрддрддрд╛ рдХреЗ рд▓рд┐рдП рдмрд╛рд╣рд░ рдлреЗрдВрдХ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ):
func executeCmd(cmd, hostname string, config *ssh.ClientConfig) string { conn, _ := ssh.Dial("tcp", hostname+":22", config) session, _ := conn.NewSession() defer session.Close() var stdoutBuf bytes.Buffer session.Stdout = &stdoutBuf session.Run(cmd) return hostname + ": " + stdoutBuf.String() }
рд╕рд╛рджрдЧреА рдФрд░ рд╕рдВрдХреНрд╖рд┐рдкреНрддрддрд╛ рдХреЗ рд▓рд┐рдП, рд╣рдо рд╣рдореЗрд╢рд╛ рд╕рд░реНрд╡рд░ рдкрд░ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреЗ рд▓рд┐рдП рд╡рд░реНрддрдорд╛рди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рд╕рд╛рде рд╣реА рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдкреЛрд░реНрдЯ 22ред
рд╣рдорд╛рд░рд╛ рдХрд╛рд░реНрдпрдХреНрд░рдо рддреИрдпрд╛рд░ рд╣реИ! рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХрд╛ рдкреВрд░реНрдг рд╕реНрд░реЛрдд рдХреЛрдб рдмрд┐рдЧрд╛рдбрд╝рдиреЗ рдХреЗ рддрд╣рдд рд╣реИ:
рдЫрд┐рдкрд╛ рд╣реБрдЖ рдкрд╛рда package main import ( "bytes" "code.google.com/p/go.crypto/ssh" "fmt" "io" "io/ioutil" "os" "time" ) type SignerContainer struct { signers []ssh.Signer } func (t *SignerContainer) Key(i int) (key ssh.PublicKey, err error) { if i >= len(t.signers) { return } key = t.signers[i].PublicKey() return } func (t *SignerContainer) Sign(i int, rand io.Reader, data []byte) (sig []byte, err error) { if i >= len(t.signers) { return } sig, err = t.signers[i].Sign(rand, data) return } func makeSigner(keyname string) (signer ssh.Signer, err error) { fp, err := os.Open(keyname) if err != nil { return } defer fp.Close() buf, _ := ioutil.ReadAll(fp) signer, _ = ssh.ParsePrivateKey(buf) return } func makeKeyring() ssh.ClientAuth { signers := []ssh.Signer{} keys := []string{os.Getenv("HOME") + "/.ssh/id_rsa", os.Getenv("HOME") + "/.ssh/id_dsa"} for _, keyname := range keys { signer, err := makeSigner(keyname) if err == nil { signers = append(signers, signer) } } return ssh.ClientAuthKeyring(&SignerContainer{signers}) } func executeCmd(cmd, hostname string, config *ssh.ClientConfig) string { conn, _ := ssh.Dial("tcp", hostname+":22", config) session, _ := conn.NewSession() defer session.Close() var stdoutBuf bytes.Buffer session.Stdout = &stdoutBuf session.Run(cmd) return hostname + ": " + stdoutBuf.String() } func main() { cmd := os.Args[1] hosts := os.Args[2:] results := make(chan string, 10) timeout := time.After(5 * time.Second) config := &ssh.ClientConfig{ User: os.Getenv("LOGNAME"), Auth: []ssh.ClientAuth{makeKeyring()}, } for _, hostname := range hosts { go func(hostname string) { results <- executeCmd(cmd, hostname, config) }(hostname) } for i := 0; i < len(hosts); i++ { select { case res := <-results: fmt.Print(res) case <-timeout: fmt.Println("Timed out!") return } } }
рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреЛ рд▓реЙрдиреНрдЪ рдХрд░реЗрдВ:
$ vim main.go
рдпрд╣ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ! рд▓реЛрдХрд▓рд╣реЛрд╕реНрдЯ, srv1 рдФрд░ srv2 рд╕рд░реНрд╡рд░ рдХреЗ рдкрд╛рд╕ рд╕рднреА рдХрдорд╛рдВрдб рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ 0.3 рд╕реЗрдХрдВрдб рдереЗ, рдФрд░ рдзреАрдореА srv2 рд╕рдлрд▓ рдирд╣реАрдВ рд╣реБрдИред рд╕реНрд░реЛрдд рд╕реЗ "рдордХреНрдЦреА рдкрд░" рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ рдХреЗ рд╕рд╛рде, рдХрд╛рд░реНрдпрдХреНрд░рдо рдореЗрдВ 5.5 рд╕реЗрдХрдВрдб рд▓рдЧреЗ, рдЬрд┐рдирдореЗрдВ рд╕реЗ 5 рд╕реЗрдХрдВрдб рдХрдорд╛рдВрдб рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░рд╛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдЯрд╛рдЗрдордЖрдЙрдЯ рдерд╛ред
рдирд┐рд╖реНрдХрд░реНрд╖
рд▓реЗрдЦ рдЫреЛрдЯрд╛ рд╣реЛ рдЧрдпрд╛, рд▓реЗрдХрд┐рди рд╕рд╛рде рд╣реА рд╣рдордиреЗ рдПрдХ рдмрд╣реБрдд рд╣реА рдЙрдкрдпреЛрдЧреА рдПрдкреНрд▓рд┐рдХреЗрд╢рди рднреА рд▓рд┐рдЦрд╛, рдЬрд┐рд╕реЗ рдЙрддреНрдкрд╛рджрди рдореЗрдВ рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд╣рдордиреЗ рдЙрддреНрдкрд╛рджрди рд╡рд╛рддрд╛рд╡рд░рдг рдореЗрдВ рдЗрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдЕрдзрд┐рдХ рдЙрдиреНрдирдд рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рдФрд░ рдЗрд╕рдиреЗ рдЙрддреНрдХреГрд╖реНрдЯ рдкрд░рд┐рдгрд╛рдо рджрд┐рдЦрд╛рдПред
рд╕рдВрджрд░реНрдн:
1. рдЧреЛ рднрд╛рд╖рд╛:
golang.org2.
go.crypto рд▓рд╛рдЗрдмреНрд░реЗрд░реА:
code.google.com/p/go/source/checkout?repo=crypto3. рдЧреЛрдПрд╕рдПрд╕рд╣рд╛ (рдПрд╕рдПрд╕рдПрдЪрдПрди-рдкреНрд░реЙрдХреНрд╕реА рдЬреЗрдиреНрд╕рди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдмрд╛рд╣рд░реА рджреБрдирд┐рдпрд╛ рдХреЗ рд╕рд╛рде рд╕рдВрдЪрд╛рд░ рдХрд░рддрд╛ рд╣реИ):
github.com/YuriyNasretdinov/GoSSHa