Skip to content

Commit

Permalink
Merge pull request #968 from spidernet-io/fix/sync-node-status-to-egt
Browse files Browse the repository at this point in the history
sync node status to egt
  • Loading branch information
weizhoublue authored Nov 16, 2023
2 parents 6daaf07 + b35428f commit 3575cba
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 37 deletions.
1 change: 1 addition & 0 deletions charts/crds/egressgateway.spidernet.io_egresstunnels.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ spec:
- Failed
- Ready
- HeartbeatTimeout
- NodeNotReady
type: string
tunnel:
properties:
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/EgressTunnel.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ status:
- `Init`: successful tunnel IP allocation
- `Ready`: the tunnel IP is allocated and tunnel is established
- `Failed`: tunnel IP allocation fails
- `HeartbeatTimeout` heartbeat Timeout for Agent
- `NodeNotReady` Node Status is NotReady
8. Packet mark value, one for each node. For example, if node A has egress traffic that needs to be forwarded to gateway node B, the traffic of node A will be marked with a mark.Each node is assigned a unique packet mark value. For instance, if Node A needs to forward Egress traffic to the gateway node B, it applies a specific mark to the packets originating from Node A.
2 changes: 2 additions & 0 deletions docs/reference/EgressTunnel.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ status:
- `Init`:分配隧道 IP 成功
- `Ready`:隧道 IP 已分配,且隧道已建成
- `Failed`:隧道 IP 分配失败
- `HeartbeatTimeout` Agent 心跳超时
- `NodeNotReady` Node 状态处于 NotReady
8. 数据包 mark 值,每个节点对应一个。例如节点 A 有 Egress 流量需要转发到网关节点 B,会对 A 节点的流量打 mark 进行标记。
56 changes: 29 additions & 27 deletions pkg/agent/vxlan.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,16 +529,16 @@ func (r *vxlanReconciler) ensureEgressTunnelStatus(node *egressv1.EgressTunnel)
return nil
}

func (r *vxlanReconciler) updateEgressTunnelStatus(node *egressv1.EgressTunnel, version int) error {
func (r *vxlanReconciler) updateEgressTunnelStatus(tunnel *egressv1.EgressTunnel, version int) error {
parent, err := r.getParent(version)
if err != nil {
return err
}

if node == nil {
node = new(egressv1.EgressTunnel)
if tunnel == nil {
tunnel = new(egressv1.EgressTunnel)
ctx := context.Background()
err = r.client.Get(ctx, types.NamespacedName{Name: r.cfg.NodeName}, node)
err = r.client.Get(ctx, types.NamespacedName{Name: r.cfg.NodeName}, tunnel)
if err != nil {
if k8sErr.IsNotFound(err) {
return nil
Expand All @@ -548,43 +548,45 @@ func (r *vxlanReconciler) updateEgressTunnelStatus(node *egressv1.EgressTunnel,
}

needUpdate := false
if node.Status.Tunnel.Parent.Name != parent.Name {
if tunnel.Status.Tunnel.Parent.Name != parent.Name {
needUpdate = true
node.Status.Tunnel.Parent.Name = parent.Name
tunnel.Status.Tunnel.Parent.Name = parent.Name
}

if version == 4 {
if node.Status.Tunnel.Parent.IPv4 != parent.IP.String() {
if tunnel.Status.Tunnel.Parent.IPv4 != parent.IP.String() {
needUpdate = true
node.Status.Tunnel.Parent.IPv4 = parent.IP.String()
tunnel.Status.Tunnel.Parent.IPv4 = parent.IP.String()
}
if node.Status.Tunnel.Parent.IPv6 != "" {
if tunnel.Status.Tunnel.Parent.IPv6 != "" {
needUpdate = true
node.Status.Tunnel.Parent.IPv6 = ""
tunnel.Status.Tunnel.Parent.IPv6 = ""
}
} else {
if node.Status.Tunnel.Parent.IPv6 != parent.IP.String() {
if tunnel.Status.Tunnel.Parent.IPv6 != parent.IP.String() {
needUpdate = true
node.Status.Tunnel.Parent.IPv6 = parent.IP.String()
tunnel.Status.Tunnel.Parent.IPv6 = parent.IP.String()
}
if node.Status.Tunnel.Parent.IPv4 != "" {
if tunnel.Status.Tunnel.Parent.IPv4 != "" {
needUpdate = true
node.Status.Tunnel.Parent.IPv4 = ""
tunnel.Status.Tunnel.Parent.IPv4 = ""
}
}

// calculate whether the state has changed, update if the status changes.
vtep := r.parseVTEP(node.Status)
vtep := r.parseVTEP(tunnel.Status)
if vtep != nil {
phase := egressv1.EgressTunnelReady
if node.Status.Phase != phase {
// We should not overwrite the updated state of the controller.
if tunnel.Status.Phase != phase &&
tunnel.Status.Phase != egressv1.EgressTunnelNodeNotReady {
needUpdate = true
node.Status.Phase = phase
tunnel.Status.Phase = phase
}
}

if needUpdate {
err := r.updateTunnelStatus(node)
err := r.updateTunnelStatus(tunnel)
if err != nil {
return err
}
Expand Down Expand Up @@ -763,20 +765,20 @@ func (r *vxlanReconciler) keepVXLAN() {
}
}

func (r *vxlanReconciler) updateTunnelStatus(node *egressv1.EgressTunnel) error {
func (r *vxlanReconciler) updateTunnelStatus(tunnel *egressv1.EgressTunnel) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(r.cfg.FileConfig.GatewayFailover.EipEvictionTimeout)*time.Second)
defer cancel()

node.Status.LastHeartbeatTime = metav1.Now()
tunnel.Status.LastHeartbeatTime = metav1.Now()
r.log.Info("update tunnel status",
"phase", node.Status.Phase,
"tunnelIPv4", node.Status.Tunnel.IPv4,
"tunnelIPv6", node.Status.Tunnel.IPv6,
"parentName", node.Status.Tunnel.Parent.Name,
"parentIPv4", node.Status.Tunnel.Parent.IPv4,
"parentIPv6", node.Status.Tunnel.Parent.IPv6,
"phase", tunnel.Status.Phase,
"tunnelIPv4", tunnel.Status.Tunnel.IPv4,
"tunnelIPv6", tunnel.Status.Tunnel.IPv6,
"parentName", tunnel.Status.Tunnel.Parent.Name,
"parentIPv4", tunnel.Status.Tunnel.Parent.IPv4,
"parentIPv6", tunnel.Status.Tunnel.Parent.IPv6,
)
err := r.client.Status().Update(ctx, node)
err := r.client.Status().Update(ctx, tunnel)
if err != nil {
return err
}
Expand Down
43 changes: 34 additions & 9 deletions pkg/controller/egress_tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ func (r *egReconciler) reconcileNode(ctx context.Context, req reconcile.Request,
return reconcile.Result{Requeue: false}, nil
}

en := new(egressv1.EgressTunnel)
err = r.client.Get(ctx, req.NamespacedName, en)
egressTunnel := new(egressv1.EgressTunnel)
err = r.client.Get(ctx, req.NamespacedName, egressTunnel)
if err != nil {
log.Info("create egress tunnel")
if !k8serr.IsNotFound(err) {
Expand All @@ -210,6 +210,30 @@ func (r *egReconciler) reconcileNode(ctx context.Context, req reconcile.Request,
return reconcile.Result{}, nil
}

// If GatewayFailover is not enabled, we watch the health status of the node,
// and switch the active node of the egress IP based on the status of the node.
if !r.config.FileConfig.GatewayFailover.Enable {
phase := egressv1.EgressTunnelReady
for _, condition := range node.Status.Conditions {
if condition.Type == corev1.NodeReady {
if condition.Status != corev1.ConditionTrue {
phase = egressv1.EgressTunnelNodeNotReady
}
}
}
// don't overwrite the EgressTunnelHeartbeatTimeout status
if egressTunnel.Status.Phase != egressv1.EgressTunnelHeartbeatTimeout {
if egressTunnel.Status.Phase != phase {
log.Info("update egress tunnel", "status", egressTunnel.Status)
egressTunnel.Status.Phase = phase
err := r.updateEgressTunnel(*egressTunnel)
if err != nil {
return reconcile.Result{Requeue: true}, err
}
}
}
}

return reconcile.Result{Requeue: false}, nil
}

Expand Down Expand Up @@ -479,23 +503,24 @@ func (r *egReconciler) keepEgressTunnel(node egressv1.EgressTunnel, log logr.Log
}

func (r *egReconciler) updateEgressTunnel(node egressv1.EgressTunnel) error {
phase := egressv1.EgressTunnelInit
if node.Status.Phase == "" {
node.Status.Phase = egressv1.EgressTunnelInit
}
if node.Status.Tunnel.Parent.Name == "" {
phase = egressv1.EgressTunnelInit
node.Status.Phase = egressv1.EgressTunnelInit
}
if node.Status.Mark == "" {
phase = egressv1.EgressTunnelPending
node.Status.Phase = egressv1.EgressTunnelPending
}
if node.Status.Tunnel.IPv4 == "" && r.allocatorV4 != nil {
phase = egressv1.EgressTunnelPending
node.Status.Phase = egressv1.EgressTunnelPending
}
if node.Status.Tunnel.IPv6 == "" && r.allocatorV6 != nil {
phase = egressv1.EgressTunnelPending
node.Status.Phase = egressv1.EgressTunnelPending
}
if node.Status.Tunnel.MAC == "" {
phase = egressv1.EgressTunnelPending
node.Status.Phase = egressv1.EgressTunnelPending
}
node.Status.Phase = phase

err := r.client.Status().Update(context.Background(), &node)
if err != nil {
Expand Down
4 changes: 3 additions & 1 deletion pkg/k8s/apis/v1beta1/egresstunnel_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type EgressTunnelSpec struct{}
type EgressTunnelStatus struct {
// +kubebuilder:validation:Optional
Tunnel Tunnel `json:"tunnel,omitempty"`
// +kubebuilder:validation:Enum=Pending;Init;Failed;Ready;HeartbeatTimeout
// +kubebuilder:validation:Enum=Pending;Init;Failed;Ready;HeartbeatTimeout;NodeNotReady
Phase EgressTunnelPhase `json:"phase,omitempty"`
// +kubebuilder:validation:Optional
Mark string `json:"mark,omitempty"`
Expand Down Expand Up @@ -77,6 +77,8 @@ const (
EgressTunnelFailed EgressTunnelPhase = "Failed"
// EgressTunnelHeartbeatTimeout tunnel heartbeat timeout
EgressTunnelHeartbeatTimeout EgressTunnelPhase = "HeartbeatTimeout"
// EgressTunnelNodeNotReady node not ready
EgressTunnelNodeNotReady EgressTunnelPhase = "NodeNotReady"
// EgressTunnelReady tunnel is available
EgressTunnelReady EgressTunnelPhase = "Ready"
)
Expand Down

1 comment on commit 3575cba

@weizhoublue
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.