container.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. // Unless explicitly stated otherwise all files in this repository are licensed
  2. // under the Apache License Version 2.0.
  3. // This product includes software developed at Datadog (https://www.datadoghq.com/).
  4. // Copyright 2016 Datadog, Inc.
  5. package internal
  6. import (
  7. "bufio"
  8. "fmt"
  9. "io"
  10. "os"
  11. "regexp"
  12. )
  13. const (
  14. // cgroupPath is the path to the cgroup file where we can find the container id if one exists.
  15. cgroupPath = "/proc/self/cgroup"
  16. )
  17. const (
  18. uuidSource = "[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}|[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$"
  19. containerSource = "[0-9a-f]{64}"
  20. taskSource = "[0-9a-f]{32}-\\d+"
  21. )
  22. var (
  23. // expLine matches a line in the /proc/self/cgroup file. It has a submatch for the last element (path), which contains the container ID.
  24. expLine = regexp.MustCompile(`^\d+:[^:]*:(.+)$`)
  25. // expContainerID matches contained IDs and sources. Source: https://github.com/Qard/container-info/blob/master/index.js
  26. expContainerID = regexp.MustCompile(fmt.Sprintf(`(%s|%s|%s)(?:.scope)?$`, uuidSource, containerSource, taskSource))
  27. // containerID is the containerID read at init from /proc/self/cgroup
  28. containerID string
  29. )
  30. func init() {
  31. containerID = readContainerID(cgroupPath)
  32. }
  33. // parseContainerID finds the first container ID reading from r and returns it.
  34. func parseContainerID(r io.Reader) string {
  35. scn := bufio.NewScanner(r)
  36. for scn.Scan() {
  37. path := expLine.FindStringSubmatch(scn.Text())
  38. if len(path) != 2 {
  39. // invalid entry, continue
  40. continue
  41. }
  42. if parts := expContainerID.FindStringSubmatch(path[1]); len(parts) == 2 {
  43. return parts[1]
  44. }
  45. }
  46. return ""
  47. }
  48. // readContainerID attempts to return the container ID from the provided file path or empty on failure.
  49. func readContainerID(fpath string) string {
  50. f, err := os.Open(fpath)
  51. if err != nil {
  52. return ""
  53. }
  54. defer f.Close()
  55. return parseContainerID(f)
  56. }
  57. // ContainerID attempts to return the container ID from /proc/self/cgroup or empty on failure.
  58. func ContainerID() string {
  59. return containerID
  60. }