Skip to content

Commit 6622e57

Browse files
authored
add feature flag enable-multi-subnet-cluster for GKE Multi-Subnet Cluster feature (#848)
* add feature flag * minor fix * fix test * tidy nil check * dedup queue item for update with same label, fix typo * Revert "dedup queue item for update with same label, fix typo" This reverts commit ebadd53. * minor fix typo * fix typo * fix comment
1 parent 31010ab commit 6622e57

File tree

8 files changed

+74
-55
lines changed

8 files changed

+74
-55
lines changed

cmd/cloud-controller-manager/nodeipamcontroller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ func startNodeIpamController(ccmConfig *cloudcontrollerconfig.CompletedConfig, n
149149
nwInformer,
150150
gnpInformer,
151151
nodeTopologyClient,
152+
nodeIPAMConfig.EnableMultiSubnetCluster,
152153
clusterCIDRs,
153154
serviceCIDR,
154155
secondaryServiceCIDR,

cmd/cloud-controller-manager/options/nodeipamcontroller.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func (o *NodeIPAMControllerOptions) AddFlags(fs *pflag.FlagSet) {
3939
fs.Int32Var(&o.NodeCIDRMaskSize, "node-cidr-mask-size", o.NodeCIDRMaskSize, "Mask size for node cidr in cluster. Default is 24 for IPv4 and 64 for IPv6.")
4040
fs.Int32Var(&o.NodeCIDRMaskSizeIPv4, "node-cidr-mask-size-ipv4", o.NodeCIDRMaskSizeIPv4, "Mask size for IPv4 node cidr in dual-stack cluster. Default is 24.")
4141
fs.Int32Var(&o.NodeCIDRMaskSizeIPv6, "node-cidr-mask-size-ipv6", o.NodeCIDRMaskSizeIPv6, "Mask size for IPv6 node cidr in dual-stack cluster. Default is 64.")
42+
fs.BoolVar(&o.EnableMultiSubnetCluster, "enable-multi-subnet-cluster", o.EnableMultiSubnetCluster, "Enabled multi-subnet cluster feature. This enables generating updated nodeTopology custom resource. ")
4243
}
4344

4445
// ApplyTo fills up NodeIpamController config with options.
@@ -59,6 +60,7 @@ func (o *NodeIPAMControllerOptions) ApplyTo(cfg *nodeipamconfig.NodeIPAMControll
5960
cfg.NodeCIDRMaskSize = o.NodeCIDRMaskSize
6061
cfg.NodeCIDRMaskSizeIPv4 = o.NodeCIDRMaskSizeIPv4
6162
cfg.NodeCIDRMaskSizeIPv6 = o.NodeCIDRMaskSizeIPv6
63+
cfg.EnableMultiSubnetCluster = o.EnableMultiSubnetCluster
6264

6365
return nil
6466
}

pkg/controller/nodeipam/config/types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,9 @@ type NodeIPAMControllerConfiguration struct {
3131
// NodeCIDRMaskSizeIPv6 is the mask size for IPv6 node cidr in dual-stack cluster.
3232
// This can be used only with dual stack clusters and is incompatible with single stack clusters.
3333
NodeCIDRMaskSizeIPv6 int32
34+
// EnableMultiSubnetCluster is bound to a command-line flag. When true, it enables
35+
// generating nodeTopology custom resource based on node's subnetwork configuration,
36+
// which is represented by a node label. Enabling this feature also assumes that a
37+
// nodeTopology CR named 'default' is already installed.
38+
EnableMultiSubnetCluster bool
3439
}

pkg/controller/nodeipam/ipam/cidr_allocator.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ type CIDRAllocatorParams struct {
115115
}
116116

117117
// New creates a new CIDR range allocator.
118-
func New(kubeClient clientset.Interface, cloud cloudprovider.Interface, nodeInformer informers.NodeInformer, nwInformer networkinformer.NetworkInformer, gnpInformer networkinformer.GKENetworkParamSetInformer, nodeTopologyClient nodetopologyclientset.Interface, allocatorType CIDRAllocatorType, allocatorParams CIDRAllocatorParams) (CIDRAllocator, error) {
118+
func New(kubeClient clientset.Interface, cloud cloudprovider.Interface, nodeInformer informers.NodeInformer, nwInformer networkinformer.NetworkInformer, gnpInformer networkinformer.GKENetworkParamSetInformer, nodeTopologyClient nodetopologyclientset.Interface, enableMultiSubnetCluster bool, allocatorType CIDRAllocatorType, allocatorParams CIDRAllocatorParams) (CIDRAllocator, error) {
119119
nodeList, err := listNodes(kubeClient)
120120
if err != nil {
121121
return nil, err
@@ -125,7 +125,7 @@ func New(kubeClient clientset.Interface, cloud cloudprovider.Interface, nodeInfo
125125
case RangeAllocatorType:
126126
return NewCIDRRangeAllocator(kubeClient, nodeInformer, allocatorParams, nodeList)
127127
case CloudAllocatorType:
128-
return NewCloudCIDRAllocator(kubeClient, cloud, nwInformer, gnpInformer, nodeTopologyClient, nodeInformer, allocatorParams)
128+
return NewCloudCIDRAllocator(kubeClient, cloud, nwInformer, gnpInformer, nodeTopologyClient, enableMultiSubnetCluster, nodeInformer, allocatorParams)
129129
default:
130130
return nil, fmt.Errorf("invalid CIDR allocator type: %v", allocatorType)
131131
}

pkg/controller/nodeipam/ipam/cloud_cidr_allocator.go

Lines changed: 58 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ const (
7171
stackIPv6 clusterStackType = "IPv6"
7272
)
7373

74+
// enableNodeTopology is bound to a command-line flag. When true, it enables
75+
// generating nodeTopology custom resource based on node's subnetwork configuration,
76+
// which is represented by a node label. Enabling this feature also assumes that a
77+
// nodeTopology CR named 'default' is already installed.
78+
var enableNodeTopology bool
79+
7480
// cloudCIDRAllocator allocates node CIDRs according to IP address aliases
7581
// assigned by the cloud provider. In this case, the allocation and
7682
// deallocation is delegated to the external provider, and the controller
@@ -100,7 +106,7 @@ type cloudCIDRAllocator struct {
100106
var _ CIDRAllocator = (*cloudCIDRAllocator)(nil)
101107

102108
// NewCloudCIDRAllocator creates a new cloud CIDR allocator.
103-
func NewCloudCIDRAllocator(client clientset.Interface, cloud cloudprovider.Interface, nwInformer networkinformer.NetworkInformer, gnpInformer networkinformer.GKENetworkParamSetInformer, nodeTopologyClient nodetopologyclientset.Interface, nodeInformer informers.NodeInformer, allocatorParams CIDRAllocatorParams) (CIDRAllocator, error) {
109+
func NewCloudCIDRAllocator(client clientset.Interface, cloud cloudprovider.Interface, nwInformer networkinformer.NetworkInformer, gnpInformer networkinformer.GKENetworkParamSetInformer, nodeTopologyClient nodetopologyclientset.Interface, enableMultiSubnetCluster bool, nodeInformer informers.NodeInformer, allocatorParams CIDRAllocatorParams) (CIDRAllocator, error) {
104110
if client == nil {
105111
klog.Fatalf("kubeClient is nil when starting NodeController")
106112
}
@@ -131,24 +137,16 @@ func NewCloudCIDRAllocator(client clientset.Interface, cloud cloudprovider.Inter
131137
stackType = stackIPv6
132138
}
133139

134-
nodeTopologySyncer := &NodeTopologySyncer{
135-
nodeTopologyClient: nodeTopologyClient,
136-
cloud: gceCloud,
137-
nodeLister: nodeInformer.Lister(),
138-
}
139-
nodetopologyQueue := NewTaskQueue("nodetopologgTaskQueue", "nodetopologyCRD", nodeTopologyWorkers, nodeTopologyKeyFun, nodeTopologySyncer.sync)
140-
141140
ca := &cloudCIDRAllocator{
142-
client: client,
143-
cloud: gceCloud,
144-
networksLister: nwInformer.Lister(),
145-
gnpLister: gnpInformer.Lister(),
146-
nodeLister: nodeInformer.Lister(),
147-
nodesSynced: nodeInformer.Informer().HasSynced,
148-
recorder: recorder,
149-
queue: workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{Name: workqueueName}),
150-
nodeTopologyQueue: nodetopologyQueue,
151-
stackType: stackType,
141+
client: client,
142+
cloud: gceCloud,
143+
networksLister: nwInformer.Lister(),
144+
gnpLister: gnpInformer.Lister(),
145+
nodeLister: nodeInformer.Lister(),
146+
nodesSynced: nodeInformer.Informer().HasSynced,
147+
recorder: recorder,
148+
queue: workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{Name: workqueueName}),
149+
stackType: stackType,
152150
}
153151

154152
nodeInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
@@ -174,26 +172,32 @@ func NewCloudCIDRAllocator(client clientset.Interface, cloud cloudprovider.Inter
174172
}),
175173
DeleteFunc: nodeutil.CreateDeleteNodeHandler(ca.ReleaseCIDR),
176174
})
177-
nodeInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
178-
AddFunc: nodeutil.CreateAddNodeHandler(func(node *v1.Node) error {
179-
if ca.nodeTopologyQueue != nil {
175+
176+
enableNodeTopology = enableMultiSubnetCluster
177+
if enableNodeTopology {
178+
nodeTopologySyncer := &NodeTopologySyncer{
179+
nodeTopologyClient: nodeTopologyClient,
180+
cloud: gceCloud,
181+
nodeLister: nodeInformer.Lister(),
182+
}
183+
nodetopologyQueue := NewTaskQueue("nodetopologyTaskQueue", "nodetopologyCRD", nodeTopologyWorkers, nodeTopologyKeyFun, nodeTopologySyncer.sync)
184+
ca.nodeTopologyQueue = nodetopologyQueue
185+
186+
nodeInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
187+
AddFunc: nodeutil.CreateAddNodeHandler(func(node *v1.Node) error {
180188
ca.nodeTopologyQueue.Enqueue(node)
181-
}
182-
return nil
183-
}),
184-
UpdateFunc: nodeutil.CreateUpdateNodeHandler(func(oldNode, newNode *v1.Node) error {
185-
if ca.nodeTopologyQueue != nil {
189+
return nil
190+
}),
191+
UpdateFunc: nodeutil.CreateUpdateNodeHandler(func(oldNode, newNode *v1.Node) error {
186192
nodetopologyQueue.Enqueue(newNode)
187-
}
188-
return nil
189-
}),
190-
DeleteFunc: nodeutil.CreateDeleteNodeHandler(func(node *v1.Node) error {
191-
if ca.nodeTopologyQueue != nil {
193+
return nil
194+
}),
195+
DeleteFunc: nodeutil.CreateDeleteNodeHandler(func(node *v1.Node) error {
192196
nodetopologyQueue.Enqueue(node)
193-
}
194-
return nil
195-
}),
196-
})
197+
return nil
198+
}),
199+
})
200+
}
197201

198202
nwInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
199203
AddFunc: func(originalObj interface{}) {
@@ -270,8 +274,6 @@ func (ca *cloudCIDRAllocator) Run(stopCh <-chan struct{}) {
270274
ctx, cancelFn := context.WithCancel(context.Background())
271275
defer cancelFn()
272276
defer ca.queue.ShutDown()
273-
defer ca.nodeTopologyQueue.Shutdown()
274-
275277
klog.Infof("Starting cloud CIDR allocator")
276278
defer klog.Infof("Shutting down cloud CIDR allocator")
277279

@@ -282,18 +284,26 @@ func (ca *cloudCIDRAllocator) Run(stopCh <-chan struct{}) {
282284
for i := 0; i < cidrUpdateWorkers; i++ {
283285
go wait.UntilWithContext(ctx, ca.runWorker, time.Second)
284286
}
285-
if ca.nodeTopologyQueue != nil {
286-
ca.nodeTopologyQueue.Run()
287-
}
288287

289-
go func() {
290-
time.Sleep(nodeTopologyReconcileInterval)
291-
wait.Until(
292-
func() {
293-
ca.nodeTopologyQueue.Enqueue(nodeTopologyReconcileFakeNode)
294-
},
295-
nodeTopologyReconcileInterval, stopCh)
296-
}()
288+
if enableNodeTopology {
289+
if ca.nodeTopologyQueue != nil {
290+
defer ca.nodeTopologyQueue.Shutdown()
291+
ca.nodeTopologyQueue.Run()
292+
}
293+
go func() {
294+
time.Sleep(nodeTopologyReconcileInterval)
295+
wait.Until(
296+
func() {
297+
if ca.nodeTopologyQueue != nil {
298+
// nodeTopologyReconcileFakeNode triggers reconciliation. Node_topology_syncer
299+
// will not find the fake node in nodeInformer cache, forcing a full reconciliation
300+
// of the nodeTopology custom resource.
301+
ca.nodeTopologyQueue.Enqueue(nodeTopologyReconcileFakeNode)
302+
}
303+
},
304+
nodeTopologyReconcileInterval, stopCh)
305+
}()
306+
}
297307

298308
<-stopCh
299309
}

pkg/controller/nodeipam/ipam/cloud_cidr_allocator_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func TestNodeTopologyQueuePeriodicSync(t *testing.T) {
143143
allocatorParams := CIDRAllocatorParams{}
144144

145145
KuberntesClientSet := fake.NewSimpleClientset()
146-
ca, _ := NewCloudCIDRAllocator(KuberntesClientSet, fakeGCE, nwInformer, gnpInformer, nodeTopologyClient, fakeNodeInformer, allocatorParams)
146+
ca, _ := NewCloudCIDRAllocator(KuberntesClientSet, fakeGCE, nwInformer, gnpInformer, nodeTopologyClient, true, fakeNodeInformer, allocatorParams)
147147
cloudAllocator, _ := ca.(*cloudCIDRAllocator)
148148
cloudAllocator.nodeTopologyQueue.Run()
149149

@@ -223,7 +223,7 @@ func TestNodeTopologyQueue_AddOrUpdate(t *testing.T) {
223223
allocatorParams := CIDRAllocatorParams{}
224224

225225
KuberntesClientSet := fake.NewSimpleClientset()
226-
ca, _ := NewCloudCIDRAllocator(KuberntesClientSet, fakeGCE, nwInformer, gnpInformer, nodeTopologyClient, fakeNodeInformer, allocatorParams)
226+
ca, _ := NewCloudCIDRAllocator(KuberntesClientSet, fakeGCE, nwInformer, gnpInformer, nodeTopologyClient, true, fakeNodeInformer, allocatorParams)
227227
cloudAllocator, _ := ca.(*cloudCIDRAllocator)
228228

229229
fakeInformerFactory.Start(wait.NeverStop)
@@ -300,7 +300,7 @@ func TestNodeTopologyCR_DELETION(t *testing.T) {
300300
allocatorParams := CIDRAllocatorParams{}
301301

302302
KuberntesClientSet := fake.NewSimpleClientset()
303-
ca, _ := NewCloudCIDRAllocator(KuberntesClientSet, fakeGCE, nwInformer, gnpInformer, nodeTopologyClient, fakeNodeInformer, allocatorParams)
303+
ca, _ := NewCloudCIDRAllocator(KuberntesClientSet, fakeGCE, nwInformer, gnpInformer, nodeTopologyClient, true, fakeNodeInformer, allocatorParams)
304304
cloudAllocator, _ := ca.(*cloudCIDRAllocator)
305305

306306
fakeInformerFactory.Start(wait.NeverStop)

pkg/controller/nodeipam/node_ipam_controller.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ func NewNodeIpamController(
7979
nwInformer networkinformer.NetworkInformer,
8080
gnpInformer networkinformer.GKENetworkParamSetInformer,
8181
nodeTopologyClient nodetopologyclientset.Interface,
82+
enableMultiSubnetCluster bool,
8283
clusterCIDRs []*net.IPNet,
8384
serviceCIDR *net.IPNet,
8485
secondaryServiceCIDR *net.IPNet,
@@ -135,7 +136,7 @@ func NewNodeIpamController(
135136
NodeCIDRMaskSizes: nodeCIDRMaskSizes,
136137
}
137138

138-
ic.cidrAllocator, err = ipam.New(kubeClient, cloud, nodeInformer, nwInformer, gnpInformer, nodeTopologyClient, ic.allocatorType, allocatorParams)
139+
ic.cidrAllocator, err = ipam.New(kubeClient, cloud, nodeInformer, nwInformer, gnpInformer, nodeTopologyClient, enableMultiSubnetCluster, ic.allocatorType, allocatorParams)
139140
if err != nil {
140141
return nil, err
141142
}

pkg/controller/nodeipam/node_ipam_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func newTestNodeIpamController(clusterCIDR []*net.IPNet, serviceCIDR *net.IPNet,
6363
fakeGCE := gce.NewFakeGCECloud(gce.DefaultTestClusterValues())
6464
return NewNodeIpamController(
6565
fakeNodeInformer, fakeGCE, clientSet, fakeNwInformer, fakeGNPInformer, nodeTopologyFakeClient,
66-
clusterCIDR, serviceCIDR, secondaryServiceCIDR, nodeCIDRMaskSizes, allocatorType,
66+
true, clusterCIDR, serviceCIDR, secondaryServiceCIDR, nodeCIDRMaskSizes, allocatorType,
6767
)
6868
}
6969

0 commit comments

Comments
 (0)