mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-01 15:07:17 +08:00
feat(region,host,host-deployer): support set uefi boot order (#22560)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/host-deployer-base:1.4.9
|
||||
FROM registry.cn-beijing.aliyuncs.com/yunionio/host-deployer-base:1.4.10
|
||||
|
||||
MAINTAINER "Yaoqi Wan wanyaoqi@yunionyun.com"
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !ignore_autogenerated
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
|
||||
@@ -261,6 +261,9 @@ const (
|
||||
VM_VIDEO_STANDARD = "std"
|
||||
VM_VIDEO_QXL = "qxl"
|
||||
VM_VIDEO_VIRTIO = "virtio"
|
||||
|
||||
VM_BOOT_MODE_BIOS = "BIOS"
|
||||
VM_BOOT_MODE_UEFI = "UEFI"
|
||||
)
|
||||
|
||||
var VM_RUNNING_STATUS = []string{VM_START_START, VM_STARTING, VM_RUNNING, VM_BLOCK_STREAM, VM_BLOCK_STREAM_FAIL}
|
||||
|
||||
@@ -666,6 +666,9 @@ func (self *SKVMGuestDriver) RequestSyncConfigOnHost(ctx context.Context, guest
|
||||
if fw_only, _ := task.GetParams().Bool("fw_only"); fw_only {
|
||||
body.Add(jsonutils.JSONTrue, "fw_only")
|
||||
}
|
||||
if setUefiBootOrder, _ := task.GetParams().Bool("set_uefi_boot_order"); setUefiBootOrder {
|
||||
body.Add(jsonutils.JSONTrue, "set_uefi_boot_order")
|
||||
}
|
||||
url := fmt.Sprintf("%s/servers/%s/sync", host.ManagerUri, guest.Id)
|
||||
header := self.getTaskRequestHeader(task)
|
||||
_, _, err = httputils.JSONRequest(httputils.GetDefaultClient(), ctx, "POST", url, header, body, false)
|
||||
|
||||
@@ -6394,6 +6394,14 @@ func (self *SGuest) PerformSetBootIndex(ctx context.Context, userCred mcclient.T
|
||||
}
|
||||
}
|
||||
|
||||
if self.Bios == api.VM_BOOT_MODE_UEFI {
|
||||
data := jsonutils.NewDict()
|
||||
data.Set("set_uefi_boot_order", jsonutils.JSONTrue)
|
||||
if err := self.startSyncTask(ctx, userCred, false, "", data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1072,7 +1072,8 @@ func (m *SGuestManager) GuestSync(ctx context.Context, params interface{}) (json
|
||||
}
|
||||
|
||||
fwOnly := jsonutils.QueryBoolean(syncParams.Body, "fw_only", false)
|
||||
return guest.SyncConfig(ctx, guestDesc, fwOnly)
|
||||
setUefiBootOrder := jsonutils.QueryBoolean(syncParams.Body, "set_uefi_boot_order", false)
|
||||
return guest.SyncConfig(ctx, guestDesc, fwOnly, setUefiBootOrder)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -1069,7 +1069,7 @@ func (s *sPodGuestInstance) PostLoad(m *SGuestManager) error {
|
||||
return LoadGuestCpuset(m, s)
|
||||
}
|
||||
|
||||
func (s *sPodGuestInstance) SyncConfig(ctx context.Context, guestDesc *desc.SGuestDesc, fwOnly bool) (jsonutils.JSONObject, error) {
|
||||
func (s *sPodGuestInstance) SyncConfig(ctx context.Context, guestDesc *desc.SGuestDesc, fwOnly, setUefiBootOrder bool) (jsonutils.JSONObject, error) {
|
||||
if err := SaveDesc(s, guestDesc); err != nil {
|
||||
return nil, errors.Wrap(err, "SaveDesc")
|
||||
}
|
||||
|
||||
@@ -2520,9 +2520,7 @@ func (s *SKVMGuestInstance) onNicChange(oldNic, newNic *desc.SGuestNetwork) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) SyncConfig(
|
||||
ctx context.Context, guestDesc *desc.SGuestDesc, fwOnly bool,
|
||||
) (jsonutils.JSONObject, error) {
|
||||
func (s *SKVMGuestInstance) SyncConfig(ctx context.Context, guestDesc *desc.SGuestDesc, fwOnly, setUefiBootOrder bool) (jsonutils.JSONObject, error) {
|
||||
var delDisks, addDisks []*desc.SGuestDisk
|
||||
var delNetworks, addNetworks []*desc.SGuestNetwork
|
||||
var changedNetworks [][2]*desc.SGuestNetwork
|
||||
@@ -2553,6 +2551,12 @@ func (s *SKVMGuestInstance) SyncConfig(
|
||||
}
|
||||
|
||||
if !s.IsRunning() {
|
||||
if setUefiBootOrder && s.getBios() == api.VM_BOOT_MODE_UEFI {
|
||||
if err := s.setUefiBootOrder(ctx); err != nil {
|
||||
log.Errorf("failed set uefi boot order %s", err)
|
||||
return nil, errors.Wrap(err, "setUefiBootOrder")
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -2602,6 +2606,13 @@ func (s *SKVMGuestInstance) SyncConfig(
|
||||
}
|
||||
}
|
||||
|
||||
if setUefiBootOrder && s.getBios() == api.VM_BOOT_MODE_UEFI {
|
||||
if err := s.setUefiBootOrder(ctx); err != nil {
|
||||
log.Errorf("failed set uefi boot order %s", err)
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) == 0 {
|
||||
hostutils.TaskComplete(ctx, nil)
|
||||
} else {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package guestman
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"path"
|
||||
@@ -36,6 +37,9 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/desc"
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestman/qemu"
|
||||
qemucerts "yunion.io/x/onecloud/pkg/hostman/guestman/qemu/certs"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/uefi"
|
||||
"yunion.io/x/onecloud/pkg/hostman/monitor"
|
||||
"yunion.io/x/onecloud/pkg/hostman/options"
|
||||
"yunion.io/x/onecloud/pkg/hostman/storageman"
|
||||
@@ -244,7 +248,7 @@ func (s *SKVMGuestInstance) getMachine() string {
|
||||
func (s *SKVMGuestInstance) getBios() string {
|
||||
bios := s.Desc.Bios
|
||||
if bios == "" {
|
||||
bios = "bios"
|
||||
bios = api.VM_BOOT_MODE_BIOS
|
||||
}
|
||||
return bios
|
||||
}
|
||||
@@ -501,6 +505,7 @@ function nic_mtu() {
|
||||
if s.Desc.Bios == qemu.BIOS_UEFI {
|
||||
if len(input.OVMFPath) == 0 {
|
||||
input.OVMFPath = options.HostOptions.OvmfPath
|
||||
input.OVMFVarsPath = options.HostOptions.OvmfVarsPath
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1116,3 +1121,69 @@ func (s *SKVMGuestInstance) vfioDevCount() int {
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) getOvmfVarsPath() string {
|
||||
return path.Join(s.HomeDir(), "OVMF_VARS.fd")
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) getDiskBootOrderType(driver string) uefi.OvmfDevicePathType {
|
||||
switch driver {
|
||||
case qemu.DISK_DRIVER_VIRTIO:
|
||||
return uefi.DEVICE_TYPE_PCI
|
||||
case qemu.DISK_DRIVER_SCSI, qemu.DISK_DRIVER_PVSCSI:
|
||||
return uefi.DEVICE_TYPE_SCSI
|
||||
case qemu.DISK_DRIVER_IDE:
|
||||
if s.manager.host.IsAarch64() {
|
||||
return uefi.DEVICE_TYPE_SCSI
|
||||
}
|
||||
return uefi.DEVICE_TYPE_IDE
|
||||
case qemu.DISK_DRIVER_SATA:
|
||||
if s.manager.host.IsAarch64() {
|
||||
return uefi.DEVICE_TYPE_SCSI
|
||||
}
|
||||
return uefi.DEVICE_TYPE_SATA
|
||||
}
|
||||
return uefi.DEVICE_TYPE_UNKNOWN
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) getCdromBootOrder() uefi.OvmfDevicePathType {
|
||||
if s.manager.host.IsAarch64() {
|
||||
return uefi.DEVICE_TYPE_SCSI_CDROM
|
||||
}
|
||||
return uefi.DEVICE_TYPE_CDROM
|
||||
}
|
||||
|
||||
func (s *SKVMGuestInstance) setUefiBootOrder(ctx context.Context) error {
|
||||
params := &deployapi.OvmfBootOrderParams{
|
||||
OvmfVarsPath: s.getOvmfVarsPath(),
|
||||
}
|
||||
devs := make([]*deployapi.BootDevices, 0)
|
||||
for i := range s.Desc.Cdroms {
|
||||
if s.Desc.Cdroms[i].BootIndex == nil || *s.Desc.Disks[i].BootIndex < 0 {
|
||||
continue
|
||||
}
|
||||
dev := &deployapi.BootDevices{
|
||||
BootOrder: int32(*s.Desc.Cdroms[i].BootIndex),
|
||||
AttachOrder: int32(s.Desc.Cdroms[i].Ordinal),
|
||||
DevType: int32(s.getCdromBootOrder()),
|
||||
}
|
||||
devs = append(devs, dev)
|
||||
}
|
||||
for i := range s.Desc.Disks {
|
||||
if s.Desc.Disks[i].BootIndex == nil || *s.Desc.Disks[i].BootIndex < 0 {
|
||||
continue
|
||||
}
|
||||
dev := &deployapi.BootDevices{
|
||||
BootOrder: int32(*s.Desc.Disks[i].BootIndex),
|
||||
AttachOrder: int32(s.Desc.Disks[i].Index),
|
||||
DevType: int32(s.getDiskBootOrderType(s.Desc.Disks[i].Driver)),
|
||||
}
|
||||
devs = append(devs, dev)
|
||||
}
|
||||
params.Devs = devs
|
||||
_, err := deployclient.GetDeployClient().SetOvmfBootOrder(ctx, params)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "SetOvmfBootOrder")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -665,6 +665,7 @@ type GenerateStartOptionsInput struct {
|
||||
OVNIntegrationBridge string
|
||||
Devices []string
|
||||
OVMFPath string
|
||||
OVMFVarsPath string
|
||||
VNCPort uint
|
||||
VNCPassword bool
|
||||
EnableLog bool
|
||||
@@ -763,7 +764,7 @@ func GenerateStartOptions(
|
||||
if input.OVMFPath == "" {
|
||||
return "", errors.Errorf("input OVMF path is empty")
|
||||
}
|
||||
fmOpt, err := drvOpt.BIOS(input.OVMFPath, input.HomeDir)
|
||||
fmOpt, err := drvOpt.BIOS(input.OVMFPath, input.OVMFVarsPath, input.HomeDir)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "bios option")
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ type QemuOptions interface {
|
||||
MemDev(sizeMB uint64) string
|
||||
MemFd(sizeMB uint64) string
|
||||
Boot(order *string, enableMenu bool) string
|
||||
BIOS(ovmfPath, homedir string) (string, error)
|
||||
BIOS(ovmfPath, ovmfVarsPath, homedir string) (string, error)
|
||||
Device(devStr string) string
|
||||
Drive(driveStr string) string
|
||||
Chardev(backend string, id string, name string) string
|
||||
@@ -272,17 +272,21 @@ func (o baseOptions) Boot(order *string, enableMenu bool) string {
|
||||
return fmt.Sprintf("-boot %s", strings.Join(opts, ","))
|
||||
}
|
||||
|
||||
func (o baseOptions) BIOS(ovmfPath, homedir string) (string, error) {
|
||||
ovmfVarsPath := path.Join(homedir, "OVMF_VARS.fd")
|
||||
if !fileutils2.Exists(ovmfVarsPath) {
|
||||
err := procutils.NewRemoteCommandAsFarAsPossible("cp", "-f", ovmfPath, ovmfVarsPath).Run()
|
||||
func (o baseOptions) BIOS(ovmfPath, ovmfVarsPath, homedir string) (string, error) {
|
||||
if ovmfVarsPath == "" || !fileutils2.Exists(ovmfVarsPath) {
|
||||
ovmfVarsPath = ovmfPath
|
||||
}
|
||||
|
||||
destOvmfVarsPath := path.Join(homedir, "OVMF_VARS.fd")
|
||||
if !fileutils2.Exists(destOvmfVarsPath) {
|
||||
err := procutils.NewRemoteCommandAsFarAsPossible("cp", "-f", ovmfVarsPath, destOvmfVarsPath).Run()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed copy ovmf vars")
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"-drive if=pflash,format=raw,unit=0,file=%s,readonly=on -drive if=pflash,format=raw,unit=1,file=%s",
|
||||
ovmfPath, ovmfVarsPath,
|
||||
ovmfPath, destOvmfVarsPath,
|
||||
), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ type GuestRuntimeInstance interface {
|
||||
|
||||
LoadDesc() error
|
||||
PostLoad(m *SGuestManager) error
|
||||
SyncConfig(ctx context.Context, guestDesc *desc.SGuestDesc, fwOnly bool) (jsonutils.JSONObject, error)
|
||||
SyncConfig(ctx context.Context, guestDesc *desc.SGuestDesc, fwOnly, setUefiBootOrder bool) (jsonutils.JSONObject, error)
|
||||
DoSnapshot(ctx context.Context, params *SDiskSnapshot) (jsonutils.JSONObject, error)
|
||||
DeleteSnapshot(ctx context.Context, params *SDeleteDiskSnapshot) (jsonutils.JSONObject, error)
|
||||
OnlineResizeDisk(ctx context.Context, disk storageman.IDisk, sizeMB int64)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc-gen-go v1.20.0
|
||||
// protoc v3.21.5
|
||||
// source: deploy.proto
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
@@ -25,6 +26,10 @@ const (
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type GuestDesc struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -1960,6 +1965,125 @@ func (x *EsxiDisksConnectionInfo) GetDisks() []*EsxiDiskInfo {
|
||||
return nil
|
||||
}
|
||||
|
||||
// cdrom, scsi cdrom, hard drive, scsi, pci
|
||||
type BootDevices struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
BootOrder int32 `protobuf:"varint,1,opt,name=BootOrder,proto3" json:"BootOrder,omitempty"`
|
||||
DevType int32 `protobuf:"varint,2,opt,name=DevType,proto3" json:"DevType,omitempty"`
|
||||
AttachOrder int32 `protobuf:"varint,3,opt,name=AttachOrder,proto3" json:"AttachOrder,omitempty"`
|
||||
}
|
||||
|
||||
func (x *BootDevices) Reset() {
|
||||
*x = BootDevices{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_deploy_proto_msgTypes[24]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *BootDevices) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BootDevices) ProtoMessage() {}
|
||||
|
||||
func (x *BootDevices) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_deploy_proto_msgTypes[24]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BootDevices.ProtoReflect.Descriptor instead.
|
||||
func (*BootDevices) Descriptor() ([]byte, []int) {
|
||||
return file_deploy_proto_rawDescGZIP(), []int{24}
|
||||
}
|
||||
|
||||
func (x *BootDevices) GetBootOrder() int32 {
|
||||
if x != nil {
|
||||
return x.BootOrder
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BootDevices) GetDevType() int32 {
|
||||
if x != nil {
|
||||
return x.DevType
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BootDevices) GetAttachOrder() int32 {
|
||||
if x != nil {
|
||||
return x.AttachOrder
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type OvmfBootOrderParams struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
OvmfVarsPath string `protobuf:"bytes,1,opt,name=OvmfVarsPath,proto3" json:"OvmfVarsPath,omitempty"`
|
||||
Devs []*BootDevices `protobuf:"bytes,2,rep,name=devs,proto3" json:"devs,omitempty"`
|
||||
}
|
||||
|
||||
func (x *OvmfBootOrderParams) Reset() {
|
||||
*x = OvmfBootOrderParams{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_deploy_proto_msgTypes[25]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *OvmfBootOrderParams) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*OvmfBootOrderParams) ProtoMessage() {}
|
||||
|
||||
func (x *OvmfBootOrderParams) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_deploy_proto_msgTypes[25]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use OvmfBootOrderParams.ProtoReflect.Descriptor instead.
|
||||
func (*OvmfBootOrderParams) Descriptor() ([]byte, []int) {
|
||||
return file_deploy_proto_rawDescGZIP(), []int{25}
|
||||
}
|
||||
|
||||
func (x *OvmfBootOrderParams) GetOvmfVarsPath() string {
|
||||
if x != nil {
|
||||
return x.OvmfVarsPath
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *OvmfBootOrderParams) GetDevs() []*BootDevices {
|
||||
if x != nil {
|
||||
return x.Devs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_deploy_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_deploy_proto_rawDesc = []byte{
|
||||
@@ -2235,40 +2359,56 @@ var file_deploy_proto_rawDesc = []byte{
|
||||
0x73, 0x6b, 0x73, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66,
|
||||
0x6f, 0x12, 0x28, 0x0a, 0x05, 0x64, 0x69, 0x73, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x45, 0x73, 0x78, 0x69, 0x44, 0x69, 0x73, 0x6b,
|
||||
0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x64, 0x69, 0x73, 0x6b, 0x73, 0x32, 0xc6, 0x03, 0x0a, 0x0b,
|
||||
0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x0d, 0x44,
|
||||
0x65, 0x70, 0x6c, 0x6f, 0x79, 0x47, 0x75, 0x65, 0x73, 0x74, 0x46, 0x73, 0x12, 0x12, 0x2e, 0x61,
|
||||
0x70, 0x69, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73,
|
||||
0x1a, 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x47, 0x75,
|
||||
0x65, 0x73, 0x74, 0x46, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a,
|
||||
0x08, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x46, 0x73, 0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x73,
|
||||
0x2e, 0x52, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x46, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a,
|
||||
0x0b, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2d, 0x0a, 0x08,
|
||||
0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x46, 0x73, 0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e,
|
||||
0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x46, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x0b,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x44, 0x0a, 0x0c, 0x53,
|
||||
0x61, 0x76, 0x65, 0x54, 0x6f, 0x47, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70,
|
||||
0x69, 0x73, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x54, 0x6f, 0x47, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50,
|
||||
0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x53, 0x61, 0x76,
|
||||
0x65, 0x54, 0x6f, 0x47, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x3d, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x49,
|
||||
0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x65,
|
||||
0x49, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x50, 0x72, 0x61, 0x6d, 0x61, 0x73, 0x1a,
|
||||
0x0f, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f,
|
||||
0x12, 0x4f, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, 0x73, 0x78, 0x69, 0x44,
|
||||
0x69, 0x73, 0x6b, 0x73, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x6e,
|
||||
0x65, 0x63, 0x74, 0x45, 0x73, 0x78, 0x69, 0x44, 0x69, 0x73, 0x6b, 0x73, 0x50, 0x61, 0x72, 0x61,
|
||||
0x6d, 0x73, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x45, 0x73, 0x78, 0x69, 0x44, 0x69,
|
||||
0x73, 0x6b, 0x73, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66,
|
||||
0x6f, 0x12, 0x41, 0x0a, 0x13, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45,
|
||||
0x73, 0x78, 0x69, 0x44, 0x69, 0x73, 0x6b, 0x73, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e,
|
||||
0x45, 0x73, 0x78, 0x69, 0x44, 0x69, 0x73, 0x6b, 0x73, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x45,
|
||||
0x6d, 0x70, 0x74, 0x79, 0x42, 0x34, 0x5a, 0x32, 0x79, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x2e, 0x69,
|
||||
0x6f, 0x2f, 0x78, 0x2f, 0x6f, 0x6e, 0x65, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x70, 0x6b, 0x67,
|
||||
0x2f, 0x68, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x64, 0x65, 0x70,
|
||||
0x6c, 0x6f, 0x79, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x33,
|
||||
0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x64, 0x69, 0x73, 0x6b, 0x73, 0x22, 0x67, 0x0a, 0x0b, 0x42,
|
||||
0x6f, 0x6f, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x42, 0x6f,
|
||||
0x6f, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x42,
|
||||
0x6f, 0x6f, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x44, 0x65, 0x76, 0x54,
|
||||
0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x44, 0x65, 0x76, 0x54, 0x79,
|
||||
0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x4f, 0x72, 0x64, 0x65,
|
||||
0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x4f,
|
||||
0x72, 0x64, 0x65, 0x72, 0x22, 0x60, 0x0a, 0x13, 0x4f, 0x76, 0x6d, 0x66, 0x42, 0x6f, 0x6f, 0x74,
|
||||
0x4f, 0x72, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x4f,
|
||||
0x76, 0x6d, 0x66, 0x56, 0x61, 0x72, 0x73, 0x50, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0c, 0x4f, 0x76, 0x6d, 0x66, 0x56, 0x61, 0x72, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12,
|
||||
0x25, 0x0a, 0x04, 0x64, 0x65, 0x76, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x73, 0x2e, 0x42, 0x6f, 0x6f, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73,
|
||||
0x52, 0x04, 0x64, 0x65, 0x76, 0x73, 0x32, 0x82, 0x04, 0x0a, 0x0b, 0x44, 0x65, 0x70, 0x6c, 0x6f,
|
||||
0x79, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x0d, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79,
|
||||
0x47, 0x75, 0x65, 0x73, 0x74, 0x46, 0x73, 0x12, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x44,
|
||||
0x65, 0x70, 0x6c, 0x6f, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1b, 0x2e, 0x61, 0x70,
|
||||
0x69, 0x73, 0x2e, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x47, 0x75, 0x65, 0x73, 0x74, 0x46, 0x73,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x69,
|
||||
0x7a, 0x65, 0x46, 0x73, 0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x52, 0x65, 0x73, 0x69,
|
||||
0x7a, 0x65, 0x46, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2d, 0x0a, 0x08, 0x46, 0x6f, 0x72, 0x6d, 0x61,
|
||||
0x74, 0x46, 0x73, 0x12, 0x14, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x46, 0x6f, 0x72, 0x6d, 0x61,
|
||||
0x74, 0x46, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x73,
|
||||
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x44, 0x0a, 0x0c, 0x53, 0x61, 0x76, 0x65, 0x54, 0x6f,
|
||||
0x47, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x18, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x53, 0x61,
|
||||
0x76, 0x65, 0x54, 0x6f, 0x47, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73,
|
||||
0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x53, 0x61, 0x76, 0x65, 0x54, 0x6f, 0x47, 0x6c,
|
||||
0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x0e,
|
||||
0x50, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6d, 0x61, 0x67, 0x65,
|
||||
0x49, 0x6e, 0x66, 0x6f, 0x50, 0x72, 0x61, 0x6d, 0x61, 0x73, 0x1a, 0x0f, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x73, 0x2e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4f, 0x0a, 0x10, 0x43,
|
||||
0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, 0x73, 0x78, 0x69, 0x44, 0x69, 0x73, 0x6b, 0x73, 0x12,
|
||||
0x1c, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, 0x73,
|
||||
0x78, 0x69, 0x44, 0x69, 0x73, 0x6b, 0x73, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x1d, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x73, 0x2e, 0x45, 0x73, 0x78, 0x69, 0x44, 0x69, 0x73, 0x6b, 0x73, 0x43, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x41, 0x0a, 0x13,
|
||||
0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, 0x73, 0x78, 0x69, 0x44, 0x69,
|
||||
0x73, 0x6b, 0x73, 0x12, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x45, 0x73, 0x78, 0x69, 0x44,
|
||||
0x69, 0x73, 0x6b, 0x73, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e,
|
||||
0x66, 0x6f, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12,
|
||||
0x3a, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x4f, 0x76, 0x6d, 0x66, 0x42, 0x6f, 0x6f, 0x74, 0x4f, 0x72,
|
||||
0x64, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x4f, 0x76, 0x6d, 0x66, 0x42,
|
||||
0x6f, 0x6f, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x0b,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x34, 0x5a, 0x32, 0x79,
|
||||
0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x2e, 0x69, 0x6f, 0x2f, 0x78, 0x2f, 0x6f, 0x6e, 0x65, 0x63, 0x6c,
|
||||
0x6f, 0x75, 0x64, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x68, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x2f,
|
||||
0x68, 0x6f, 0x73, 0x74, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69,
|
||||
0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -2283,7 +2423,7 @@ func file_deploy_proto_rawDescGZIP() []byte {
|
||||
return file_deploy_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_deploy_proto_msgTypes = make([]protoimpl.MessageInfo, 24)
|
||||
var file_deploy_proto_msgTypes = make([]protoimpl.MessageInfo, 26)
|
||||
var file_deploy_proto_goTypes = []interface{}{
|
||||
(*GuestDesc)(nil), // 0: apis.GuestDesc
|
||||
(*Disk)(nil), // 1: apis.Disk
|
||||
@@ -2309,6 +2449,8 @@ var file_deploy_proto_goTypes = []interface{}{
|
||||
(*EsxiDiskInfo)(nil), // 21: apis.EsxiDiskInfo
|
||||
(*ConnectEsxiDisksParams)(nil), // 22: apis.ConnectEsxiDisksParams
|
||||
(*EsxiDisksConnectionInfo)(nil), // 23: apis.EsxiDisksConnectionInfo
|
||||
(*BootDevices)(nil), // 24: apis.BootDevices
|
||||
(*OvmfBootOrderParams)(nil), // 25: apis.OvmfBootOrderParams
|
||||
}
|
||||
var file_deploy_proto_depIdxs = []int32{
|
||||
2, // 0: apis.GuestDesc.nics:type_name -> apis.Nic
|
||||
@@ -2333,25 +2475,28 @@ var file_deploy_proto_depIdxs = []int32{
|
||||
3, // 19: apis.ConnectEsxiDisksParams.vddk_info:type_name -> apis.VDDKConInfo
|
||||
21, // 20: apis.ConnectEsxiDisksParams.access_info:type_name -> apis.EsxiDiskInfo
|
||||
21, // 21: apis.EsxiDisksConnectionInfo.disks:type_name -> apis.EsxiDiskInfo
|
||||
11, // 22: apis.DeployAgent.DeployGuestFs:input_type -> apis.DeployParams
|
||||
12, // 23: apis.DeployAgent.ResizeFs:input_type -> apis.ResizeFsParams
|
||||
15, // 24: apis.DeployAgent.FormatFs:input_type -> apis.FormatFsParams
|
||||
17, // 25: apis.DeployAgent.SaveToGlance:input_type -> apis.SaveToGlanceParams
|
||||
19, // 26: apis.DeployAgent.ProbeImageInfo:input_type -> apis.ProbeImageInfoPramas
|
||||
22, // 27: apis.DeployAgent.ConnectEsxiDisks:input_type -> apis.ConnectEsxiDisksParams
|
||||
23, // 28: apis.DeployAgent.DisconnectEsxiDisks:input_type -> apis.EsxiDisksConnectionInfo
|
||||
9, // 29: apis.DeployAgent.DeployGuestFs:output_type -> apis.DeployGuestFsResponse
|
||||
8, // 30: apis.DeployAgent.ResizeFs:output_type -> apis.Empty
|
||||
8, // 31: apis.DeployAgent.FormatFs:output_type -> apis.Empty
|
||||
18, // 32: apis.DeployAgent.SaveToGlance:output_type -> apis.SaveToGlanceResponse
|
||||
20, // 33: apis.DeployAgent.ProbeImageInfo:output_type -> apis.ImageInfo
|
||||
23, // 34: apis.DeployAgent.ConnectEsxiDisks:output_type -> apis.EsxiDisksConnectionInfo
|
||||
8, // 35: apis.DeployAgent.DisconnectEsxiDisks:output_type -> apis.Empty
|
||||
29, // [29:36] is the sub-list for method output_type
|
||||
22, // [22:29] is the sub-list for method input_type
|
||||
22, // [22:22] is the sub-list for extension type_name
|
||||
22, // [22:22] is the sub-list for extension extendee
|
||||
0, // [0:22] is the sub-list for field type_name
|
||||
24, // 22: apis.OvmfBootOrderParams.devs:type_name -> apis.BootDevices
|
||||
11, // 23: apis.DeployAgent.DeployGuestFs:input_type -> apis.DeployParams
|
||||
12, // 24: apis.DeployAgent.ResizeFs:input_type -> apis.ResizeFsParams
|
||||
15, // 25: apis.DeployAgent.FormatFs:input_type -> apis.FormatFsParams
|
||||
17, // 26: apis.DeployAgent.SaveToGlance:input_type -> apis.SaveToGlanceParams
|
||||
19, // 27: apis.DeployAgent.ProbeImageInfo:input_type -> apis.ProbeImageInfoPramas
|
||||
22, // 28: apis.DeployAgent.ConnectEsxiDisks:input_type -> apis.ConnectEsxiDisksParams
|
||||
23, // 29: apis.DeployAgent.DisconnectEsxiDisks:input_type -> apis.EsxiDisksConnectionInfo
|
||||
25, // 30: apis.DeployAgent.SetOvmfBootOrder:input_type -> apis.OvmfBootOrderParams
|
||||
9, // 31: apis.DeployAgent.DeployGuestFs:output_type -> apis.DeployGuestFsResponse
|
||||
8, // 32: apis.DeployAgent.ResizeFs:output_type -> apis.Empty
|
||||
8, // 33: apis.DeployAgent.FormatFs:output_type -> apis.Empty
|
||||
18, // 34: apis.DeployAgent.SaveToGlance:output_type -> apis.SaveToGlanceResponse
|
||||
20, // 35: apis.DeployAgent.ProbeImageInfo:output_type -> apis.ImageInfo
|
||||
23, // 36: apis.DeployAgent.ConnectEsxiDisks:output_type -> apis.EsxiDisksConnectionInfo
|
||||
8, // 37: apis.DeployAgent.DisconnectEsxiDisks:output_type -> apis.Empty
|
||||
8, // 38: apis.DeployAgent.SetOvmfBootOrder:output_type -> apis.Empty
|
||||
31, // [31:39] is the sub-list for method output_type
|
||||
23, // [23:31] is the sub-list for method input_type
|
||||
23, // [23:23] is the sub-list for extension type_name
|
||||
23, // [23:23] is the sub-list for extension extendee
|
||||
0, // [0:23] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_deploy_proto_init() }
|
||||
@@ -2648,6 +2793,30 @@ func file_deploy_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_deploy_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*BootDevices); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_deploy_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*OvmfBootOrderParams); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@@ -2655,7 +2824,7 @@ func file_deploy_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_deploy_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 24,
|
||||
NumMessages: 26,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@@ -206,6 +206,19 @@ message EsxiDisksConnectionInfo {
|
||||
repeated EsxiDiskInfo disks = 1;
|
||||
}
|
||||
|
||||
|
||||
// cdrom, scsi cdrom, hard drive, scsi, pci
|
||||
message BootDevices {
|
||||
int32 BootOrder = 1;
|
||||
int32 DevType = 2;
|
||||
int32 AttachOrder = 3;
|
||||
}
|
||||
|
||||
message OvmfBootOrderParams {
|
||||
string OvmfVarsPath = 1;
|
||||
repeated BootDevices devs = 2;
|
||||
}
|
||||
|
||||
service DeployAgent {
|
||||
rpc DeployGuestFs (DeployParams) returns (DeployGuestFsResponse);
|
||||
rpc ResizeFs (ResizeFsParams) returns (Empty);
|
||||
@@ -214,4 +227,5 @@ service DeployAgent {
|
||||
rpc ProbeImageInfo(ProbeImageInfoPramas) returns (ImageInfo);
|
||||
rpc ConnectEsxiDisks(ConnectEsxiDisksParams) returns (EsxiDisksConnectionInfo);
|
||||
rpc DisconnectEsxiDisks(EsxiDisksConnectionInfo) returns (Empty);
|
||||
rpc SetOvmfBootOrder(OvmfBootOrderParams) returns (Empty);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc v3.21.5
|
||||
// source: deploy.proto
|
||||
|
||||
package apis
|
||||
|
||||
@@ -16,7 +12,6 @@ import (
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
// DeployAgentClient is the client API for DeployAgent service.
|
||||
@@ -30,6 +25,7 @@ type DeployAgentClient interface {
|
||||
ProbeImageInfo(ctx context.Context, in *ProbeImageInfoPramas, opts ...grpc.CallOption) (*ImageInfo, error)
|
||||
ConnectEsxiDisks(ctx context.Context, in *ConnectEsxiDisksParams, opts ...grpc.CallOption) (*EsxiDisksConnectionInfo, error)
|
||||
DisconnectEsxiDisks(ctx context.Context, in *EsxiDisksConnectionInfo, opts ...grpc.CallOption) (*Empty, error)
|
||||
SetOvmfBootOrder(ctx context.Context, in *OvmfBootOrderParams, opts ...grpc.CallOption) (*Empty, error)
|
||||
}
|
||||
|
||||
type deployAgentClient struct {
|
||||
@@ -103,6 +99,15 @@ func (c *deployAgentClient) DisconnectEsxiDisks(ctx context.Context, in *EsxiDis
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *deployAgentClient) SetOvmfBootOrder(ctx context.Context, in *OvmfBootOrderParams, opts ...grpc.CallOption) (*Empty, error) {
|
||||
out := new(Empty)
|
||||
err := c.cc.Invoke(ctx, "/apis.DeployAgent/SetOvmfBootOrder", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// DeployAgentServer is the server API for DeployAgent service.
|
||||
// All implementations must embed UnimplementedDeployAgentServer
|
||||
// for forward compatibility
|
||||
@@ -114,6 +119,7 @@ type DeployAgentServer interface {
|
||||
ProbeImageInfo(context.Context, *ProbeImageInfoPramas) (*ImageInfo, error)
|
||||
ConnectEsxiDisks(context.Context, *ConnectEsxiDisksParams) (*EsxiDisksConnectionInfo, error)
|
||||
DisconnectEsxiDisks(context.Context, *EsxiDisksConnectionInfo) (*Empty, error)
|
||||
SetOvmfBootOrder(context.Context, *OvmfBootOrderParams) (*Empty, error)
|
||||
mustEmbedUnimplementedDeployAgentServer()
|
||||
}
|
||||
|
||||
@@ -142,6 +148,9 @@ func (UnimplementedDeployAgentServer) ConnectEsxiDisks(context.Context, *Connect
|
||||
func (UnimplementedDeployAgentServer) DisconnectEsxiDisks(context.Context, *EsxiDisksConnectionInfo) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method DisconnectEsxiDisks not implemented")
|
||||
}
|
||||
func (UnimplementedDeployAgentServer) SetOvmfBootOrder(context.Context, *OvmfBootOrderParams) (*Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SetOvmfBootOrder not implemented")
|
||||
}
|
||||
func (UnimplementedDeployAgentServer) mustEmbedUnimplementedDeployAgentServer() {}
|
||||
|
||||
// UnsafeDeployAgentServer may be embedded to opt out of forward compatibility for this service.
|
||||
@@ -152,7 +161,7 @@ type UnsafeDeployAgentServer interface {
|
||||
}
|
||||
|
||||
func RegisterDeployAgentServer(s grpc.ServiceRegistrar, srv DeployAgentServer) {
|
||||
s.RegisterService(&DeployAgent_ServiceDesc, srv)
|
||||
s.RegisterService(&_DeployAgent_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _DeployAgent_DeployGuestFs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
@@ -281,10 +290,25 @@ func _DeployAgent_DisconnectEsxiDisks_Handler(srv interface{}, ctx context.Conte
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// DeployAgent_ServiceDesc is the grpc.ServiceDesc for DeployAgent service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var DeployAgent_ServiceDesc = grpc.ServiceDesc{
|
||||
func _DeployAgent_SetOvmfBootOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(OvmfBootOrderParams)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DeployAgentServer).SetOvmfBootOrder(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/apis.DeployAgent/SetOvmfBootOrder",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DeployAgentServer).SetOvmfBootOrder(ctx, req.(*OvmfBootOrderParams))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _DeployAgent_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "apis.DeployAgent",
|
||||
HandlerType: (*DeployAgentServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
@@ -316,6 +340,10 @@ var DeployAgent_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "DisconnectEsxiDisks",
|
||||
Handler: _DeployAgent_DisconnectEsxiDisks_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SetOvmfBootOrder",
|
||||
Handler: _DeployAgent_SetOvmfBootOrder_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "deploy.proto",
|
||||
|
||||
@@ -127,3 +127,13 @@ func (c *DeployClient) DisconnectEsxiDisks(
|
||||
client := deployapi.NewDeployAgentClient(conn)
|
||||
return client.DisconnectEsxiDisks(ctx, in, opts...)
|
||||
}
|
||||
|
||||
func (c *DeployClient) SetOvmfBootOrder(ctx context.Context, in *deployapi.OvmfBootOrderParams, opts ...grpc.CallOption) (*deployapi.Empty, error) {
|
||||
conn, err := grcpDialWithUnixSocket(ctx, c.socketPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
client := deployapi.NewDeployAgentClient(conn)
|
||||
return client.SetOvmfBootOrder(ctx, in, opts...)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -32,6 +33,7 @@ import (
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
app_common "yunion.io/x/onecloud/pkg/cloudcommon/app"
|
||||
commonconsts "yunion.io/x/onecloud/pkg/cloudcommon/consts"
|
||||
@@ -45,6 +47,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver"
|
||||
deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/consts"
|
||||
"yunion.io/x/onecloud/pkg/hostman/hostdeployer/uefi"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
"yunion.io/x/onecloud/pkg/util/qemuimg"
|
||||
@@ -264,6 +267,75 @@ func (*DeployerServer) DisconnectEsxiDisks(
|
||||
return new(deployapi.Empty), nil
|
||||
}
|
||||
|
||||
func (*DeployerServer) SetOvmfBootOrder(ctx context.Context, req *deployapi.OvmfBootOrderParams) (*deployapi.Empty, error) {
|
||||
log.Infof("Request SetOvmfBootOrder of %s", req.OvmfVarsPath)
|
||||
if !fileutils2.Exists(req.OvmfVarsPath) {
|
||||
return new(deployapi.Empty), errors.Errorf("ovmf %s not found", req.OvmfVarsPath)
|
||||
}
|
||||
|
||||
// parse boot entry from ovmf vars
|
||||
bootEntries, bootOrder, ovmfJsonTmpPath, err := uefi.ParseUefiVars(req.OvmfVarsPath)
|
||||
if err != nil {
|
||||
return new(deployapi.Empty), errors.Wrapf(err, "failed parse uefi vars %s", req.OvmfVarsPath)
|
||||
}
|
||||
|
||||
sort.Slice(req.Devs, func(i, j int) bool {
|
||||
return req.Devs[i].AttachOrder < req.Devs[j].AttachOrder
|
||||
})
|
||||
bootEntryIdx := map[string]*deployapi.BootDevices{}
|
||||
bootentryOrder := map[int32]string{}
|
||||
findBootentry := func(dev *deployapi.BootDevices) {
|
||||
for x, bootEntry := range bootEntries {
|
||||
if _, ok := bootEntryIdx[bootEntry.ID]; ok {
|
||||
continue
|
||||
}
|
||||
log.Errorf("bootentry %v type %v", x, bootEntry.GetType())
|
||||
if bootEntry.GetType() == uefi.OvmfDevicePathType(dev.DevType) {
|
||||
bootEntryIdx[bootEntry.ID] = dev
|
||||
bootentryOrder[dev.BootOrder] = bootEntry.ID
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := range req.Devs {
|
||||
findBootentry(req.Devs[i])
|
||||
}
|
||||
sort.Slice(req.Devs, func(i, j int) bool {
|
||||
return req.Devs[i].BootOrder < req.Devs[j].BootOrder
|
||||
})
|
||||
newBootOrder := []uint16{}
|
||||
for i := range req.Devs {
|
||||
bentry, ok := bootentryOrder[req.Devs[i].BootOrder]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
order, err := uefi.ParseBootentryToBootorder(bentry)
|
||||
if err != nil {
|
||||
log.Errorf("failed ParseBootentryToBootorder %s %s", bentry, err)
|
||||
continue
|
||||
}
|
||||
newBootOrder = append(newBootOrder, order)
|
||||
}
|
||||
for i := range bootOrder {
|
||||
if utils.IsInArray(bootOrder[i], newBootOrder) {
|
||||
continue
|
||||
}
|
||||
newBootOrder = append(newBootOrder, bootOrder[i])
|
||||
}
|
||||
|
||||
if err := uefi.UpdateBootOrderInJson(ovmfJsonTmpPath, newBootOrder); err != nil {
|
||||
log.Errorf("failed UpdateBootOrderInJson %s", err)
|
||||
return new(deployapi.Empty), errors.Wrapf(err, "failed UpdateBootOrderInJson %v", newBootOrder)
|
||||
}
|
||||
out, err := uefi.ApplyJsonToVars(ovmfJsonTmpPath, req.OvmfVarsPath, req.OvmfVarsPath)
|
||||
if err != nil {
|
||||
log.Errorf("failed ApplyJsonToVars %s %s", out, err)
|
||||
return new(deployapi.Empty), errors.Wrapf(err, "failed ApplyJsonToVars %v", out)
|
||||
}
|
||||
|
||||
return new(deployapi.Empty), nil
|
||||
}
|
||||
|
||||
type SDeployService struct {
|
||||
*service.SServiceBase
|
||||
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package uefi
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type OvmfDevicePathType int
|
||||
|
||||
const (
|
||||
DEVICE_TYPE_UNKNOWN OvmfDevicePathType = 0
|
||||
DEVICE_TYPE_CDROM OvmfDevicePathType = 1
|
||||
DEVICE_TYPE_IDE OvmfDevicePathType = 2
|
||||
DEVICE_TYPE_SCSI OvmfDevicePathType = 3
|
||||
DEVICE_TYPE_SCSI_CDROM OvmfDevicePathType = 4
|
||||
DEVICE_TYPE_PCI OvmfDevicePathType = 5
|
||||
DEVICE_TYPE_SATA OvmfDevicePathType = 6
|
||||
)
|
||||
|
||||
type BootEntry struct {
|
||||
ID string // Boot0000, Boot0001, etc.
|
||||
Name string // Entry title
|
||||
DevPaths []*DevicePathElement // Device path elements
|
||||
RawData string // Raw hex data
|
||||
}
|
||||
|
||||
func (b *BootEntry) GetType() OvmfDevicePathType {
|
||||
lenElements := len(b.DevPaths)
|
||||
if lenElements == 0 {
|
||||
return DEVICE_TYPE_UNKNOWN
|
||||
}
|
||||
devElement := b.DevPaths[lenElements-1]
|
||||
// fetch last device path element type
|
||||
switch devElement.devType {
|
||||
case DevicePathTypeHardware:
|
||||
if devElement.subType == 0x01 {
|
||||
return DEVICE_TYPE_PCI
|
||||
}
|
||||
case DevicePathTypeMessaging:
|
||||
switch devElement.subType {
|
||||
case 0x01:
|
||||
if strings.HasPrefix(b.Name, "UEFI QEMU DVD-ROM") {
|
||||
return DEVICE_TYPE_CDROM
|
||||
} else if strings.HasPrefix(b.Name, "UEFI QEMU HARDDISK") {
|
||||
return DEVICE_TYPE_IDE
|
||||
}
|
||||
case 0x02:
|
||||
if strings.HasPrefix(b.Name, "UEFI QEMU QEMU CD-ROM") {
|
||||
return DEVICE_TYPE_SCSI_CDROM
|
||||
} else if strings.HasPrefix(b.Name, "UEFI QEMU QEMU HARDDISK") {
|
||||
return DEVICE_TYPE_SCSI
|
||||
}
|
||||
case 0x12:
|
||||
return DEVICE_TYPE_SATA
|
||||
}
|
||||
}
|
||||
|
||||
return DEVICE_TYPE_UNKNOWN
|
||||
}
|
||||
|
||||
// ParseBootEntryData parses a boot entry from hex data
|
||||
func ParseBootEntryData(hexData string) (string, []*DevicePathElement, error) {
|
||||
// Decode hex data
|
||||
data, err := hex.DecodeString(hexData)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to decode hex data: %v", err)
|
||||
}
|
||||
|
||||
// Check minimum length
|
||||
if len(data) < 8 {
|
||||
return "", nil, fmt.Errorf("data too short")
|
||||
}
|
||||
|
||||
// Parse attributes and path list length
|
||||
// attributes := binary.LittleEndian.Uint32(data[0:4])
|
||||
pathListLen := binary.LittleEndian.Uint16(data[4:6])
|
||||
|
||||
// Extract description string
|
||||
descData := data[6:]
|
||||
descBytes, strLen := ExtractUCS16String(descData)
|
||||
name := DecodeUTF16LE(descBytes)
|
||||
|
||||
// Calculate path list start
|
||||
pathListStart := 6 + uint32(strLen)
|
||||
|
||||
// Check if we have enough data for the path list
|
||||
if pathListLen == 0 {
|
||||
return name, []*DevicePathElement{}, nil
|
||||
}
|
||||
|
||||
if uint32(len(data)) < pathListStart+uint32(pathListLen) {
|
||||
return name, nil, fmt.Errorf("invalid path list length")
|
||||
}
|
||||
|
||||
// Extract path list
|
||||
pathListData := data[pathListStart : pathListStart+uint32(pathListLen)]
|
||||
|
||||
// Parse device path elements
|
||||
devPaths, err := ParseDevicePathElements(pathListData)
|
||||
if err != nil {
|
||||
return name, nil, fmt.Errorf("failed to parse device path: %v", err)
|
||||
}
|
||||
|
||||
return name, devPaths, nil
|
||||
}
|
||||
|
||||
// ParseBootOrder parses a boot order from hex data
|
||||
func ParseBootOrder(hexData string) ([]uint16, error) {
|
||||
// Decode hex data
|
||||
data, err := hex.DecodeString(hexData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode hex data: %v", err)
|
||||
}
|
||||
|
||||
// Check data length
|
||||
if len(data) == 0 {
|
||||
return []uint16{}, nil
|
||||
}
|
||||
|
||||
// Check if data length is valid (must be even)
|
||||
if len(data)%2 != 0 {
|
||||
return nil, fmt.Errorf("invalid boot order data length (must be even)")
|
||||
}
|
||||
|
||||
// Parse boot order (2 bytes per entry)
|
||||
var bootOrder []uint16
|
||||
for i := 0; i < len(data); i += 2 {
|
||||
entryNum := binary.LittleEndian.Uint16(data[i : i+2])
|
||||
bootOrder = append(bootOrder, entryNum)
|
||||
}
|
||||
|
||||
return bootOrder, nil
|
||||
}
|
||||
|
||||
func ParseBootentryToBootorder(entry string) (uint16, error) {
|
||||
if !strings.HasPrefix(entry, "Boot") {
|
||||
return 0, fmt.Errorf("unknonw boot entry %s", entry)
|
||||
}
|
||||
hexData := entry[4:]
|
||||
// Decode hex data
|
||||
data, err := hex.DecodeString(hexData)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to decode hex data %s: %v", hexData, err)
|
||||
}
|
||||
return binary.BigEndian.Uint16(data), nil
|
||||
}
|
||||
|
||||
// BuildBootOrderHex builds a hex string from boot order list
|
||||
func BuildBootOrderHex(bootOrder []uint16) string {
|
||||
// Allocate space for boot order (2 bytes per entry)
|
||||
data := make([]byte, len(bootOrder)*2)
|
||||
for i, entry := range bootOrder {
|
||||
// Write little-endian uint16
|
||||
binary.LittleEndian.PutUint16(data[i*2:], entry)
|
||||
}
|
||||
|
||||
// Return hex string
|
||||
return hex.EncodeToString(data)
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package uefi
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// DevicePathType constants
|
||||
const (
|
||||
DevicePathTypeHardware = 0x01
|
||||
DevicePathTypeACPI = 0x02
|
||||
DevicePathTypeMessaging = 0x03
|
||||
DevicePathTypeMedia = 0x04
|
||||
DevicePathTypeEnd = 0x7F
|
||||
)
|
||||
|
||||
// DevicePathElement represents a UEFI device path element
|
||||
type DevicePathElement struct {
|
||||
devType byte
|
||||
subType byte
|
||||
data []byte
|
||||
}
|
||||
|
||||
func (e *DevicePathElement) String() string {
|
||||
return fmt.Sprintf("devType %v, subType %v", e.devType, e.subType)
|
||||
}
|
||||
|
||||
// Type returns the device path type
|
||||
func (e *DevicePathElement) Type() byte {
|
||||
return e.devType
|
||||
}
|
||||
|
||||
// SubType returns the device path subtype
|
||||
func (e *DevicePathElement) SubType() byte {
|
||||
return e.subType
|
||||
}
|
||||
|
||||
// ParseDevicePathElements parses a device path from binary data
|
||||
func ParseDevicePathElements(data []byte) ([]*DevicePathElement, error) {
|
||||
if len(data) == 0 {
|
||||
return nil, fmt.Errorf("empty device path data")
|
||||
}
|
||||
|
||||
var elements []*DevicePathElement
|
||||
pos := 0
|
||||
|
||||
for pos < len(data) {
|
||||
// Check if we have enough data for the header
|
||||
if pos+4 > len(data) {
|
||||
return nil, fmt.Errorf("truncated device path data")
|
||||
}
|
||||
|
||||
// Parse header
|
||||
devType := data[pos]
|
||||
subType := data[pos+1]
|
||||
length := binary.LittleEndian.Uint16(data[pos+2 : pos+4])
|
||||
|
||||
// Validate length
|
||||
if length < 4 {
|
||||
return nil, fmt.Errorf("invalid device path element length")
|
||||
}
|
||||
|
||||
// Check if we have enough data for the element
|
||||
if pos+int(length) > len(data) {
|
||||
return nil, fmt.Errorf("truncated device path element")
|
||||
}
|
||||
|
||||
// Check if this is the end of the device path
|
||||
if devType == DevicePathTypeEnd {
|
||||
break
|
||||
}
|
||||
|
||||
element := &DevicePathElement{
|
||||
devType: devType,
|
||||
subType: subType,
|
||||
data: data[pos+4 : pos+int(length)],
|
||||
}
|
||||
elements = append(elements, element)
|
||||
|
||||
pos += int(length)
|
||||
}
|
||||
|
||||
return elements, nil
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package uefi // import "yunion.io/x/onecloud/pkg/hostman/hostdeployer/uefi"
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package uefi
|
||||
|
||||
import (
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
// ExtractUCS16String extracts a UCS-16 string from a byte array
|
||||
// Returns the string data and the total length (including null terminator)
|
||||
func ExtractUCS16String(data []byte) ([]byte, uint32) {
|
||||
// Find the null terminator (two consecutive zero bytes)
|
||||
var i int
|
||||
for i = 0; i < len(data)-1; i += 2 {
|
||||
if data[i] == 0 && data[i+1] == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Include the null terminator in the length
|
||||
strLen := i + 2
|
||||
|
||||
// If we reached the end without finding a null terminator,
|
||||
// use the entire data length
|
||||
if i >= len(data)-1 {
|
||||
strLen = len(data)
|
||||
i = len(data)
|
||||
if i%2 != 0 {
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
// Return the string data and length
|
||||
return data[:i], uint32(strLen)
|
||||
}
|
||||
|
||||
// DecodeUTF16LE decodes a UTF-16LE byte array to a string
|
||||
func DecodeUTF16LE(b []byte) string {
|
||||
// Check if the byte array is empty
|
||||
if len(b) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Convert bytes to uint16 array
|
||||
u16s := make([]uint16, len(b)/2)
|
||||
for i := range u16s {
|
||||
// Little-endian: low byte first, then high byte
|
||||
u16s[i] = uint16(b[i*2]) | (uint16(b[i*2+1]) << 8)
|
||||
}
|
||||
|
||||
// Decode UTF-16 to UTF-8
|
||||
return string(utf16.Decode(u16s))
|
||||
}
|
||||
|
||||
// EncodeUTF16LE encodes a string to UTF-16LE bytes
|
||||
func EncodeUTF16LE(s string) []byte {
|
||||
u16s := utf16.Encode([]rune(s))
|
||||
bytes := make([]byte, len(u16s)*2)
|
||||
for i, u16 := range u16s {
|
||||
bytes[i*2] = byte(u16)
|
||||
bytes[i*2+1] = byte(u16 >> 8)
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package uefi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
func DumpOvmfVarsToJson(ovmfVarsPath string) (string, error) {
|
||||
// Create temporary file for JSON output
|
||||
jsonFile, err := ioutil.TempFile("", "ovmf-vars-*.json")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create temporary file: %v", err)
|
||||
}
|
||||
jsonPath := jsonFile.Name()
|
||||
jsonFile.Close()
|
||||
|
||||
output, err := procutils.NewCommand("virt-fw-vars", "-i", ovmfVarsPath, "--output-json", jsonPath).Output()
|
||||
if err != nil {
|
||||
os.Remove(jsonPath)
|
||||
return "", errors.Wrapf(err, "virt-fw-vars failed dump to json %s", output)
|
||||
}
|
||||
return jsonPath, nil
|
||||
}
|
||||
|
||||
func ParseUefiVars(ovmfVarsPath string) ([]*BootEntry, []uint16, string, error) {
|
||||
jsonPath, err := DumpOvmfVarsToJson(ovmfVarsPath)
|
||||
if err != nil {
|
||||
return nil, nil, "", errors.Wrap(err, "DumpOvmfVarsToJson")
|
||||
}
|
||||
|
||||
bootEntry, bootOrder, err := ParseVarsJson(jsonPath)
|
||||
if err != nil {
|
||||
return nil, nil, "", errors.Wrap(err, "ParseVarsJson")
|
||||
}
|
||||
sort.Slice(bootEntry, func(i, j int) bool {
|
||||
return bootEntry[i].ID < bootEntry[j].ID
|
||||
})
|
||||
return bootEntry, bootOrder, jsonPath, nil
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package uefi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"yunion.io/x/log"
|
||||
|
||||
"yunion.io/x/onecloud/pkg/util/procutils"
|
||||
)
|
||||
|
||||
// VarsData represents the UEFI variables data
|
||||
type VarsData struct {
|
||||
Version int `json:"version"`
|
||||
Variables []Variable `json:"variables"`
|
||||
}
|
||||
|
||||
// Variable represents a UEFI variable
|
||||
type Variable struct {
|
||||
Name string `json:"name"`
|
||||
GUID string `json:"guid"`
|
||||
Attr int `json:"attr"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
// EFI_GLOBAL_VARIABLE_GUID is the GUID for EFI global variables
|
||||
const EFI_GLOBAL_VARIABLE_GUID = "8be4df61-93ca-11d2-aa0d-00e098032b8c"
|
||||
|
||||
// ParseVarsJson parses UEFI variables from a JSON file
|
||||
func ParseVarsJson(jsonPath string) ([]*BootEntry, []uint16, error) {
|
||||
// Read JSON file
|
||||
data, err := ioutil.ReadFile(jsonPath)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to read JSON file: %v", err)
|
||||
}
|
||||
|
||||
// Parse JSON
|
||||
var varsData VarsData
|
||||
err = json.Unmarshal(data, &varsData)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse JSON: %v", err)
|
||||
}
|
||||
|
||||
// Parse boot entries and boot order
|
||||
var bootEntries []*BootEntry
|
||||
var bootOrder []uint16
|
||||
|
||||
for _, v := range varsData.Variables {
|
||||
// Check if this is a boot entry
|
||||
if len(v.Name) >= 8 && v.Name[:4] == "Boot" && v.GUID == EFI_GLOBAL_VARIABLE_GUID {
|
||||
// Check if this is the boot order
|
||||
if v.Name == "BootOrder" {
|
||||
var err error
|
||||
bootOrder, err = ParseBootOrder(v.Data)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to parse boot order: %v", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse boot entry
|
||||
name, devPaths, err := ParseBootEntryData(v.Data)
|
||||
if err != nil {
|
||||
log.Errorf("failed to parse boot entry %s: %s", v.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Create boot entry
|
||||
entry := &BootEntry{
|
||||
ID: v.Name,
|
||||
Name: name,
|
||||
DevPaths: devPaths,
|
||||
RawData: v.Data,
|
||||
}
|
||||
|
||||
// Add entry to list
|
||||
bootEntries = append(bootEntries, entry)
|
||||
}
|
||||
}
|
||||
|
||||
return bootEntries, bootOrder, nil
|
||||
}
|
||||
|
||||
// UpdateBootOrderInJson updates the boot order in a UEFI variables JSON file
|
||||
func UpdateBootOrderInJson(jsonPath string, bootOrder []uint16) error {
|
||||
// Read JSON file
|
||||
data, err := ioutil.ReadFile(jsonPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read JSON file: %v", err)
|
||||
}
|
||||
|
||||
// Parse JSON
|
||||
var varsData VarsData
|
||||
err = json.Unmarshal(data, &varsData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse JSON: %v", err)
|
||||
}
|
||||
|
||||
bootOrderHex := BuildBootOrderHex(bootOrder)
|
||||
bootOrderFound := false
|
||||
for i, v := range varsData.Variables {
|
||||
if v.Name == "BootOrder" && v.GUID == EFI_GLOBAL_VARIABLE_GUID {
|
||||
varsData.Variables[i].Data = bootOrderHex
|
||||
bootOrderFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Add boot order if not found
|
||||
if !bootOrderFound {
|
||||
varsData.Variables = append(varsData.Variables, Variable{
|
||||
Name: "BootOrder",
|
||||
GUID: EFI_GLOBAL_VARIABLE_GUID,
|
||||
Attr: 7, // NV+BS+RT
|
||||
Data: bootOrderHex,
|
||||
})
|
||||
}
|
||||
|
||||
// Write updated JSON
|
||||
updatedData, err := json.MarshalIndent(varsData, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal JSON: %v", err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(jsonPath, updatedData, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write JSON file: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ApplyJsonToVars applies a JSON file to OVMF_VARS.fd
|
||||
func ApplyJsonToVars(jsonPath, inputVarsPath, outputVarsPath string) ([]byte, error) {
|
||||
// Execute virt-fw-vars to apply JSON
|
||||
output, err := procutils.NewCommand("virt-fw-vars", "-i", inputVarsPath, "-o", outputVarsPath, "--set-json", jsonPath).Output()
|
||||
if err != nil {
|
||||
return output, fmt.Errorf("failed to execute virt-fw-vars --set-json command: %v", err)
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
||||
@@ -1,3 +1,17 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package container_device
|
||||
|
||||
import (
|
||||
|
||||
@@ -105,8 +105,9 @@ type SHostOptions struct {
|
||||
DnsServer string `help:"Address of host DNS server"`
|
||||
DnsServerLegacy string `help:"Deprecated Address of host DNS server"`
|
||||
|
||||
ChntpwPath string `help:"path to chntpw tool" default:"/usr/local/bin/chntpw.static"`
|
||||
OvmfPath string `help:"Path to OVMF.fd" default:"/opt/cloud/contrib/OVMF.fd"`
|
||||
ChntpwPath string `help:"path to chntpw tool" default:"/usr/local/bin/chntpw.static"`
|
||||
OvmfPath string `help:"Path to OVMF.fd" default:"/opt/cloud/contrib/OVMF.fd"`
|
||||
OvmfVarsPath string `help:"Path to OVMF_VARS.fd" default:"/opt/cloud/contrib/OVMF_VARS.fd"`
|
||||
|
||||
LinuxDefaultRootUser bool `help:"Default account for linux system is root"`
|
||||
WindowsDefaultAdminUser bool `default:"true" help:"Default account for Windows system is Administrator"`
|
||||
|
||||
@@ -1 +1,15 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cgroup // import "yunion.io/x/onecloud/pkg/util/cgrouputils/cgroup"
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cgroupv1
|
||||
|
||||
import (
|
||||
|
||||
@@ -1 +1,15 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cgroupv2 // import "yunion.io/x/onecloud/pkg/util/cgrouputils/cgroupv2"
|
||||
|
||||
Reference in New Issue
Block a user