Skip to content

Commit

Permalink
feat(climc,apigateway): pod and container log (#20523)
Browse files Browse the repository at this point in the history
  • Loading branch information
zexi authored Jun 13, 2024
1 parent 41e3ff1 commit e31af68
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 37 deletions.
21 changes: 2 additions & 19 deletions cmd/climc/shell/compute/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
package compute

import (
"bufio"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
Expand Down Expand Up @@ -125,24 +123,9 @@ func init() {
if err != nil {
return err
}
reader, err := man.Log(s, opts.ID, input)
if err != nil {
if err := man.LogToWriter(s, opts.ID, input, os.Stdout); err != nil {
return errors.Wrap(err, "get container log")
}
defer reader.Close()

r := bufio.NewReader(reader)
for {
bytes, err := r.ReadBytes('\n')
if _, err := os.Stdout.Write(bytes); err != nil {
return errors.Wrap(err, "write container log to stdout")
}
if err != nil {
if err != io.EOF {
return errors.Wrap(err, "read container log")
}
return nil
}
}
return nil
})
}
41 changes: 33 additions & 8 deletions cmd/climc/shell/compute/server_pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package compute

import (
"os"

"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/sets"
Expand Down Expand Up @@ -44,36 +46,59 @@ func init() {
return nil
})

R(&options.PodExecOptions{}, "pod-exec", "Execute a command in a container", func(s *mcclient.ClientSession, opt *options.PodExecOptions) error {
getContainerId := func(s *mcclient.ClientSession, scope string, podId string, container string) (string, error) {
listOpt := map[string]string{
"guest_id": opt.ID,
"guest_id": podId,
}
if len(opt.Scope) != 0 {
listOpt["scope"] = opt.Scope
if len(scope) != 0 {
listOpt["scope"] = scope
}
ctrs, err := modules.Containers.List(s, jsonutils.Marshal(listOpt))
if err != nil {
return errors.Wrapf(err, "list containers by guest_id %s", opt.ID)
return "", errors.Wrapf(err, "list containers by guest_id %s", podId)
}
if len(ctrs.Data) == 0 {
return errors.Errorf("count of container is 0")
return "", errors.Errorf("count of container is 0")
}
var ctrId string
if opt.Container == "" {
if container == "" {
ctrId, _ = ctrs.Data[0].GetString("id")
} else {
for _, ctr := range ctrs.Data {
id, _ := ctr.GetString("id")
name, _ := ctr.GetString("name")
if opt.Container == id || opt.Container == name {
if container == id || container == name {
ctrId, _ = ctr.GetString("id")
break
}
}
}
return ctrId, nil
}

R(&options.PodExecOptions{}, "pod-exec", "Execute a command in a container", func(s *mcclient.ClientSession, opt *options.PodExecOptions) error {
ctrId, err := getContainerId(s, opt.Scope, opt.ID, opt.Container)
if err != nil {
return err
}
return modules.Containers.Exec(s, ctrId, opt.ToAPIInput())
})

R(&options.PodLogOptions{}, "pod-log", "Get container log of a pod", func(s *mcclient.ClientSession, opt *options.PodLogOptions) error {
ctrId, err := getContainerId(s, opt.Scope, opt.ID, opt.Container)
if err != nil {
return err
}
input, err := opt.ToAPIInput()
if err != nil {
return err
}
if err := modules.Containers.LogToWriter(s, ctrId, input, os.Stdout); err != nil {
return errors.Wrap(err, "get container log")
}
return nil
})

type MigratePortMappingsOptions struct {
options.ServerIdOptions
RemovePort []int `help:"remove port"`
Expand Down
24 changes: 24 additions & 0 deletions pkg/mcclient/modules/compute/mod_containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package compute

import (
"bufio"
"context"
"fmt"
"io"
Expand Down Expand Up @@ -118,6 +119,29 @@ func (man ContainerManager) Log(s *mcclient.ClientSession, id string, opt *api.P
return reader, nil
}

func (man ContainerManager) LogToWriter(s *mcclient.ClientSession, id string, opt *api.PodLogOptions, out io.Writer) error {
reader, err := man.Log(s, id, opt)
if err != nil {
return errors.Wrap(err, "get container log")
}
defer reader.Close()

r := bufio.NewReader(reader)
for {
bytes, err := r.ReadBytes('\n')
if _, err := out.Write(bytes); err != nil {
return errors.Wrap(err, "write container log to stdout")
}
if err != nil {
if err != io.EOF {
return errors.Wrap(err, "read container log")
}
return nil
}
}
return nil
}

var (
Containers ContainerManager
)
Expand Down
34 changes: 32 additions & 2 deletions pkg/mcclient/modules/webconsole/mod_webconsole.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"yunion.io/x/onecloud/pkg/mcclient/modulebase"
"yunion.io/x/onecloud/pkg/mcclient/modules/compute"
"yunion.io/x/onecloud/pkg/mcclient/modules/k8s"
compute_options "yunion.io/x/onecloud/pkg/mcclient/options/compute"
)

var (
Expand Down Expand Up @@ -76,7 +77,7 @@ func (m WebConsoleManager) DoAdbShell(s *mcclient.ClientSession, id string, para
return m.DoConnect(s, "adb", id, "shell", params)
}

func (m WebConsoleManager) DoContainerExec(s *mcclient.ClientSession, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
func (m WebConsoleManager) doContainerAction(s *mcclient.ClientSession, data jsonutils.JSONObject, getArgs func(containerId string) []string) (jsonutils.JSONObject, error) {
containerId, err := data.GetString("container_id")
if err != nil {
return nil, errors.Wrap(err, "get container_id")
Expand Down Expand Up @@ -105,7 +106,36 @@ func (m WebConsoleManager) DoContainerExec(s *mcclient.ClientSession, data jsonu
InstanceName: containerName,
IPs: strings.Split(serverDetails.IPs, ","),
}
return m.doCloudShell(s, info, "/opt/yunion/bin/climc", "container-exec", containerId, "sh")
args := getArgs(containerId)
return m.doCloudShell(s, info, "/opt/yunion/bin/climc", args...)
}

func (m WebConsoleManager) DoContainerExec(s *mcclient.ClientSession, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
opt := new(compute_options.ContainerLogOptions)
data.Unmarshal(opt)
return m.doContainerAction(s, data, func(containerId string) []string {
args := []string{"container-exec"}
if opt.Tail > 0 {
args = append(args, "--tail", fmt.Sprintf("%d", opt.Tail))
}
if opt.LimitBytes > 0 {
args = append(args, "--limit-bytes", fmt.Sprintf("%d", opt.LimitBytes))
}
if opt.Since != "" {
args = append(args, "--since", opt.Since)
}
if opt.Follow {
args = append(args, "-f")
}
args = append(args, containerId)
return []string{"container-exec", containerId}
})
}

func (m WebConsoleManager) DoContainerLog(s *mcclient.ClientSession, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
return m.doContainerAction(s, data, func(containerId string) []string {
return []string{"container-log", containerId, "sh"}
})
}

type CloudShellRequest struct {
Expand Down
10 changes: 5 additions & 5 deletions pkg/mcclient/options/compute/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,11 +344,11 @@ func (o *ContainerExecSyncOptions) Params() (jsonutils.JSONObject, error) {

type ContainerLogOptions struct {
ServerIdOptions
Since string `help:"Only return logs newer than a relative duration like 5s, 2m, or 3h"`
Follow bool `help:"Follow log output" short-token:"f"`
Tail int64 `help:"Lines of recent log file to display"`
Timestamps bool `help:"Show timestamps on each line in the log output"`
LimitBytes int64 `help:"Maximum amount of bytes that can be used."`
Since string `help:"Only return logs newer than a relative duration like 5s, 2m, or 3h" json:"since"`
Follow bool `help:"Follow log output" short-token:"f" json:"follow"`
Tail int64 `help:"Lines of recent log file to display" json:"tail"`
Timestamps bool `help:"Show timestamps on each line in the log output" json:"timestamps"`
LimitBytes int64 `help:"Maximum amount of bytes that can be used." json:"limitBytes"`
}

func (o *ContainerLogOptions) Params() (jsonutils.JSONObject, error) {
Expand Down
6 changes: 6 additions & 0 deletions pkg/mcclient/options/compute/server_pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,12 @@ type PodExecOptions struct {
Container string `help:"Container name. If omitted, use the first container." short-token:"c"`
}

type PodLogOptions struct {
ContainerLogOptions
Scope string `help:"Scope of containers query" choices:"system|domain|project"`
Container string `help:"Container name. If omitted, use the first container." short-token:"c"`
}

type PodSetPortMappingOptions struct {
ServerIdOptions
PortMapping []string `help:"Port mapping of the pod and the format is: host_port=8080,port=80,protocol=<tcp|udp>,host_port_range=<int>-<int>" short-token:"p"`
Expand Down
3 changes: 0 additions & 3 deletions pkg/util/pod/stream/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"golang.org/x/net/http2"
"k8s.io/apimachinery/pkg/util/net"
"moul.io/http2curl/v2"

"yunion.io/x/log"
"yunion.io/x/pkg/util/httputils"
Expand Down Expand Up @@ -46,8 +45,6 @@ func (r *Request) Stream(ctx context.Context, method string, url string) (io.Rea
client = httputils.GetTimeoutClient(1 * time.Hour)
}

curlCmd, _ := http2curl.GetCurlCommand(req)
log.Infof("curl: %s", curlCmd)
resp, err := client.Do(req)
if err != nil {
return nil, err
Expand Down

0 comments on commit e31af68

Please sign in to comment.