mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-10-30 18:23:35 +08:00
feat(climc,apigateway): pod and container log (#20523)
This commit is contained in:
@@ -15,9 +15,7 @@
|
||||
package compute
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -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
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
package compute
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
@@ -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"`
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package compute
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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 (
|
||||
@@ -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")
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user