Skip to content

Commit 99f7df3

Browse files
committed
improve default_servicecidr_controller startup
The default service-cidr controller blocks the apiserver because it needs to create the default ServiceCIDR so Services can be allocated. If the apiserver is started without the default ServiceCIDR any attempt to createa new Service will fail, and this is a breaking change for users and installers that does not retry on this operation. Instead of using a channel to signal the controller is ready, just implement two loops, a first one that verifies that is ready and that polls with a shorted interval, and leave the second loop with the existing interval. Change-Id: I54303af9faeaa9c5cce2a840b6b7b0320cd2f4ad
1 parent 68e3ced commit 99f7df3

File tree

2 files changed

+23
-26
lines changed

2 files changed

+23
-26
lines changed

pkg/controlplane/controller/defaultservicecidr/default_servicecidr_controller.go

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,6 @@ func NewController(
8282
c.eventBroadcaster = broadcaster
8383
c.eventRecorder = recorder
8484

85-
c.readyCh = make(chan struct{})
86-
8785
return c
8886
}
8987

@@ -99,8 +97,6 @@ type Controller struct {
9997
serviceCIDRLister networkingv1alpha1listers.ServiceCIDRLister
10098
serviceCIDRsSynced cache.InformerSynced
10199

102-
readyCh chan struct{} // channel to block until the default ServiceCIDR exists
103-
104100
interval time.Duration
105101
}
106102

@@ -120,28 +116,40 @@ func (c *Controller) Start(stopCh <-chan struct{}) {
120116
return
121117
}
122118

123-
go wait.Until(c.sync, c.interval, stopCh)
119+
// derive a context from the stopCh so we can cancel the poll loop
120+
ctx := wait.ContextForChannel(stopCh)
121+
// wait until first successfully sync
122+
// this blocks apiserver startup so poll with a short interval
123+
err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(ctx context.Context) (bool, error) {
124+
syncErr := c.sync()
125+
return syncErr == nil, nil
126+
})
127+
if err != nil {
128+
klog.Infof("error initializing the default ServiceCIDR: %v", err)
124129

125-
select {
126-
case <-stopCh:
127-
case <-c.readyCh:
128130
}
131+
132+
// run the sync loop in the background with the defined interval
133+
go wait.Until(func() {
134+
err := c.sync()
135+
if err != nil {
136+
klog.Infof("error trying to sync the default ServiceCIDR: %v", err)
137+
}
138+
}, c.interval, stopCh)
129139
}
130140

131-
func (c *Controller) sync() {
141+
func (c *Controller) sync() error {
132142
// check if the default ServiceCIDR already exist
133143
serviceCIDR, err := c.serviceCIDRLister.Get(DefaultServiceCIDRName)
134144
// if exists
135145
if err == nil {
136-
c.setReady()
137146
c.syncStatus(serviceCIDR)
138-
return
147+
return nil
139148
}
140149

141150
// unknown error
142151
if !apierrors.IsNotFound(err) {
143-
klog.Infof("error trying to obtain the default ServiceCIDR: %v", err)
144-
return
152+
return err
145153
}
146154

147155
// default ServiceCIDR does not exist
@@ -156,21 +164,11 @@ func (c *Controller) sync() {
156164
}
157165
serviceCIDR, err = c.client.NetworkingV1alpha1().ServiceCIDRs().Create(context.Background(), serviceCIDR, metav1.CreateOptions{})
158166
if err != nil && !apierrors.IsAlreadyExists(err) {
159-
klog.Infof("error creating default ServiceCIDR: %v", err)
160167
c.eventRecorder.Eventf(serviceCIDR, v1.EventTypeWarning, "KubernetesDefaultServiceCIDRError", "The default ServiceCIDR can not be created")
161-
return
168+
return err
162169
}
163-
164-
c.setReady()
165170
c.syncStatus(serviceCIDR)
166-
}
167-
168-
func (c *Controller) setReady() {
169-
select {
170-
case <-c.readyCh:
171-
default:
172-
close(c.readyCh)
173-
}
171+
return nil
174172
}
175173

176174
func (c *Controller) syncStatus(serviceCIDR *networkingapiv1alpha1.ServiceCIDR) {

pkg/controlplane/controller/defaultservicecidr/default_servicecidr_controller_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ func newController(t *testing.T, objects []*networkingapiv1alpha1.ServiceCIDR) (
5656
eventRecorder: record.NewFakeRecorder(100),
5757
serviceCIDRLister: serviceCIDRInformer.Lister(),
5858
serviceCIDRsSynced: func() bool { return true },
59-
readyCh: make(chan struct{}),
6059
}
6160

6261
return client, c

0 commit comments

Comments
 (0)