-
Notifications
You must be signed in to change notification settings - Fork 2
/
system.go
152 lines (134 loc) · 3.33 KB
/
system.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
152
// Copyright (c) 2018-2019, AT&T Intellectual Property. All rights reserved.
// SPDX-License-Identifier: GPL-2.0-only
package forwarding
import (
"io"
"os"
"regexp"
"text/template"
"github.com/danos/vyatta-service-dns/internal/fswatcher"
"github.com/danos/vyatta-service-dns/internal/log"
"github.com/danos/vyatta-service-dns/internal/process"
"github.com/msoap/byline"
)
const systemFile = `### Autogenerated by vci-service-dns
### Note: Manual changes to this file will be lost during
### the next commit.
{{range . -}}
server={{.}} # system
{{end -}}
`
var systemFileTemplate *template.Template
func init() {
t := template.New("SystemConf")
t.Funcs(template.FuncMap{})
systemFileTemplate = template.Must(t.Parse(systemFile))
}
type systemConfig struct {
proc process.Process
watcher *systemWatcher
watchFile string
confFile string
}
func (c *systemConfig) removeConfFile() {
err := os.Remove(c.confFile)
if err != nil {
log.Dlog.Println("system-config", err)
}
}
func (c *systemConfig) Set(system bool) error {
if !system {
c.watcher.stop()
c.removeConfFile()
c.watcher = nil
} else {
c.watcher.stop()
c.removeConfFile()
c.watcher = startSystemWatcher(c.proc, c.confFile, c.watchFile)
}
return nil
}
// This would be better done by listening for a notification on VCI.
// TODO: implement this notification in system name-server component and switch this
// to use it.
type systemWatcher struct {
proc process.Process
watcher *fswatcher.Watcher
confFile string
watchFile string
}
func startSystemWatcher(proc process.Process, confFile, watchFile string) *systemWatcher {
out := &systemWatcher{
proc: proc,
confFile: confFile,
watchFile: watchFile,
}
if _, err := os.Stat(watchFile); err == nil {
err := out.writeConffileFromResolv(watchFile)
if err != nil {
log.Dlog.Println("system nameserver watcher:", err)
}
}
out.watcher = fswatcher.Start(
fswatcher.LogPrefix("system nameserver watcher:"),
fswatcher.Logger(log.Dlog),
fswatcher.Handler(watchFile, out),
)
return out
}
func (w *systemWatcher) writeConffileFromResolv(resolv string) error {
f, err := os.Open(resolv)
if err != nil {
return err
}
defer f.Close()
out, err := os.OpenFile(w.confFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
defer out.Close()
err = writeDnsmasqSystemConfig(out, readSystemNameservers(f))
if err != nil {
return err
}
return nil
}
func (w *systemWatcher) createOrWrite(name string) error {
err := w.writeConffileFromResolv(name)
if err != nil {
return err
}
return w.proc.Restart()
}
func (w *systemWatcher) CloseWrite(name string) error {
if name != w.watchFile {
return nil
}
return w.createOrWrite(name)
}
func (w *systemWatcher) stop() {
if w == nil {
return
}
w.watcher.Stop()
}
func writeDnsmasqSystemConfig(w io.Writer, ns []string) error {
if len(ns) == 0 {
return nil
}
return systemFileTemplate.Execute(w, ns)
}
func readSystemNameservers(r io.Reader) []string {
var ns []string
err := byline.NewReader(r).
GrepByRegexp(regexp.MustCompile("# system added by vyatta-system-nameservers")).
AWKMode(func(line string, fields []string, vars byline.AWKVars) (string, error) {
ns = append(ns, fields[1])
return "", nil
}).
Discard()
if err != nil {
log.Wlog.Println("read-system-nameservers:", err)
}
return ns
}