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

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