pkg/exporter/nettop/docker.go (113 lines of code) (raw):
package nettop
import (
"context"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"strings"
log "github.com/sirupsen/logrus"
)
var (
dockerhttpc *http.Client
dockerInfo *slimDockerInfo
)
const dockersock = "/var/run/docker.sock"
type slimDocker struct {
State slimDockerState `json:"State"`
HostConfig slimDockerHostConfig `json:"HostConfig"`
}
type slimDockerState struct {
Status string `json:"Status"`
Pid int `json:"Pid"`
}
type slimDockerHostConfig struct {
CgroupParent string `json:"CgroupParent"`
}
type slimDockerInfo struct {
CgroupDriver string `json:"CgroupDriver"`
}
func initializeDockerClient() {
if dockerhttpc != nil {
return
}
dockerhttpc = &http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial("unix", dockersock)
},
},
}
}
func initializeDockerInfo() error {
info, err := dockerHTTPRequest("/info")
if err != nil {
return err
}
dockerInfo = &slimDockerInfo{}
if err := json.Unmarshal(info, dockerInfo); err != nil {
return fmt.Errorf("failed unmarshal %s to slimDockerInfo: %w", string(info), err)
}
return nil
}
func dockerHTTPRequest(path string) ([]byte, error) {
path = strings.TrimPrefix(path, "/")
url := fmt.Sprintf("http://localhost/%s", path)
resp, err := dockerhttpc.Get(url)
if err != nil {
return nil, fmt.Errorf("failed request docker %s: %w", url, err)
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed read docker response: %w", err)
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("failed request docker %s, status code: %d, body: %s", url, resp.StatusCode, string(data))
}
return data, nil
}
func getSandboxInfoSpecForDocker(id string) (*sandboxInfoSpec, error) {
if dockerhttpc == nil {
initializeDockerClient()
}
if dockerInfo == nil {
if err := initializeDockerInfo(); err != nil {
return nil, fmt.Errorf("failed get docker info: %w", err)
}
}
b, err := dockerHTTPRequest(fmt.Sprintf("/containers/%s/json", id))
if err != nil {
return nil, fmt.Errorf("failed read container detail for %s from docker docker: %w", id, err)
}
docker := &slimDocker{}
if err := json.Unmarshal(b, docker); err != nil {
return nil, fmt.Errorf("failed unmarsh docker response for %s to slimDocker: %w", id, err)
}
return buildSandboxInfoSpecForDocker(docker)
}
func adjustCgroupParent(rawCgroupParent string) string {
if dockerInfo.CgroupDriver == "cgroupfs" {
return rawCgroupParent
}
arr := strings.Split(rawCgroupParent, "-")
if len(arr) == 2 {
//guaranteed pod, cgroup parent: kubepods-podfd9ea419_d65a_454e_9697_f7312cf47af7.slice
return fmt.Sprintf("/%[1]s.slice/%[1]s-%[2]s", arr[0], arr[1])
} else if len(arr) == 3 {
//besteffort and burstable pod, cgroup parent: kubepods-burstable-podf4c0cdd8e0920b18d85d50904cb0f13d.slice
return fmt.Sprintf("/%[1]s.slice/%[1]s-%[2]s.slice/%[1]s-%[2]s-%[3]s", arr[0], arr[1], arr[2])
}
log.Errorf("invalid cgroup parent path: %s", rawCgroupParent)
return ""
}
func buildSandboxInfoSpecForDocker(docker *slimDocker) (*sandboxInfoSpec, error) {
cgroupParent := adjustCgroupParent(docker.HostConfig.CgroupParent)
return &sandboxInfoSpec{
Pid: docker.State.Pid,
Config: Config{
Linux: Linux{
CgroupParent: cgroupParent,
},
},
}, nil
}