Skip to content

Commit 21f1917

Browse files
Merge pull request #22759 from dcbw/proxy-init-node-network-ready
sdn: wait for proxy initialization before declaring node network ready
2 parents e8a2d41 + bd17f33 commit 21f1917

4 files changed

Lines changed: 130 additions & 55 deletions

File tree

pkg/cmd/openshift-sdn/cmd.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
kerrors "k8s.io/apimachinery/pkg/api/errors"
1717
"k8s.io/client-go/tools/clientcmd"
18+
"k8s.io/client-go/tools/record"
1819
kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
1920
"k8s.io/kubernetes/pkg/util/interrupt"
2021

@@ -28,19 +29,23 @@ import (
2829
"github.com/openshift/origin/pkg/version"
2930
)
3031

32+
const openshiftCNIFile string = "80-openshift-network.conf"
33+
3134
// OpenShiftSDN stores the variables needed to initialize the real networking
3235
// processess from the command line.
3336
type OpenShiftSDN struct {
3437
ConfigFilePath string
3538
KubeConfigFilePath string
3639
URLOnlyKubeConfigFilePath string
40+
cniConfFile string
3741

3842
NodeConfig *configapi.NodeConfig
3943
ProxyConfig *kubeproxyconfig.KubeProxyConfiguration
4044

41-
informers *informers
42-
OsdnNode *sdnnode.OsdnNode
43-
OsdnProxy *sdnproxy.OsdnProxy
45+
informers *informers
46+
OsdnNode *sdnnode.OsdnNode
47+
sdnRecorder record.EventRecorder
48+
OsdnProxy *sdnproxy.OsdnProxy
4449
}
4550

4651
var networkLong = `
@@ -97,6 +102,11 @@ func (sdn *OpenShiftSDN) Run(c *cobra.Command, errout io.Writer, stopCh chan str
97102
klog.Fatal(err)
98103
}
99104

105+
// Exit early if we can't create the CNI config file directory
106+
if err := os.MkdirAll(filepath.Base(sdn.cniConfFile), 0755); err != nil {
107+
klog.Fatal(err)
108+
}
109+
100110
// Set up a watch on our config file; if it changes, we should exit -
101111
// (we don't have the ability to dynamically reload config changes).
102112
if err := watchForChanges(sdn.ConfigFilePath, stopCh); err != nil {
@@ -164,6 +174,12 @@ func (sdn *OpenShiftSDN) ValidateAndParse() error {
164174
return err
165175
}
166176

177+
cniConfDir := "/etc/cni/net.d"
178+
if val, ok := sdn.NodeConfig.KubeletArguments["cni-conf-dir"]; ok && len(val) == 1 {
179+
cniConfDir = val[0]
180+
}
181+
sdn.cniConfFile = filepath.Join(cniConfDir, openshiftCNIFile)
182+
167183
return nil
168184
}
169185

@@ -200,9 +216,17 @@ func (sdn *OpenShiftSDN) Start(stopCh <-chan struct{}) error {
200216
if err != nil {
201217
return err
202218
}
203-
sdn.runProxy()
219+
proxyInitChan := make(chan bool)
220+
sdn.runProxy(proxyInitChan)
204221
sdn.informers.start(stopCh)
205222

223+
klog.V(2).Infof("openshift-sdn network plugin waiting for proxy startup to comlete")
224+
<-proxyInitChan
225+
klog.V(2).Infof("openshift-sdn network plugin registering startup")
226+
if err := sdn.writeConfigFile(); err != nil {
227+
klog.Fatal(err)
228+
}
229+
klog.V(2).Infof("openshift-sdn network plugin ready")
206230
return nil
207231
}
208232

pkg/cmd/openshift-sdn/proxy.go

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"net"
66
"net/http"
7+
"sync"
78
"time"
89

910
"k8s.io/api/core/v1"
@@ -127,8 +128,9 @@ func (sdn *OpenShiftSDN) initProxy() error {
127128
return err
128129
}
129130

130-
// runProxy starts the configured proxy process.
131-
func (sdn *OpenShiftSDN) runProxy() {
131+
// runProxy starts the configured proxy process and closes the provided channel
132+
// when the proxy has initialized
133+
func (sdn *OpenShiftSDN) runProxy(waitChan chan<- bool) {
132134
protocol := utiliptables.ProtocolIpv4
133135
bindAddr := net.ParseIP(sdn.ProxyConfig.BindAddress)
134136
if bindAddr.To4() == nil {
@@ -270,10 +272,6 @@ func (sdn *OpenShiftSDN) runProxy() {
270272
proxier = hybridProxier
271273
}
272274

273-
iptInterface.AddReloadFunc(proxier.Sync)
274-
serviceConfig.RegisterEventHandler(servicesHandler)
275-
go serviceConfig.Run(utilwait.NeverStop)
276-
277275
endpointsConfig := pconfig.NewEndpointsConfig(
278276
sdn.informers.KubeInformers.Core().V1().Endpoints(),
279277
sdn.ProxyConfig.ConfigSyncPeriod.Duration,
@@ -283,7 +281,15 @@ func (sdn *OpenShiftSDN) runProxy() {
283281
klog.Fatalf("error: node proxy plugin startup failed: %v", err)
284282
}
285283
endpointsHandler = sdn.OsdnProxy
286-
endpointsConfig.RegisterEventHandler(endpointsHandler)
284+
285+
// Wrap the proxy to know when it finally initializes
286+
waitingProxy := newWaitingProxyHandler(servicesHandler, endpointsHandler, waitChan)
287+
288+
iptInterface.AddReloadFunc(proxier.Sync)
289+
serviceConfig.RegisterEventHandler(waitingProxy)
290+
go serviceConfig.Run(utilwait.NeverStop)
291+
292+
endpointsConfig.RegisterEventHandler(waitingProxy)
287293
go endpointsConfig.Run(utilwait.NeverStop)
288294

289295
// Start up healthz server
@@ -346,3 +352,73 @@ func getNodeIP(client kv1core.CoreV1Interface, hostname string) (net.IP, error)
346352

347353
return nodeIP, nil
348354
}
355+
356+
type waitingProxyHandler struct {
357+
sync.Mutex
358+
359+
// waitChan will be closed when both services and endpoints have
360+
// been synced in the proxy
361+
waitChan chan<- bool
362+
initialized bool
363+
364+
serviceChild pconfig.ServiceHandler
365+
serviceSynced bool
366+
endpointsChild pconfig.EndpointsHandler
367+
endpointsSynced bool
368+
}
369+
370+
func newWaitingProxyHandler(serviceChild pconfig.ServiceHandler, endpointsChild pconfig.EndpointsHandler, waitChan chan<- bool) *waitingProxyHandler {
371+
return &waitingProxyHandler{
372+
serviceChild: serviceChild,
373+
endpointsChild: endpointsChild,
374+
waitChan: waitChan,
375+
}
376+
}
377+
378+
func (wph *waitingProxyHandler) checkInitialized() {
379+
if !wph.initialized && wph.serviceSynced && wph.endpointsSynced {
380+
klog.V(2).Info("openshift-sdn proxy services and endpoints initialized")
381+
wph.initialized = true
382+
close(wph.waitChan)
383+
}
384+
}
385+
386+
func (wph *waitingProxyHandler) OnServiceAdd(service *v1.Service) {
387+
wph.serviceChild.OnServiceAdd(service)
388+
}
389+
390+
func (wph *waitingProxyHandler) OnServiceUpdate(oldService, service *v1.Service) {
391+
wph.serviceChild.OnServiceUpdate(oldService, service)
392+
}
393+
394+
func (wph *waitingProxyHandler) OnServiceDelete(service *v1.Service) {
395+
wph.serviceChild.OnServiceDelete(service)
396+
}
397+
398+
func (wph *waitingProxyHandler) OnServiceSynced() {
399+
wph.serviceChild.OnServiceSynced()
400+
wph.Lock()
401+
defer wph.Unlock()
402+
wph.serviceSynced = true
403+
wph.checkInitialized()
404+
}
405+
406+
func (wph *waitingProxyHandler) OnEndpointsAdd(endpoints *v1.Endpoints) {
407+
wph.endpointsChild.OnEndpointsAdd(endpoints)
408+
}
409+
410+
func (wph *waitingProxyHandler) OnEndpointsUpdate(oldEndpoints, endpoints *v1.Endpoints) {
411+
wph.endpointsChild.OnEndpointsUpdate(oldEndpoints, endpoints)
412+
}
413+
414+
func (wph *waitingProxyHandler) OnEndpointsDelete(endpoints *v1.Endpoints) {
415+
wph.endpointsChild.OnEndpointsDelete(endpoints)
416+
}
417+
418+
func (wph *waitingProxyHandler) OnEndpointsSynced() {
419+
wph.endpointsChild.OnEndpointsSynced()
420+
wph.Lock()
421+
defer wph.Unlock()
422+
wph.endpointsSynced = true
423+
wph.checkInitialized()
424+
}

pkg/cmd/openshift-sdn/sdn.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package openshift_sdn
22

33
import (
4+
"io/ioutil"
45
"strings"
56

67
kclientv1 "k8s.io/api/core/v1"
@@ -26,10 +27,6 @@ func (sdn *OpenShiftSDN) initSDN() error {
2627
if val, ok := sdn.NodeConfig.KubeletArguments["cni-bin-dir"]; ok && len(val) == 1 {
2728
cniBinDir = val[0]
2829
}
29-
cniConfDir := "/etc/cni/net.d"
30-
if val, ok := sdn.NodeConfig.KubeletArguments["cni-conf-dir"]; ok && len(val) == 1 {
31-
cniConfDir = val[0]
32-
}
3330

3431
// dockershim + kube CNI driver delegates hostport handling to plugins,
3532
// while CRI-O handles hostports itself. Thus we need to disable the
@@ -38,7 +35,7 @@ func (sdn *OpenShiftSDN) initSDN() error {
3835

3936
eventBroadcaster := record.NewBroadcaster()
4037
eventBroadcaster.StartRecordingToSink(&kv1core.EventSinkImpl{Interface: sdn.informers.KubeClient.CoreV1().Events("")})
41-
eventRecorder := eventBroadcaster.NewRecorder(scheme.Scheme, kclientv1.EventSource{Component: "openshift-sdn", Host: sdn.NodeConfig.NodeName})
38+
sdn.sdnRecorder = eventBroadcaster.NewRecorder(scheme.Scheme, kclientv1.EventSource{Component: "openshift-sdn", Host: sdn.NodeConfig.NodeName})
4239

4340
var err error
4441
sdn.OsdnNode, err = sdnnode.New(&sdnnode.OsdnNodeConfig{
@@ -47,7 +44,6 @@ func (sdn *OpenShiftSDN) initSDN() error {
4744
SelfIP: sdn.NodeConfig.NodeIP,
4845
RuntimeEndpoint: runtimeEndpoint,
4946
CNIBinDir: cniBinDir,
50-
CNIConfDir: cniConfDir,
5147
MTU: sdn.NodeConfig.NetworkConfig.MTU,
5248
NetworkClient: sdn.informers.NetworkClient,
5349
KClient: sdn.informers.KubeClient,
@@ -57,7 +53,7 @@ func (sdn *OpenShiftSDN) initSDN() error {
5753
MasqueradeBit: sdn.ProxyConfig.IPTables.MasqueradeBit,
5854
ProxyMode: sdn.ProxyConfig.Mode,
5955
EnableHostports: enableHostports,
60-
Recorder: eventRecorder,
56+
Recorder: sdn.sdnRecorder,
6157
})
6258
return err
6359
}
@@ -66,3 +62,18 @@ func (sdn *OpenShiftSDN) initSDN() error {
6662
func (sdn *OpenShiftSDN) runSDN() error {
6763
return sdn.OsdnNode.Start()
6864
}
65+
66+
func (sdn *OpenShiftSDN) writeConfigFile() error {
67+
// Make an event that openshift-sdn started
68+
sdn.sdnRecorder.Eventf(&kclientv1.ObjectReference{Kind: "Node", Name: sdn.NodeConfig.NodeName}, kclientv1.EventTypeNormal, "Starting", "openshift-sdn done initializing node networking.")
69+
70+
// Write our CNI config file out to disk to signal to kubelet that
71+
// our network plugin is ready
72+
return ioutil.WriteFile(sdn.cniConfFile, []byte(`
73+
{
74+
"cniVersion": "0.3.1",
75+
"name": "openshift-sdn",
76+
"type": "openshift-sdn"
77+
}
78+
`), 0644)
79+
}

pkg/network/node/node.go

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ package node
44

55
import (
66
"fmt"
7-
"io/ioutil"
87
"net"
9-
"os"
10-
"path/filepath"
118
"strings"
129
"sync"
1310
"time"
@@ -47,10 +44,7 @@ import (
4744
"github.com/openshift/origin/pkg/util/ovs"
4845
)
4946

50-
const (
51-
openshiftCNIFile = "80-openshift-network.conf"
52-
hostLocalDataDir = "/var/lib/cni/networks"
53-
)
47+
const hostLocalDataDir = "/var/lib/cni/networks"
5448

5549
type osdnPolicy interface {
5650
Name() string
@@ -77,7 +71,6 @@ type OsdnNodeConfig struct {
7771
MTU uint32
7872
EnableHostports bool
7973
CNIBinDir string
80-
CNIConfDir string
8174

8275
NetworkClient networkclient.Interface
8376
KClient kubernetes.Interface
@@ -105,7 +98,6 @@ type OsdnNode struct {
10598
useConnTrack bool
10699
iptablesSyncPeriod time.Duration
107100
mtu uint32
108-
cniDirPath string
109101

110102
// Synchronizes operations on egressPolicies
111103
egressPoliciesLock sync.Mutex
@@ -151,10 +143,6 @@ func New(c *OsdnNodeConfig) (*OsdnNode, error) {
151143
return nil, fmt.Errorf("%q plugin is not compatible with proxy-mode %q", c.PluginName, c.ProxyMode)
152144
}
153145

154-
// If our CNI config file exists, remove it so that kubelet doesn't think
155-
// we're ready yet
156-
os.Remove(filepath.Join(c.CNIConfDir, openshiftCNIFile))
157-
158146
if err := c.setNodeIP(); err != nil {
159147
return nil, err
160148
}
@@ -182,7 +170,6 @@ func New(c *OsdnNodeConfig) (*OsdnNode, error) {
182170
kubeInformers: c.KubeInformers,
183171
networkInformers: c.NetworkInformers,
184172
egressIP: newEgressIPWatcher(oc, c.SelfIP, c.MasqueradeBit),
185-
cniDirPath: c.CNIConfDir,
186173

187174
runtimeEndpoint: c.RuntimeEndpoint,
188175
// 2 minutes is the current default value used in kubelet
@@ -337,34 +324,11 @@ func (node *OsdnNode) Start() error {
337324
}
338325
}
339326

340-
if err := os.MkdirAll(node.cniDirPath, 0755); err != nil {
341-
return err
342-
}
343-
344327
go kwait.Forever(node.policy.SyncVNIDRules, time.Hour)
345328
go kwait.Forever(func() {
346329
gatherPeriodicMetrics(node.oc.ovs)
347330
}, time.Minute*2)
348331

349-
klog.V(2).Infof("openshift-sdn network plugin registering startup")
350-
351-
// Make an event that openshift-sdn started
352-
node.recorder.Eventf(&corev1.ObjectReference{Kind: "Node", Name: node.hostName}, corev1.EventTypeNormal, "Starting", "Starting openshift-sdn.")
353-
354-
// Write our CNI config file out to disk to signal to kubelet that
355-
// our network plugin is ready
356-
err = ioutil.WriteFile(filepath.Join(node.cniDirPath, openshiftCNIFile), []byte(`
357-
{
358-
"cniVersion": "0.3.1",
359-
"name": "openshift-sdn",
360-
"type": "openshift-sdn"
361-
}
362-
`), 0644)
363-
if err != nil {
364-
return err
365-
}
366-
367-
klog.V(2).Infof("openshift-sdn network plugin ready")
368332
return nil
369333
}
370334

0 commit comments

Comments
 (0)