From f739c8ff0e1be8373f58828234ac854db06a6943 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Wed, 1 Jul 2020 14:14:37 +0800 Subject: [PATCH] fix: validate candiate ip for sync-fix-nics --- pkg/apis/compute/guests.go | 5 +++++ pkg/compute/models/guest_actions.go | 31 +++++++++++++++++++++++------ pkg/compute/models/networks.go | 7 +++++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index eecc0364fa..abdf2ecaa7 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -340,3 +340,8 @@ type GuestSaveToTemplateInput struct { // The generate name of guest template GenerateName string `json:"generate_name"` } + +type GuestSyncFixNicsInput struct { + // 需要修正的IP地址列表 + Ip []string `json:"ip"` +} diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 8fba9c4caf..fc39f783e6 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -4066,14 +4066,14 @@ func (self *SGuest) createConvertedServer( func (self *SGuest) AllowPerformSyncFixNics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, - data jsonutils.JSONObject) bool { + input api.GuestSyncFixNicsInput) bool { return db.IsAdminAllowPerform(userCred, self, "sync-fix-nics") } func (self *SGuest) PerformSyncFixNics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, - data jsonutils.JSONObject) (jsonutils.JSONObject, error) { + input api.GuestSyncFixNicsInput) (jsonutils.JSONObject, error) { iVM, err := self.GetIVM() if err != nil { return nil, httperrors.NewGeneralError(err) @@ -4086,11 +4086,30 @@ func (self *SGuest) PerformSyncFixNics(ctx context.Context, if host == nil { return nil, httperrors.NewInternalServerError("host not found???") } - iplistArray, err := data.Get("ip") - if err != nil { - return nil, httperrors.NewInputParameterError("missing field ip, list of ip") + iplist := input.Ip + // validate iplist + if len(iplist) == 0 { + return nil, httperrors.NewInputParameterError("empty ip list") + } + for _, ip := range iplist { + // ip is reachable on host + net, err := host.getNetworkOfIPOnHost(ip) + if err != nil { + return nil, httperrors.NewInputParameterError("Unreachable IP %s: %s", ip, err) + } + // check ip is reserved or free + rip := ReservedipManager.GetReservedIP(net, ip) + if rip == nil { + // check ip is free + nip, err := net.GetFreeIPWithLock(ctx, userCred, nil, nil, ip, "", false) + if err != nil { + return nil, httperrors.NewInputParameterError("Unavailable IP %s: occupied", ip) + } + if nip != ip { + return nil, httperrors.NewInputParameterError("Unavailable IP %s: occupied", ip) + } + } } - iplist := iplistArray.(*jsonutils.JSONArray).GetStringArray() errs := make([]error, 0) for i := range vnics { ip := vnics[i].GetIP() diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index e62f6787d2..dd4aa482b1 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -430,6 +430,13 @@ func (self *SNetwork) getFreeIP(addrTable map[string]bool, recentUsedAddrTable m return "", httperrors.NewInsufficientResourceError("Out of IP address") } +func (self *SNetwork) GetFreeIPWithLock(ctx context.Context, userCred mcclient.TokenCredential, addrTable map[string]bool, recentUsedAddrTable map[string]bool, candidate string, allocDir api.IPAllocationDirection, reserved bool) (string, error) { + lockman.LockObject(ctx, self) + defer lockman.ReleaseObject(ctx, self) + + return self.GetFreeIP(ctx, userCred, addrTable, recentUsedAddrTable, candidate, allocDir, reserved) +} + func (self *SNetwork) GetFreeIP(ctx context.Context, userCred mcclient.TokenCredential, addrTable map[string]bool, recentUsedAddrTable map[string]bool, candidate string, allocDir api.IPAllocationDirection, reserved bool) (string, error) { // if reserved true, first try find IP in reserved IP pool if reserved {