From 2004e00a4200161942f0ce6ec6834f4a84d3a627 Mon Sep 17 00:00:00 2001 From: Qiu Jian Date: Mon, 8 Nov 2021 11:58:45 +0800 Subject: [PATCH] fix: qemu extra options support multiple values --- pkg/apis/compute/guests.go | 29 +++++++++++++++++++ pkg/compute/models/guest_actions.go | 40 +++++++++++++++++++------- pkg/hostman/guestman/qemu-arm.go | 5 +--- pkg/hostman/guestman/qemu-kvmhelper.go | 22 +++++++++++--- 4 files changed, 77 insertions(+), 19 deletions(-) diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index 259ccf55e6..7fc7cf8afd 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -19,9 +19,11 @@ import ( "time" "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/apis/billing" + "yunion.io/x/onecloud/pkg/httperrors" ) type ServerListInput struct { @@ -700,3 +702,30 @@ type ServerChangeDiskStorageInternalInput struct { StorageId string `json:"storage_id"` TargetDiskId string `json:"target_disk_id"` } + +type ServerSetExtraOptionInput struct { + Key string `json:"key"` + Value string `json:"value"` +} + +func (o ServerSetExtraOptionInput) Validate() error { + if len(o.Key) == 0 { + return errors.Wrap(httperrors.ErrBadRequest, "empty key") + } + if len(o.Value) == 0 { + return errors.Wrap(httperrors.ErrBadRequest, "empty value") + } + return nil +} + +type ServerDelExtraOptionInput struct { + Key string `json:"key"` + Value string `json:"value"` +} + +func (o ServerDelExtraOptionInput) Validate() error { + if len(o.Key) == 0 { + return errors.Wrap(httperrors.ErrBadRequest, "empty key") + } + return nil +} diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index 56a5ecd238..e46bb82f95 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -3662,18 +3662,22 @@ func (self *SGuest) StartReconcileBackup(ctx context.Context, userCred mcclient. return nil } -func (self *SGuest) AllowPerformSetExtraOption(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { +func (self *SGuest) AllowPerformSetExtraOption(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerSetExtraOptionInput) bool { return db.IsAdminAllowPerform(userCred, self, "set-extra-option") } -func (self *SGuest) PerformSetExtraOption(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - key, err := data.GetString("key") +func (self *SGuest) PerformSetExtraOption(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerSetExtraOptionInput) (jsonutils.JSONObject, error) { + err := input.Validate() if err != nil { - return nil, httperrors.NewMissingParameterError("key") + return nil, errors.Wrap(err, "input.Validate") } - value, _ := data.GetString("value") extraOptions := self.GetExtraOptions(userCred) - extraOptions.Set(key, jsonutils.NewString(value)) + optVal := make([]string, 0) + extraOptions.Unmarshal(&optVal, input.Key) + if !utils.IsInStringArray(input.Value, optVal) { + optVal = append(optVal, input.Value) + } + extraOptions.Set(input.Key, jsonutils.Marshal(optVal)) return nil, self.SetExtraOptions(ctx, userCred, extraOptions) } @@ -3690,17 +3694,31 @@ func (self *SGuest) SetExtraOptions(ctx context.Context, userCred mcclient.Token return self.SetMetadata(ctx, "extra_options", extraOptions, userCred) } -func (self *SGuest) AllowPerformDelExtraOption(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool { +func (self *SGuest) AllowPerformDelExtraOption(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerDelExtraOptionInput) bool { return db.IsAdminAllowPerform(userCred, self, "del-extra-option") } -func (self *SGuest) PerformDelExtraOption(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { - key, err := data.GetString("key") +func (self *SGuest) PerformDelExtraOption(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerDelExtraOptionInput) (jsonutils.JSONObject, error) { + err := input.Validate() if err != nil { - return nil, httperrors.NewMissingParameterError("key") + return nil, errors.Wrap(err, "input.Validate") } extraOptions := self.GetExtraOptions(userCred) - extraOptions.Remove(key) + var newOpt []string + if len(input.Value) > 0 { + optVal := make([]string, 0) + extraOptions.Unmarshal(&optVal, input.Key) + for _, v := range optVal { + if v != input.Value { + newOpt = append(newOpt, v) + } + } + } + if len(newOpt) > 0 { + extraOptions.Set(input.Key, jsonutils.Marshal(newOpt)) + } else if extraOptions.Contains(input.Key) { + extraOptions.Remove(input.Key) + } return nil, self.SetExtraOptions(ctx, userCred, extraOptions) } diff --git a/pkg/hostman/guestman/qemu-arm.go b/pkg/hostman/guestman/qemu-arm.go index e8494aeabf..dbe72ba74e 100644 --- a/pkg/hostman/guestman/qemu-arm.go +++ b/pkg/hostman/guestman/qemu-arm.go @@ -303,10 +303,7 @@ function nic_mtu() { } cmd += fmt.Sprintf(" -pidfile %s", s.GetPidFilePath()) - extraOptions, _ := s.Desc.GetMap("extra_options") - for k, v := range extraOptions { - cmd += fmt.Sprintf(" -%s %s", k, v.String()) - } + cmd += s.extraOptions() // cmd += s.getQgaDesc() if fileutils2.Exists("/dev/random") { diff --git a/pkg/hostman/guestman/qemu-kvmhelper.go b/pkg/hostman/guestman/qemu-kvmhelper.go index 688df29144..61ae9066b5 100644 --- a/pkg/hostman/guestman/qemu-kvmhelper.go +++ b/pkg/hostman/guestman/qemu-kvmhelper.go @@ -361,6 +361,23 @@ func (s *SKVMGuestInstance) generateStartScript(data *jsonutils.JSONDict) (strin } } +func (s *SKVMGuestInstance) extraOptions() string { + cmd := " " + extraOptions, _ := s.Desc.GetMap("extra_options") + for k, v := range extraOptions { + switch jsonV := v.(type) { + case *jsonutils.JSONArray: + for i := 0; i < jsonV.Size(); i++ { + vAtI, _ := jsonV.GetAt(i) + cmd += fmt.Sprintf(" -%s %s", k, vAtI.String()) + } + default: + cmd += fmt.Sprintf(" -%s %s", k, v.String()) + } + } + return cmd +} + func (s *SKVMGuestInstance) _generateStartScript(data *jsonutils.JSONDict) (string, error) { var ( uuid, _ = s.Desc.GetString("uuid") @@ -671,10 +688,7 @@ function nic_mtu() { } cmd += fmt.Sprintf(" -pidfile %s", s.GetPidFilePath()) - extraOptions, _ := s.Desc.GetMap("extra_options") - for k, v := range extraOptions { - cmd += fmt.Sprintf(" -%s %s", k, v.String()) - } + cmd += s.extraOptions() cmd += s.getQgaDesc() if fileutils2.Exists("/dev/random") {