From 1d272634e900022c73b178100f099bd72cbb042b Mon Sep 17 00:00:00 2001 From: dn Date: Wed, 27 May 2026 10:47:32 +0300 Subject: [PATCH] topo: skip creating empty meshnet Topology CR for nodes with no links When a node has no Links in its meshnet TopologySpec, kne currently still creates a `Topology` CR with `spec: {}`. meshnetd's `Get(podName)` RPC then reads the CR, fails the `unstructured.NestedSlice(... "spec", "links")` lookup with `!found`, logs `could not find 'Link' array in pod's spec` and returns an empty Pod struct. The CNI plugin sees `NodeIp == ""` and aborts the sandbox with the (misleading) error: plugin type="meshnet" failed (add): meshnetd provided no HOST_IP address: or HOST_INTF: Every pod scheduled on a node with no links is then stuck in FailedCreatePodSandBox loops until kubelet's 4-minute deadline. Skip the CR creation for unconnected nodes. The meshnet CNI plugin already handles "no Topology CR for this pod" gracefully (plugin/meshnet.go cmdAdd treats Get error as `not a topology pod returning`) and chains through to the next plugin, so the result is the same as for any other workload on the cluster. This is a no-op for topologies whose nodes all have links and significantly improves robustness for sparse/scale-test topologies where some nodes are intentionally isolated. --- topo/topo.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/topo/topo.go b/topo/topo.go index 7905ff84a..dbe2729c1 100644 --- a/topo/topo.go +++ b/topo/topo.go @@ -554,6 +554,19 @@ func (m *Manager) topologySpecs(ctx context.Context) ([]*topologyv1.Topology, er // replace node name with pod name, for peer pod attribute in each link for nodeName, specs := range nodeSpecs { for _, spec := range specs { + // Skip Topology CRs with no links: meshnetd's Get RPC + // treats a missing `spec.links` field as an error + // (`could not find 'Link' array in pod's spec`) and the + // CNI plugin then aborts pod sandbox creation with a + // misleading `meshnetd provided no HOST_IP` message. + // For unconnected nodes we simply don't create the CR; + // the meshnet CNI plugin already handles "no Topology + // CR" gracefully and falls through to the next plugin + // in the chain. + if len(spec.Spec.Links) == 0 { + log.V(1).Infof("Skipping empty Topology spec for node %s (no links)", nodeName) + continue + } for l := range spec.Spec.Links { link := &spec.Spec.Links[l] peerSpecs, ok := nodeSpecs[link.PeerPod]