-
Notifications
You must be signed in to change notification settings - Fork 1
/
container.go
151 lines (124 loc) · 3.43 KB
/
container.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package main
import (
"context"
"fmt"
"os"
"os/signal"
"strconv"
"syscall"
"time"
typesContainer "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"ldddns.arnested.dk/internal/container"
"ldddns.arnested.dk/internal/hostname"
"ldddns.arnested.dk/internal/log"
)
//nolint:cyclop
func handleContainer(
ctx context.Context,
docker *client.Client,
containerID string,
egs *entryGroups,
status string,
config Config,
) error {
entryGroup, commit, err := egs.get(containerID)
defer commit()
if err != nil {
return fmt.Errorf("cannot get entry group for container: %w", err)
}
empty, err := entryGroup.IsEmpty()
if err != nil {
return fmt.Errorf("checking whether Avahi entry group is empty: %w", err)
}
if !empty {
err := entryGroup.Reset()
if err != nil {
return fmt.Errorf("resetting Avahi entry group is empty: %w", err)
}
}
if status == "die" || status == "kill" || status == "pause" {
return nil
}
containerJSON, err := docker.ContainerInspect(ctx, containerID)
if err != nil {
return fmt.Errorf("inspecting container: %w", err)
}
containerInfo := container.Container{ContainerJSON: containerJSON}
if ignoreOneoff(containerInfo, config) {
return nil
}
ipNumbers := containerInfo.IPAddresses()
if len(ipNumbers) == 0 {
return nil
}
hostnames, err := hostname.Hostnames(containerInfo, config.HostnameLookup)
if err != nil {
return fmt.Errorf("getting hostnames: %w", err)
}
for _, hostname := range hostnames {
addAddress(entryGroup, hostname, ipNumbers)
}
if services := containerInfo.Services(); len(hostnames) > 0 {
addServices(entryGroup, hostnames[0], ipNumbers, services, containerInfo.Name())
}
return nil
}
func ignoreOneoff(containerInfo container.Container, config Config) bool {
if !config.IgnoreDockerComposeOneoff {
return false
}
oneoff, ok := containerInfo.Config.Labels["com.docker.compose.oneoff"]
if !ok {
return false
}
if oneoff != "True" {
return false
}
log.Logf(log.PriNotice, "Ignoring oneoff container: %s", containerInfo.ID)
return true
}
func handleExistingContainers(ctx context.Context, config Config, docker *client.Client, egs *entryGroups) {
containers, err := docker.ContainerList(ctx, typesContainer.ListOptions{})
if err != nil {
log.Logf(log.PriErr, "getting container list: %v", err)
}
for _, container := range containers {
err = handleContainer(ctx, docker, container.ID, egs, "start", config)
if err != nil {
log.Logf(log.PriErr, "handling container: %v", err)
continue
}
}
}
func listen(ctx context.Context, config Config, docker *client.Client, egs *entryGroups, started time.Time) {
filter := filters.NewArgs()
filter.Add("type", "container")
filter.Add("event", "die")
filter.Add("event", "kill")
filter.Add("event", "pause")
filter.Add("event", "start")
filter.Add("event", "unpause")
msgs, errs := docker.Events(ctx, events.ListOptions{
Filters: filter,
Since: strconv.FormatInt(started.Unix(), 10),
Until: "",
})
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGTERM)
for {
select {
case err := <-errs:
panic(fmt.Errorf("go error reading docker events: %w", err))
case msg := <-msgs:
err := handleContainer(ctx, docker, msg.ID, egs, msg.Status, config)
if err != nil {
log.Logf(log.PriErr, "handling container: %v", err)
}
case <-sig:
return
}
}
}