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 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package main
  2. import (
  3. "fmt"
  4. "github.com/docker/docker/client"
  5. "go.uber.org/zap"
  6. "go.uber.org/zap/zapcore"
  7. "os"
  8. "os/signal"
  9. "strings"
  10. "syscall"
  11. "time"
  12. )
  13. type Container struct {
  14. Id string
  15. Name string
  16. Labels map[string]string
  17. }
  18. type LabelConfig struct {
  19. Hostnames string
  20. }
  21. type Hostname struct {
  22. Name string
  23. Alternatives map[string]bool
  24. Containers []Container
  25. }
  26. type Config struct {
  27. Templates []TemplateConfig
  28. Labels LabelConfig
  29. }
  30. func monitorSignals() <-chan bool {
  31. signals := make(chan os.Signal, 1)
  32. done := make(chan bool, 1)
  33. signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
  34. go func() {
  35. sig := <-signals
  36. fmt.Printf("Received %s signal\n", sig)
  37. done <- true
  38. }()
  39. return done
  40. }
  41. func main() {
  42. config := zap.NewDevelopmentConfig()
  43. config.DisableCaller = true
  44. config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
  45. config.OutputPaths = []string{"stdout"}
  46. config.ErrorOutputPaths = []string{"stdout"}
  47. logger, _ := config.Build()
  48. sugar := logger.Sugar()
  49. sugar.Info("Dotege is starting")
  50. done := monitorSignals()
  51. containerChan := make(chan Container, 1)
  52. expiryChan := make(chan string, 1)
  53. labelConfig := LabelConfig{
  54. Hostnames: "com.chameth.vhost",
  55. }
  56. cli, err := client.NewEnvClient()
  57. if err != nil {
  58. panic(err)
  59. }
  60. templateGenerator := NewTemplateGenerator(sugar)
  61. templateGenerator.AddTemplate(TemplateConfig{
  62. Source: "./templates/domains.txt.tpl",
  63. Destination: "domains.txt",
  64. })
  65. templateGenerator.AddTemplate(TemplateConfig{
  66. Source: "./templates/haproxy.cfg.tpl",
  67. Destination: "haproxy.cfg",
  68. })
  69. monitor := NewContainerMonitor(sugar, cli, containerChan, expiryChan)
  70. go monitor.Monitor()
  71. go func() {
  72. containers := make(map[string]Container)
  73. timer := time.NewTimer(time.Hour)
  74. timer.Stop()
  75. for {
  76. select {
  77. case container := <-containerChan:
  78. containers[container.Name] = container
  79. timer.Reset(100 * time.Millisecond)
  80. case name := <-expiryChan:
  81. delete(containers, name)
  82. timer.Reset(100 * time.Millisecond)
  83. case <-timer.C:
  84. templateGenerator.Generate(Context{
  85. Containers: containers,
  86. Hostnames: getHostnames(containers, labelConfig),
  87. })
  88. }
  89. }
  90. }()
  91. <-done
  92. err = cli.Close()
  93. if err != nil {
  94. panic(err)
  95. }
  96. }
  97. func getHostnames(containers map[string]Container, config LabelConfig) (hostnames map[string]Hostname) {
  98. hostnames = make(map[string]Hostname)
  99. for _, container := range containers {
  100. if label, ok := container.Labels[config.Hostnames]; ok {
  101. names := strings.Split(strings.Replace(label, ",", " ", -1), " ")
  102. if hostname, ok := hostnames[names[0]]; ok {
  103. hostname.Containers = append(hostname.Containers, container)
  104. } else {
  105. hostnames[names[0]] = Hostname{
  106. Name: names[0],
  107. Alternatives: make(map[string]bool),
  108. Containers: []Container{container},
  109. }
  110. }
  111. addAlternatives(hostnames[names[0]], names[1:])
  112. }
  113. }
  114. return
  115. }
  116. func addAlternatives(hostname Hostname, alternatives []string) {
  117. for _, alternative := range alternatives {
  118. hostname.Alternatives[alternative] = true
  119. }
  120. }