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.

deployer.go 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package certs
  2. import (
  3. "github.com/csmith/dotege/model"
  4. "go.uber.org/zap"
  5. "io/ioutil"
  6. "os"
  7. "path"
  8. "time"
  9. )
  10. // CertificateDeployer deploys certificates according to their configuration.
  11. type CertificateDeployer struct {
  12. logger *zap.SugaredLogger
  13. certChannel <-chan model.FoundCertificate
  14. deployChannel chan bool
  15. certs map[string]model.FoundCertificate
  16. hostnames map[string]*model.Hostname
  17. }
  18. // NewCertificateDeployer creates a new CertificateDeployer.
  19. func NewCertificateDeployer(logger *zap.SugaredLogger, channel <-chan model.FoundCertificate) *CertificateDeployer {
  20. deployer := &CertificateDeployer{
  21. logger: logger,
  22. certChannel: channel,
  23. deployChannel: make(chan bool, 1),
  24. certs: make(map[string]model.FoundCertificate),
  25. }
  26. go deployer.monitor()
  27. go deployer.deployAll()
  28. return deployer
  29. }
  30. func (c *CertificateDeployer) monitor() {
  31. select {
  32. case cert := <-c.certChannel:
  33. c.certs[cert.Hostname] = cert
  34. c.deployChannel <- true
  35. }
  36. }
  37. func (c *CertificateDeployer) deployAll() {
  38. select {
  39. case <-c.deployChannel:
  40. c.logger.Debug("Checking for certificates requiring deploySingle")
  41. for _, hostname := range c.hostnames {
  42. if cert, ok := c.certs[hostname.Name]; ok {
  43. c.deploySingle(cert, hostname)
  44. }
  45. }
  46. }
  47. }
  48. func (c *CertificateDeployer) deploySingle(cert model.FoundCertificate, hostname *model.Hostname) {
  49. if (hostname.CertActions & model.COMBINE) == model.COMBINE {
  50. chain := c.readFile(cert.FullChain)
  51. pkey := c.readFile(cert.PrivateKey)
  52. c.deployFile("combined.pem", append(chain, pkey...), cert.ModTime, hostname)
  53. } else {
  54. c.deployFile("cert.pem", c.readFile(cert.Cert), cert.ModTime, hostname)
  55. c.deployFile("chain.pem", c.readFile(cert.Chain), cert.ModTime, hostname)
  56. c.deployFile("fullchain.pem", c.readFile(cert.FullChain), cert.ModTime, hostname)
  57. c.deployFile("privkey.pem", c.readFile(cert.PrivateKey), cert.ModTime, hostname)
  58. }
  59. }
  60. func (c *CertificateDeployer) deployFile(name string, content []byte, modTime time.Time, hostname *model.Hostname) {
  61. var target string
  62. if (hostname.CertActions & model.FLATTEN) == model.FLATTEN {
  63. target = path.Join(hostname.CertDestination, hostname.Name+".pem")
  64. } else {
  65. target = path.Join(hostname.CertDestination, hostname.Name, name)
  66. }
  67. info, err := os.Stat(target)
  68. if err != nil && info.ModTime().After(modTime) {
  69. c.logger.Debugf("Not writing %s as it was modified more recently than our cert", target)
  70. return
  71. }
  72. err = ioutil.WriteFile(target, content, 0700)
  73. if err != nil {
  74. c.logger.Warnf("Unable to write certificate %s - %s", target, err.Error())
  75. } else {
  76. c.logger.Info("Updated certificate file %s", target)
  77. }
  78. }
  79. func (c *CertificateDeployer) readFile(name string) []byte {
  80. data, err := ioutil.ReadFile(name)
  81. if err != nil {
  82. c.logger.Errorf("Unable to read certificate file %s - %s", name, err.Error())
  83. }
  84. return data
  85. }
  86. func (c *CertificateDeployer) UpdateHostnames(hostnames map[string]*model.Hostname) {
  87. c.hostnames = hostnames
  88. c.deployChannel <- true
  89. }