-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
util.go
177 lines (150 loc) · 4.65 KB
/
util.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package util
import (
"bufio"
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/DataDog/datadog-agent/pkg/config"
"github.com/DataDog/datadog-agent/pkg/util/docker"
)
// ErrNotImplemented is the "not implemented" error given by `gopsutil` when an
// OS doesn't support and API. Unfortunately it's in an internal package so
// we can't import it so we'll copy it here.
var ErrNotImplemented = errors.New("not implemented yet")
// ReadLines reads contents from a file and splits them by new lines.
func ReadLines(filename string) ([]string, error) {
f, err := os.Open(filename)
if err != nil {
return []string{""}, err
}
defer f.Close()
var ret []string
scanner := bufio.NewScanner(f)
for scanner.Scan() {
ret = append(ret, scanner.Text())
}
return ret, scanner.Err()
}
// GetEnv retrieves the environment variable key. If it does not exist it returns the default.
func GetEnv(key string, dfault string, combineWith ...string) string {
value := os.Getenv(key)
if value == "" {
value = dfault
}
switch len(combineWith) {
case 0:
return value
case 1:
return filepath.Join(value, combineWith[0])
default:
var b bytes.Buffer
b.WriteString(value)
for _, v := range combineWith {
b.WriteRune('/')
b.WriteString(v)
}
return b.String()
}
}
// HostProc returns the location of a host's procfs. This can and will be
// overridden when running inside a container.
func HostProc(combineWith ...string) string {
return GetEnv("HOST_PROC", "/proc", combineWith...)
}
// HostSys returns the location of a host's /sys. This can and will be overridden
// when running inside a container.
func HostSys(combineWith ...string) string {
return GetEnv("HOST_SYS", "/sys", combineWith...)
}
// PathExists returns a boolean indicating if the given path exists on the file system.
func PathExists(filename string) bool {
if _, err := os.Stat(filename); err == nil {
return true
}
return false
}
// StringInSlice returns true if the given searchString is in the given slice, false otherwise.
func StringInSlice(slice []string, searchString string) bool {
for _, curString := range slice {
if curString == searchString {
return true
}
}
return false
}
// GetDockerSocketPath is only for exposing the sockpath out of the module
func GetDockerSocketPath() (string, error) {
// If we don't have a docker.sock then return a known error.
sockPath := GetEnv("DOCKER_SOCKET_PATH", "/var/run/docker.sock")
if !PathExists(sockPath) {
return "", docker.ErrDockerNotAvailable
}
return sockPath, nil
}
// GetPlatform returns the current platform we are running on by calling
// 1. python -m platform
// 2. "uname -a"
// 3. "lsb_release -a"
// 4. reading redhat-release
func GetPlatform() (string, error) {
pyOut, pyErr := execCmd("python", "-m", "platform")
if pyErr == nil {
return pyOut, nil
}
unameOut, unameErr := execCmd("uname", "-a")
if unameErr == nil {
return unameOut, nil
}
lsbOut, lsbErr := execCmd("lsb_release", "-a")
if lsbErr == nil {
return lsbOut, nil
}
redhatRaw, redhatErr := ioutil.ReadFile("/etc/redhat-release")
if redhatErr == nil {
return strings.ToLower(string(redhatRaw)), nil
}
return "", fmt.Errorf("error retrieving platform, with python: %s, with uname: %s, with lsb_release: %s, reading redhat-release: %s", pyErr, unameErr, lsbErr, redhatErr)
}
// IsDebugfsMounted would test the existence of file /sys/kernel/debug/tracing/kprobe_events to determine if debugfs is mounted or not
// returns a boolean and a possible error message
func IsDebugfsMounted() (bool, string) {
_, err := os.Stat("/sys/kernel/debug/tracing/kprobe_events")
if err != nil {
if os.IsPermission(err) {
return false, "system-probe does not have permission to access debugfs"
} else if os.IsNotExist(err) {
return false, "debugfs is not mounted and is needed for eBPF-based checks, run \"sudo mount -t debugfs none /sys/kernel/debug\" to mount debugfs"
} else {
return false, fmt.Sprintf("an error occurred while accessing debugfs: %s", err)
}
}
return true, ""
}
func execCmd(head string, args ...string) (string, error) {
cmd := exec.Command(head, args...)
var stdout, stderr bytes.Buffer
cmd.Stdout, cmd.Stderr = &stdout, &stderr
if err := cmd.Run(); err != nil {
return "", err
}
errStr := stderr.String()
if errStr != "" {
return "", fmt.Errorf("non empty stderr received: %s", errStr)
}
return strings.ToLower(strings.TrimSpace(stdout.String())), nil
}
// GetProcRoot retrieves the current procfs dir we should use
func GetProcRoot() string {
if v := os.Getenv("HOST_PROC"); v != "" {
return v
}
if config.IsContainerized() && PathExists("/host") {
return "/host/proc"
}
return "/proc"
}