fix(baremetal): record uefi info

This commit is contained in:
Zexi Li
2021-06-16 12:49:56 +08:00
parent 382962fd0e
commit e76592de73
17 changed files with 506 additions and 58 deletions
+111 -3
View File
@@ -50,6 +50,7 @@ import (
"yunion.io/x/onecloud/pkg/baremetal/utils/disktool"
"yunion.io/x/onecloud/pkg/baremetal/utils/ipmitool"
raiddrivers "yunion.io/x/onecloud/pkg/baremetal/utils/raid/drivers"
"yunion.io/x/onecloud/pkg/baremetal/utils/uefi"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/compute/baremetal"
"yunion.io/x/onecloud/pkg/hostman/guestfs"
@@ -1306,6 +1307,19 @@ func (b *SBaremetalInstance) GetRawIPMIConfig() *types.SIPMIInfo {
return &ipmiInfo
}
func (b *SBaremetalInstance) GetUEFIInfo() (*types.EFIBootMgrInfo, error) {
key := "uefi_info"
if !b.desc.Contains(key) {
return nil, nil
}
info := new(types.EFIBootMgrInfo)
if err := b.desc.Unmarshal(info, key); err != nil {
return nil, errors.Wrap(err, "Unmarshal json")
}
return info, nil
}
func (b *SBaremetalInstance) GetAccessIp() string {
accessIp, _ := b.desc.GetString("access_ip")
return accessIp
@@ -1434,13 +1448,16 @@ func (b *SBaremetalInstance) SSHReachable() (bool, error) {
return false, errors.NewAggregate(errs)
}
func (b *SBaremetalInstance) sshRun(hostCmd string, serverCmd string) ([]string, error) {
func (b *SBaremetalInstance) sshRunWrapper(
hostRun func(hostCli *ssh.Client) ([]string, error),
serverRun func(serverCli *ssh.Client) ([]string, error),
) ([]string, error) {
hostCli, err := b.GetHostSSHClient()
if err != nil {
log.Warningf("Get host ssh client error: %v", err)
} else {
if hostCli != nil {
return hostCli.RawRun(hostCmd)
return hostRun(hostCli)
}
}
@@ -1448,10 +1465,99 @@ func (b *SBaremetalInstance) sshRun(hostCmd string, serverCmd string) ([]string,
if err != nil {
return nil, errors.Wrapf(err, "Get baremetal %s server ssh client", b.GetName())
}
return serverCli.RunWithTTY(serverCmd)
return serverRun(serverCli)
}
func (b *SBaremetalInstance) sshRun(hostCmd string, serverCmd string) ([]string, error) {
return b.sshRunWrapper(
func(hostCli *ssh.Client) ([]string, error) {
return hostCli.RawRun(hostCmd)
},
func(serverCli *ssh.Client) ([]string, error) {
return serverCli.RunWithTTY(serverCmd)
},
)
}
func (b *SBaremetalInstance) adjustUEFIWrapper(cli *ssh.Client, f func() error) error {
isUEFI, err := uefi.RemoteIsUEFIBoot(cli)
if err != nil {
return errors.Wrap(err, "Check is uefi boot")
}
if !isUEFI {
return nil
}
return f()
}
func (b *SBaremetalInstance) AdjustUEFICurrentBootOrder(hostCli *ssh.Client) error {
return b.adjustUEFIWrapper(hostCli, func() error {
mgr, err := uefi.NewEFIBootMgrFromRemote(hostCli, false)
if err != nil {
return errors.Wrap(err, "NewEFIBootMgrFromRemote")
}
if err := uefi.RemoteSetCurrentBootAtFirst(hostCli, mgr); err != nil {
return errors.Wrap(err, "Set current boot order at first")
}
return b.SendUEFIInfo(mgr)
})
}
func (b *SBaremetalInstance) SendUEFIInfo(mgr *uefi.BootMgr) error {
info, err := mgr.ToEFIBootMgrInfo()
if err != nil {
return err
}
desc := b.desc
uefiData := jsonutils.Marshal(info)
desc.Add(uefiData, "uefi_info")
if err := b.SaveDesc(desc); err != nil {
return errors.Wrap(err, "Save uefi_info")
}
updateData := jsonutils.NewDict()
updateData.Add(uefiData, "uefi_info")
if _, err := modules.Hosts.Update(b.GetClientSession(), b.GetId(), updateData); err != nil {
return errors.Wrap(err, "Update cloud uefi info")
}
return nil
}
func (b *SBaremetalInstance) adjustServerUEFIBootOrder(srvCli *ssh.Client) error {
return b.adjustUEFIWrapper(srvCli, func() error {
info, err := b.GetUEFIInfo()
if err != nil {
return errors.Wrap(err, "GetUEFIInfo from local desc")
}
if info == nil {
return uefi.RemoteTryToSetPXEBoot(srvCli)
}
if err := uefi.RemoteTryToSetPXEBoot(srvCli); err != nil {
log.Warningf("RemoteTryToSetPXEBoot error: %v", err)
}
_, err = uefi.RemoteSetBootOrderByInfo(srvCli, info.GetPXEEntry())
return err
})
}
func (b *SBaremetalInstance) AdjustUEFIBootOrder() error {
_, err := b.sshRunWrapper(
func(hostCli *ssh.Client) ([]string, error) {
return nil, b.AdjustUEFICurrentBootOrder(hostCli)
},
func(srvCli *ssh.Client) ([]string, error) {
return nil, b.adjustServerUEFIBootOrder(srvCli)
},
)
return err
}
func (b *SBaremetalInstance) SSHReboot() error {
if !b.HasBMC() {
// try adjust uefi boot order before reboot
if err := b.AdjustUEFIBootOrder(); err != nil {
return errors.Wrap(err, "Adjust uefi boot order")
}
}
if _, err := b.sshRun("/sbin/reboot", "sudo shutdown -r now && exit"); err != nil {
if !ssh.IsExitMissingError(err) {
return errors.Wrap(err, "Try reboot")
@@ -2288,7 +2394,9 @@ func (s *SBaremetalServer) DoDiskConfig(term *ssh.Client) error {
if err != nil {
return fmt.Errorf("CalculateLayout: %v", err)
}
log.Errorf("===layouts: %s", jsonutils.Marshal(layouts).PrettyString())
diskConfs := baremetal.GroupLayoutResultsByDriverAdapter(layouts)
log.Errorf("===diskConfs: %s", jsonutils.Marshal(diskConfs).PrettyString())
for _, dConf := range diskConfs {
driver := dConf.Driver
raidDrv := raiddrivers.GetDriver(driver, term)
+10 -10
View File
@@ -328,23 +328,23 @@ func (req *dhcpRequest) findBaremetalsOfAnyMac(session *mcclient.ClientSession,
// createOrUpdateBaremetal create or update baremetal by client MAC
func (req *dhcpRequest) createOrUpdateBaremetal(session *mcclient.ClientSession) (jsonutils.JSONObject, error) {
// first try UUID
ret, err := req.findBaremetalsByUuid(session)
// first try mac and is_baremetal=true
ret, err := req.findBaremetalsOfAnyMac(session, true)
if err != nil {
return nil, err
}
if len(ret.Data) == 0 {
// try mac and is_baremetal=true
ret, err = req.findBaremetalsOfAnyMac(session, true)
// try mac and host_type=baremetal
ret, err = req.findBaremetalsOfAnyMac(session, false)
if err != nil {
return nil, err
}
if len(ret.Data) == 0 {
// try mac and host_type=baremetal
ret, err = req.findBaremetalsOfAnyMac(session, false)
if err != nil {
return nil, err
}
}
if len(ret.Data) == 0 {
// try UUID
ret, err = req.findBaremetalsByUuid(session)
if err != nil {
return nil, err
}
}
switch len(ret.Data) {
+2 -21
View File
@@ -26,7 +26,6 @@ import (
"yunion.io/x/pkg/errors"
o "yunion.io/x/onecloud/pkg/baremetal/options"
"yunion.io/x/onecloud/pkg/baremetal/utils/uefi"
"yunion.io/x/onecloud/pkg/cloudcommon/object"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/mcclient"
@@ -492,24 +491,6 @@ func (self *SBaremetalPXEBootTaskBase) GetName() string {
return "BaremetalPXEBootTaskBase"
}
func AdjustUEFIBootOrder(term *ssh.Client) error {
isUEFI, err := uefi.RemoteIsUEFIBoot(term)
if err != nil {
return errors.Wrap(err, "Check baremetal is UEFI boot")
}
if !isUEFI {
return nil
}
mgr, err := uefi.NewEFIBootMgrFromRemote(term)
if err != nil {
return errors.Wrap(err, "NewEFIBootMgrFromRemote")
}
if err := uefi.RemoteSetCurrentBootAtFirst(term, mgr); err != nil {
return errors.Wrap(err, "Set current pxe boot at fist")
}
return nil
func AdjustUEFIBootOrder(term *ssh.Client, bm IBaremetal) error {
return bm.AdjustUEFICurrentBootOrder(term)
}
+14 -1
View File
@@ -22,6 +22,7 @@ import (
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
"yunion.io/x/onecloud/pkg/baremetal/utils/uefi"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/ssh"
@@ -30,6 +31,7 @@ import (
type IServerBaseDeployTask interface {
IPXEBootTask
RemoveEFIOSEntry() bool
DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error)
PostDeploys(term *ssh.Client) error
}
@@ -75,6 +77,10 @@ func (self *SBaremetalServerBaseDeployTask) GetFinishAction() string {
return ""
}
func (self *SBaremetalServerBaseDeployTask) RemoveEFIOSEntry() bool {
return false
}
func (self *SBaremetalServerBaseDeployTask) DoDeploys(_ *ssh.Client) (jsonutils.JSONObject, error) {
return nil, nil
}
@@ -85,12 +91,19 @@ func (self *SBaremetalServerBaseDeployTask) PostDeploys(_ *ssh.Client) error {
func (self *SBaremetalServerBaseDeployTask) OnPXEBoot(ctx context.Context, term *ssh.Client, args interface{}) error {
log.Infof("%s called on stage pxeboot, args: %v", self.GetName(), args)
if self.IServerBaseDeployTask().RemoveEFIOSEntry() {
if err := uefi.RemoteTryRemoveOSBootEntry(term); err != nil {
return errors.Wrap(err, "Remote uefi boot entry")
}
}
result, err := self.IServerBaseDeployTask().DoDeploys(term)
if err != nil {
return errors.Wrap(err, "Do deploy")
}
if err := AdjustUEFIBootOrder(term); err != nil {
if err := AdjustUEFIBootOrder(term, self.Baremetal); err != nil {
return errors.Wrap(err, "Adjust UEFI boot order")
}
+15 -13
View File
@@ -137,22 +137,24 @@ func (task *sBaremetalPrepareTask) prepareBaremetalInfo(cli *ssh.Client) (*barem
if ipmiInfo == nil {
ipmiInfo = &types.SIPMIInfo{}
}
if !ipmiInfo.Present && ipmiEnable {
if !ipmiInfo.Verified && !ipmiInfo.Present && ipmiEnable {
ipmiInfo.Present = true
ipmiInfo.Verified = false
}
return &baremetalPrepareInfo{
sysInfo,
cpuInfo,
dmiCPUInfo,
memInfo,
nicsInfo,
diskInfo,
storageDriver,
ipmiInfo,
isolatedDevicesInfo,
}, nil
prepareInfo := &baremetalPrepareInfo{
sysInfo: sysInfo,
cpuInfo: cpuInfo,
dmiCpuInfo: dmiCPUInfo,
memInfo: memInfo,
nicsInfo: nicsInfo,
diskInfo: diskInfo,
storageDriver: storageDriver,
ipmiInfo: ipmiInfo,
isolatedDevicesInfo: isolatedDevicesInfo,
}
return prepareInfo, nil
}
func (task *sBaremetalPrepareTask) configIPMISetting(cli *ssh.Client, i *baremetalPrepareInfo) error {
@@ -327,7 +329,7 @@ func (task *sBaremetalPrepareTask) DoPrepare(cli *ssh.Client) error {
log.Errorf("SetNTP fail: %s", err)
}
if err = AdjustUEFIBootOrder(cli); err != nil {
if err = AdjustUEFIBootOrder(cli, task.baremetal); err != nil {
logclient.AddActionLogWithStartable(task, task.baremetal, logclient.ACT_PREPARE, err, task.userCred, false)
return errors.Wrap(err, "Adjust UEFI boot order")
}
+4
View File
@@ -46,6 +46,10 @@ func (self *SBaremetalServerCreateTask) GetName() string {
return "BaremetalServerCreateTask"
}
func (self *SBaremetalServerCreateTask) RemoveEFIOSEntry() bool {
return true
}
func (self *SBaremetalServerCreateTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
// Build raid
err := self.Baremetal.GetServer().DoDiskConfig(term)
+4
View File
@@ -43,6 +43,10 @@ func (self *SBaremetalServerDeployTask) GetName() string {
return "BaremetalServerDeployTask"
}
func (self *SBaremetalServerDeployTask) RemoveEFIOSEntry() bool {
return false
}
func (self *SBaremetalServerDeployTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
return self.Baremetal.GetServer().DoDeploy(term, self.data, false)
}
+4
View File
@@ -44,6 +44,10 @@ func (self *SBaremetalServerDestroyTask) GetName() string {
return "BaremetalServerDestroyTask"
}
func (self *SBaremetalServerDestroyTask) RemoveEFIOSEntry() bool {
return true
}
func (self *SBaremetalServerDestroyTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
if err := self.Baremetal.GetServer().DoEraseDisk(term); err != nil {
log.Errorf("Delete server do erase disk: %v", err)
+2
View File
@@ -23,6 +23,7 @@ import (
baremetaltypes "yunion.io/x/onecloud/pkg/baremetal/types"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/ssh"
)
type IBaremetal interface {
@@ -73,6 +74,7 @@ type IBaremetal interface {
SSHReachable() (bool, error)
SSHReboot() error
SSHShutdown() error
AdjustUEFICurrentBootOrder(cli *ssh.Client) error
}
type IBmManager interface {
+4
View File
@@ -45,6 +45,10 @@ func (self *SBaremetalServerRebuildTask) GetName() string {
return "BaremetalServerRebuildTask"
}
func (self *SBaremetalServerRebuildTask) RemoveEFIOSEntry() bool {
return true
}
func (self *SBaremetalServerRebuildTask) DoDeploys(term *ssh.Client) (jsonutils.JSONObject, error) {
parts, err := self.Baremetal.GetServer().DoRebuildRootDisk(term)
if err != nil {
+18 -1
View File
@@ -616,7 +616,24 @@ func (tool *PartitionTool) parseLsDisk(lines []string, driver string) {
}
minCnt := int(math.Min(float64(len(disks)), float64(len(tool.diskTable[driver]))))
for i := 0; i < minCnt; i++ {
tool.diskTable[driver][i].SetInfo(disks[i])
driverDisk := tool.diskTable[driver][i]
if utils.IsInStringArray(driver, []string{NONRAID_DRIVER, PCIE_DRIVER}) {
// find size matched disk from disks
size := driverDisk.sizeMB
var remoteDisk *types.SDiskInfo
for ri := range disks {
if disks[ri].Size == size {
remoteDisk = disks[ri]
// remove matched disks
disks = append(disks[:ri], disks[ri+1:]...)
break
}
}
driverDisk.SetInfo(remoteDisk)
} else {
// raid disk set by order
driverDisk.SetInfo(disks[i])
}
}
}
+161 -7
View File
@@ -22,13 +22,17 @@ import (
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudcommon/types"
"yunion.io/x/onecloud/pkg/util/regutils2"
"yunion.io/x/onecloud/pkg/util/ssh"
)
const (
// efibootmgr useage: https://github.com/rhboot/efibootmgr
CMD_EFIBOOTMGR = "/usr/sbin/efibootmgr"
CMD_EFIBOOTMGR = "/usr/sbin/efibootmgr"
SUDO_EFIBOOTMGR = "sudo efibootmgr"
MAC_KEYWORD = "MAC"
)
type BootMgr struct {
@@ -60,6 +64,13 @@ type BootEntry struct {
IsActive bool
}
func getEFIBootMgrCmd(sudo bool) string {
if sudo {
return SUDO_EFIBOOTMGR
}
return CMD_EFIBOOTMGR
}
func ParseEFIBootMGR(input string) (*BootMgr, error) {
lines := strings.Split(input, "\n")
@@ -213,8 +224,15 @@ func parseEFIBootMGREntry(line string) *BootEntry {
}
}
func NewEFIBootMgrFromRemote(cli *ssh.Client) (*BootMgr, error) {
cmd := CMD_EFIBOOTMGR
func NewEFIBootMgrFromRemote(cli *ssh.Client, sudo bool) (*BootMgr, error) {
return newEFIBootMgrFromRemote(cli, sudo, true)
}
func newEFIBootMgrFromRemote(cli *ssh.Client, sudo bool, verbose bool) (*BootMgr, error) {
cmd := getEFIBootMgrCmd(sudo)
if verbose {
cmd = fmt.Sprintf("%s -v", cmd)
}
lines, err := cli.RawRun(cmd)
if err != nil {
return nil, errors.Wrapf(err, "Execute command: %s", cmd)
@@ -222,8 +240,8 @@ func NewEFIBootMgrFromRemote(cli *ssh.Client) (*BootMgr, error) {
return ParseEFIBootMGR(strings.Join(lines, "\n"))
}
func (m *BootMgr) GetCommand() string {
return CMD_EFIBOOTMGR
func (m *BootMgr) GetCommand(sudo bool) string {
return getEFIBootMgrCmd(sudo)
}
func (m *BootMgr) GetBootCurrent() string {
@@ -246,6 +264,15 @@ func (m *BootMgr) GetBootEntry(num string) *BootEntry {
return m.entries[num]
}
func (m *BootMgr) GetBootEntryByDesc(desc string) *BootEntry {
for _, entry := range m.entries {
if strings.Contains(entry.Description, desc) {
return entry
}
}
return nil
}
func (m *BootMgr) FindBootOrderPos(num string) int {
return stringArraryFindItemPos(m.bootOrder, num)
}
@@ -293,8 +320,12 @@ func (m *BootMgr) MoveBootOrder(num string, pos int) *BootMgr {
return m
}
func getSetBootOrderArgs(bootOrder []string) string {
return strings.Join(bootOrder, ",")
}
func (m *BootMgr) GetSetBootOrderArgs() string {
return strings.Join(m.bootOrder, ",")
return getSetBootOrderArgs(m.bootOrder)
}
func RemoteIsUEFIBoot(cli *ssh.Client) (bool, error) {
@@ -311,6 +342,45 @@ func RemoteIsUEFIBoot(cli *ssh.Client) (bool, error) {
return false, nil
}
func convertToEFIBootMgrInfo(info *BootMgr) (*types.EFIBootMgrInfo, error) {
data := &types.EFIBootMgrInfo{
PxeBootNum: info.GetBootCurrent(),
BootOrder: make([]*types.EFIBootEntry, len(info.GetBootOrder())),
}
for idx, orderNum := range info.GetBootOrder() {
entry := info.GetBootEntry(orderNum)
if entry == nil {
return nil, errors.Errorf("Not found boot entry by %q", orderNum)
}
data.BootOrder[idx] = &types.EFIBootEntry{
BootNum: entry.BootNum,
Description: entry.Description,
IsActive: entry.IsActive,
}
}
return data, nil
}
func (mgr *BootMgr) ToEFIBootMgrInfo() (*types.EFIBootMgrInfo, error) {
return convertToEFIBootMgrInfo(mgr)
}
func (mgr *BootMgr) sortEntryByKeyword(keyword string) *BootMgr {
newOrder := []string{}
oldOrder := []string{}
for _, num := range mgr.bootOrder {
entry := mgr.GetBootEntry(num)
if strings.Contains(entry.Description, keyword) {
newOrder = append(newOrder, num)
} else {
oldOrder = append(oldOrder, num)
}
}
newOrder = append(newOrder, oldOrder...)
mgr.bootOrder = newOrder
return mgr
}
func RemoteSetCurrentBootAtFirst(cli *ssh.Client, mgr *BootMgr) error {
curPos := mgr.FindBootOrderPos(mgr.GetBootCurrent())
if curPos == -1 {
@@ -318,7 +388,91 @@ func RemoteSetCurrentBootAtFirst(cli *ssh.Client, mgr *BootMgr) error {
}
// move to first
mgr.MoveBootOrder(mgr.GetBootCurrent(), 0)
cmd := fmt.Sprintf("%s -o %s", mgr.GetCommand(), mgr.GetSetBootOrderArgs())
cmd := fmt.Sprintf("%s -o %s", mgr.GetCommand(false), mgr.GetSetBootOrderArgs())
_, err := cli.Run(cmd)
return err
}
func RemoteSetBootOrder(cli *ssh.Client, order []string) error {
cmd := fmt.Sprintf("%s -o %s", SUDO_EFIBOOTMGR, getSetBootOrderArgs(order))
_, err := cli.RunWithTTY(cmd)
return err
}
func RemoteSetBootOrderByInfo(cli *ssh.Client, entry *types.EFIBootEntry) (*BootMgr, error) {
mgr, err := newEFIBootMgrFromRemote(cli, true, true)
if err != nil {
return nil, err
}
curEntry := mgr.GetBootEntryByDesc(entry.Description)
if curEntry == nil {
return nil, errors.Wrapf(err, "Not found remote boot entry by %q", entry.Description)
}
mgr = mgr.sortEntryByKeyword(curEntry.Description)
return mgr, RemoteSetBootOrder(cli, mgr.GetBootOrder())
}
func RemoteTryToSetPXEBoot(cli *ssh.Client) error {
mgr, err := newEFIBootMgrFromRemote(cli, true, true)
if err != nil {
return err
}
mgr = mgr.sortEntryByKeyword(MAC_KEYWORD)
return RemoteSetBootOrder(cli, mgr.GetBootOrder())
}
func remoteISUEFIBootWrap(cli *ssh.Client, f func(*ssh.Client) error) error {
isUEFI, err := RemoteIsUEFIBoot(cli)
if err != nil {
return errors.Wrap(err, "Check is UEFI boot")
}
if !isUEFI {
return nil
}
return f(cli)
}
func RemoteTryRemoveOSBootEntry(hostCli *ssh.Client) error {
return remoteISUEFIBootWrap(hostCli, remoteTryRemoveOSBootEntry)
}
func remoteTryRemoveOSBootEntry(hostCli *ssh.Client) error {
mgr, err := newEFIBootMgrFromRemote(hostCli, false, true)
if err != nil {
return err
}
// TODO: find other ways to decide whether entry is OS boot
osKeywords := []string{
"linux",
"centos",
"ubuntu",
"windows",
"grub",
}
isOsEntry := func(desc string) bool {
for _, key := range osKeywords {
desc := strings.ToLower(desc)
if strings.Contains(desc, key) {
return true
}
}
return false
}
for _, entry := range mgr.entries {
if !isOsEntry(entry.Description) {
continue
}
// delete entry and remove it from BootOrder
cmd := fmt.Sprintf("%s -b %s -B", mgr.GetCommand(false), entry.BootNum)
if _, err := hostCli.Run(cmd); err != nil {
return errors.Wrapf(err, "remove boot entry: %s", entry.Description)
}
}
return nil
}
+35
View File
@@ -0,0 +1,35 @@
// 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 types
type EFIBootMgrInfo struct {
PxeBootNum string `json:"pxe_boot_num"`
BootOrder []*EFIBootEntry `json:"boot_order"`
}
type EFIBootEntry struct {
BootNum string `json:"boot_num"`
Description string `json:"description"`
IsActive bool `json:"is_active"`
}
func (info *EFIBootMgrInfo) GetPXEEntry() *EFIBootEntry {
for _, e := range info.BootOrder {
if e.BootNum == info.PxeBootNum {
return e
}
}
return nil
}
+61
View File
@@ -21,6 +21,9 @@ import (
"github.com/stretchr/testify/assert"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
@@ -1277,6 +1280,33 @@ var (
Index: 0,
},
}
pcie2Storages = []*BaremetalStorage{
{
Driver: DISK_DRIVER_LINUX,
Dev: "sda",
Rotate: true,
Size: 3815447,
Adapter: 0,
Index: 0,
},
{
Driver: DISK_DRIVER_PCIE,
Dev: "nvme0n1",
Rotate: false,
Size: 1953514,
Adapter: 0,
Index: 0,
},
{
Driver: DISK_DRIVER_PCIE,
Dev: "nvme1n1",
Rotate: false,
Size: 122104,
Adapter: 0,
Index: 0,
},
}
)
func TestPCIEStoragesAllocable(t *testing.T) {
@@ -1331,3 +1361,34 @@ func TestPCIEStoragesAllocable(t *testing.T) {
t.Errorf("Disk not allocable")
}
}
func Test2PCIEStoragesAllocable(t *testing.T) {
adapter0 := 0
confs := []*api.BaremetalDiskConfig{
{
Adapter: &adapter0,
Conf: DISK_CONF_NONE,
Count: 0,
Driver: DISK_DRIVER_PCIE,
Range: []int64{1},
Type: DISK_TYPE_SSD,
},
}
layouts, err := CalculateLayout(confs, pcie2Storages)
if err != nil {
t.Errorf("CalculateLayout error: %v", err)
return
}
log.Errorf("layouts: %s", jsonutils.Marshal(layouts))
disks := []*api.DiskConfig{
{
Backend: api.STORAGE_LOCAL,
Driver: "scsi",
SizeMb: -1,
},
}
if ok := IsDisksAllocable(layouts, disks); !ok {
t.Errorf("Disk not allocable")
}
}
+36 -1
View File
@@ -188,6 +188,9 @@ type SHost struct {
// IPv4地址,作为么有云vpc访问外网时的网关
OvnMappedIpAddr string `width:"16" charset:"ascii" nullable:"true" list:"user"`
// UEFI详情
UefiInfo jsonutils.JSONObject `nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
}
func (manager *SHostManager) GetContextManagers() [][]db.IModelManager {
@@ -3527,6 +3530,10 @@ func (self *SHost) PostUpdate(ctx context.Context, userCred mcclient.TokenCreden
log.Errorf("baremetal host %s update related server %s spec error: %v", self.GetName(), guest.GetName(), err)
}
}
if err := self.startSyncConfig(ctx, userCred, "", true); err != nil {
log.Errorf("start sync host %q config after updated", self.GetName())
}
}
func (self *SHost) UpdateDnsRecords(isAdd bool) {
@@ -3940,6 +3947,17 @@ func (self *SHost) HasBMC() bool {
return false
}
func (self *SHost) IsUEFIBoot() bool {
info, _ := self.GetUEFIInfo()
if info == nil {
return false
}
if len(info.PxeBootNum) == 0 {
return false
}
return true
}
func (self *SHost) isRedfishCapable() bool {
ipmiInfo, _ := self.GetIpmiInfo()
if ipmiInfo.Verified && ipmiInfo.RedfishApi {
@@ -5624,6 +5642,17 @@ func (host *SHost) GetIpmiInfo() (types.SIPMIInfo, error) {
return info, nil
}
func (host *SHost) GetUEFIInfo() (*types.EFIBootMgrInfo, error) {
if host.UefiInfo == nil {
return nil, nil
}
info := new(types.EFIBootMgrInfo)
if err := host.UefiInfo.Unmarshal(info); err != nil {
return nil, errors.Wrap(err, "host.UefiInfo.Unmarshal")
}
return info, nil
}
func (self *SHost) AllowGetDetailsJnlp(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
return db.IsAdminAllowGetSpec(userCred, self, "jnlp")
}
@@ -5725,7 +5754,13 @@ func (self *SHost) PerformSyncConfig(ctx context.Context, userCred mcclient.Toke
}
func (self *SHost) StartSyncConfig(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
task, err := taskman.TaskManager.NewTask(ctx, "BaremetalSyncConfigTask", self, userCred, nil, parentTaskId, "", nil)
return self.startSyncConfig(ctx, userCred, parentTaskId, false)
}
func (self *SHost) startSyncConfig(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, noStatus bool) error {
data := jsonutils.NewDict()
data.Add(jsonutils.NewBool(noStatus), "not_sync_status")
task, err := taskman.TaskManager.NewTask(ctx, "BaremetalSyncConfigTask", self, userCred, data, parentTaskId, "", nil)
if err != nil {
return err
}
@@ -54,9 +54,14 @@ func (self *BaremetalSyncConfigTask) DoSyncConfig(ctx context.Context, baremetal
}
func (self *BaremetalSyncConfigTask) OnSyncConfigComplete(ctx context.Context, baremetal *models.SHost, body jsonutils.JSONObject) {
logclient.AddActionLogWithStartable(self, baremetal, logclient.ACT_SYNC_CONF, "", self.UserCred, true)
notSyncStatus, _ := self.Params.Bool("not_sync_status")
if notSyncStatus {
self.SetStageComplete(ctx, nil)
return
}
self.SetStage("OnSyncstatusComplete", nil)
baremetal.StartSyncstatus(ctx, self.UserCred, self.GetTaskId())
logclient.AddActionLogWithStartable(self, baremetal, logclient.ACT_SYNC_CONF, "", self.UserCred, true)
}
func (self *BaremetalSyncConfigTask) OnSyncstatusComplete(ctx context.Context, baremetal *models.SHost, body jsonutils.JSONObject) {
+19
View File
@@ -596,6 +596,10 @@ func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics
if mainNic != nil {
mainIp = mainNic.Ip
}
var systemdResolveConfig strings.Builder
dnss := []string{}
domains := []string{}
for i := range allNics {
nicDesc := allNics[i]
cmds.WriteString(fmt.Sprintf("auto %s\n", nicDesc.Name))
@@ -628,8 +632,10 @@ func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics
dnslist := netutils2.GetNicDns(nicDesc)
if len(dnslist) > 0 {
cmds.WriteString(fmt.Sprintf(" dns-nameservers %s\n", strings.Join(dnslist, " ")))
dnss = append(dnss, dnslist...)
if len(nicDesc.Domain) > 0 {
cmds.WriteString(fmt.Sprintf(" dns-search %s\n", nicDesc.Domain))
domains = append(domains, nicDesc.Domain)
}
}
if len(nicDesc.TeamingSlaves) > 0 {
@@ -644,6 +650,19 @@ func (d *sDebianLikeRootFs) DeployNetworkingScripts(rootFs IDiskPartition, nics
cmds.WriteString("\n")
}
}
if len(dnss) != 0 {
systemdResolveConfig.WriteString("[Resolve]\n")
systemdResolveConfig.WriteString(fmt.Sprintf("DNS=%s\n", strings.Join(dnss, " ")))
if len(domains) != 0 {
systemdResolveConfig.WriteString(fmt.Sprintf("Domains=%s\n", strings.Join(domains, " ")))
}
systemdResolveFn := "/etc/systemd/resolved.conf"
content := systemdResolveConfig.String()
if err := rootFs.FilePutContents(systemdResolveFn, content, false, false); err != nil {
log.Warningf("Put %s to %s error: %v", content, systemdResolveFn, err)
}
}
log.Debugf("%s", cmds.String())
return rootFs.FilePutContents(fn, cmds.String(), false, false)
}