From 618c1a059afeb31ea87ec8b4bd405c6be174f9b3 Mon Sep 17 00:00:00 2001 From: Zexi Li Date: Thu, 30 May 2024 15:16:06 +0800 Subject: [PATCH] feat(webconsole,apigateway): display info for container exec (#20403) --- pkg/apis/webconsole/k8s.go | 7 ++++ .../modules/webconsole/mod_webconsole.go | 36 +++++++++++++++++-- pkg/webconsole/command/kube_command.go | 26 +++++++++++++- pkg/webconsole/session/session.go | 18 ++++++++++ 4 files changed, 83 insertions(+), 4 deletions(-) diff --git a/pkg/apis/webconsole/k8s.go b/pkg/apis/webconsole/k8s.go index de7a492c6f..077ce98bc8 100644 --- a/pkg/apis/webconsole/k8s.go +++ b/pkg/apis/webconsole/k8s.go @@ -20,10 +20,17 @@ type SK8sRequest struct { Container string `json:"container"` } +type SK8sShellDisplayInfo struct { + InstanceName string `json:"instanceName"` + IPs []string `json:"ips,omitempty"` +} + type SK8sShellRequest struct { SK8sRequest Command string `json:"command"` Args []string `json:"args"` Env map[string]string `json:"env"` + + DisplayInfo *SK8sShellDisplayInfo `json:"display_info"` } diff --git a/pkg/mcclient/modules/webconsole/mod_webconsole.go b/pkg/mcclient/modules/webconsole/mod_webconsole.go index 61b91f24aa..82efeb0952 100644 --- a/pkg/mcclient/modules/webconsole/mod_webconsole.go +++ b/pkg/mcclient/modules/webconsole/mod_webconsole.go @@ -16,15 +16,18 @@ package webconsole import ( "fmt" + "strings" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" + compute_api "yunion.io/x/onecloud/pkg/apis/compute" webconsole_api "yunion.io/x/onecloud/pkg/apis/webconsole" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modulebase" + "yunion.io/x/onecloud/pkg/mcclient/modules/compute" "yunion.io/x/onecloud/pkg/mcclient/modules/k8s" ) @@ -81,14 +84,40 @@ func (m WebConsoleManager) DoContainerExec(s *mcclient.ClientSession, data jsonu if containerId == "" { return nil, httperrors.NewNotEmptyError("container_id") } - return m.doCloudShell(s, "/opt/yunion/bin/climc", "container-exec", containerId, "sh") + obj, err := compute.Containers.Get(s, containerId, nil) + if err != nil { + return nil, errors.Wrapf(err, "get container by %s", containerId) + } + containerName, _ := obj.GetString("name") + serverId, _ := obj.GetString("guest_id") + if serverId == "" { + return nil, httperrors.NewNotFoundError("not found guest_id from container %s", obj) + } + serverObj, err := compute.Servers.Get(s, serverId, nil) + if err != nil { + return nil, errors.Wrapf(err, "get server by %s", serverId) + } + serverDetails := &compute_api.ServerDetails{} + if err := serverObj.Unmarshal(serverDetails); err != nil { + return nil, errors.Wrapf(err, "unmarshal server details: %s", serverObj) + } + info := &webconsole_api.SK8sShellDisplayInfo{ + InstanceName: containerName, + IPs: strings.Split(serverDetails.IPs, ","), + } + return m.doCloudShell(s, info, "/opt/yunion/bin/climc", "container-exec", containerId, "sh") +} + +type CloudShellRequest struct { + InstanceName string `json:"instance_name"` + IPs []string `json:"ips"` } func (m WebConsoleManager) DoCloudShell(s *mcclient.ClientSession, _ jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return m.doCloudShell(s, "/bin/bash") + return m.doCloudShell(s, nil, "/bin/bash") } -func (m WebConsoleManager) doCloudShell(s *mcclient.ClientSession, cmd string, args ...string) (jsonutils.JSONObject, error) { +func (m WebConsoleManager) doCloudShell(s *mcclient.ClientSession, info *webconsole_api.SK8sShellDisplayInfo, cmd string, args ...string) (jsonutils.JSONObject, error) { adminSession := auth.GetAdminSession(s.GetContext(), s.GetRegion()) query := jsonutils.NewDict() @@ -154,6 +183,7 @@ func (m WebConsoleManager) doCloudShell(s *mcclient.ClientSession, cmd string, a "OS_SECRET_KEY": "", "OS_TRY_TERM_WIDTH": "false", } + req.DisplayInfo = info return m.DoK8sConnect(s, podName, "shell", jsonutils.Marshal(req)) } diff --git a/pkg/webconsole/command/kube_command.go b/pkg/webconsole/command/kube_command.go index 0cf06c02d6..528fedb8d9 100644 --- a/pkg/webconsole/command/kube_command.go +++ b/pkg/webconsole/command/kube_command.go @@ -41,6 +41,9 @@ type K8sEnv struct { type Kubectl struct { *BaseCommand kubeconfig string + // For display info + InstanceName string + IPs []string } func NewKubectlCommand(s *mcclient.ClientSession, kubeconfig, namespace string) *Kubectl { @@ -55,6 +58,22 @@ func NewKubectlCommand(s *mcclient.ClientSession, kubeconfig, namespace string) } } +func (c *Kubectl) SetInstanceName(name string) { + c.InstanceName = name +} + +func (c *Kubectl) GetInstanceName() string { + return c.InstanceName +} + +func (c *Kubectl) SetIPs(ips []string) { + c.IPs = ips +} + +func (c *Kubectl) GetIPs() []string { + return c.IPs +} + func (c *Kubectl) GetCommand() *exec.Cmd { cmd := c.BaseCommand.GetCommand() cmd.Env = append(cmd.Env, fmt.Sprintf("KUBECONFIG=%s", c.kubeconfig)) @@ -135,12 +154,17 @@ func NewPodBashCommand(env *K8sEnv) ICommand { } args = append(args, shellRequest.Args...) - return NewKubectlCommand(env.Session, env.Kubeconfig, env.Namespace).Exec(). + kExec := NewKubectlCommand(env.Session, env.Kubeconfig, env.Namespace).Exec(). Stdin(). TTY(). Pod(env.Pod). Container(env.Container). Command(shellRequest.Command, args...) + if shellRequest.DisplayInfo != nil { + kExec.SetInstanceName(shellRequest.DisplayInfo.InstanceName) + kExec.SetIPs(shellRequest.DisplayInfo.IPs) + } + return kExec } type KubectlLog struct { diff --git a/pkg/webconsole/session/session.go b/pkg/webconsole/session/session.go index e06a7eef75..fae7d8eebd 100644 --- a/pkg/webconsole/session/session.go +++ b/pkg/webconsole/session/session.go @@ -106,6 +106,13 @@ type ISessionData interface { GetDisplayInfo(ctx context.Context) (*SDisplayInfo, error) } +type ISessionCommand interface { + command.ICommand + + GetInstanceName() string + GetIPs() []string +} + type RandomSessionData struct { command.ICommand id string @@ -134,6 +141,17 @@ func (s *RandomSessionData) GetDisplayInfo(ctx context.Context) (*SDisplayInfo, dispInfo := SDisplayInfo{} dispInfo.WaterMark = fetchWaterMark(userInfo) dispInfo.InstanceName = s.GetCommand().String() + si, ok := s.ICommand.(ISessionCommand) + if ok { + iName := si.GetInstanceName() + if iName != "" { + dispInfo.InstanceName = iName + } + ips := si.GetIPs() + if len(ips) > 0 { + dispInfo.Ips = strings.Join(ips, ",") + } + } return &dispInfo, nil }