67 lines
1.9 KiB
Go
67 lines
1.9 KiB
Go
|
|
package agent
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"encoding/json"
|
||
|
|
"fmt"
|
||
|
|
"log/slog"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
corev1 "k8s.io/api/core/v1"
|
||
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||
|
|
"k8s.io/apimachinery/pkg/types"
|
||
|
|
"k8s.io/client-go/kubernetes"
|
||
|
|
"k8s.io/client-go/rest"
|
||
|
|
)
|
||
|
|
|
||
|
|
// keepNetworkAvailable maintains a NetworkUnavailable=False condition on
|
||
|
|
// the node's status. Calico-node sets this False while it owns CNI; on
|
||
|
|
// shutdown it sets it to True with reason CalicoIsDown, which adds the
|
||
|
|
// node.kubernetes.io/network-unavailable taint and blocks new scheduling.
|
||
|
|
// Once flock-agent is in charge, we own the condition.
|
||
|
|
//
|
||
|
|
// Re-applies every minute — heartbeat-style — so a stale condition from a
|
||
|
|
// previous CNI is overwritten without an explicit transition.
|
||
|
|
func keepNetworkAvailable(ctx context.Context, cfg *rest.Config, node string, logger *slog.Logger) {
|
||
|
|
cs, err := kubernetes.NewForConfig(cfg)
|
||
|
|
if err != nil {
|
||
|
|
logger.Warn("network-condition: kubernetes client", "err", err)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
apply := func() {
|
||
|
|
now := metav1.Now()
|
||
|
|
patch := map[string]interface{}{
|
||
|
|
"status": map[string]interface{}{
|
||
|
|
"conditions": []corev1.NodeCondition{{
|
||
|
|
Type: corev1.NodeNetworkUnavailable,
|
||
|
|
Status: corev1.ConditionFalse,
|
||
|
|
Reason: "FlockReady",
|
||
|
|
Message: "flock-agent owns CNI on this node",
|
||
|
|
LastHeartbeatTime: now,
|
||
|
|
LastTransitionTime: now,
|
||
|
|
}},
|
||
|
|
},
|
||
|
|
}
|
||
|
|
body, _ := json.Marshal(patch)
|
||
|
|
_, err := cs.CoreV1().Nodes().Patch(ctx, node, types.MergePatchType, body, metav1.PatchOptions{}, "status")
|
||
|
|
if err != nil {
|
||
|
|
logger.Warn("network-condition: patch failed", "err", err)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
}
|
||
|
|
apply()
|
||
|
|
t := time.NewTicker(60 * time.Second)
|
||
|
|
defer t.Stop()
|
||
|
|
for {
|
||
|
|
select {
|
||
|
|
case <-ctx.Done():
|
||
|
|
return
|
||
|
|
case <-t.C:
|
||
|
|
apply()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// silence unused-import warnings on non-Linux builds where this is unused.
|
||
|
|
var _ = fmt.Sprintf
|