Skip to content

Commit a6c0b7c

Browse files
committed
pkg/ipam: Hold agent IPAM while static IP is not assigned
This gates readiness of the agent by holding the constructor of the IPAM allocator if a static IP is requested and not assigned yet. This applies for CRD and multi-pool backed allocators. Signed-off-by: Alex Melhem <alex.melhem@datadoghq.com>
1 parent 214b09d commit a6c0b7c

2 files changed

Lines changed: 65 additions & 1 deletion

File tree

pkg/ipam/crd.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,10 @@ func newNodeStore(logger *slog.Logger, nodeName string, conf *option.DaemonConfi
207207
logfields.Required, required,
208208
logfields.Available, numAvailable,
209209
)
210-
if minimumReached {
210+
requestedStaticIP, assignedStaticIP := store.staticIPStatus()
211+
staticIPReady := !requestedStaticIP || assignedStaticIP != ""
212+
213+
if minimumReached && staticIPReady {
211214
scopedLog.Info(
212215
"All required IPs are available in CRD-backed allocation pool",
213216
)
@@ -358,6 +361,17 @@ func (n *nodeStore) hasMinimumIPsInPool(localNodeStore *node.LocalNodeStore) (mi
358361
return
359362
}
360363

364+
func (n *nodeStore) staticIPStatus() (requested bool, assigned string) {
365+
n.mutex.RLock()
366+
defer n.mutex.RUnlock()
367+
368+
if n.ownNode == nil {
369+
return false, ""
370+
}
371+
372+
return len(n.ownNode.Spec.IPAM.StaticIPTags) > 0, n.ownNode.Status.IPAM.AssignedStaticIP
373+
}
374+
361375
// deleteLocalNodeResource is called when the CiliumNode resource representing
362376
// the local node has been deleted.
363377
func (n *nodeStore) deleteLocalNodeResource() {

pkg/ipam/crd_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,56 @@ func TestMarkForReleaseNoAllocate(t *testing.T) {
143143
require.Equal(t, ipamOption.IPAMDoNotRelease, string(cn.Status.IPAM.ReleaseIPs["1.1.1.3"]))
144144
}
145145

146+
func TestNodeStoreStaticIPStatus(t *testing.T) {
147+
newNode := func(tags map[string]string, assigned string) *ciliumv2.CiliumNode {
148+
cn := newCiliumNode("node1", 0, 0, 0)
149+
cn.Spec.IPAM.StaticIPTags = tags
150+
cn.Status.IPAM.AssignedStaticIP = assigned
151+
return cn
152+
}
153+
154+
tests := []struct {
155+
name string
156+
ownNode *ciliumv2.CiliumNode
157+
wantRequestedStaticIP bool
158+
wantAssignedStaticIP string
159+
}{
160+
{
161+
name: "nil node",
162+
ownNode: nil,
163+
wantRequestedStaticIP: false,
164+
wantAssignedStaticIP: "",
165+
},
166+
{
167+
name: "no static IP requested",
168+
ownNode: newNode(nil, ""),
169+
wantRequestedStaticIP: false,
170+
wantAssignedStaticIP: "",
171+
},
172+
{
173+
name: "static IP requested but not yet assigned",
174+
ownNode: newNode(map[string]string{"env": "prod"}, ""),
175+
wantRequestedStaticIP: true,
176+
wantAssignedStaticIP: "",
177+
},
178+
{
179+
name: "static IP requested and assigned",
180+
ownNode: newNode(map[string]string{"env": "prod"}, "1.2.3.4"),
181+
wantRequestedStaticIP: true,
182+
wantAssignedStaticIP: "1.2.3.4",
183+
},
184+
}
185+
186+
for _, tt := range tests {
187+
t.Run(tt.name, func(t *testing.T) {
188+
store := &nodeStore{ownNode: tt.ownNode}
189+
requested, assigned := store.staticIPStatus()
190+
assert.Equal(t, tt.wantRequestedStaticIP, requested)
191+
assert.Equal(t, tt.wantAssignedStaticIP, assigned)
192+
})
193+
}
194+
}
195+
146196
type ipMasqMapDummy struct{}
147197

148198
func (m ipMasqMapDummy) Update(netip.Prefix) error { return nil }

0 commit comments

Comments
 (0)