mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-21 14:19:49 +08:00
climc: add server and host ssh terminal util
This commit is contained in:
@@ -18,11 +18,13 @@ import (
|
||||
"fmt"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -664,4 +666,44 @@ func init() {
|
||||
printObject(result)
|
||||
return nil
|
||||
})
|
||||
|
||||
type HostSSHLoginOptions struct {
|
||||
ID string `help:"ID or name of host"`
|
||||
Port int `help:"SSH service port" default:"22"`
|
||||
}
|
||||
R(&HostSSHLoginOptions{}, "host-ssh", "SSH login of a host", func(s *mcclient.ClientSession, args *HostSSHLoginOptions) error {
|
||||
srvid, e := modules.Hosts.GetId(s, args.ID, nil)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
i, e := modules.Hosts.GetLoginInfo(s, srvid, nil)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
host, err := i.GetString("ip")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := i.GetString("username")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
passwd, err := i.GetString("password")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
port := 22
|
||||
if args.Port != 22 {
|
||||
port = args.Port
|
||||
}
|
||||
sshCli, err := ssh.NewClient(host, port, user, passwd, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("ssh %s:%d", host, port)
|
||||
if err := sshCli.RunTerminal(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/options"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/ssh"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -1218,4 +1219,77 @@ func init() {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
R(&options.ServerSSHLoginOptions{}, "server-ssh", "Use SSH login a server", func(s *mcclient.ClientSession, opts *options.ServerSSHLoginOptions) error {
|
||||
srv, err := modules.Servers.Get(s, opts.ID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
srvid, err := srv.GetString("id")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
address := make([]string, 0)
|
||||
nics, err := srv.GetArray("nics")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, nic := range nics {
|
||||
if addr, err := nic.GetString("ip_addr"); err == nil {
|
||||
address = append(address, addr)
|
||||
}
|
||||
}
|
||||
if len(address) == 0 {
|
||||
return fmt.Errorf("Not found ip address from server %s", opts.ID)
|
||||
}
|
||||
|
||||
params := jsonutils.NewDict()
|
||||
if len(opts.Key) > 0 {
|
||||
privateKey, e := ioutil.ReadFile(opts.Key)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
params.Add(jsonutils.NewString(string(privateKey)), "private_key")
|
||||
}
|
||||
|
||||
i, e := modules.Servers.GetLoginInfo(s, srvid, params)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
passwd, err := i.GetString("password")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if opts.Password != "" {
|
||||
passwd = opts.Password
|
||||
}
|
||||
user, err := i.GetString("username")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if opts.User != "" {
|
||||
user = opts.User
|
||||
}
|
||||
|
||||
host := address[0]
|
||||
if opts.Host != "" {
|
||||
host = opts.Host
|
||||
}
|
||||
port := 22
|
||||
if opts.Port != 22 {
|
||||
port = opts.Port
|
||||
}
|
||||
|
||||
sshCli, err := ssh.NewClient(host, port, user, passwd, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("ssh %s:%d", host, port)
|
||||
if err := sshCli.RunTerminal(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -68,6 +68,14 @@ type ServerLoginInfoOptions struct {
|
||||
Key string `help:"File name of private key, if password is encrypted by key"`
|
||||
}
|
||||
|
||||
type ServerSSHLoginOptions struct {
|
||||
ServerLoginInfoOptions
|
||||
Host string `help:"IP address or hostname of the server"`
|
||||
Port int `help:"SSH service port" default:"22"`
|
||||
User string `help:"SSH login user"`
|
||||
Password string `help:"SSH password"`
|
||||
}
|
||||
|
||||
type ServerIdsOptions struct {
|
||||
ID []string `help:"ID of servers to operate" metavar:"SERVER" json:"-"`
|
||||
}
|
||||
|
||||
@@ -18,10 +18,12 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
@@ -168,3 +170,57 @@ func ParseOutput(output []byte) []string {
|
||||
func (s *Client) Close() {
|
||||
s.client.Close()
|
||||
}
|
||||
|
||||
func (s *Client) RunTerminal() error {
|
||||
defer s.Close()
|
||||
session, err := s.client.NewSession()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "open new session")
|
||||
}
|
||||
defer session.Close()
|
||||
|
||||
fd := int(os.Stdin.Fd())
|
||||
state, err := terminal.MakeRaw(fd)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "make raw terminal")
|
||||
}
|
||||
defer terminal.Restore(fd, state)
|
||||
|
||||
w, h, err := terminal.GetSize(fd)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get terminal size")
|
||||
}
|
||||
|
||||
modes := ssh.TerminalModes{
|
||||
ssh.ECHO: 1,
|
||||
ssh.TTY_OP_ISPEED: 14400,
|
||||
ssh.TTY_OP_OSPEED: 14400,
|
||||
}
|
||||
|
||||
term := os.Getenv("TERM")
|
||||
if term == "" {
|
||||
term = "xterm-256color"
|
||||
}
|
||||
if err := session.RequestPty(term, h, w, modes); err != nil {
|
||||
return errors.Wrap(err, "session xterm")
|
||||
}
|
||||
|
||||
session.Stdout = os.Stdout
|
||||
session.Stderr = os.Stderr
|
||||
session.Stdin = os.Stdin
|
||||
|
||||
if err := session.Shell(); err != nil {
|
||||
return errors.Wrap(err, "session shell")
|
||||
}
|
||||
|
||||
if err := session.Wait(); err != nil {
|
||||
if e, ok := err.(*ssh.ExitError); ok {
|
||||
switch e.ExitStatus() {
|
||||
case 130:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.Wrap(err, "ssh wait")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user