Skip to content

Commit 42a5965

Browse files
Merge pull request #19987 from smarterclayton/dns
Remove the node from dnsmasq config when shutting down
2 parents 9d969d1 + f8d0494 commit 42a5965

File tree

10 files changed

+111
-45
lines changed

10 files changed

+111
-45
lines changed

pkg/cmd/server/kubernetes/network/network.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ func (c *NetworkConfig) RunSDN() {
4848
}
4949

5050
// RunDNS starts the DNS server as soon as services are loaded.
51-
func (c *NetworkConfig) RunDNS() {
51+
func (c *NetworkConfig) RunDNS(stopCh <-chan struct{}) {
5252
go func() {
5353
glog.Infof("Starting DNS on %s", c.DNSServer.Config.DnsAddr)
54-
err := c.DNSServer.ListenAndServe()
54+
err := c.DNSServer.ListenAndServe(stopCh)
5555
glog.Fatalf("DNS server failed to start: %v", err)
5656
}()
5757
}

pkg/cmd/server/kubernetes/network/options/options.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ func Build(options configapi.NodeConfig) (*kubeproxyconfig.KubeProxyConfiguratio
3939
return nil, fmt.Errorf("The provided value to bind to must be an ip:port: %q", addr)
4040
}
4141
proxyconfig.BindAddress = ip.String()
42-
// MetricsBindAddress - disable by default but allow enablement until we switch to
43-
// reading proxy config directly
44-
proxyconfig.MetricsBindAddress = ""
42+
// MetricsBindAddress - enable as a separate port in the 11xxx range for now, but only
43+
// on localhost. Metrics contains no tenant information.
44+
// TODO: move this to a secured port that we can query from prometheus.
45+
proxyconfig.MetricsBindAddress = "localhost:11256"
4546
if arg := options.ProxyArguments["metrics-bind-address"]; len(arg) > 0 {
4647
proxyconfig.MetricsBindAddress = arg[0]
4748
}

pkg/cmd/server/origin/dns_server.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66

77
"github.com/golang/glog"
88

9+
"k8s.io/apimachinery/pkg/util/wait"
10+
911
cmdutil "github.com/openshift/origin/pkg/cmd/util"
1012
"github.com/openshift/origin/pkg/dns"
1113
)
@@ -52,7 +54,7 @@ func (c *MasterConfig) RunDNSServer() {
5254

5355
go func() {
5456
s := dns.NewServer(config, services, endpoints, "apiserver")
55-
err := s.ListenAndServe()
57+
err := s.ListenAndServe(wait.NeverStop)
5658
glog.Fatalf("Could not start DNS: %v", err)
5759
}()
5860

pkg/cmd/server/start/start_allinone.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/spf13/cobra"
1717

1818
kerrors "k8s.io/apimachinery/pkg/api/errors"
19+
"k8s.io/apimachinery/pkg/util/wait"
1920
"k8s.io/apiserver/pkg/util/flag"
2021
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
2122
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@@ -26,7 +27,6 @@ import (
2627
configapi "github.com/openshift/origin/pkg/cmd/server/apis/config"
2728
"github.com/openshift/origin/pkg/cmd/server/origin"
2829
tsbcmd "github.com/openshift/origin/pkg/templateservicebroker/cmd/server"
29-
"k8s.io/apimachinery/pkg/util/wait"
3030
)
3131

3232
type AllInOneOptions struct {
@@ -310,7 +310,7 @@ func (o AllInOneOptions) StartAllInOne() error {
310310
ConfigFile: o.NodeConfigFile,
311311
Output: o.MasterOptions.Output,
312312
}
313-
if err := nodeOptions.RunNode(); err != nil {
313+
if err := nodeOptions.RunNode(wait.NeverStop); err != nil {
314314
return err
315315
}
316316

pkg/cmd/server/start/start_node.go

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"path/filepath"
1010
"strings"
1111
"syscall"
12+
"time"
1213

1314
"github.com/coreos/go-systemd/daemon"
1415
"github.com/golang/glog"
@@ -18,11 +19,11 @@ import (
1819
kerrors "k8s.io/apimachinery/pkg/api/errors"
1920
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2021
"k8s.io/apimachinery/pkg/util/sets"
21-
"k8s.io/apimachinery/pkg/util/wait"
2222
kubeletapp "k8s.io/kubernetes/cmd/kubelet/app"
2323
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
2424
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
2525
"k8s.io/kubernetes/pkg/master/ports"
26+
"k8s.io/kubernetes/pkg/util/interrupt"
2627

2728
"github.com/openshift/library-go/pkg/crypto"
2829
"github.com/openshift/origin/pkg/cmd/server/admin"
@@ -115,14 +116,26 @@ var networkLong = templates.LongDesc(`
115116

116117
// NewCommandStartNetwork provides a CLI handler for 'start network' command
117118
func NewCommandStartNetwork(basename string, out, errout io.Writer) (*cobra.Command, *NodeOptions) {
118-
options := &NodeOptions{Output: out}
119+
options := &NodeOptions{
120+
ExpireDays: crypto.DefaultCertificateLifetimeInDays,
121+
Output: out,
122+
}
119123

120124
cmd := &cobra.Command{
121125
Use: "network",
122126
Short: "Launch node network",
123127
Long: fmt.Sprintf(networkLong, basename),
124128
Run: func(c *cobra.Command, args []string) {
125-
options.Run(c, errout, args, wait.NeverStop)
129+
ch := make(chan struct{})
130+
interrupt.New(func(s os.Signal) {
131+
close(ch)
132+
fmt.Fprintf(errout, "interrupt: Gracefully shutting down ...\n")
133+
time.Sleep(200 * time.Millisecond)
134+
os.Exit(1)
135+
}).Run(func() error {
136+
options.Run(c, errout, args, ch)
137+
return nil
138+
})
126139
},
127140
}
128141

@@ -209,7 +222,7 @@ func (o NodeOptions) Complete(cmd *cobra.Command) error {
209222

210223
// StartNode calls RunNode and then waits forever
211224
func (o NodeOptions) StartNode(stopCh <-chan struct{}) error {
212-
if err := o.RunNode(); err != nil {
225+
if err := o.RunNode(stopCh); err != nil {
213226
return err
214227
}
215228

@@ -227,7 +240,7 @@ func (o NodeOptions) StartNode(stopCh <-chan struct{}) error {
227240
// 2. Reads fully specified node config OR builds a fully specified node config from the args
228241
// 3. Writes the fully specified node config and exits if needed
229242
// 4. Starts the node based on the fully specified config
230-
func (o NodeOptions) RunNode() error {
243+
func (o NodeOptions) RunNode(stopCh <-chan struct{}) error {
231244
nodeConfig, configFile, err := o.resolveNodeConfig()
232245
if err != nil {
233246
return err
@@ -277,7 +290,7 @@ func (o NodeOptions) RunNode() error {
277290
return originnode.WriteKubeletFlags(*nodeConfig)
278291
}
279292

280-
return StartNode(*nodeConfig, o.NodeArgs.Components)
293+
return StartNode(*nodeConfig, o.NodeArgs.Components, stopCh)
281294
}
282295

283296
// resolveNodeConfig creates a new configuration on disk by reading from the master, reads
@@ -421,7 +434,7 @@ func execKubelet(kubeletArgs []string) error {
421434
}
422435

423436
// StartNode launches the node processes.
424-
func StartNode(nodeConfig configapi.NodeConfig, components *utilflags.ComponentFlag) error {
437+
func StartNode(nodeConfig configapi.NodeConfig, components *utilflags.ComponentFlag, stopCh <-chan struct{}) error {
425438
kubeletArgs, err := nodeoptions.ComputeKubeletFlags(nodeConfig.KubeletArguments, nodeConfig)
426439
if err != nil {
427440
return fmt.Errorf("cannot create kubelet args: %v", err)
@@ -476,12 +489,12 @@ func StartNode(nodeConfig configapi.NodeConfig, components *utilflags.ComponentF
476489
networkConfig.RunProxy()
477490
}
478491
if components.Enabled(ComponentDNS) && networkConfig.DNSServer != nil {
479-
networkConfig.RunDNS()
492+
networkConfig.RunDNS(stopCh)
480493
}
481494

482-
networkConfig.InternalKubeInformers.Start(wait.NeverStop)
495+
networkConfig.InternalKubeInformers.Start(stopCh)
483496
if networkConfig.InternalNetworkInformers != nil {
484-
networkConfig.InternalNetworkInformers.Start(wait.NeverStop)
497+
networkConfig.InternalNetworkInformers.Start(stopCh)
485498
}
486499

487500
return nil

pkg/dns/dnsmasq.go

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ type dnsmasqMonitor struct {
3030
metricError *prometheus.CounterVec
3131
metricRestart prometheus.Counter
3232

33+
ready func() bool
34+
3335
// dnsIP is the IP address this DNS server is reachable at from dnsmasq
3436
dnsIP string
3537
// dnsDomain is the domain name for this DNS server that dnsmasq should forward to
@@ -57,7 +59,10 @@ func (m *dnsmasqMonitor) initMetrics() {
5759
}
5860
}
5961

60-
func (m *dnsmasqMonitor) Start() error {
62+
func (m *dnsmasqMonitor) Start(stopCh <-chan struct{}) error {
63+
if m.ready == nil {
64+
m.ready = func() bool { return true }
65+
}
6166
m.initMetrics()
6267
conn, err := utildbus.New().SystemBus()
6368
if err != nil {
@@ -66,14 +71,17 @@ func (m *dnsmasqMonitor) Start() error {
6671
if err := conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, fmt.Sprintf("type='signal',path='%s',interface='%s'", dbusDnsmasqPath, dbusDnsmasqInterface)).Store(); err != nil {
6772
return fmt.Errorf("unable to add a match rule to the system DBus: %v", err)
6873
}
69-
go m.run(conn, utilwait.NeverStop)
74+
go m.run(conn, stopCh)
7075
return nil
7176
}
7277

7378
func (m *dnsmasqMonitor) run(conn utildbus.Connection, stopCh <-chan struct{}) {
7479
ch := make(chan *godbus.Signal, 20)
7580
defer func() {
7681
utilruntime.HandleCrash()
82+
glog.V(2).Infof("dnsmasq monitor shutting down")
83+
// clear our configuration on shutdown
84+
m.refresh(conn, false)
7785
// unregister the handler
7886
conn.Signal(ch)
7987
}()
@@ -89,7 +97,7 @@ func (m *dnsmasqMonitor) run(conn utildbus.Connection, stopCh <-chan struct{}) {
8997
case "uk.org.thekelleys.dnsmasq.Up":
9098
m.metricRestart.Inc()
9199
glog.V(2).Infof("dnsmasq restarted, refreshing server configuration")
92-
if err := m.refresh(conn); err != nil {
100+
if err := m.refresh(conn, m.ready()); err != nil {
93101
utilruntime.HandleError(fmt.Errorf("unable to refresh dnsmasq status on dnsmasq startup: %v", err))
94102
m.metricError.WithLabelValues("restart").Inc()
95103
} else {
@@ -101,7 +109,11 @@ func (m *dnsmasqMonitor) run(conn utildbus.Connection, stopCh <-chan struct{}) {
101109

102110
// no matter what, always keep trying to refresh dnsmasq
103111
go utilwait.Until(func() {
104-
if err := m.refresh(conn); err != nil {
112+
for !m.ready() {
113+
glog.V(4).Infof("Waiting for DNS data to be available to update dnsmasq")
114+
time.Sleep(time.Second)
115+
}
116+
if err := m.refresh(conn, true); err != nil {
105117
utilruntime.HandleError(fmt.Errorf("unable to periodically refresh dnsmasq status: %v", err))
106118
m.metricError.WithLabelValues("periodic").Inc()
107119
} else {
@@ -113,14 +125,19 @@ func (m *dnsmasqMonitor) run(conn utildbus.Connection, stopCh <-chan struct{}) {
113125
}
114126

115127
// refresh invokes dnsmasq with the requested configuration
116-
func (m *dnsmasqMonitor) refresh(conn utildbus.Connection) error {
128+
func (m *dnsmasqMonitor) refresh(conn utildbus.Connection, ready bool) error {
117129
m.lock.Lock()
118130
defer m.lock.Unlock()
119-
addresses := []string{
120-
fmt.Sprintf("/in-addr.arpa/%s", m.dnsIP),
121-
fmt.Sprintf("/%s/%s", m.dnsDomain, m.dnsIP),
131+
var addresses []string
132+
if ready {
133+
addresses = []string{
134+
fmt.Sprintf("/in-addr.arpa/%s", m.dnsIP),
135+
fmt.Sprintf("/%s/%s", m.dnsDomain, m.dnsIP),
136+
}
137+
glog.V(4).Infof("Instructing dnsmasq to set the following servers: %v", addresses)
138+
} else {
139+
glog.V(2).Infof("DNS data is not ready, removing configuration from dnsmasq")
122140
}
123-
glog.V(5).Infof("Instructing dnsmasq to set the following servers: %v", addresses)
124141
return conn.Object(dbusDnsmasqInterface, dbusDnsmasqPath).
125142
Call("uk.org.thekelleys.SetDomainServers", 0, addresses).
126143
Store()

pkg/dns/dnsmasq_test.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ func Test_dnsmasqMonitor_run(t *testing.T) {
1818
m := &dnsmasqMonitor{
1919
dnsIP: "127.0.0.1",
2020
dnsDomain: "test.domain",
21+
ready: func() bool { return true },
2122
}
2223
m.initMetrics()
2324
conn := utildbus.NewFakeConnection()
24-
//fake := utildbus.NewFake(conn, nil)
25+
stopCh := make(chan struct{})
2526

2627
callCh := make(chan string, 1)
2728
conn.AddObject(dbusDnsmasqInterface, dbusDnsmasqPath, func(method string, args ...interface{}) ([]interface{}, error) {
@@ -32,18 +33,36 @@ func Test_dnsmasqMonitor_run(t *testing.T) {
3233
t.Errorf("unexpected args: %v", args)
3334
return nil, fmt.Errorf("unexpected args")
3435
}
35-
if arr, ok := args[0].([]string); !ok || !reflect.DeepEqual([]string{"/in-addr.arpa/127.0.0.1", "/test.domain/127.0.0.1"}, arr) {
36+
37+
// we send empty after shutdown
38+
completed := false
39+
select {
40+
case <-stopCh:
41+
completed = true
42+
default:
43+
}
44+
45+
arr, ok := args[0].([]string)
46+
if !ok {
47+
t.Errorf("unexpected args: %v", args)
48+
return nil, fmt.Errorf("unexpected args")
49+
}
50+
expected := []string{"/in-addr.arpa/127.0.0.1", "/test.domain/127.0.0.1"}
51+
if completed {
52+
expected = nil
53+
}
54+
if !reflect.DeepEqual(expected, arr) {
3655
t.Errorf("unexpected args: %v", args)
3756
return nil, fmt.Errorf("unexpected args")
3857
}
58+
3959
return nil, nil
4060
default:
4161
t.Errorf("unexpected method: %v", method)
4262
return nil, fmt.Errorf("unexpected method")
4363
}
4464
})
4565

46-
stopCh := make(chan struct{})
4766
go m.run(conn, stopCh)
4867

4968
// should always set on startup
@@ -110,7 +129,7 @@ func (c *threadsafeDBusConn) EmitSignal(name, path, iface, signal string, args .
110129
}
111130

112131
func Test_dnsmasqMonitor_run_metrics(t *testing.T) {
113-
m := &dnsmasqMonitor{dnsIP: "127.0.0.1", dnsDomain: "test.domain"}
132+
m := &dnsmasqMonitor{dnsIP: "127.0.0.1", dnsDomain: "test.domain", ready: func() bool { return true }}
114133
m.initMetrics()
115134
fakeConn := utildbus.NewFakeConnection()
116135
conn := &threadsafeDBusConn{conn: fakeConn}

pkg/dns/server.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,44 +25,37 @@ type Server struct {
2525
Services ServiceAccessor
2626
Endpoints EndpointsAccessor
2727
MetricsName string
28-
29-
Stop chan struct{}
3028
}
3129

3230
// NewServer creates a server.
3331
func NewServer(config *server.Config, services ServiceAccessor, endpoints EndpointsAccessor, metricsName string) *Server {
34-
stop := make(chan struct{})
3532
return &Server{
3633
Config: config,
3734
Services: services,
3835
Endpoints: endpoints,
3936
MetricsName: metricsName,
40-
Stop: stop,
4137
}
4238
}
4339

4440
// ListenAndServe starts a DNS server that exposes services and values stored in etcd (if etcdclient
4541
// is not nil). It will block until the server exits.
46-
func (s *Server) ListenAndServe() error {
47-
monitorDnsmasq(s.Config, s.MetricsName)
42+
func (s *Server) ListenAndServe(stopCh <-chan struct{}) error {
43+
monitorDnsmasq(s.Config, s.MetricsName, stopCh, func() bool { return s.Services.HasSynced() && s.Endpoints.HasSynced() })
4844

4945
resolver := NewServiceResolver(s.Config, s.Services, s.Endpoints, openshiftFallback)
5046
resolvers := server.FirstBackend{resolver}
5147
if len(s.MetricsName) > 0 {
5248
metrics.RegisterPrometheusMetrics(s.MetricsName, "")
5349
}
5450
dns := server.New(resolvers, s.Config)
55-
if s.Stop != nil {
56-
defer close(s.Stop)
57-
}
5851
return dns.Run()
5952
}
6053

6154
// monitorDnsmasq attempts to start the dnsmasq monitoring goroutines to keep dnsmasq
6255
// in sync with this server. It will take no action if the current config DnsAddr does
6356
// not point to port 53 (dnsmasq does not support alternate upstream ports). It will
6457
// convert the bind address from 0.0.0.0 to the BindNetwork appropriate listen address.
65-
func monitorDnsmasq(config *server.Config, metricsName string) {
58+
func monitorDnsmasq(config *server.Config, metricsName string, stopCh <-chan struct{}, readyFn func() bool) {
6659
if host, port, err := net.SplitHostPort(config.DnsAddr); err == nil && port == "53" {
6760
if ip := net.ParseIP(host); ip != nil && ip.IsUnspecified() {
6861
if config.BindNetwork == "ipv6" {
@@ -73,10 +66,11 @@ func monitorDnsmasq(config *server.Config, metricsName string) {
7366
}
7467
monitor := &dnsmasqMonitor{
7568
metricsName: metricsName,
69+
ready: readyFn,
7670
dnsIP: host,
7771
dnsDomain: strings.TrimSuffix(config.Domain, "."),
7872
}
79-
if err := monitor.Start(); err != nil {
73+
if err := monitor.Start(stopCh); err != nil {
8074
glog.Warningf("Unable to start dnsmasq monitor: %v", err)
8175
} else {
8276
glog.V(2).Infof("Monitoring dnsmasq to point cluster queries to %s", host)

0 commit comments

Comments
 (0)