docker.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package worker
  2. import (
  3. "fmt"
  4. "os"
  5. "time"
  6. "github.com/codeskyblue/go-sh"
  7. )
  8. type dockerHook struct {
  9. emptyHook
  10. image string
  11. volumes []string
  12. options []string
  13. }
  14. func newDockerHook(p mirrorProvider, gCfg dockerConfig, mCfg mirrorConfig) *dockerHook {
  15. volumes := []string{}
  16. volumes = append(volumes, gCfg.Volumes...)
  17. volumes = append(volumes, mCfg.DockerVolumes...)
  18. options := []string{}
  19. options = append(options, gCfg.Options...)
  20. options = append(options, mCfg.DockerOptions...)
  21. return &dockerHook{
  22. emptyHook: emptyHook{
  23. provider: p,
  24. },
  25. image: mCfg.DockerImage,
  26. volumes: volumes,
  27. options: options,
  28. }
  29. }
  30. func (d *dockerHook) preExec() error {
  31. p := d.provider
  32. logDir := p.LogDir()
  33. logFile := p.LogFile()
  34. workingDir := p.WorkingDir()
  35. if _, err := os.Stat(workingDir); os.IsNotExist(err) {
  36. logger.Debugf("Making dir %s", workingDir)
  37. if err = os.MkdirAll(workingDir, 0755); err != nil {
  38. return fmt.Errorf("Error making dir %s: %s", workingDir, err.Error())
  39. }
  40. }
  41. // Override workingDir
  42. ctx := p.EnterContext()
  43. ctx.Set(
  44. "volumes", []string{
  45. fmt.Sprintf("%s:%s", logDir, logDir),
  46. fmt.Sprintf("%s:%s", logFile, logFile),
  47. fmt.Sprintf("%s:%s", workingDir, workingDir),
  48. },
  49. )
  50. return nil
  51. }
  52. func (d *dockerHook) postExec() error {
  53. // sh.Command(
  54. // "docker", "rm", "-f", d.Name(),
  55. // ).Run()
  56. name := d.Name()
  57. retry := 10
  58. for ; retry > 0; retry-- {
  59. out, err := sh.Command(
  60. "docker", "ps", "-a",
  61. "--filter", "name=^"+name+"$",
  62. "--format", "{{.Status}}",
  63. ).Output()
  64. if err != nil {
  65. logger.Errorf("docker ps failed: %v", err)
  66. break
  67. }
  68. if len(out) == 0 {
  69. break
  70. }
  71. logger.Debugf("container %s still exists: '%s'", name, string(out))
  72. time.Sleep(1 * time.Second)
  73. }
  74. if retry == 0 {
  75. logger.Warningf("container %s not removed automatically, next sync may fail", name)
  76. }
  77. d.provider.ExitContext()
  78. return nil
  79. }
  80. // Volumes returns the configured volumes and
  81. // runtime-needed volumes, including mirror dirs
  82. // and log files
  83. func (d *dockerHook) Volumes() []string {
  84. vols := make([]string, len(d.volumes))
  85. copy(vols, d.volumes)
  86. p := d.provider
  87. ctx := p.Context()
  88. if ivs, ok := ctx.Get("volumes"); ok {
  89. vs := ivs.([]string)
  90. vols = append(vols, vs...)
  91. }
  92. return vols
  93. }
  94. func (d *dockerHook) LogFile() string {
  95. p := d.provider
  96. ctx := p.Context()
  97. if iv, ok := ctx.Get(_LogFileKey + ":docker"); ok {
  98. v := iv.(string)
  99. return v
  100. }
  101. return p.LogFile()
  102. }
  103. func (d *dockerHook) Name() string {
  104. p := d.provider
  105. return "tunasync-job-" + p.Name()
  106. }