-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The DNS subsystem should manage keeping dnsmasq in sync
On startup the DNS server will start a background subsystem that uses DBus to keep dnsmasq pointing in-addr.arpa and cluster.local at the local DNS server. If the configuration does not allow that (dnsmasq can only talk to servers on port 53, for example) then DBus will not be synced. The subsystem listens for dnsmasq restart events and applies configuration, so no on-disk configuration should be necessary. If the subsystem cannot talk to dbus the monitor routine is not configured.
- Loading branch information
1 parent
2186bc1
commit 0ee3e12
Showing
3 changed files
with
129 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package dns | ||
|
||
import ( | ||
"fmt" | ||
"sync" | ||
"time" | ||
|
||
godbus "github.com/godbus/dbus" | ||
"github.com/golang/glog" | ||
|
||
utilruntime "k8s.io/apimachinery/pkg/util/runtime" | ||
utilwait "k8s.io/apimachinery/pkg/util/wait" | ||
utildbus "k8s.io/kubernetes/pkg/util/dbus" | ||
) | ||
|
||
const ( | ||
// dnsmasqRetryInterval is the duration between attempts to register and listen to DBUS. | ||
dnsmasqRetryInterval = 2 * time.Second | ||
// dnsmasqRefreshInterval is the maximum time between refreshes of the current dnsmasq configuration. | ||
dnsmasqRefreshInterval = 30 * time.Second | ||
dbusDnsmasqPath = "/uk/org/thekelleys/dnsmasq" | ||
dbusDnsmasqInterface = "uk.org.thekelleys.dnsmasq" | ||
) | ||
|
||
type dnsmasqMonitor struct { | ||
// dnsIP is the IP address this DNS server is reachable at from dnsmasq | ||
dnsIP string | ||
// dnsDomain is the domain name for this DNS server that dnsmasq should forward to | ||
dnsDomain string | ||
// lock controls sending a dnsmasq refresh | ||
lock sync.Mutex | ||
} | ||
|
||
func (m *dnsmasqMonitor) Start() error { | ||
conn, err := utildbus.New().SystemBus() | ||
if err != nil { | ||
return fmt.Errorf("cannot connect to DBus: %v", err) | ||
} | ||
if err := conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, fmt.Sprintf("type='signal',path='%s',interface='%s'", dbusDnsmasqPath, dbusDnsmasqInterface)).Store(); err != nil { | ||
return fmt.Errorf("unable to add a match rule to the system DBus: %v", err) | ||
} | ||
// allow this to fail if dnsmasq hasn't started yet | ||
if err := m.refresh(conn); err != nil { | ||
utilruntime.HandleError(fmt.Errorf("unable to set dnsmasq on startup: %v", err)) | ||
} | ||
go m.run(conn, utilwait.NeverStop) | ||
return nil | ||
} | ||
|
||
func (m *dnsmasqMonitor) run(conn utildbus.Connection, stopCh <-chan struct{}) { | ||
ch := make(chan *godbus.Signal, 20) | ||
defer func() { | ||
utilruntime.HandleCrash() | ||
// unregister the handler | ||
conn.Signal(ch) | ||
}() | ||
conn.Signal(ch) | ||
|
||
// watch for dnsmasq restart | ||
go utilwait.Until(func() { | ||
for s := range ch { | ||
if s.Path != dbusDnsmasqPath { | ||
continue | ||
} | ||
switch s.Name { | ||
case "uk.org.thekelleys.dnsmasq.Up": | ||
glog.V(2).Infof("dnsmasq restarted, refreshing server configuration") | ||
if err := m.refresh(conn); err != nil { | ||
utilruntime.HandleError(fmt.Errorf("unable to refresh dnsmasq status on dnsmasq startup: %v", err)) | ||
} | ||
} | ||
} | ||
}, dnsmasqRetryInterval, stopCh) | ||
|
||
// no matter what, always keep trying to refresh dnsmasq | ||
go utilwait.Until(func() { | ||
if err := m.refresh(conn); err != nil { | ||
utilruntime.HandleError(fmt.Errorf("unable to periodically refresh dnsmasq status: %v", err)) | ||
} | ||
}, dnsmasqRefreshInterval, stopCh) | ||
|
||
<-stopCh | ||
} | ||
|
||
// refresh invokes dnsmasq with the requested configuration | ||
func (m *dnsmasqMonitor) refresh(conn utildbus.Connection) error { | ||
m.lock.Lock() | ||
defer m.lock.Unlock() | ||
addresses := []string{ | ||
fmt.Sprintf("/in-addr.arpa/%s", m.dnsIP), | ||
fmt.Sprintf("/%s/%s", m.dnsDomain, m.dnsIP), | ||
} | ||
glog.V(5).Infof("Instructing dnsmasq to set the following servers: %v", addresses) | ||
return conn.Object(dbusDnsmasqInterface, dbusDnsmasqPath). | ||
Call("uk.org.thekelleys.SetDomainServers", 0, addresses). | ||
Store() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters