-
Notifications
You must be signed in to change notification settings - Fork 0
/
encio_id_linux.go
84 lines (72 loc) · 1.97 KB
/
encio_id_linux.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
package encio
import (
"bufio"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"os"
"os/exec"
"strings"
"github.com/denisbrodbeck/machineid"
)
const cgroupFile = "/proc/1/cgroup"
const (
idLXC = "lxc"
idDocker = "docker"
idDockerNew = "0::/"
)
var machineIDFn = protectedIDwrapper
// protectedIDwrapper is a wrapper around machineid.ProtectedID. If executed
// inside docker container, the machineid.ProtectedID will fail, because it
// relies on /etc/machine-id that may not be present. If it fails to locate
// the machine ID it calls genID which will attempt to generate an ID using
// hostname, which is pretty random in docker, unless the user has assigned
// a specific name.
func protectedIDwrapper(appID string) (string, error) {
if inContainer, err := isInContainer(cgroupFile); !inContainer || err != nil {
return machineid.ProtectedID(appID)
}
compound := append(genID(), []byte(appID)...)
id := sha256.Sum256(compound)
return hex.EncodeToString(id[:]), nil
}
// genID generates an ID either from hostname or, if it is unable to get the
// hostname, it will return "no-machine-id"
func genID() []byte {
if id, err := os.Hostname(); err == nil {
return []byte(id)
}
if buf, err := exec.Command("uname", "-n").Output(); err == nil {
return buf
}
var b = make([]byte, 32)
if _, err := rand.Read(b); err != nil {
return b
}
return []byte("no-machine-id")
}
// isInContainer checks if the service is being executed in docker or lxc
// container.
func isInContainer(cgroupPath string) (bool, error) {
const maxlines = 5 // maximum lines to scan
f, err := os.Open(cgroupPath)
if err != nil {
return false, err
}
defer f.Close()
scan := bufio.NewScanner(f)
lines := 0
for scan.Scan() && !(lines > maxlines) {
text := scan.Text()
for _, s := range []string{idDockerNew, idDocker, idLXC} {
if strings.Contains(text, s) {
return true, nil
}
}
lines++
}
if err := scan.Err(); err != nil {
return false, err
}
return false, nil
}