Parcourir la source

Add signalling on update

master
Chris Smith il y a 5 ans
Parent
révision
7daea071e8
4 fichiers modifiés avec 59 ajouts et 3 suppressions
  1. 7
    0
      README.adoc
  2. 42
    2
      dotege.go
  3. 7
    0
      model/model.go
  4. 3
    1
      template_generator.go

+ 7
- 0
README.adoc Voir le fichier

38
 +
38
 +
39
 The default value is `P384`.
39
 The default value is `P384`.
40
 
40
 
41
+`DOTEGE_SIGNAL_CONTAINER`::
42
+The name of a container that should be sent a signal when the template or certificates
43
+are changed. No signal is sent if not specified.
44
+
45
+`DOTEGE_SIGNAL_TYPE`::
46
+The type of signal to send to the `DOTEGE_SIGNAL_CONTAINER`. Defaults to `HUP`.
47
+
41
 `DOTEGE_TEMPLATE_DESTINATION`::
48
 `DOTEGE_TEMPLATE_DESTINATION`::
42
 Location to write the templated configuration file to. Defaults to `/data/output/haproxy.cfg`.
49
 Location to write the templated configuration file to. Defaults to `/data/output/haproxy.cfg`.
43
 
50
 

+ 42
- 2
dotege.go Voir le fichier

1
 package main
1
 package main
2
 
2
 
3
 import (
3
 import (
4
+	"context"
4
 	"fmt"
5
 	"fmt"
5
 	"github.com/csmith/dotege/model"
6
 	"github.com/csmith/dotege/model"
6
 	"github.com/docker/docker/client"
7
 	"github.com/docker/docker/client"
27
 	envAcmeKeyTypeDefault         = "P384"
28
 	envAcmeKeyTypeDefault         = "P384"
28
 	envAcmeCacheLocationKey       = "DOTEGE_ACME_CACHE_FILE"
29
 	envAcmeCacheLocationKey       = "DOTEGE_ACME_CACHE_FILE"
29
 	envAcmeCacheLocationDefault   = "/data/config/certs.json"
30
 	envAcmeCacheLocationDefault   = "/data/config/certs.json"
31
+	envSignalContainerKey         = "DOTEGE_SIGNAL_CONTAINER"
32
+	envSignalContainerDefault     = ""
33
+	envSignalTypeKey              = "DOTEGE_SIGNAL_TYPE"
34
+	envSignalTypeDefault          = "HUP"
30
 	envTemplateDestinationKey     = "DOTEGE_TEMPLATE_DESTINATION"
35
 	envTemplateDestinationKey     = "DOTEGE_TEMPLATE_DESTINATION"
31
 	envTemplateDestinationDefault = "/data/output/haproxy.cfg"
36
 	envTemplateDestinationDefault = "/data/output/haproxy.cfg"
32
 	envTemplateSourceKey          = "DOTEGE_TEMPLATE_SOURCE"
37
 	envTemplateSourceKey          = "DOTEGE_TEMPLATE_SOURCE"
37
 	logger             *zap.SugaredLogger
42
 	logger             *zap.SugaredLogger
38
 	certificateManager *CertificateManager
43
 	certificateManager *CertificateManager
39
 	config             *model.Config
44
 	config             *model.Config
45
+	dockerClient       *client.Client
46
+	containers         = make(map[string]*model.Container)
40
 )
47
 )
41
 
48
 
42
 func requiredVar(key string) (value string) {
49
 func requiredVar(key string) (value string) {
81
 	return logger.Sugar()
88
 	return logger.Sugar()
82
 }
89
 }
83
 
90
 
91
+func createSignalConfig() []model.ContainerSignal {
92
+	name := optionalVar(envSignalContainerKey, envSignalContainerDefault)
93
+	if name == envSignalContainerDefault {
94
+		return []model.ContainerSignal{}
95
+	} else {
96
+		return []model.ContainerSignal{
97
+			{
98
+				Name:   name,
99
+				Signal: optionalVar(envSignalTypeKey, envSignalTypeDefault),
100
+			},
101
+		}
102
+	}
103
+}
104
+
84
 func createConfig() {
105
 func createConfig() {
85
 	config = &model.Config{
106
 	config = &model.Config{
86
 		Templates: []model.TemplateConfig{
107
 		Templates: []model.TemplateConfig{
100
 			KeyType:       certcrypto.KeyType(optionalVar(envAcmeKeyTypeKey, envAcmeKeyTypeDefault)),
121
 			KeyType:       certcrypto.KeyType(optionalVar(envAcmeKeyTypeKey, envAcmeKeyTypeDefault)),
101
 			CacheLocation: optionalVar(envAcmeCacheLocationKey, envAcmeCacheLocationDefault),
122
 			CacheLocation: optionalVar(envAcmeCacheLocationKey, envAcmeCacheLocationDefault),
102
 		},
123
 		},
124
+		Signals:                createSignalConfig(),
103
 		DefaultCertActions:     model.COMBINE | model.FLATTEN,
125
 		DefaultCertActions:     model.COMBINE | model.FLATTEN,
104
 		DefaultCertDestination: optionalVar(envCertDestinationKey, envCertDestinationDefault),
126
 		DefaultCertDestination: optionalVar(envCertDestinationKey, envCertDestinationDefault),
105
 	}
127
 	}
139
 
161
 
140
 	jitterTimer := time.NewTimer(time.Minute)
162
 	jitterTimer := time.NewTimer(time.Minute)
141
 	redeployTimer := time.NewTicker(time.Hour * 24)
163
 	redeployTimer := time.NewTicker(time.Hour * 24)
142
-	containers := make(map[string]*model.Container)
143
 
164
 
144
 	go func() {
165
 	go func() {
145
 		err := monitorContainers(dockerClient, dockerStopChan, func(container *model.Container) {
166
 		err := monitorContainers(dockerClient, dockerStopChan, func(container *model.Container) {
146
 			containers[container.Name] = container
167
 			containers[container.Name] = container
147
 			jitterTimer.Reset(100 * time.Millisecond)
168
 			jitterTimer.Reset(100 * time.Millisecond)
148
 			deployCertForContainer(container)
169
 			deployCertForContainer(container)
170
+			signalContainer()
149
 		}, func(name string) {
171
 		}, func(name string) {
150
 			delete(containers, name)
172
 			delete(containers, name)
151
 			jitterTimer.Reset(100 * time.Millisecond)
173
 			jitterTimer.Reset(100 * time.Millisecond)
161
 			select {
183
 			select {
162
 			case <-jitterTimer.C:
184
 			case <-jitterTimer.C:
163
 				hostnames := getHostnames(containers, *config)
185
 				hostnames := getHostnames(containers, *config)
164
-				templateGenerator.Generate(Context{
186
+				updated := templateGenerator.Generate(Context{
165
 					Containers: containers,
187
 					Containers: containers,
166
 					Hostnames:  hostnames,
188
 					Hostnames:  hostnames,
167
 				})
189
 				})
190
+				if updated {
191
+					signalContainer()
192
+				}
168
 			case <-redeployTimer.C:
193
 			case <-redeployTimer.C:
169
 				logger.Info("Performing periodic certificate refresh")
194
 				logger.Info("Performing periodic certificate refresh")
170
 				for _, container := range containers {
195
 				for _, container := range containers {
171
 					deployCertForContainer(container)
196
 					deployCertForContainer(container)
197
+					signalContainer()
172
 				}
198
 				}
173
 			}
199
 			}
174
 		}
200
 		}
183
 	}
209
 	}
184
 }
210
 }
185
 
211
 
212
+func signalContainer() {
213
+	for _, s := range config.Signals {
214
+		container, ok := containers[s.Name]
215
+		if ok {
216
+			err := dockerClient.ContainerKill(context.Background(), container.Id, s.Signal)
217
+			if err != nil {
218
+				logger.Errorf("Unable to send signal %s to container %s: %s", s.Signal, s.Name, err.Error())
219
+			}
220
+		} else {
221
+			logger.Warnf("Couldn't signal container %s as it is not running", s.Name)
222
+		}
223
+	}
224
+}
225
+
186
 func getHostnamesForContainer(container *model.Container) []string {
226
 func getHostnamesForContainer(container *model.Container) []string {
187
 	if label, ok := container.Labels[config.Labels.Hostnames]; ok {
227
 	if label, ok := container.Labels[config.Labels.Hostnames]; ok {
188
 		return strings.Split(strings.Replace(label, ",", " ", -1), " ")
228
 		return strings.Split(strings.Replace(label, ",", " ", -1), " ")

+ 7
- 0
model/model.go Voir le fichier

54
 // Config is the user-definable configuration for Dotege.
54
 // Config is the user-definable configuration for Dotege.
55
 type Config struct {
55
 type Config struct {
56
 	Templates              []TemplateConfig
56
 	Templates              []TemplateConfig
57
+	Signals                []ContainerSignal
57
 	Labels                 LabelConfig
58
 	Labels                 LabelConfig
58
 	DefaultCertActions     CertActions
59
 	DefaultCertActions     CertActions
59
 	DefaultCertDestination string
60
 	DefaultCertDestination string
66
 	Destination string
67
 	Destination string
67
 }
68
 }
68
 
69
 
70
+// ContainerSignal describes a container that should be sent a signal when the config/certs change.
71
+type ContainerSignal struct {
72
+	Name   string
73
+	Signal string
74
+}
75
+
69
 // FoundCertificate describes a certificate we've located on disk.
76
 // FoundCertificate describes a certificate we've located on disk.
70
 type FoundCertificate struct {
77
 type FoundCertificate struct {
71
 	Hostname   string
78
 	Hostname   string

+ 3
- 1
template_generator.go Voir le fichier

58
 	})
58
 	})
59
 }
59
 }
60
 
60
 
61
-func (t *TemplateGenerator) Generate(context Context) {
61
+func (t *TemplateGenerator) Generate(context Context) (updated bool) {
62
 	for _, tmpl := range t.templates {
62
 	for _, tmpl := range t.templates {
63
 		t.logger.Debugf("Checking for updates to %s", tmpl.config.Source)
63
 		t.logger.Debugf("Checking for updates to %s", tmpl.config.Source)
64
 		builder := &strings.Builder{}
64
 		builder := &strings.Builder{}
67
 			panic(err)
67
 			panic(err)
68
 		}
68
 		}
69
 		if tmpl.content != builder.String() {
69
 		if tmpl.content != builder.String() {
70
+			updated = true
70
 			t.logger.Infof("Writing updated template to %s", tmpl.config.Destination)
71
 			t.logger.Infof("Writing updated template to %s", tmpl.config.Destination)
71
 			tmpl.content = builder.String()
72
 			tmpl.content = builder.String()
72
 			err = ioutil.WriteFile(tmpl.config.Destination, []byte(builder.String()), 0666)
73
 			err = ioutil.WriteFile(tmpl.config.Destination, []byte(builder.String()), 0666)
75
 			}
76
 			}
76
 		}
77
 		}
77
 	}
78
 	}
79
+	return
78
 }
80
 }

Chargement…
Annuler
Enregistrer