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.

dotege.go 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. package main
  2. import (
  3. "fmt"
  4. "github.com/docker/distribution/context"
  5. "github.com/docker/docker/api/types"
  6. "github.com/docker/docker/api/types/filters"
  7. "github.com/docker/docker/client"
  8. "os"
  9. "os/signal"
  10. "sort"
  11. "strings"
  12. "syscall"
  13. "text/template"
  14. "time"
  15. )
  16. type Container struct {
  17. Id string
  18. Name string
  19. Labels map[string]string
  20. }
  21. type Context struct {
  22. Containers map[string]Container
  23. }
  24. var funcMap = template.FuncMap{
  25. "replace": func(from, to, input string) string { return strings.Replace(input, from, to, -1) },
  26. "split": func(sep, input string) []string { return strings.Split(input, sep) },
  27. "join": func(sep string, input []string) string { return strings.Join(input, sep) },
  28. "sortlines": func(input string) string {
  29. lines := strings.Split(input, "\n")
  30. sort.Strings(lines)
  31. return strings.Join(lines, "\n")
  32. },
  33. }
  34. func main() {
  35. sigs := make(chan os.Signal, 1)
  36. done := make(chan bool, 1)
  37. containerChan := make(chan Container, 1)
  38. expiryChan := make(chan string, 1)
  39. signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
  40. cli, err := client.NewEnvClient()
  41. if err != nil {
  42. panic(err)
  43. }
  44. go func() {
  45. sig := <-sigs
  46. fmt.Printf("Received %s signal\n", sig)
  47. err := cli.Close()
  48. if err != nil {
  49. panic(err)
  50. }
  51. done <- true
  52. }()
  53. go func() {
  54. const deletionTime = 10 * time.Second
  55. expiryTimes := make(map[string]time.Time)
  56. expiryTimer := time.NewTimer(time.Hour)
  57. nextExpiry := time.Now()
  58. expiryTimer.Stop()
  59. args := filters.NewArgs()
  60. args.Add("type", "container")
  61. args.Add("event", "create")
  62. args.Add("event", "destroy")
  63. eventsChan, errChan := cli.Events(context.Background(), types.EventsOptions{Filters: args})
  64. containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
  65. if err != nil {
  66. panic(err)
  67. }
  68. for _, container := range containers {
  69. containerChan <- Container{
  70. Id: container.ID,
  71. Name: container.Names[0][1:],
  72. Labels: container.Labels,
  73. }
  74. }
  75. for {
  76. select {
  77. case event := <-eventsChan:
  78. if event.Action == "create" {
  79. container, err := cli.ContainerInspect(context.Background(), event.Actor.ID)
  80. if err != nil {
  81. panic(err)
  82. }
  83. containerChan <- Container{
  84. Id: container.ID,
  85. Name: container.Name[1:],
  86. Labels: container.Config.Labels,
  87. }
  88. } else {
  89. now := time.Now()
  90. expiryTime := now.Add(deletionTime)
  91. expiryTimes[event.Actor.Attributes["name"]] = expiryTime
  92. fmt.Printf("Scheduling expiry timer for %s\n", event.Actor.Attributes["name"])
  93. if nextExpiry.Before(now) || nextExpiry.After(expiryTime) {
  94. fmt.Printf("Starting expiry timer with default duration\n")
  95. expiryTimer.Reset(deletionTime + 1*time.Second)
  96. nextExpiry = expiryTime
  97. }
  98. }
  99. case <-expiryTimer.C:
  100. now := time.Now()
  101. next := 0 * time.Second
  102. for name, expiryTime := range expiryTimes {
  103. if expiryTime.Before(now) {
  104. fmt.Printf("Expiring %s\n", name)
  105. delete(expiryTimes, name)
  106. expiryChan <- name
  107. } else if next == 0 || expiryTime.Sub(now) < next {
  108. next = expiryTime.Sub(now)
  109. }
  110. }
  111. if next > 0 {
  112. fmt.Printf("Starting expiry timer with duration %s\n", next)
  113. expiryTimer.Reset(next + 1*time.Second)
  114. nextExpiry = now.Add(next)
  115. }
  116. case err := <-errChan:
  117. panic(err)
  118. }
  119. }
  120. }()
  121. go func() {
  122. var templates []*template.Template
  123. containers := make(map[string]Container)
  124. timer := time.NewTimer(time.Hour)
  125. timer.Stop()
  126. tmpl, err := template.New("domains.txt.tpl").Funcs(funcMap).ParseFiles("./templates/domains.txt.tpl")
  127. if err != nil {
  128. panic(err)
  129. }
  130. templates = append(templates, tmpl)
  131. tmpl, err = template.New("haproxy.cfg.tpl").Funcs(funcMap).ParseFiles("./templates/haproxy.cfg.tpl")
  132. if err != nil {
  133. panic(err)
  134. }
  135. templates = append(templates, tmpl)
  136. for {
  137. select {
  138. case container := <-containerChan:
  139. containers[container.Name] = container
  140. timer.Reset(100 * time.Millisecond)
  141. case name := <-expiryChan:
  142. delete(containers, name)
  143. timer.Reset(100 * time.Millisecond)
  144. case <-timer.C:
  145. for _, tmpl := range templates {
  146. fmt.Printf("--- Writing %s ---\n", tmpl.Name())
  147. err = tmpl.Execute(os.Stdout, Context{Containers: containers})
  148. fmt.Printf("--- / writing %s ---\n", tmpl.Name())
  149. if err != nil {
  150. panic(err)
  151. }
  152. }
  153. }
  154. }
  155. }()
  156. <-done
  157. }