|
@@ -1,6 +1,7 @@
|
1
|
1
|
package main
|
2
|
2
|
|
3
|
3
|
import (
|
|
4
|
+ "context"
|
4
|
5
|
"fmt"
|
5
|
6
|
"github.com/csmith/dotege/model"
|
6
|
7
|
"github.com/docker/docker/client"
|
|
@@ -27,6 +28,10 @@ const (
|
27
|
28
|
envAcmeKeyTypeDefault = "P384"
|
28
|
29
|
envAcmeCacheLocationKey = "DOTEGE_ACME_CACHE_FILE"
|
29
|
30
|
envAcmeCacheLocationDefault = "/data/config/certs.json"
|
|
31
|
+ envSignalContainerKey = "DOTEGE_SIGNAL_CONTAINER"
|
|
32
|
+ envSignalContainerDefault = ""
|
|
33
|
+ envSignalTypeKey = "DOTEGE_SIGNAL_TYPE"
|
|
34
|
+ envSignalTypeDefault = "HUP"
|
30
|
35
|
envTemplateDestinationKey = "DOTEGE_TEMPLATE_DESTINATION"
|
31
|
36
|
envTemplateDestinationDefault = "/data/output/haproxy.cfg"
|
32
|
37
|
envTemplateSourceKey = "DOTEGE_TEMPLATE_SOURCE"
|
|
@@ -37,6 +42,8 @@ var (
|
37
|
42
|
logger *zap.SugaredLogger
|
38
|
43
|
certificateManager *CertificateManager
|
39
|
44
|
config *model.Config
|
|
45
|
+ dockerClient *client.Client
|
|
46
|
+ containers = make(map[string]*model.Container)
|
40
|
47
|
)
|
41
|
48
|
|
42
|
49
|
func requiredVar(key string) (value string) {
|
|
@@ -81,6 +88,20 @@ func createLogger() *zap.SugaredLogger {
|
81
|
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
|
105
|
func createConfig() {
|
85
|
106
|
config = &model.Config{
|
86
|
107
|
Templates: []model.TemplateConfig{
|
|
@@ -100,6 +121,7 @@ func createConfig() {
|
100
|
121
|
KeyType: certcrypto.KeyType(optionalVar(envAcmeKeyTypeKey, envAcmeKeyTypeDefault)),
|
101
|
122
|
CacheLocation: optionalVar(envAcmeCacheLocationKey, envAcmeCacheLocationDefault),
|
102
|
123
|
},
|
|
124
|
+ Signals: createSignalConfig(),
|
103
|
125
|
DefaultCertActions: model.COMBINE | model.FLATTEN,
|
104
|
126
|
DefaultCertDestination: optionalVar(envCertDestinationKey, envCertDestinationDefault),
|
105
|
127
|
}
|
|
@@ -139,13 +161,13 @@ func main() {
|
139
|
161
|
|
140
|
162
|
jitterTimer := time.NewTimer(time.Minute)
|
141
|
163
|
redeployTimer := time.NewTicker(time.Hour * 24)
|
142
|
|
- containers := make(map[string]*model.Container)
|
143
|
164
|
|
144
|
165
|
go func() {
|
145
|
166
|
err := monitorContainers(dockerClient, dockerStopChan, func(container *model.Container) {
|
146
|
167
|
containers[container.Name] = container
|
147
|
168
|
jitterTimer.Reset(100 * time.Millisecond)
|
148
|
169
|
deployCertForContainer(container)
|
|
170
|
+ signalContainer()
|
149
|
171
|
}, func(name string) {
|
150
|
172
|
delete(containers, name)
|
151
|
173
|
jitterTimer.Reset(100 * time.Millisecond)
|
|
@@ -161,14 +183,18 @@ func main() {
|
161
|
183
|
select {
|
162
|
184
|
case <-jitterTimer.C:
|
163
|
185
|
hostnames := getHostnames(containers, *config)
|
164
|
|
- templateGenerator.Generate(Context{
|
|
186
|
+ updated := templateGenerator.Generate(Context{
|
165
|
187
|
Containers: containers,
|
166
|
188
|
Hostnames: hostnames,
|
167
|
189
|
})
|
|
190
|
+ if updated {
|
|
191
|
+ signalContainer()
|
|
192
|
+ }
|
168
|
193
|
case <-redeployTimer.C:
|
169
|
194
|
logger.Info("Performing periodic certificate refresh")
|
170
|
195
|
for _, container := range containers {
|
171
|
196
|
deployCertForContainer(container)
|
|
197
|
+ signalContainer()
|
172
|
198
|
}
|
173
|
199
|
}
|
174
|
200
|
}
|
|
@@ -183,6 +209,20 @@ func main() {
|
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
|
226
|
func getHostnamesForContainer(container *model.Container) []string {
|
187
|
227
|
if label, ok := container.Labels[config.Labels.Hostnames]; ok {
|
188
|
228
|
return strings.Split(strings.Replace(label, ",", " ", -1), " ")
|