From 517115971770f6ca92b55d7b7061f1a496c9b88b Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Sun, 18 Feb 2024 11:58:02 +0800 Subject: [PATCH] fix: server change ip addr support ipv6 --- pkg/apis/compute/guests.go | 3 ++ pkg/compute/models/guest_actions.go | 44 ++++++++++++------- .../tasks/guest_qga_restart_network_task.go | 37 +++++++++++----- pkg/compute/tasks/guest_sync_task.go | 11 +++-- .../guestman/guesthandlers/guesthandler.go | 11 +++-- pkg/hostman/monitor/qga/qga.go | 28 ++++++++++-- pkg/hostman/monitor/qmp.go | 3 ++ 7 files changed, 96 insertions(+), 41 deletions(-) diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index edc121ed379..255198ed778 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -1127,6 +1127,9 @@ type ServerQgaSetNetworkInput struct { Device string Ipmask string Gateway string + + Ipmask6 string + Gateway6 string } type ServerQgaGetNetworkInput struct { diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 1e465de4e2f..0c094266852 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -925,7 +925,7 @@ func (self *SGuest) PerformAttachdisk(ctx context.Context, userCred mcclient.Tok return nil, self.GetDriver().StartGuestAttachDiskTask(ctx, userCred, self, taskData, "") } -func (self *SGuest) StartRestartNetworkTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, ip string, inBlockStream bool) error { +/*func (self *SGuest) StartRestartNetworkTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, ip string, inBlockStream bool) error { data := jsonutils.NewDict() data.Set("ip", jsonutils.NewString(ip)) data.Set("in_block_stream", jsonutils.NewBool(inBlockStream)) @@ -936,13 +936,21 @@ func (self *SGuest) StartRestartNetworkTask(ctx context.Context, userCred mcclie task.ScheduleRun(nil) } return nil -} +}*/ -func (self *SGuest) StartQgaRestartNetworkTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, device string, ipMask string, gateway string, prevIp string, inBlockStream bool) error { +func (self *SGuest) StartQgaRestartNetworkTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, device string, ipMask, gateway, ipMask6, gateway6 string, prevIp string, inBlockStream bool) error { data := jsonutils.NewDict() data.Set("device", jsonutils.NewString(device)) data.Set("ip_mask", jsonutils.NewString(ipMask)) - data.Set("gateway", jsonutils.NewString(gateway)) + if len(gateway) > 0 { + data.Set("gateway", jsonutils.NewString(gateway)) + } + if len(ipMask6) > 0 { + data.Set("ip_mask6", jsonutils.NewString(ipMask6)) + if len(gateway6) > 0 { + data.Set("gateway6", jsonutils.NewString(gateway6)) + } + } data.Set("prev_ip", jsonutils.NewString(prevIp)) data.Set("in_block_stream", jsonutils.NewBool(inBlockStream)) if task, err := taskman.TaskManager.NewTask(ctx, "GuestQgaRestartNetworkTask", self, userCred, data, parentTaskId, "", nil); err != nil { @@ -2453,15 +2461,7 @@ func (self *SGuest) PerformChangeIpaddr( return nil, nil } - //Get the detailed description of the NIC - networkJsonDesc := ngn.getJsonDesc() - newIpAddr := networkJsonDesc.Ip - newMacAddr := networkJsonDesc.Mac - newMaskLen := networkJsonDesc.Masklen - newGateway := networkJsonDesc.Gateway - ipMask := fmt.Sprintf("%s/%d", newIpAddr, newMaskLen) - - notes := gn.GetShortDesc(ctx) + notes := ngn.GetShortDesc(ctx) if gn != nil { notes.Add(jsonutils.NewString(gn.IpAddr), "prev_ip") } @@ -2476,11 +2476,23 @@ func (self *SGuest) PerformChangeIpaddr( if self.Hypervisor == api.HYPERVISOR_KVM && restartNetwork && (self.Status == api.VM_RUNNING || self.Status == api.VM_BLOCK_STREAM) { taskData.Set("restart_network", jsonutils.JSONTrue) taskData.Set("prev_ip", jsonutils.NewString(gn.IpAddr)) - taskData.Set("prev_mac", jsonutils.NewString(newMacAddr)) + taskData.Set("prev_mac", jsonutils.NewString(gn.MacAddr)) net := ngn.GetNetwork() taskData.Set("is_vpc_network", jsonutils.NewBool(net.isOneCloudVpcNetwork())) - taskData.Set("ip_mask", jsonutils.NewString(ipMask)) - taskData.Set("gateway", jsonutils.NewString(newGateway)) + + networkJsonDesc := ngn.getJsonDesc() + + taskData.Set("ip_mask", jsonutils.NewString(fmt.Sprintf("%s/%d", networkJsonDesc.Ip, networkJsonDesc.Masklen))) + if ngn.IsDefault && len(networkJsonDesc.Gateway) > 0 { + taskData.Set("gateway", jsonutils.NewString(networkJsonDesc.Gateway)) + } + if len(ngn.Ip6Addr) > 0 { + taskData.Set("ip_mask6", jsonutils.NewString(fmt.Sprintf("%s/%d", networkJsonDesc.Ip6, networkJsonDesc.Masklen6))) + if ngn.IsDefault && len(networkJsonDesc.Gateway6) > 0 { + taskData.Set("gateway6", jsonutils.NewString(networkJsonDesc.Gateway6)) + } + } + if self.Status == api.VM_BLOCK_STREAM { taskData.Set("in_block_stream", jsonutils.JSONTrue) } diff --git a/pkg/compute/tasks/guest_qga_restart_network_task.go b/pkg/compute/tasks/guest_qga_restart_network_task.go index 8c3cdf1bcc2..c5de1362853 100644 --- a/pkg/compute/tasks/guest_qga_restart_network_task.go +++ b/pkg/compute/tasks/guest_qga_restart_network_task.go @@ -16,8 +16,10 @@ package tasks import ( "context" + "time" "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" @@ -44,36 +46,51 @@ func (self *GuestQgaRestartNetworkTask) OnRestartNetwork(ctx context.Context, gu device, _ := self.Params.GetString("device") ipMask, _ := self.Params.GetString("ip_mask") gateway, _ := self.Params.GetString("gateway") + ipMask6, _ := self.Params.GetString("ip_mask6") + gateway6, _ := self.Params.GetString("gateway6") prevIp, _ := self.Params.GetString("prev_ip") inBlockStream, _ := self.Params.Bool("in_block_stream") - _, err := self.requestSetNetwork(ctx, guest, device, ipMask, gateway) + _, err := self.requestSetNetwork(ctx, guest, device, ipMask, gateway, ipMask6, gateway6) + var errs []error + const MAX_TRIES = 3 //the first set maybe fail,if failed, try again - if err != nil { + for err != nil && len(errs) < MAX_TRIES { + errs = append(errs, err) logclient.AddActionLogWithStartable(self, guest, logclient.ACT_RESTART_NETWORK, err, self.UserCred, false) - _, err = self.requestSetNetwork(ctx, guest, device, ipMask, gateway) + _, err = self.requestSetNetwork(ctx, guest, device, ipMask, gateway, ipMask6, gateway6) if err != nil { - logclient.AddActionLogWithStartable(self, guest, logclient.ACT_RESTART_NETWORK, err, self.UserCred, false) - self.taskFailed(ctx, guest, prevIp, inBlockStream, err) - return + time.Sleep(time.Second) + continue + } else { + errs = nil + break } } + + if len(errs) > 0 { + self.taskFailed(ctx, guest, prevIp, inBlockStream, errors.NewAggregate(errs)) + return + } + logclient.AddActionLogWithStartable(self, guest, logclient.ACT_QGA_NETWORK_SUCCESS, "qga restart network success", self.UserCred, true) guest.UpdateQgaStatus(api.QGA_STATUS_AVAILABLE) guest.StartSyncstatus(ctx, self.UserCred, "") self.SetStageComplete(ctx, nil) } -func (self *GuestQgaRestartNetworkTask) requestSetNetwork(ctx context.Context, guest *models.SGuest, device string, ipMask string, gateway string) (jsonutils.JSONObject, error) { +func (self *GuestQgaRestartNetworkTask) requestSetNetwork(ctx context.Context, guest *models.SGuest, device string, ipMask, gateway, ipMask6, gateway6 string) (jsonutils.JSONObject, error) { host, err := guest.GetHost() if err != nil { self.taskFailed(ctx, guest, "", false, err) return nil, err } inputQgaNet := &api.ServerQgaSetNetworkInput{ - Device: device, - Ipmask: ipMask, - Gateway: gateway, + Device: device, + Ipmask: ipMask, + Gateway: gateway, + Ipmask6: ipMask6, + Gateway6: gateway6, } // if success, log network related information diff --git a/pkg/compute/tasks/guest_sync_task.go b/pkg/compute/tasks/guest_sync_task.go index 76f10a03986..b60a3cafc15 100644 --- a/pkg/compute/tasks/guest_sync_task.go +++ b/pkg/compute/tasks/guest_sync_task.go @@ -85,11 +85,10 @@ func (self *GuestSyncConfTask) StartRestartNetworkTask(ctx context.Context, gues log.Errorf("unable to get ip_mask when restart_network is true when sync guest") return } - gateway, err := self.Params.GetString("gateway") - if err != nil { - log.Errorf("unable to get gateway when restart_network is true when sync guest") - return - } + gateway, _ := self.Params.GetString("gateway") + ipMask6, _ := self.Params.GetString("ip_mask6") + gateway6, _ := self.Params.GetString("gateway6") + isVpcNetwork := jsonutils.QueryBoolean(self.Params, "is_vpc_network", false) // try use qga restart network @@ -116,7 +115,7 @@ func (self *GuestSyncConfTask) StartRestartNetworkTask(ctx context.Context, gues time.Sleep(10 * time.Second) } return guest.StartQgaRestartNetworkTask( - ctx, self.UserCred, "", ifnameDevice, ipMask, gateway, prevIp, inBlockStream) + ctx, self.UserCred, "", ifnameDevice, ipMask, gateway, ipMask6, gateway6, prevIp, inBlockStream) }() if err != nil { log.Errorf("guest %s failed start qga restart network task: %s", guest.GetName(), err) diff --git a/pkg/hostman/guestman/guesthandlers/guesthandler.go b/pkg/hostman/guestman/guesthandlers/guesthandler.go index 73e7512aa23..355c36ceab0 100644 --- a/pkg/hostman/guestman/guesthandlers/guesthandler.go +++ b/pkg/hostman/guestman/guesthandlers/guesthandler.go @@ -932,14 +932,13 @@ func qgaSetNetwork(ctx context.Context, userCred mcclient.TokenCredential, sid s if input.Ipmask == "" { return nil, httperrors.NewMissingParameterError("ipmask") } - if input.Gateway == "" { - return nil, httperrors.NewMissingParameterError("gateway") - } qgaNetMod := &monitor.NetworkModify{ - Device: input.Device, - Ipmask: input.Ipmask, - Gateway: input.Gateway, + Device: input.Device, + Ipmask: input.Ipmask, + Gateway: input.Gateway, + Ipmask6: input.Ipmask6, + Gateway6: input.Gateway6, } return gm.QgaSetNetwork(qgaNetMod, sid, input.Timeout) } diff --git a/pkg/hostman/monitor/qga/qga.go b/pkg/hostman/monitor/qga/qga.go index 862d9faabab..dd185f19615 100644 --- a/pkg/hostman/monitor/qga/qga.go +++ b/pkg/hostman/monitor/qga/qga.go @@ -421,12 +421,24 @@ func (qga *QemuGuestAgent) QgaSetWindowsNetwork(qgaNetMod *monitor.NetworkModify if err != nil { return err } + + var gatewayStr string + if len(qgaNetMod.Gateway) > 0 { + gatewayStr = fmt.Sprintf("gateway=%s", qgaNetMod.Gateway) + } networkCmd := fmt.Sprintf( - "netsh interface ip set address name=\"%s\" source=static addr=%s mask=%s gateway=%s & "+ + "netsh interface ip set address name=\"%s\" source=static addr=%s mask=%s %s & "+ "netsh interface ip set address name=\"%s\" dhcp", - qgaNetMod.Device, ip, subnetMask, qgaNetMod.Gateway, qgaNetMod.Device, + qgaNetMod.Device, ip, subnetMask, gatewayStr, qgaNetMod.Device, ) + if len(qgaNetMod.Ipmask6) > 0 { + networkCmd += fmt.Sprintf(" & netsh interface ipv6 set address \"%s\" %s", qgaNetMod.Device, qgaNetMod.Ipmask6) + if len(qgaNetMod.Gateway6) > 0 { + networkCmd += fmt.Sprintf(" & netsh interface ipv6 set route ::/0 \"%s\" %s", qgaNetMod.Device, qgaNetMod.Gateway6) + } + } + log.Infof("networkCmd: %s", networkCmd) arg := []string{"/C", networkCmd} cmdExecNet := &monitor.Command{ @@ -447,7 +459,17 @@ func (qga *QemuGuestAgent) QgaSetWindowsNetwork(qgaNetMod *monitor.NetworkModify } func (qga *QemuGuestAgent) QgaSetLinuxNetwork(qgaNetMod *monitor.NetworkModify) error { - args := []string{"-c", fmt.Sprintf("/sbin/dhclient -r %s && /sbin/dhclient -1 %s", qgaNetMod.Device, qgaNetMod.Device)} + cmd := fmt.Sprintf("/usr/sbin/ip addr flush dev %s && /usr/sbin/ip addr add %s dev %s", qgaNetMod.Device, qgaNetMod.Ipmask, qgaNetMod.Device) + if len(qgaNetMod.Gateway) > 0 { + cmd += fmt.Sprintf(" && /usr/sbin/ip route add default via %s dev %s", qgaNetMod.Gateway, qgaNetMod.Device) + } + if len(qgaNetMod.Ipmask6) > 0 { + cmd += fmt.Sprintf(" && /usr/sbin/ip -6 addr add %s dev %s", qgaNetMod.Ipmask6, qgaNetMod.Device) + if len(qgaNetMod.Gateway6) > 0 { + cmd += fmt.Sprintf(" && /usr/sbin/ip -6 route add default via %s dev %s", qgaNetMod.Gateway6, qgaNetMod.Device) + } + } + args := []string{"-c", "'" + cmd + "'"} _, err := qga.GuestExecCommand("/bin/bash", args, []string{}, "", false) return err } diff --git a/pkg/hostman/monitor/qmp.go b/pkg/hostman/monitor/qmp.go index dfc554d7610..d4da0504983 100644 --- a/pkg/hostman/monitor/qmp.go +++ b/pkg/hostman/monitor/qmp.go @@ -85,6 +85,9 @@ type NetworkModify struct { Device string `json:"device"` Ipmask string `json:"ipmask"` Gateway string `json:"gateway"` + + Ipmask6 string `json:"ipmask6"` + Gateway6 string `json:"gateway6"` } type Version struct {