main.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. package main
  2. import (
  3. "bytes"
  4. "net/http"
  5. _ "net/http/pprof"
  6. "os"
  7. "path"
  8. "runtime"
  9. "strings"
  10. "github.com/coroot/coroot-node-agent/common"
  11. "github.com/coroot/coroot-node-agent/containers"
  12. "github.com/coroot/coroot-node-agent/flags"
  13. "github.com/coroot/coroot-node-agent/logs"
  14. "github.com/coroot/coroot-node-agent/node"
  15. "github.com/coroot/coroot-node-agent/profiling"
  16. "github.com/coroot/coroot-node-agent/tracing"
  17. "github.com/prometheus/client_golang/prometheus"
  18. "github.com/prometheus/client_golang/prometheus/promhttp"
  19. "golang.org/x/mod/semver"
  20. "golang.org/x/sys/unix"
  21. "golang.org/x/time/rate"
  22. "k8s.io/klog/v2"
  23. )
  24. var (
  25. version = "unknown"
  26. )
  27. const minSupportedKernelVersion = "4.16"
  28. func uname() (string, string, error) {
  29. runtime.LockOSThread()
  30. defer runtime.UnlockOSThread()
  31. f, err := os.Open("/proc/1/ns/uts")
  32. if err != nil {
  33. return "", "", err
  34. }
  35. defer f.Close()
  36. self, err := os.Open("/proc/self/ns/uts")
  37. if err != nil {
  38. return "", "", err
  39. }
  40. defer self.Close()
  41. defer func() {
  42. unix.Setns(int(self.Fd()), unix.CLONE_NEWUTS)
  43. }()
  44. err = unix.Setns(int(f.Fd()), unix.CLONE_NEWUTS)
  45. if err != nil {
  46. return "", "", err
  47. }
  48. var utsname unix.Utsname
  49. if err := unix.Uname(&utsname); err != nil {
  50. return "", "", err
  51. }
  52. hostname := string(bytes.Split(utsname.Nodename[:], []byte{0})[0])
  53. kernelVersion := string(bytes.Split(utsname.Release[:], []byte{0})[0])
  54. return hostname, kernelVersion, nil
  55. }
  56. func machineID() string {
  57. for _, p := range []string{"sys/devices/virtual/dmi/id/product_uuid", "etc/machine-id", "var/lib/dbus/machine-id"} {
  58. payload, err := os.ReadFile(path.Join("/proc/1/root", p))
  59. if err != nil {
  60. klog.Warningln("failed to read machine-id:", err)
  61. continue
  62. }
  63. id := strings.TrimSpace(strings.Replace(string(payload), "-", "", -1))
  64. klog.Infoln("machine-id: ", id)
  65. return id
  66. }
  67. return ""
  68. }
  69. func whitelistNodeExternalNetworks() {
  70. netdevs, err := node.NetDevices()
  71. if err != nil {
  72. klog.Warningln("failed to get network interfaces:", err)
  73. return
  74. }
  75. for _, iface := range netdevs {
  76. for _, p := range iface.IPPrefixes {
  77. if p.IP().IsLoopback() || common.IsIpPrivate(p.IP()) {
  78. continue
  79. }
  80. // if the node has an external network IP, whitelist that network
  81. common.ConnectionFilter.WhitelistPrefix(p)
  82. }
  83. }
  84. }
  85. func main() {
  86. klog.LogToStderr(false)
  87. klog.SetOutput(&RateLimitedLogOutput{limiter: rate.NewLimiter(rate.Limit(*flags.LogPerSecond), *flags.LogBurst)})
  88. klog.Infoln("agent version:", version)
  89. hostname, kv, err := uname()
  90. if err != nil {
  91. klog.Exitln("failed to get uname:", err)
  92. }
  93. klog.Infoln("hostname:", hostname)
  94. klog.Infoln("kernel version:", kv)
  95. ver := common.KernelMajorMinor(kv)
  96. if ver == "" {
  97. klog.Exitln("invalid kernel version:", kv)
  98. }
  99. if semver.Compare("v"+ver, "v"+minSupportedKernelVersion) == -1 {
  100. klog.Exitf("the minimum Linux kernel version required is %s or later", minSupportedKernelVersion)
  101. }
  102. whitelistNodeExternalNetworks()
  103. machineId := machineID()
  104. tracing.Init(machineId, hostname, version)
  105. logs.Init(machineId, hostname, version)
  106. registry := prometheus.NewRegistry()
  107. registerer := prometheus.WrapRegistererWith(prometheus.Labels{"machine_id": machineId}, registry)
  108. registerer.MustRegister(info("node_agent_info", version))
  109. if err := registerer.Register(node.NewCollector(hostname, kv)); err != nil {
  110. klog.Exitln(err)
  111. }
  112. processInfoCh := profiling.Init(machineId, hostname)
  113. cr, err := containers.NewRegistry(registerer, kv, processInfoCh)
  114. if err != nil {
  115. klog.Exitln(err)
  116. }
  117. defer cr.Close()
  118. profiling.Start()
  119. defer profiling.Stop()
  120. http.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{ErrorLog: logger{}, Registry: registerer}))
  121. klog.Infoln("listening on:", *flags.ListenAddress)
  122. klog.Errorln(http.ListenAndServe(*flags.ListenAddress, nil))
  123. }
  124. func info(name, version string) prometheus.Collector {
  125. g := prometheus.NewGauge(prometheus.GaugeOpts{
  126. Name: name,
  127. ConstLabels: prometheus.Labels{"version": version},
  128. })
  129. g.Set(1)
  130. return g
  131. }
  132. type logger struct{}
  133. func (l logger) Println(v ...interface{}) {
  134. klog.Errorln(v...)
  135. }
  136. type RateLimitedLogOutput struct {
  137. limiter *rate.Limiter
  138. }
  139. func (o *RateLimitedLogOutput) Write(data []byte) (int, error) {
  140. if !o.limiter.Allow() {
  141. return len(data), nil
  142. }
  143. return os.Stderr.Write(data)
  144. }