diff --git a/pkg/apis/compute/guest_const.go b/pkg/apis/compute/guest_const.go index de9b30b3cb..098a4def1a 100644 --- a/pkg/apis/compute/guest_const.go +++ b/pkg/apis/compute/guest_const.go @@ -183,6 +183,15 @@ const ( const ( VM_MACHINE_TYPE_PC = "pc" VM_MACHINE_TYPE_Q35 = "q35" + + VM_MACHINE_TYPE_ARM_VIRT = "virt" + + VM_VDI_PROTOCOL_VNC = "vnc" + VM_VDI_PROTOCOL_SPICE = "spice" + + VM_VIDEO_STANDARD = "std" + VM_VIDEO_QXL = "qxl" + VM_VIDEO_VIRTIO = "virtio" ) var VM_RUNNING_STATUS = []string{VM_START_START, VM_STARTING, VM_RUNNING, VM_BLOCK_STREAM, VM_BLOCK_STREAM_FAIL} diff --git a/pkg/compute/guestdrivers/base.go b/pkg/compute/guestdrivers/base.go index b50940b7a2..3a30d8ee20 100644 --- a/pkg/compute/guestdrivers/base.go +++ b/pkg/compute/guestdrivers/base.go @@ -411,8 +411,12 @@ func (self *SBaseGuestDriver) RequestLiveMigrate(ctx context.Context, guest *mod return fmt.Errorf("Not Implement RequestLiveMigrate") } -func (self *SBaseGuestDriver) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerUpdateInput) error { - return nil +func (self *SVirtualizedGuestDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *api.ServerCreateInput) (*api.ServerCreateInput, error) { + return input, nil +} + +func (self *SBaseGuestDriver) ValidateUpdateData(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, input api.ServerUpdateInput) (api.ServerUpdateInput, error) { + return input, nil } func (self *SBaseGuestDriver) RequestRemoteUpdate(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, replaceTags bool) error { diff --git a/pkg/compute/guestdrivers/kvm.go b/pkg/compute/guestdrivers/kvm.go index 15525d523b..2f183033ed 100644 --- a/pkg/compute/guestdrivers/kvm.go +++ b/pkg/compute/guestdrivers/kvm.go @@ -816,3 +816,102 @@ func (self *SKVMGuestDriver) RequestChangeDiskStorage(ctx context.Context, userC _, _, err = httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, body, false) return err } + +func (self *SKVMGuestDriver) validateVdiProtocol(vdi string) error { + if !utils.IsInStringArray(vdi, []string{api.VM_VDI_PROTOCOL_VNC, api.VM_VDI_PROTOCOL_SPICE}) { + return httperrors.NewInputParameterError("unsupported vdi protocol") + } + return nil +} + +func (self *SKVMGuestDriver) validateVGA(ovdi, ovga string, nvdi, nvga *string) (vdi, vga string) { + vdi = ovdi + if nvdi != nil { + vdi = *nvdi + } + if vdi != api.VM_VDI_PROTOCOL_VNC && vdi != api.VM_VDI_PROTOCOL_SPICE { + vdi = api.VM_VDI_PROTOCOL_VNC + } + var candidateVga []string + switch vdi { + case api.VM_VDI_PROTOCOL_VNC: + candidateVga = []string{api.VM_VIDEO_STANDARD, api.VM_VIDEO_QXL, api.VM_VIDEO_VIRTIO} + case api.VM_VDI_PROTOCOL_SPICE: + candidateVga = []string{api.VM_VIDEO_QXL, api.VM_VIDEO_VIRTIO} + } + vga = ovga + if nvga != nil { + vga = *nvga + } + if !utils.IsInStringArray(vga, candidateVga) { + vga = candidateVga[0] + } + return +} + +func (self *SKVMGuestDriver) validateMachineType(machine string, osArch string) error { + var candidate []string + switch osArch { + case apis.OS_ARCH_AARCH64: + candidate = []string{api.VM_MACHINE_TYPE_ARM_VIRT} + default: + candidate = []string{api.VM_MACHINE_TYPE_PC, api.VM_MACHINE_TYPE_Q35} + } + if !utils.IsInStringArray(machine, candidate) { + return httperrors.NewInputParameterError("Invalid machine type %s", machine) + } + return nil +} + +func (self *SKVMGuestDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *api.ServerCreateInput) (*api.ServerCreateInput, error) { + input, err := self.SVirtualizedGuestDriver.ValidateCreateData(ctx, userCred, input) + if err != nil { + return input, errors.Wrap(err, "SVirtualizedGuestDriver.ValidateCreateData") + } + if input.Vdi != "" { + err = self.validateVdiProtocol(input.Vdi) + if err != nil { + return nil, errors.Wrap(err, "validateVdiProtocol") + } + } + + if input.Vdi != "" || input.Vga != "" { + input.Vdi, input.Vga = self.validateVGA("", "", &input.Vdi, &input.Vga) + } + + if input.Machine != "" { + if err := self.validateMachineType(input.Machine, input.OsArch); err != nil { + return nil, errors.Wrap(err, "validateMachineType") + } + } + return input, nil +} + +func (self *SKVMGuestDriver) ValidateUpdateData(ctx context.Context, guest *models.SGuest, userCred mcclient.TokenCredential, input api.ServerUpdateInput) (api.ServerUpdateInput, error) { + input, err := self.SVirtualizedGuestDriver.ValidateUpdateData(ctx, guest, userCred, input) + if err != nil { + return input, errors.Wrap(err, "SVirtualizedGuestDriver.ValidateUpdateData") + } + + if input.Vdi != nil { + err = self.validateVdiProtocol(*input.Vdi) + if err != nil { + return input, errors.Wrap(err, "validateVdiProtocol") + } + } + + if input.Vga != nil || input.Vdi != nil { + vdi, vga := self.validateVGA(guest.Vdi, guest.Vga, input.Vdi, input.Vga) + input.Vdi = &vdi + input.Vga = &vga + } + + if input.Machine != nil { + err := self.validateMachineType(*input.Machine, guest.OsArch) + if err != nil { + return input, errors.Wrap(err, "ValidateMachineType") + } + } + + return input, nil +} diff --git a/pkg/compute/guestdrivers/virtualization.go b/pkg/compute/guestdrivers/virtualization.go index 7a3f1b76c8..c9c033d83b 100644 --- a/pkg/compute/guestdrivers/virtualization.go +++ b/pkg/compute/guestdrivers/virtualization.go @@ -265,31 +265,6 @@ func (self *SVirtualizedGuestDriver) RequestStopGuestForDelete(ctx context.Conte return nil } -func (self *SVirtualizedGuestDriver) ValidateMachineType(machine string) error { - if !utils.IsInStringArray(machine, []string{api.VM_MACHINE_TYPE_PC, api.VM_MACHINE_TYPE_Q35}) { - return httperrors.NewBadRequestError("Invalid machine %q", machine) - } - return nil -} - -func (self *SVirtualizedGuestDriver) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, input *api.ServerCreateInput) (*api.ServerCreateInput, error) { - if input.Machine != "" { - if err := self.ValidateMachineType(input.Machine); err != nil { - return nil, err - } - } - return input, nil -} - -func (self *SVirtualizedGuestDriver) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerUpdateInput) error { - if input.Machine != nil { - if err := self.ValidateMachineType(*input.Machine); err != nil { - return err - } - } - return nil -} - func (self *SVirtualizedGuestDriver) ValidateCreateDataOnHost(ctx context.Context, userCred mcclient.TokenCredential, bmName string, host *models.SHost, input *api.ServerCreateInput) (*api.ServerCreateInput, error) { if host.HostStatus != api.HOST_ONLINE { return nil, httperrors.NewInvalidStatusError("Host %s is not online", bmName) diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index 85cda2e3b1..75350666f0 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -205,7 +205,7 @@ type IGuestDriver interface { RequestMigrate(ctx context.Context, guest *SGuest, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, task taskman.ITask) error RequestLiveMigrate(ctx context.Context, guest *SGuest, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, task taskman.ITask) error - ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, input api.ServerUpdateInput) error + ValidateUpdateData(ctx context.Context, guest *SGuest, userCred mcclient.TokenCredential, input api.ServerUpdateInput) (api.ServerUpdateInput, error) RequestRemoteUpdate(ctx context.Context, guest *SGuest, userCred mcclient.TokenCredential, replaceTags bool) error RequestOpenForward(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest, req *guestdriver_types.OpenForwardRequest) (*guestdriver_types.OpenForwardResponse, error) diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 112743ede2..ae2875b3a4 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -985,43 +985,12 @@ func (self *SGuest) ValidateUpdateData(ctx context.Context, userCred mcclient.To return input, httperrors.NewInputParameterError("name is too short") } - if input.Vdi != nil { - if !utils.IsInStringArray(*input.Vdi, []string{"vnc", "spice"}) { - return input, httperrors.NewInputParameterError("unsupported vdi protocol") - } - } - - if input.Vga != nil || input.Vdi != nil { - vdi := self.Vdi - if input.Vdi != nil { - vdi = *input.Vdi - } - if vdi != "vnc" && vdi != "spice" { - vdi = "vnc" - input.Vdi = &vdi - } - var candidateVga []string - switch vdi { - case "vnc": - candidateVga = []string{"std", "qxl", "virtio"} - case "spice": - candidateVga = []string{"qxl", "virtio"} - } - vga := self.Vga - if input.Vga != nil { - vga = *input.Vga - } - if !utils.IsInStringArray(vga, candidateVga) { - vga = candidateVga[0] - input.Vga = &vga - } - } - - if err := self.GetDriver().ValidateUpdateData(ctx, userCred, input); err != nil { - return input, err - } - var err error + input, err = self.GetDriver().ValidateUpdateData(ctx, self, userCred, input) + if err != nil { + return input, errors.Wrap(err, "GetDriver().ValidateUpdateData") + } + input.VirtualResourceBaseUpdateInput, err = self.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.VirtualResourceBaseUpdateInput) if err != nil { return input, errors.Wrap(err, "SVirtualResourceBase.ValidateUpdateData")