Skip to content
This repository was archived by the owner on May 24, 2025. It is now read-only.

Commit 03d58e4

Browse files
committed
#5: added readme and optimized a little bit
1 parent 8030ab2 commit 03d58e4

File tree

2 files changed

+52
-50
lines changed

2 files changed

+52
-50
lines changed

README.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
11
# Dovecot Director Controller
22

3-
Dovecot director is used to keep a temporary user -> mail server (= dovecot server) mapping, as described in <a href="https://wiki.dovecot.org/Director">dovecot docs</a>.
4-
If a dovecot director and dovecot server are used in a kubernetes cluster, mappings are not being updated in case a dovecot container restarts for example.
5-
To update the new pod ip and therefore to correct the mapping a manual execution of the command "doveadm reload" needs to be done on the dovecot director server.
6-
Since no one wants to waste manual effort on responses to ordinary container events this tool intends to automatically execute said command on the dovecot director shell whenever a dovecot container/pod becomes ready.
3+
Dovecot director is used to keep a temporary user -> mail server (= dovecot server) mapping, as described in
4+
[dovecot docs](https://wiki.dovecot.org/Director).
5+
6+
If a dovecot director and dovecot server are used in a kubernetes cluster, mappings are not being updated in case a
7+
dovecot container restarts for example since dovecot is not made to be used with private IPs as it is in k8s setup.
8+
To update the new pod ip and therefore to correct the mapping, a manual execution of the command `doveadm reload` needs
9+
to be done on the dovecot director server.
10+
11+
Since no one wants to waste manual effort on responses to ordinary container events this tool intends to automatically
12+
execute said command on the dovecot director pod container shell whenever a dovecot container/pod becomes ready
13+
or when the tls secret is changed or updated.
714

815

916
### Usage
1017

1118
Runs inside and outside of a kubernetes cluster.
19+
1220
If you don't run it inside a k8s cluster it tries to load the kubeconfig in the executing users homedir.
1321
If it does not exist you need to specify the absolute path with command flag "-c".
1422

1523
Environment variables needed for successful execution:
16-
* `DOVECOT_NAMESPACE`(string): Namespace name which must contain both dovecot director and dovecot pods
17-
* `DOVECOT_LABELS`(string): All labels given to dovecot for conclusive identification of dovecot pods, same format as in `DOVECOT_DIRECTOR_LABELS`
24+
* `DOVECOT_NAMESPACE`(string): Name of namespace that must contain both dovecot and dovecot director pods
1825
* `DOVECOT_DIRECTOR_LABELS`(string): All labels given to dovecot director for conclusive identification of dovecot director pods in the following format: `<LABEL1>=<VALUE1>,<LABEL2>=<VALUE2>`
19-
* `DOVECOT_DIRECTOR_CONTAINER_NAME` (string) (optional): Container Name of dovecot-director in Pod. Defaults to first Container in Pod if not set.
26+
* `DOVECOT_LABELS`(string): All labels given to dovecot for conclusive identification of dovecot pods, same format as in `DOVECOT_DIRECTOR_LABELS`
27+
28+
Optional environment parameters:
29+
* `DOVECOT_DIRECTOR_CONTAINER_NAME` (string) : Container Name of dovecot-director in Pod. Defaults to first Container in Pod if not set.
30+
* `SYNC_FREQUENCY_DURATION` (int, seconds, default: 70): This parameter is based on kubelets parameter `--sync-frequency duration` which is
31+
by default set to 60s, so if you change the value of kubelets parameter you should use the same value plus a few seconds
32+
to trigger at `doveadm reload` after adding/changing tls secrets successfully
2033

2134
### Used Library
2235
https://github.com/kubernetes/client-go

cmd/main.go

Lines changed: 32 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ func main() {
4242
}
4343
dovecotDirectorLabels = os.Getenv("DOVECOT_DIRECTOR_LABELS")
4444
dovecotDirectorContainerName = os.Getenv("DOVECOT_DIRECTOR_CONTAINER_NAME")
45-
45+
dovecotLabels = os.Getenv("DOVECOT_LABELS")
46+
namespace = os.Getenv("DOVECOT_NAMESPACE")
4647
syncFrequencyDurationEnv := os.Getenv("SYNC_FREQUENCY_DURATION")
48+
4749
syncFrequencyDuration = 70
4850
if syncFrequencyDurationEnv != "" {
4951
syncFrequencyDuration, err = strconv.Atoi(syncFrequencyDurationEnv)
@@ -52,14 +54,10 @@ func main() {
5254
}
5355
}
5456

55-
dovecotLabels = os.Getenv("DOVECOT_LABELS")
56-
namespace = os.Getenv("DOVECOT_NAMESPACE")
57-
5857
dovecotPods := GetPodsByLabel(clientset, namespace, dovecotLabels)
5958
initialDovecotPodCount = len(dovecotPods.Items)
6059

61-
go StartWatcherSecret(clientset, namespace)
62-
StartWatcherPods(clientset, namespace)
60+
StartWatchers(clientset, namespace)
6361
}
6462

6563
func GetPodsByLabel(clientset *kubernetes.Clientset, namespace string, labels string) *v1.PodList {
@@ -162,66 +160,57 @@ func ExecuteDoveAdm(clientset *kubernetes.Clientset, dovecotDirectorLabels strin
162160
}
163161
}
164162

165-
func StartWatcherPods(clientset *kubernetes.Clientset, namespace string) {
166-
optionsModifierFunc := func(options *metav1.ListOptions) {
167-
options.LabelSelector = dovecotLabels
168-
}
169-
watchlist := cache.NewFilteredListWatchFromClient(
163+
func StartWatchers(clientset *kubernetes.Clientset, namespace string) {
164+
watchlistSecrets := cache.NewFilteredListWatchFromClient(
170165
clientset.CoreV1().RESTClient(),
171-
"pods",
166+
"secrets",
172167
namespace,
173-
optionsModifierFunc)
174-
175-
_, controller := cache.NewInformer(
176-
watchlist,
177-
&v1.Pod{},
168+
func(options *metav1.ListOptions) {},
169+
)
170+
_, controllerSecrets := cache.NewInformer(
171+
watchlistSecrets,
172+
&v1.Secret{},
178173
time.Second*0,
179174
cache.ResourceEventHandlerFuncs{
180175
AddFunc: func(obj interface{}) {
181-
pod := obj.(*v1.Pod)
182-
handleEvent(pod, clientset)
176+
secret := obj.(*v1.Secret)
177+
if secret.Type == "kubernetes.io/tls" {
178+
go ExecuteDoveAdm(clientset, dovecotDirectorLabels, syncFrequencyDuration)
179+
}
183180
},
184181
UpdateFunc: func(oldObj, newObj interface{}) {
185-
pod := newObj.(*v1.Pod)
186-
handleEvent(pod, clientset)
182+
secret := newObj.(*v1.Secret)
183+
if secret.Type == "kubernetes.io/tls" {
184+
go ExecuteDoveAdm(clientset, dovecotDirectorLabels, syncFrequencyDuration)
185+
}
187186
},
188187
},
189188
)
190189

191-
go controller.Run(make(chan struct{}))
192-
for {
193-
time.Sleep(time.Second)
194-
}
195-
}
196-
197-
func StartWatcherSecret(clientset *kubernetes.Clientset, namespace string) {
198-
watchlist := cache.NewFilteredListWatchFromClient(
190+
watchlistPods := cache.NewFilteredListWatchFromClient(
199191
clientset.CoreV1().RESTClient(),
200-
"secrets",
192+
"pods",
201193
namespace,
202-
func(options *metav1.ListOptions) {})
194+
func(options *metav1.ListOptions) { options.LabelSelector = dovecotLabels },
195+
)
203196

204-
_, controller := cache.NewInformer(
205-
watchlist,
206-
&v1.Secret{},
197+
_, controllerPods := cache.NewInformer(
198+
watchlistPods,
199+
&v1.Pod{},
207200
time.Second*0,
208201
cache.ResourceEventHandlerFuncs{
209202
AddFunc: func(obj interface{}) {
210-
secret := obj.(*v1.Secret)
211-
if secret.Type == "kubernetes.io/tls" {
212-
go ExecuteDoveAdm(clientset, dovecotDirectorLabels, syncFrequencyDuration)
213-
}
203+
handleEvent(obj.(*v1.Pod), clientset)
214204
},
215205
UpdateFunc: func(oldObj, newObj interface{}) {
216-
secret := newObj.(*v1.Secret)
217-
if secret.Type == "kubernetes.io/tls" {
218-
go ExecuteDoveAdm(clientset, dovecotDirectorLabels, syncFrequencyDuration)
219-
}
206+
handleEvent(newObj.(*v1.Pod), clientset)
220207
},
221208
},
222209
)
223210

224-
go controller.Run(make(chan struct{}))
211+
go controllerPods.Run(make(chan struct{}))
212+
go controllerSecrets.Run(make(chan struct{}))
213+
225214
for {
226215
time.Sleep(time.Second)
227216
}

0 commit comments

Comments
 (0)