fix: support server change ipv6 address (#22016)

Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
Jian Qiu
2025-01-25 15:40:01 +08:00
committed by GitHub
co-authored by Qiu Jian
parent f6fa781156
commit 8fc56dcd4f
10 changed files with 179 additions and 52 deletions
+2 -2
View File
@@ -93,12 +93,12 @@ require (
k8s.io/cri-api v0.22.17
k8s.io/klog/v2 v2.20.0
moul.io/http2curl/v2 v2.3.0
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250108102611-1b422fb27e8b
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250113015514-eb7eb3112a75
yunion.io/x/executor v0.0.0-20241205080005-48f5b1212256
yunion.io/x/jsonutils v1.0.1-0.20240930100528-1671a2d0d22f
yunion.io/x/log v1.0.1-0.20240305175729-7cf2d6cd5a91
yunion.io/x/ovsdb v0.0.0-20230306173834-f164f413a900
yunion.io/x/pkg v1.10.3
yunion.io/x/pkg v1.10.4-0.20250123070256-9247ce856f07
yunion.io/x/s3cli v0.0.0-20241221171442-1c11599d28e1
yunion.io/x/sqlchemy v1.1.3-0.20240926163039-d41512b264e1
yunion.io/x/structarg v0.0.0-20231017124457-df4d5009457c
+4 -4
View File
@@ -1376,8 +1376,8 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250108102611-1b422fb27e8b h1:CnmPWb1fnMwF1ZlUxSCCIjiwdlfLd6/vFlScvHPIMjQ=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250108102611-1b422fb27e8b/go.mod h1:KQ/jWx7bZlmjCE711KEWuvHW/dzpdr/UTlBjjutkj0Y=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250113015514-eb7eb3112a75 h1:3GfPFiOXGcNlbMZbLg2TTov7VdRx2FS+FzrHQsmj64o=
yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250113015514-eb7eb3112a75/go.mod h1:KQ/jWx7bZlmjCE711KEWuvHW/dzpdr/UTlBjjutkj0Y=
yunion.io/x/executor v0.0.0-20241205080005-48f5b1212256 h1:kLKQ6zbgPDQflRwoHFAjxNChcbhXIFgsUVLkJwiXu/8=
yunion.io/x/executor v0.0.0-20241205080005-48f5b1212256/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws=
yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634=
@@ -1391,8 +1391,8 @@ yunion.io/x/ovsdb v0.0.0-20230306173834-f164f413a900 h1:Hu/4ERvoWaN6aiFs4h4/yvVB
yunion.io/x/ovsdb v0.0.0-20230306173834-f164f413a900/go.mod h1:0vLkNEhlmA64HViPBAnSTUMrx5QP1CLsxXmxDKQ80tc=
yunion.io/x/pkg v0.0.0-20190620104149-945c25821dbf/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/pkg v0.0.0-20190628082551-f4033ba2ea30/go.mod h1:t6rEGG2sQ4J7DhFxSZVOTjNd0YO/KlfWQyK1W4tog+E=
yunion.io/x/pkg v1.10.3 h1:oaJAtMSIwASgF6jB/0W37iOQBLh6ICswfPL3ISnRZC4=
yunion.io/x/pkg v1.10.3/go.mod h1:0Bwxqd9MA3ACi119/l02FprY/o9gHahmYC2bsSbnVpM=
yunion.io/x/pkg v1.10.4-0.20250123070256-9247ce856f07 h1:XZsL8+YpgVBHMcRwdpZ4cOfSZCc+KsgUCTdV3KeK8FI=
yunion.io/x/pkg v1.10.4-0.20250123070256-9247ce856f07/go.mod h1:0Bwxqd9MA3ACi119/l02FprY/o9gHahmYC2bsSbnVpM=
yunion.io/x/s3cli v0.0.0-20241221171442-1c11599d28e1 h1:1KJ3YYinydPHpDEQRXdr/T8SYcKZ5Er+m489H+PnaQ4=
yunion.io/x/s3cli v0.0.0-20241221171442-1c11599d28e1/go.mod h1:0iFKpOs1y4lbCxeOmq3Xx/0AcQoewVPwj62eRluioEo=
yunion.io/x/sqlchemy v1.1.3-0.20240926163039-d41512b264e1 h1:HWPqY1I5JSmM6Sks6FyK9hnq/MjL7FDghM6M8DXHob0=
+27 -11
View File
@@ -253,11 +253,27 @@ func ParseNetworkConfigByJSON(desc jsonutils.JSONObject, idx int) (*compute.Netw
return conf, err
}
func isQuoteChar(ch byte) (bool, string) {
switch ch {
case '[':
return true, "]"
default:
return false, ""
}
}
func splitConfig(confStr string) ([]string, error) {
return utils.FindWords2([]byte(confStr), 0, ":", isQuoteChar)
}
func ParseNetworkConfig(desc string, idx int) (*compute.NetworkConfig, error) {
if len(desc) == 0 {
return nil, ErrorEmptyDesc
}
parts := strings.Split(desc, ":")
parts, err := splitConfig(desc)
if err != nil {
return nil, errors.Wrap(err, "splitConfig")
}
netConfig := new(compute.NetworkConfig)
netConfig.Index = idx
for _, p := range parts {
@@ -300,23 +316,23 @@ func ParseNetworkConfig(desc string, idx int) (*compute.NetworkConfig, error) {
}
netConfig.Addresses6[i] = addr6.String()
}
} else if p == "[require_designated_ip]" {
} else if p == "require_designated_ip" {
netConfig.RequireDesignatedIP = true
} else if p == "[random_exit]" {
} else if p == "random_exit" {
netConfig.Exit = true
} else if p == "[random]" {
} else if p == "random" {
netConfig.Exit = false
} else if p == "[private]" {
} else if p == "private" {
netConfig.Private = true
} else if p == "[reserved]" {
} else if p == "reserved" {
netConfig.Reserved = true
} else if p == "[teaming]" {
} else if p == "teaming" {
netConfig.RequireTeaming = true
} else if p == "[try-teaming]" {
} else if p == "try-teaming" {
netConfig.TryTeaming = true
} else if p == "[defaultgw]" {
} else if p == "defaultgw" {
netConfig.IsDefault = true
} else if p == "[ipv6]" {
} else if p == "ipv6" {
netConfig.RequireIPv6 = true
} else if strings.HasPrefix(p, "standby-port=") {
netConfig.StandbyPortCount, _ = strconv.Atoi(p[len("standby-port="):])
@@ -332,7 +348,7 @@ func ParseNetworkConfig(desc string, idx int) (*compute.NetworkConfig, error) {
return nil, err
}
netConfig.BwLimit = bw
} else if p == "[vip]" {
} else if p == "vip" {
netConfig.Vip = true
} else if strings.HasPrefix(p, "sriov-nic-id=") {
netConfig.SriovDevice = &compute.IsolatedDeviceConfig{
+65
View File
@@ -282,3 +282,68 @@ func TestParseBaremetalRootDiskMatcher(t *testing.T) {
})
}
}
func TestParseNetworkConfig(t *testing.T) {
tests := []struct {
args string
want *compute.NetworkConfig
}{
{
args: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94",
want: &compute.NetworkConfig{Network: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94"},
},
{
args: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94:172.22.121.12",
want: &compute.NetworkConfig{
Network: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94",
Address: "172.22.121.12",
},
},
{
args: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94:172.22.121.12:[fd:3ffe:3200:90::2]",
want: &compute.NetworkConfig{
Network: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94",
Address: "172.22.121.12",
Address6: "fd:3ffe:3200:90::2",
},
},
{
args: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94:172.22.121.12:[fd:3ffe:3200:90::2]:[teaming]",
want: &compute.NetworkConfig{
Network: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94",
Address: "172.22.121.12",
Address6: "fd:3ffe:3200:90::2",
RequireTeaming: true,
},
},
{
args: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94:172.22.121.12:[fd:3ffe:3200:90::2]:wire=77a7d3a7-022d-4b48-8bb6-e37ea3a20c94",
want: &compute.NetworkConfig{
Network: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94",
Address: "172.22.121.12",
Address6: "fd:3ffe:3200:90::2",
Wire: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94",
},
},
{
args: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94:172.22.121.12:[fd:3ffe:3200:90::2]:wire=77a7d3a7-022d-4b48-8bb6-e37ea3a20c94:[try-teaming]",
want: &compute.NetworkConfig{
Network: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94",
Address: "172.22.121.12",
Address6: "fd:3ffe:3200:90::2",
Wire: "77a7d3a7-022d-4b48-8bb6-e37ea3a20c94",
TryTeaming: true,
},
},
}
for _, tt := range tests {
t.Run(tt.args, func(t *testing.T) {
got, err := ParseNetworkConfig(tt.args, 0)
if err != nil {
t.Errorf("ParseNetworkConfig %s fail %s", tt.args, err)
} else if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ParseNetworkConfig() got = %v, want %v", got, tt.want)
}
})
}
}
+5 -1
View File
@@ -2602,7 +2602,11 @@ func (self *SGuest) PerformChangeIpaddr(
if input.NetConf != nil {
conf = input.NetConf
} else if len(input.NetDesc) > 0 {
netConf, err := cmdline.ParseNetworkConfigByJSON(jsonutils.NewString(input.NetDesc), -1)
netDescJson, err := jsonutils.ParseString(input.NetDesc)
if err != nil {
netDescJson = jsonutils.NewString(input.NetDesc)
}
netConf, err := cmdline.ParseNetworkConfigByJSON(netDescJson, -1)
if err != nil {
return nil, httperrors.NewInputParameterError("fail to parse net_desc %s: %s", input.NetDesc, err)
}
+2 -2
View File
@@ -1785,7 +1785,7 @@ sigs.k8s.io/structured-merge-diff/v4/value
# sigs.k8s.io/yaml v1.2.0
## explicit; go 1.12
sigs.k8s.io/yaml
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250108102611-1b422fb27e8b
# yunion.io/x/cloudmux v0.3.10-0-alpha.1.0.20250113015514-eb7eb3112a75
## explicit; go 1.21
yunion.io/x/cloudmux/pkg/apis
yunion.io/x/cloudmux/pkg/apis/billing
@@ -1882,7 +1882,7 @@ yunion.io/x/log/hooks
yunion.io/x/ovsdb/cli_util
yunion.io/x/ovsdb/schema/ovn_nb
yunion.io/x/ovsdb/types
# yunion.io/x/pkg v1.10.3
# yunion.io/x/pkg v1.10.4-0.20250123070256-9247ce856f07
## explicit; go 1.18
yunion.io/x/pkg/appctx
yunion.io/x/pkg/errors
+19 -11
View File
@@ -94,7 +94,8 @@ type DataDisks struct {
type SInstance struct {
multicloud.SInstanceBase
SKsTag
host *SHost
host *SHost
region *SRegion
InstanceID string `json:"InstanceId"`
ProjectID string `json:"ProjectId"`
@@ -186,16 +187,16 @@ func (region *SRegion) GetInstance(instanceId string) (*SInstance, error) {
if err != nil {
return nil, errors.Wrap(err, "GetInstances")
}
for _, instance := range instances {
if instance.GetGlobalId() == instanceId {
return &instance, nil
for i := range instances {
if instances[i].GetGlobalId() == instanceId {
return &instances[i], nil
}
}
return nil, errors.Wrapf(err, "instance id:%s", instanceId)
return nil, errors.Wrapf(cloudprovider.ErrNotFound, instanceId)
}
func (ins *SInstance) Refresh() error {
extIns, err := ins.host.zone.region.GetInstance(ins.GetGlobalId())
extIns, err := ins.getRegion().GetInstance(ins.GetGlobalId())
if err != nil {
return errors.Wrap(err, "GetInstance")
}
@@ -203,13 +204,20 @@ func (ins *SInstance) Refresh() error {
}
func (ins *SInstance) GetTags() (map[string]string, error) {
tags, err := ins.host.zone.region.ListTags("kec-instance", ins.InstanceID)
tags, err := ins.getRegion().ListTags("kec-instance", ins.InstanceID)
if err != nil {
return nil, err
}
return tags.GetTags(), nil
}
func (ins *SInstance) getRegion() *SRegion {
if ins.region != nil {
return ins.region
}
return ins.host.zone.region
}
func (ins *SInstance) AssignSecurityGroup(secgroupId string) error {
return cloudprovider.ErrNotImplemented
}
@@ -320,7 +328,7 @@ func (ins *SInstance) GetHypervisor() string {
}
func (ins *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
disks, err := ins.host.zone.region.GetDiskByInstanceId(ins.GetId())
disks, err := ins.getRegion().GetDiskByInstanceId(ins.GetId())
if err != nil {
return nil, errors.Wrap(err, "getDisks")
}
@@ -339,7 +347,7 @@ func (ins *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
if len(eipIds) == 0 {
return nil, cloudprovider.ErrNotFound
}
eips, err := ins.host.zone.region.GetEips(eipIds)
eips, err := ins.getRegion().GetEips(eipIds)
if err != nil {
return nil, errors.Wrap(err, "get eips")
}
@@ -348,7 +356,7 @@ func (ins *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) {
}
for _, eip := range eips {
if utils.IsInStringArray(eip.GetId(), eipIds) {
eip.region = ins.host.zone.region
eip.region = ins.getRegion()
return &eip, nil
}
}
@@ -371,7 +379,7 @@ func (ins *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) {
func (ins *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
// TODO
resp, err := ins.host.zone.region.ecsRequest("GetVNCAddress", map[string]string{"InstanceId": ins.InstanceID})
resp, err := ins.getRegion().ecsRequest("GetVNCAddress", map[string]string{"InstanceId": ins.InstanceID})
if err != nil {
return nil, errors.Wrap(err, "GetVNCAddress")
}
+22
View File
@@ -238,6 +238,28 @@ func (region *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) {
return iStores, nil
}
func (r *SRegion) GetIVMs() ([]cloudprovider.ICloudVM, error) {
vms, err := r.GetInstances("", nil)
if err != nil {
return nil, err
}
ret := []cloudprovider.ICloudVM{}
for i := range vms {
vms[i].region = r
ret = append(ret, &vms[i])
}
return ret, nil
}
func (r *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) {
vm, err := r.GetInstance(id)
if err != nil {
return nil, err
}
vm.region = r
return vm, nil
}
func (region *SRegion) ecsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) {
return region.client.ec2Request(region.Region, action, params)
}
+4 -4
View File
@@ -32,9 +32,9 @@ import (
)
var RegionLocations = map[string]string{
"cn-beijing": "华2(北京)",
"cn-beijing": "华2(北京)",
"cn-shanghai": "华东2(上海)",
"cn-guangzhou": "华东2(广州)",
"cn-guangzhou": "华南1(广州)",
"ap-southeast-1": "亚太东南(柔佛)",
"cn-hongkong": "中国香港",
}
@@ -88,9 +88,9 @@ func (region *SRegion) GetId() string {
func (region *SRegion) GetName() string {
if localName, ok := RegionLocations[region.RegionId]; ok {
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_VOLCENGINE_CN, localName)
return localName
}
return fmt.Sprintf("%s %s", CLOUD_PROVIDER_VOLCENGINE_CN, region.RegionId)
return region.RegionId
}
func (region *SRegion) GetGlobalId() string {
+29 -17
View File
@@ -39,28 +39,32 @@ func Unquote(str string) string {
}
func findString(str []byte, offset int) (string, int) {
return _findWord(str, offset, "\n\r")
return _findWord(str, offset, "\n\r", isQuoteCharInternal)
}
func findWord(str []byte, offset int) (string, int) {
return _findWord(str, offset, " :,\t\n}]")
return _findWord(str, offset, " :,\t\n}]", isQuoteCharInternal)
}
func _findWord(str []byte, offset int, sepChars string) (string, int) {
func isQuoteCharInternal(ch byte) (bool, string) {
switch ch {
case '"':
return true, "\""
case '\'':
return true, "'"
default:
return false, ""
}
}
func _findWord(str []byte, offset int, sepChars string, isQuoteChar func(ch byte) (bool, string)) (string, int) {
var buffer bytes.Buffer
i := skipEmpty(str, offset)
if i >= len(str) {
return "", i
}
var endstr string
quote := false
if str[i] == '"' {
quote = true
endstr = "\""
i++
} else if str[i] == '\'' {
quote = true
endstr = "'"
quote, endstr := isQuoteChar(str[i])
if quote {
i++
} else {
// endstr = " :,\t\n\r}]"
@@ -98,22 +102,30 @@ func _findWord(str []byte, offset int, sepChars string) (string, int) {
}
func FindWords(str []byte, offset int) []string {
words, err := FindWords2(str, offset, " :,\t\n}]", isQuoteCharInternal)
if err != nil {
panic(err.Error())
}
return words
}
func FindWords2(str []byte, offset int, sepChars string, isQuoteChar func(ch byte) (bool, string)) ([]string, error) {
words := make([]string, 0)
for offset < len(str) {
word, i := findWord(str, offset)
word, i := _findWord(str, offset, sepChars, isQuoteChar)
words = append(words, word)
i = skipEmpty(str, i)
if i < len(str) {
if str[i] == ',' {
if strings.IndexByte(sepChars, str[i]) >= 0 {
offset = i + 1
} else {
panic(fmt.Sprintf("Malformed multi value string: %s", string(str[offset:])))
return nil, fmt.Errorf("Malformed multi value string: %s", string(str[offset:]))
}
} else {
offset = i
}
}
return words
return words, nil
}
func TagMap(tag reflect.StructTag) map[string]string {
@@ -155,7 +167,7 @@ func SplitCSV(csv string) []string {
str := []byte(csv)
for offset < len(str) {
var word string
word, offset = _findWord(str, offset, ",\r\n")
word, offset = _findWord(str, offset, ",\r\n", isQuoteCharInternal)
words = append(words, word)
if offset < len(str) {
offset++