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

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