实例地址恒以主网卡为准,修复多网卡覆写随机

This commit is contained in:
2026-07-16 12:31:36 +08:00
parent 4e2bab3032
commit 99b551401e
2 changed files with 64 additions and 7 deletions
+19 -4
View File
@@ -400,6 +400,7 @@ func fillInstanceIPs(ctx context.Context, cc core.ComputeClient, vn core.Virtual
wg sync.WaitGroup wg sync.WaitGroup
mu sync.Mutex mu sync.Mutex
sem = make(chan struct{}, 8) sem = make(chan struct{}, 8)
primarySeen = make(map[*Instance]bool)
) )
for _, att := range attResp.Items { for _, att := range attResp.Items {
inst, ok := active[deref(att.InstanceId)] inst, ok := active[deref(att.InstanceId)]
@@ -416,16 +417,30 @@ func fillInstanceIPs(ctx context.Context, cc core.ComputeClient, vn core.Virtual
return return
} }
mu.Lock() mu.Lock()
inst.SubnetID = deref(vnicResp.SubnetId) applyVnicAddrs(inst, vnicResp.Vnic, primarySeen)
inst.PrivateIP = deref(vnicResp.PrivateIp)
inst.PublicIP = deref(vnicResp.PublicIp)
inst.Ipv6Addresses = vnicResp.Ipv6Addresses
mu.Unlock() mu.Unlock()
}(att.VnicId, inst) }(att.VnicId, inst)
} }
wg.Wait() wg.Wait()
} }
// applyVnicAddrs 将 VNIC 地址写入实例。多网卡实例以主网卡为准:
// 主网卡返回前先用先到的网卡兜底,主网卡到达后覆盖并锁定,避免并发
// 完成顺序决定展示结果。调用方需持有保护 inst 与 primarySeen 的锁。
func applyVnicAddrs(inst *Instance, v core.Vnic, primarySeen map[*Instance]bool) {
isPrimary := v.IsPrimary != nil && *v.IsPrimary
if !isPrimary && (primarySeen[inst] || inst.SubnetID != "") {
return
}
inst.SubnetID = deref(v.SubnetId)
inst.PrivateIP = deref(v.PrivateIp)
inst.PublicIP = deref(v.PublicIp)
inst.Ipv6Addresses = v.Ipv6Addresses
if isPrimary {
primarySeen[inst] = true
}
}
func toInstance(inst core.Instance) Instance { func toInstance(inst core.Instance) Instance {
out := Instance{ out := Instance{
ID: deref(inst.Id), ID: deref(inst.Id),
+42
View File
@@ -5,9 +5,51 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/oracle/oci-go-sdk/v65/common"
"github.com/oracle/oci-go-sdk/v65/core" "github.com/oracle/oci-go-sdk/v65/core"
) )
func TestApplyVnicAddrs(t *testing.T) {
primary := core.Vnic{
IsPrimary: common.Bool(true),
SubnetId: common.String("sub-a"),
PrivateIp: common.String("10.0.0.2"),
PublicIp: common.String("1.1.1.1"),
}
secondary := core.Vnic{
IsPrimary: common.Bool(false),
SubnetId: common.String("sub-b"),
PrivateIp: common.String("10.0.0.9"),
}
secondary2 := core.Vnic{
SubnetId: common.String("sub-c"),
PrivateIp: common.String("10.0.0.7"),
}
tests := []struct {
name string
order []core.Vnic
wantPrivate string
wantSubnet string
}{
{name: "主卡先到不被次卡覆盖", order: []core.Vnic{primary, secondary}, wantPrivate: "10.0.0.2", wantSubnet: "sub-a"},
{name: "次卡先兜底主卡后覆盖", order: []core.Vnic{secondary, primary}, wantPrivate: "10.0.0.2", wantSubnet: "sub-a"},
{name: "无主卡时先到者保留", order: []core.Vnic{secondary, secondary2}, wantPrivate: "10.0.0.9", wantSubnet: "sub-b"},
{name: "仅次卡也能兜底", order: []core.Vnic{secondary2}, wantPrivate: "10.0.0.7", wantSubnet: "sub-c"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
inst := &Instance{}
seen := make(map[*Instance]bool)
for _, v := range tt.order {
applyVnicAddrs(inst, v, seen)
}
if inst.PrivateIP != tt.wantPrivate || inst.SubnetID != tt.wantSubnet {
t.Errorf("got (%q, %q), want (%q, %q)", inst.PrivateIP, inst.SubnetID, tt.wantPrivate, tt.wantSubnet)
}
})
}
}
func TestShellSingleQuote(t *testing.T) { func TestShellSingleQuote(t *testing.T) {
tests := []struct { tests := []struct {
name string name string