Docker template generator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

container_monitor.go 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package main
  2. import (
  3. "context"
  4. "github.com/docker/docker/api/types"
  5. "github.com/docker/docker/api/types/filters"
  6. "github.com/docker/docker/client"
  7. "go.uber.org/zap"
  8. "time"
  9. )
  10. type ContainerMonitor struct {
  11. logger *zap.SugaredLogger
  12. newContainers chan<- Container
  13. goneContainerNames chan<- string
  14. client *client.Client
  15. expiryTimes map[string]time.Time
  16. deletionTime time.Duration
  17. nextExpiry time.Time
  18. expiryTimer *time.Timer
  19. }
  20. func NewContainerMonitor(logger *zap.SugaredLogger, client *client.Client, newContainerChannel chan<- Container, goneContainerChannel chan<- string) *ContainerMonitor {
  21. timer := time.NewTimer(time.Hour)
  22. timer.Stop()
  23. return &ContainerMonitor{
  24. logger: logger,
  25. newContainers: newContainerChannel,
  26. goneContainerNames: goneContainerChannel,
  27. client: client,
  28. expiryTimes: make(map[string]time.Time),
  29. deletionTime: 10 * time.Second,
  30. expiryTimer: timer,
  31. nextExpiry: time.Now(),
  32. }
  33. }
  34. func (c *ContainerMonitor) Monitor() {
  35. args := filters.NewArgs()
  36. args.Add("type", "container")
  37. args.Add("event", "create")
  38. args.Add("event", "destroy")
  39. eventsChan, errChan := c.client.Events(context.Background(), types.EventsOptions{Filters: args})
  40. c.publishExistingContainers()
  41. for {
  42. select {
  43. case event := <-eventsChan:
  44. if event.Action == "create" {
  45. c.publishNewContainer(event.Actor.ID)
  46. } else {
  47. c.scheduleExpiry(event.Actor.Attributes["name"])
  48. }
  49. case <-c.expiryTimer.C:
  50. c.publishExpiredContainers()
  51. case err := <-errChan:
  52. c.logger.Fatal("Error received from docker events API", err)
  53. }
  54. }
  55. }
  56. func (c *ContainerMonitor) publishExistingContainers() {
  57. containers, err := c.client.ContainerList(context.Background(), types.ContainerListOptions{})
  58. if err != nil {
  59. c.logger.Fatal("Error received trying to list containers", err)
  60. }
  61. for _, container := range containers {
  62. c.logger.Infof("Found existing container %s", container.Names[0][1:])
  63. c.newContainers <- Container{
  64. Id: container.ID,
  65. Name: container.Names[0][1:],
  66. Labels: container.Labels,
  67. }
  68. }
  69. }
  70. func (c *ContainerMonitor) publishNewContainer(id string) {
  71. container, err := c.client.ContainerInspect(context.Background(), id)
  72. if err != nil {
  73. c.logger.Fatal("Error received trying to inspect container", err)
  74. }
  75. c.newContainers <- Container{
  76. Id: container.ID,
  77. Name: container.Name[1:],
  78. Labels: container.Config.Labels,
  79. }
  80. c.logger.Info("Found new container %s", container.Name[1:])
  81. delete(c.expiryTimes, container.Name[1:])
  82. }
  83. func (c *ContainerMonitor) scheduleExpiry(name string) {
  84. now := time.Now()
  85. expiryTime := now.Add(c.deletionTime)
  86. c.expiryTimes[name] = expiryTime
  87. c.logger.Info("Scheduling expiry timer for %s", name)
  88. if c.nextExpiry.Before(now) || c.nextExpiry.After(expiryTime) {
  89. c.logger.Debug("Starting expiry timer with default duration")
  90. c.expiryTimer.Reset(c.deletionTime + 1*time.Second)
  91. c.nextExpiry = expiryTime
  92. }
  93. }
  94. func (c *ContainerMonitor) publishExpiredContainers() {
  95. now := time.Now()
  96. next := 0 * time.Second
  97. for name, expiryTime := range c.expiryTimes {
  98. if expiryTime.Before(now) {
  99. c.logger.Info("Expiring %s", name)
  100. delete(c.expiryTimes, name)
  101. c.goneContainerNames <- name
  102. } else if next == 0 || expiryTime.Sub(now) < next {
  103. next = expiryTime.Sub(now)
  104. }
  105. }
  106. if next > 0 {
  107. c.logger.Debugf("Starting expiry timer with duration %s\n", next)
  108. c.expiryTimer.Reset(next + 1*time.Second)
  109. c.nextExpiry = now.Add(next)
  110. }
  111. }