mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-15 07:40:59 +00:00
fix(node): adopt a matching deployed inbound instead of recreating it (#6197)
* fix(node): adopt compatible origin inbounds without mutation * fix(nodes): preserve ambiguous and adopted aliases --------- Co-authored-by: n0ctal <293235942+n0ctal@users.noreply.github.com>
This commit is contained in:
@@ -96,13 +96,15 @@ func (s *InboundService) ReconcileNode(ctx context.Context, rt *runtime.Remote,
|
||||
if err := db.Model(model.Inbound{}).Where("node_id = ?", nodeID).Find(&inbounds).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
remoteTags, err := rt.ListRemoteTags(ctx)
|
||||
remoteInbounds, err := rt.ListInboundOptions(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
remoteTags := make([]string, 0, len(remoteInbounds))
|
||||
remoteTagSet := make(map[string]struct{}, len(remoteTags))
|
||||
for _, tag := range remoteTags {
|
||||
remoteTagSet[tag] = struct{}{}
|
||||
for _, remoteIb := range remoteInbounds {
|
||||
remoteTags = append(remoteTags, remoteIb.Tag)
|
||||
remoteTagSet[remoteIb.Tag] = struct{}{}
|
||||
}
|
||||
prefix := nodeTagPrefix(&nodeID)
|
||||
desiredTags := make(map[string]struct{}, len(inbounds)*2)
|
||||
@@ -129,6 +131,33 @@ func (s *InboundService) ReconcileNode(ctx context.Context, rt *runtime.Remote,
|
||||
if built, bErr := s.buildInboundForNodePush(db, ib); bErr == nil {
|
||||
runtimeIb = built
|
||||
}
|
||||
if !existsOnNode && n.Guid != "" && ib.OriginNodeGuid == n.Guid {
|
||||
var compatible []runtime.RemoteInboundOption
|
||||
for _, remoteIb := range remoteInbounds {
|
||||
if remoteIb.Port == runtimeIb.Port &&
|
||||
remoteIb.Protocol == runtimeIb.Protocol &&
|
||||
strings.TrimSpace(remoteIb.Listen) == strings.TrimSpace(runtimeIb.Listen) {
|
||||
compatible = append(compatible, remoteIb)
|
||||
}
|
||||
}
|
||||
switch len(compatible) {
|
||||
case 1:
|
||||
alias := compatible[0]
|
||||
desiredTags[alias.Tag] = struct{}{}
|
||||
rt.AdoptInboundAlias(runtimeIb, alias)
|
||||
existsOnNode = true
|
||||
logger.Infof("adopted compatible inbound %q on node %s as %q", alias.Tag, n.Name, ib.Tag)
|
||||
case 0:
|
||||
// No compatible occupant: keep the normal create path, which
|
||||
// leaves a real port/protocol drift loud.
|
||||
default:
|
||||
for _, candidate := range compatible {
|
||||
desiredTags[candidate.Tag] = struct{}{}
|
||||
}
|
||||
errs = append(errs, fmt.Errorf("reconcile inbound %q: ambiguous compatible remote inbounds", ib.Tag))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if _, err := rt.ReconcileInbound(ctx, runtimeIb, existsOnNode); err != nil {
|
||||
errs = append(errs, fmt.Errorf("reconcile inbound %q: %w", ib.Tag, err))
|
||||
}
|
||||
@@ -514,6 +543,29 @@ func (s *InboundService) setRemoteTrafficLocked(nodeID int, snap *runtime.Traffi
|
||||
}
|
||||
|
||||
c, ok := tagToCentral[snapIb.Tag]
|
||||
if !ok {
|
||||
origin := originGuidFor(snapIb)
|
||||
var compatible []*model.Inbound
|
||||
for i := range central {
|
||||
candidate := ¢ral[i]
|
||||
if candidate.OriginNodeGuid == origin &&
|
||||
candidate.Port == snapIb.Port &&
|
||||
candidate.Protocol == snapIb.Protocol &&
|
||||
strings.TrimSpace(candidate.Listen) == strings.TrimSpace(snapIb.Listen) {
|
||||
compatible = append(compatible, candidate)
|
||||
}
|
||||
}
|
||||
switch len(compatible) {
|
||||
case 1:
|
||||
c, ok = compatible[0], true
|
||||
tagToCentral[snapIb.Tag] = c
|
||||
snapTags[c.Tag] = struct{}{}
|
||||
case 0:
|
||||
// A genuinely new inbound follows the normal adoption path.
|
||||
default:
|
||||
return false, fmt.Errorf("setRemoteTraffic: inbound %q has ambiguous compatible central aliases", snapIb.Tag)
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
if dirty {
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user