Browse Source

Refactor into separate types

master
Chris Smith 5 years ago
parent
commit
485fda9a84
3 changed files with 218 additions and 129 deletions
  1. 123
    0
      container_monitor.go
  2. 25
    129
      dotege.go
  3. 70
    0
      template_generator.go

+ 123
- 0
container_monitor.go View File

@@ -0,0 +1,123 @@
1
+package main
2
+
3
+import (
4
+	"context"
5
+	"fmt"
6
+	"github.com/docker/docker/api/types"
7
+	"github.com/docker/docker/api/types/filters"
8
+	"github.com/docker/docker/client"
9
+	"time"
10
+)
11
+
12
+type ContainerMonitor struct {
13
+	newContainers      chan<- Container
14
+	goneContainerNames chan<- string
15
+	client             *client.Client
16
+	expiryTimes        map[string]time.Time
17
+	deletionTime       time.Duration
18
+	nextExpiry         time.Time
19
+	expiryTimer        *time.Timer
20
+}
21
+
22
+func NewContainerMonitor(client *client.Client, newContainerChannel chan<- Container, goneContainerChannel chan<- string) *ContainerMonitor {
23
+	timer := time.NewTimer(time.Hour)
24
+	timer.Stop()
25
+
26
+	return &ContainerMonitor{
27
+		newContainers:      newContainerChannel,
28
+		goneContainerNames: goneContainerChannel,
29
+		client:             client,
30
+		expiryTimes:        make(map[string]time.Time),
31
+		deletionTime:       10 * time.Second,
32
+		expiryTimer:        timer,
33
+		nextExpiry:         time.Now(),
34
+	}
35
+}
36
+
37
+func (c *ContainerMonitor) Monitor() {
38
+	args := filters.NewArgs()
39
+	args.Add("type", "container")
40
+	args.Add("event", "create")
41
+	args.Add("event", "destroy")
42
+	eventsChan, errChan := c.client.Events(context.Background(), types.EventsOptions{Filters: args})
43
+
44
+	c.publishExistingContainers()
45
+
46
+	for {
47
+		select {
48
+		case event := <-eventsChan:
49
+			if event.Action == "create" {
50
+				c.publishNewContainer(event.Actor.ID)
51
+			} else {
52
+				c.scheduleExpiry(event.Actor.Attributes["name"])
53
+			}
54
+
55
+		case <-c.expiryTimer.C:
56
+			c.publishExpiredContainers()
57
+
58
+		case err := <-errChan:
59
+			panic(err)
60
+		}
61
+	}
62
+}
63
+
64
+func (c *ContainerMonitor) publishExistingContainers() {
65
+	containers, err := c.client.ContainerList(context.Background(), types.ContainerListOptions{})
66
+	if err != nil {
67
+		panic(err)
68
+	}
69
+
70
+	for _, container := range containers {
71
+		c.newContainers <- Container{
72
+			Id:     container.ID,
73
+			Name:   container.Names[0][1:],
74
+			Labels: container.Labels,
75
+		}
76
+	}
77
+}
78
+
79
+func (c *ContainerMonitor) publishNewContainer(id string) {
80
+	container, err := c.client.ContainerInspect(context.Background(), id)
81
+	if err != nil {
82
+		panic(err)
83
+	}
84
+	c.newContainers <- Container{
85
+		Id:     container.ID,
86
+		Name:   container.Name[1:],
87
+		Labels: container.Config.Labels,
88
+	}
89
+	delete(c.expiryTimes, container.Name[1:])
90
+}
91
+
92
+func (c *ContainerMonitor) scheduleExpiry(name string) {
93
+	now := time.Now()
94
+	expiryTime := now.Add(c.deletionTime)
95
+	c.expiryTimes[name] = expiryTime
96
+	fmt.Printf("Scheduling expiry timer for %s\n", name)
97
+	if c.nextExpiry.Before(now) || c.nextExpiry.After(expiryTime) {
98
+		fmt.Printf("Starting expiry timer with default duration\n")
99
+		c.expiryTimer.Reset(c.deletionTime + 1*time.Second)
100
+		c.nextExpiry = expiryTime
101
+	}
102
+}
103
+
104
+func (c *ContainerMonitor) publishExpiredContainers() {
105
+	now := time.Now()
106
+	next := 0 * time.Second
107
+
108
+	for name, expiryTime := range c.expiryTimes {
109
+		if expiryTime.Before(now) {
110
+			fmt.Printf("Expiring %s\n", name)
111
+			delete(c.expiryTimes, name)
112
+			c.goneContainerNames <- name
113
+		} else if next == 0 || expiryTime.Sub(now) < next {
114
+			next = expiryTime.Sub(now)
115
+		}
116
+	}
117
+
118
+	if next > 0 {
119
+		fmt.Printf("Starting expiry timer with duration %s\n", next)
120
+		c.expiryTimer.Reset(next + 1*time.Second)
121
+		c.nextExpiry = now.Add(next)
122
+	}
123
+}

+ 25
- 129
dotege.go View File

@@ -2,16 +2,10 @@ package main
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"github.com/docker/distribution/context"
6
-	"github.com/docker/docker/api/types"
7
-	"github.com/docker/docker/api/types/filters"
8 5
 	"github.com/docker/docker/client"
9 6
 	"os"
10 7
 	"os/signal"
11
-	"sort"
12
-	"strings"
13 8
 	"syscall"
14
-	"text/template"
15 9
 	"time"
16 10
 )
17 11
 
@@ -21,140 +15,44 @@ type Container struct {
21 15
 	Labels map[string]string
22 16
 }
23 17
 
24
-type Context struct {
25
-	Containers map[string]Container
26
-}
18
+func monitorSignals() <-chan bool {
19
+	signals := make(chan os.Signal, 1)
20
+	done := make(chan bool, 1)
21
+
22
+	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
27 23
 
28
-var funcMap = template.FuncMap{
29
-	"replace": func(from, to, input string) string { return strings.Replace(input, from, to, -1) },
30
-	"split":   func(sep, input string) []string { return strings.Split(input, sep) },
31
-	"join":    func(sep string, input []string) string { return strings.Join(input, sep) },
32
-	"sortlines": func(input string) string {
33
-		lines := strings.Split(input, "\n")
34
-		sort.Strings(lines)
35
-		return strings.Join(lines, "\n")
36
-	},
24
+	go func() {
25
+		sig := <-signals
26
+		fmt.Printf("Received %s signal\n", sig)
27
+		done <- true
28
+	}()
29
+
30
+	return done
37 31
 }
38 32
 
39 33
 func main() {
40
-	sigs := make(chan os.Signal, 1)
41
-	done := make(chan bool, 1)
34
+	done := monitorSignals()
42 35
 	containerChan := make(chan Container, 1)
43 36
 	expiryChan := make(chan string, 1)
44 37
 
45
-	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
46
-
47 38
 	cli, err := client.NewEnvClient()
48 39
 	if err != nil {
49 40
 		panic(err)
50 41
 	}
51 42
 
52
-	go func() {
53
-		sig := <-sigs
54
-		fmt.Printf("Received %s signal\n", sig)
55
-		err := cli.Close()
56
-		if err != nil {
57
-			panic(err)
58
-		}
59
-		done <- true
60
-	}()
61
-
62
-	go func() {
63
-		const deletionTime = 10 * time.Second
64
-
65
-		expiryTimes := make(map[string]time.Time)
66
-		expiryTimer := time.NewTimer(time.Hour)
67
-		nextExpiry := time.Now()
68
-		expiryTimer.Stop()
43
+	templateGenerator := NewTemplateGenerator()
44
+	templateGenerator.AddTemplate(TemplateConfig{
45
+		Source: "./templates/domains.txt.tpl",
46
+	})
69 47
 
70
-		args := filters.NewArgs()
71
-		args.Add("type", "container")
72
-		args.Add("event", "create")
73
-		args.Add("event", "destroy")
74
-		eventsChan, errChan := cli.Events(context.Background(), types.EventsOptions{Filters: args})
75
-
76
-		containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
77
-		if err != nil {
78
-			panic(err)
79
-		}
80
-
81
-		for _, container := range containers {
82
-			containerChan <- Container{
83
-				Id:     container.ID,
84
-				Name:   container.Names[0][1:],
85
-				Labels: container.Labels,
86
-			}
87
-		}
88
-
89
-		for {
90
-			select {
91
-			case event := <-eventsChan:
92
-				if event.Action == "create" {
93
-					container, err := cli.ContainerInspect(context.Background(), event.Actor.ID)
94
-					if err != nil {
95
-						panic(err)
96
-					}
97
-					containerChan <- Container{
98
-						Id:     container.ID,
99
-						Name:   container.Name[1:],
100
-						Labels: container.Config.Labels,
101
-					}
102
-				} else {
103
-					now := time.Now()
104
-					expiryTime := now.Add(deletionTime)
105
-					expiryTimes[event.Actor.Attributes["name"]] = expiryTime
106
-					fmt.Printf("Scheduling expiry timer for %s\n", event.Actor.Attributes["name"])
107
-					if nextExpiry.Before(now) || nextExpiry.After(expiryTime) {
108
-						fmt.Printf("Starting expiry timer with default duration\n")
109
-						expiryTimer.Reset(deletionTime + 1*time.Second)
110
-						nextExpiry = expiryTime
111
-					}
112
-				}
113
-
114
-			case <-expiryTimer.C:
115
-				now := time.Now()
116
-				next := 0 * time.Second
117
-
118
-				for name, expiryTime := range expiryTimes {
119
-					if expiryTime.Before(now) {
120
-						fmt.Printf("Expiring %s\n", name)
121
-						delete(expiryTimes, name)
122
-						expiryChan <- name
123
-					} else if next == 0 || expiryTime.Sub(now) < next {
124
-						next = expiryTime.Sub(now)
125
-					}
126
-				}
127
-
128
-				if next > 0 {
129
-					fmt.Printf("Starting expiry timer with duration %s\n", next)
130
-					expiryTimer.Reset(next + 1*time.Second)
131
-					nextExpiry = now.Add(next)
132
-				}
133
-
134
-			case err := <-errChan:
135
-				panic(err)
136
-			}
137
-		}
138
-	}()
48
+	monitor := NewContainerMonitor(cli, containerChan, expiryChan)
49
+	go monitor.Monitor()
139 50
 
140 51
 	go func() {
141
-		var templates []*template.Template
142 52
 		containers := make(map[string]Container)
143 53
 		timer := time.NewTimer(time.Hour)
144 54
 		timer.Stop()
145 55
 
146
-		tmpl, err := template.New("domains.txt.tpl").Funcs(funcMap).ParseFiles("./templates/domains.txt.tpl")
147
-		if err != nil {
148
-			panic(err)
149
-		}
150
-		templates = append(templates, tmpl)
151
-
152
-		tmpl, err = template.New("haproxy.cfg.tpl").Funcs(funcMap).ParseFiles("./templates/haproxy.cfg.tpl")
153
-		if err != nil {
154
-			panic(err)
155
-		}
156
-		templates = append(templates, tmpl)
157
-
158 56
 		for {
159 57
 			select {
160 58
 			case container := <-containerChan:
@@ -164,17 +62,15 @@ func main() {
164 62
 				delete(containers, name)
165 63
 				timer.Reset(100 * time.Millisecond)
166 64
 			case <-timer.C:
167
-				for _, tmpl := range templates {
168
-					fmt.Printf("--- Writing %s ---\n", tmpl.Name())
169
-					err = tmpl.Execute(os.Stdout, Context{Containers: containers})
170
-					fmt.Printf("--- / writing %s ---\n", tmpl.Name())
171
-					if err != nil {
172
-						panic(err)
173
-					}
174
-				}
65
+				templateGenerator.Generate(Context{Containers: containers})
175 66
 			}
176 67
 		}
177 68
 	}()
178 69
 
179 70
 	<-done
71
+
72
+	err = cli.Close()
73
+	if err != nil {
74
+		panic(err)
75
+	}
180 76
 }

+ 70
- 0
template_generator.go View File

@@ -0,0 +1,70 @@
1
+package main
2
+
3
+import (
4
+	"fmt"
5
+	"os"
6
+	"path"
7
+	"sort"
8
+	"strings"
9
+	"text/template"
10
+)
11
+
12
+type Context struct {
13
+	Containers map[string]Container
14
+}
15
+
16
+type TemplateConfig struct {
17
+	Source      string
18
+	Destination string
19
+}
20
+
21
+type Template struct {
22
+	config   TemplateConfig
23
+	content  string
24
+	template *template.Template
25
+}
26
+
27
+type TemplateGenerator struct {
28
+	templates []*Template
29
+}
30
+
31
+var funcMap = template.FuncMap{
32
+	"replace": func(from, to, input string) string { return strings.Replace(input, from, to, -1) },
33
+	"split":   func(sep, input string) []string { return strings.Split(input, sep) },
34
+	"join":    func(sep string, input []string) string { return strings.Join(input, sep) },
35
+	"sortlines": func(input string) string {
36
+		lines := strings.Split(input, "\n")
37
+		sort.Strings(lines)
38
+		return strings.Join(lines, "\n")
39
+	},
40
+}
41
+
42
+func NewTemplateGenerator() *TemplateGenerator {
43
+	return &TemplateGenerator{}
44
+}
45
+
46
+func (t *TemplateGenerator) AddTemplate(config TemplateConfig) {
47
+	tmpl, err := template.New(path.Base(config.Source)).Funcs(funcMap).ParseFiles(config.Source)
48
+	if err != nil {
49
+		panic(err)
50
+	}
51
+
52
+	t.templates = append(t.templates, &Template{
53
+		config:   config,
54
+		content:  "", // TODO: Read this in initially
55
+		template: tmpl,
56
+	})
57
+}
58
+
59
+func (t *TemplateGenerator) Generate(context Context) {
60
+	for _, tmpl := range t.templates {
61
+		// TODO: Actually write to file :)
62
+		// TODO: Retrieve the output and check if it matches our cache
63
+		fmt.Printf("--- Writing %s to %s ---\n", tmpl.config.Source, tmpl.config.Destination)
64
+		err := tmpl.template.Execute(os.Stdout, context)
65
+		fmt.Printf("--- / writing %s ---\n", tmpl.config.Destination)
66
+		if err != nil {
67
+			panic(err)
68
+		}
69
+	}
70
+}

Loading…
Cancel
Save