diff --git a/pkg/mcclient/options/webconsole.go b/pkg/mcclient/options/webconsole.go index ec9e8c8c7f..d8b431316b 100644 --- a/pkg/mcclient/options/webconsole.go +++ b/pkg/mcclient/options/webconsole.go @@ -75,8 +75,9 @@ type WebConsoleSshOptions struct { Ip string `help:"IP to connect if multiple IPs on server"` Port int `help:"Remote server port"` Username string `help:"Remote server username"` - KeepUsername bool `help:"Keep remove username` + KeepUsername bool `help:"Keep remove username"` Password string `help:"Remote server password"` + ResourceType string `help:"Resource Type" choices:"host|server"` } func (opt *WebConsoleSshOptions) Params() (*jsonutils.JSONDict, error) { diff --git a/pkg/webconsole/service/handlers.go b/pkg/webconsole/service/handlers.go index dfd1529716..d9d6e0474d 100644 --- a/pkg/webconsole/service/handlers.go +++ b/pkg/webconsole/service/handlers.go @@ -186,14 +186,54 @@ func handleSshShell(ctx context.Context, w http.ResponseWriter, r *http.Request) } idStr := env.Params[""] if !regutils.MatchIPAddr(idStr) { - ip, port, guestDetails, err := session.ResolveServerSSHIPPortById(ctx, env.ClientSessin, idStr, sshConnInfo.IP, sshConnInfo.Port) - if err != nil { - httperrors.GeneralServerError(ctx, w, err) + var tryServer = func() error { + ip, port, guestDetails, err := session.ResolveServerSSHIPPortById(ctx, env.ClientSessin, idStr, sshConnInfo.IP, sshConnInfo.Port) + if err != nil { + return err + } + sshConnInfo.IP = ip + sshConnInfo.Port = port + sshConnInfo.GuestDetails = guestDetails + return nil + } + var tryHost = func() error { + ip, port, hostDetails, err := session.ResolveHostSSHIPPortById(ctx, env.ClientSessin, idStr, sshConnInfo.IP, sshConnInfo.Port) + if err != nil { + return err + } + sshConnInfo.IP = ip + sshConnInfo.Port = port + sshConnInfo.HostDetails = hostDetails + return nil + } + switch sshConnInfo.ResourceType { + case "server": + err = tryServer() + if err != nil { + httperrors.GeneralServerError(ctx, w, err) + return + } + case "host": + err = tryHost() + if err != nil { + httperrors.GeneralServerError(ctx, w, err) + return + } + default: + for _, try := range []func() error{ + tryServer, + tryHost, + } { + err = try() + if err == nil { + s := session.NewSshSession(ctx, env.ClientSessin, sshConnInfo) + handleSshSession(ctx, s, w) + return + } + } + httperrors.NewResourceNotFoundError("%s not found", idStr) return } - sshConnInfo.IP = ip - sshConnInfo.Port = port - sshConnInfo.GuestDetails = guestDetails } else { // directly ssh IP should be deprecated gradually sshConnInfo.IP = idStr diff --git a/pkg/webconsole/session/display_info.go b/pkg/webconsole/session/display_info.go index dbcac8125f..bea13b02b7 100644 --- a/pkg/webconsole/session/display_info.go +++ b/pkg/webconsole/session/display_info.go @@ -51,6 +51,13 @@ func (dispInfo *SDisplayInfo) fetchGuestInfo(guestDetails *compute_api.ServerDet dispInfo.Ips = guestDetails.IPs } +func (dispInfo *SDisplayInfo) fetchHostInfo(hostDetails *compute_api.HostDetails) { + dispInfo.Hypervisor = hostDetails.HostType + dispInfo.OsArch = hostDetails.CpuArchitecture + dispInfo.InstanceName = hostDetails.Name + dispInfo.Ips = hostDetails.AccessIp +} + func (dispInfo *SDisplayInfo) populateParams(params url.Values) url.Values { if options.Options.EnableWatermark && len(dispInfo.WaterMark) > 0 { params["water_mark"] = []string{dispInfo.WaterMark} @@ -123,3 +130,16 @@ func FetchServerInfo(ctx context.Context, s *mcclient.ClientSession, sid string) } return &guestDetails, nil } + +func FetchHostInfo(ctx context.Context, s *mcclient.ClientSession, id string) (*compute_api.HostDetails, error) { + hostInfo, err := compute.Hosts.Get(s, id, nil) + if err != nil { + return nil, errors.Wrapf(err, "GetById %s", id) + } + hostDetails := compute_api.HostDetails{} + err = hostInfo.Unmarshal(&hostDetails) + if err != nil { + return nil, errors.Wrap(err, "Unmarshal guest info") + } + return &hostDetails, nil +} diff --git a/pkg/webconsole/session/resolve_sshinfo.go b/pkg/webconsole/session/resolve_sshinfo.go index 542cf0533e..138c61b12c 100644 --- a/pkg/webconsole/session/resolve_sshinfo.go +++ b/pkg/webconsole/session/resolve_sshinfo.go @@ -36,8 +36,10 @@ type SSshConnectionInfo struct { KeepUsername bool `json:"keep_username"` Password string `json:"password"` Name string `json:"name"` + ResourceType string `json:"resource_type" choices:"host|server"` GuestDetails *compute_api.ServerDetails + HostDetails *compute_api.HostDetails } func ResolveServerSSHIPPortById(ctx context.Context, s *mcclient.ClientSession, id string, ip string, port int) (string, int, *compute_api.ServerDetails, error) { @@ -125,6 +127,18 @@ func resolveServerIPPortById(ctx context.Context, s *mcclient.ClientSession, id return ip, port, guestDetails, nil } +func ResolveHostSSHIPPortById(ctx context.Context, s *mcclient.ClientSession, id string, ip string, port int) (string, int, *compute_api.HostDetails, error) { + if port <= 0 { + port = 22 + } + + hostDetails, err := FetchHostInfo(ctx, s, id) + if err != nil { + return "", 0, nil, errors.Wrap(err, "fetchServerInfo") + } + return hostDetails.AccessIp, port, hostDetails, nil +} + type sForwardInfo struct { ProxyAddr string `json:"proxy_addr"` ProxyPort int `json:"proxy_port"` diff --git a/pkg/webconsole/session/ssh_session.go b/pkg/webconsole/session/ssh_session.go index 3aad7516f0..87cc81d4bd 100644 --- a/pkg/webconsole/session/ssh_session.go +++ b/pkg/webconsole/session/ssh_session.go @@ -51,6 +51,7 @@ type SSshSession struct { Password string guestDetails *compute_api.ServerDetails + hostDetails *compute_api.HostDetails } func NewSshSession(ctx context.Context, us *mcclient.ClientSession, conn SSshConnectionInfo) *SSshSession { @@ -65,6 +66,7 @@ func NewSshSession(ctx context.Context, us *mcclient.ClientSession, conn SSshCon Password: conn.Password, guestDetails: conn.GuestDetails, + hostDetails: conn.HostDetails, } if conn.Port <= 0 { ret.Port = 22 @@ -147,6 +149,8 @@ func (s *SSshSession) GetDisplayInfo(ctx context.Context) (*SDisplayInfo, error) dispInfo.WaterMark = fetchWaterMark(userInfo) if s.guestDetails != nil { dispInfo.fetchGuestInfo(s.guestDetails) + } else if s.hostDetails != nil { + dispInfo.fetchHostInfo(s.hostDetails) } else { dispInfo.Ips = s.Host if len(s.name) > 0 {