utils.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package utils
  2. import (
  3. "crypto/rand"
  4. "encoding/hex"
  5. "encoding/json"
  6. "io"
  7. "os"
  8. "path/filepath"
  9. "strings"
  10. "syscall"
  11. )
  12. const (
  13. exitSignalOffset = 128
  14. )
  15. // GenerateRandomName returns a new name joined with a prefix. This size
  16. // specified is used to truncate the randomly generated value
  17. func GenerateRandomName(prefix string, size int) (string, error) {
  18. id := make([]byte, 32)
  19. if _, err := io.ReadFull(rand.Reader, id); err != nil {
  20. return "", err
  21. }
  22. if size > 64 {
  23. size = 64
  24. }
  25. return prefix + hex.EncodeToString(id)[:size], nil
  26. }
  27. // ResolveRootfs ensures that the current working directory is
  28. // not a symlink and returns the absolute path to the rootfs
  29. func ResolveRootfs(uncleanRootfs string) (string, error) {
  30. rootfs, err := filepath.Abs(uncleanRootfs)
  31. if err != nil {
  32. return "", err
  33. }
  34. return filepath.EvalSymlinks(rootfs)
  35. }
  36. // ExitStatus returns the correct exit status for a process based on if it
  37. // was signaled or exited cleanly
  38. func ExitStatus(status syscall.WaitStatus) int {
  39. if status.Signaled() {
  40. return exitSignalOffset + int(status.Signal())
  41. }
  42. return status.ExitStatus()
  43. }
  44. // WriteJSON writes the provided struct v to w using standard json marshaling
  45. func WriteJSON(w io.Writer, v interface{}) error {
  46. data, err := json.Marshal(v)
  47. if err != nil {
  48. return err
  49. }
  50. _, err = w.Write(data)
  51. return err
  52. }
  53. // CleanPath makes a path safe for use with filepath.Join. This is done by not
  54. // only cleaning the path, but also (if the path is relative) adding a leading
  55. // '/' and cleaning it (then removing the leading '/'). This ensures that a
  56. // path resulting from prepending another path will always resolve to lexically
  57. // be a subdirectory of the prefixed path. This is all done lexically, so paths
  58. // that include symlinks won't be safe as a result of using CleanPath.
  59. func CleanPath(path string) string {
  60. // Deal with empty strings nicely.
  61. if path == "" {
  62. return ""
  63. }
  64. // Ensure that all paths are cleaned (especially problematic ones like
  65. // "/../../../../../" which can cause lots of issues).
  66. path = filepath.Clean(path)
  67. // If the path isn't absolute, we need to do more processing to fix paths
  68. // such as "../../../../<etc>/some/path". We also shouldn't convert absolute
  69. // paths to relative ones.
  70. if !filepath.IsAbs(path) {
  71. path = filepath.Clean(string(os.PathSeparator) + path)
  72. // This can't fail, as (by definition) all paths are relative to root.
  73. path, _ = filepath.Rel(string(os.PathSeparator), path)
  74. }
  75. // Clean the path again for good measure.
  76. return filepath.Clean(path)
  77. }
  78. // SearchLabels searches a list of key-value pairs for the provided key and
  79. // returns the corresponding value. The pairs must be separated with '='.
  80. func SearchLabels(labels []string, query string) string {
  81. for _, l := range labels {
  82. parts := strings.SplitN(l, "=", 2)
  83. if len(parts) < 2 {
  84. continue
  85. }
  86. if parts[0] == query {
  87. return parts[1]
  88. }
  89. }
  90. return ""
  91. }