| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938 |
- // 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 tasks
- import (
- "context"
- "fmt"
- "net"
- "strings"
- "time"
- "yunion.io/x/cloudmux/pkg/apis/compute"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/netutils"
- "yunion.io/x/pkg/util/seclib"
- "yunion.io/x/pkg/utils"
- "yunion.io/x/onecloud/pkg/apis"
- api "yunion.io/x/onecloud/pkg/apis/compute"
- baremetalapi "yunion.io/x/onecloud/pkg/apis/compute/baremetal"
- o "yunion.io/x/onecloud/pkg/baremetal/options"
- "yunion.io/x/onecloud/pkg/baremetal/profiles"
- "yunion.io/x/onecloud/pkg/baremetal/utils/detect_storages"
- "yunion.io/x/onecloud/pkg/baremetal/utils/ipmitool"
- "yunion.io/x/onecloud/pkg/cloudcommon/types"
- "yunion.io/x/onecloud/pkg/compute/baremetal"
- "yunion.io/x/onecloud/pkg/hostman/isolated_device"
- "yunion.io/x/onecloud/pkg/mcclient"
- modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
- "yunion.io/x/onecloud/pkg/util/logclient"
- "yunion.io/x/onecloud/pkg/util/ssh"
- "yunion.io/x/onecloud/pkg/util/sysutils"
- )
- type sBaremetalPrepareTask struct {
- baremetal IBaremetal
- startTime time.Time
- userCred mcclient.TokenCredential
- }
- func newBaremetalPrepareTask(baremetal IBaremetal, userCred mcclient.TokenCredential) *sBaremetalPrepareTask {
- return &sBaremetalPrepareTask{
- baremetal: baremetal,
- userCred: userCred,
- startTime: time.Now().UTC(),
- }
- }
- type baremetalPrepareInfo struct {
- architecture string
- sysInfo *types.SSystemInfo
- cpuInfo *types.SCPUInfo
- dmiCpuInfo *types.SDMICPUInfo
- memInfo *types.SDMIMemInfo
- nicsInfo []*types.SNicDevInfo
- diskInfo []*baremetal.BaremetalStorage
- storageDriver string
- ipmiInfo *types.SIPMIInfo
- isolatedDevicesInfo []*isolated_device.PCIDevice
- }
- func (task *sBaremetalPrepareTask) GetStartTime() time.Time {
- return task.startTime
- }
- func (task *sBaremetalPrepareTask) prepareBaremetalInfo(cli *ssh.Client) (*baremetalPrepareInfo, error) {
- arch, err := getArchitecture(cli)
- if err != nil {
- return nil, errors.Wrap(err, "getArchitecture")
- }
- if arch == apis.OS_ARCH_X86_64 {
- if _, err := cli.Run("/lib/mos/sysinit.sh"); err != nil {
- return nil, errors.Wrap(err, "run /lib/mos/sysinit.sh")
- }
- } else {
- log.Infof("Skip running /lib/mos/sysinit.sh when arch is %q", arch)
- }
- sysInfo, err := getDMISysinfo(cli)
- if err != nil {
- return nil, err
- }
- cpuInfo, err := getCPUInfo(cli)
- if err != nil {
- return nil, err
- }
- dmiCPUInfo, err := getDMICPUInfo(cli)
- if err != nil {
- return nil, err
- }
- memInfo, err := getDMIMemInfo(cli)
- if err != nil {
- return nil, err
- }
- nicsInfo, err := getNicsInfo(cli)
- if err != nil {
- return nil, err
- }
- dhcpServerIp, err := task.baremetal.GetDHCPServerIP()
- if err != nil {
- log.Errorf("failed get dhcp server %s", err)
- }
- isolatedDevicesInfo, err := getIsolatedDevicesInfo(cli, dhcpServerIp)
- if err != nil {
- return nil, err
- }
- raidDiskInfo, nonRaidDiskInfo, pcieDiskInfo, err := detect_storages.DetectStorageInfo(cli, true)
- if err != nil {
- return nil, err
- }
- diskInfo := make([]*baremetal.BaremetalStorage, 0)
- diskInfo = append(diskInfo, raidDiskInfo...)
- diskInfo = append(diskInfo, nonRaidDiskInfo...)
- diskInfo = append(diskInfo, pcieDiskInfo...)
- var storageDriver string
- if len(raidDiskInfo) > 0 {
- raidDrivers := []string{}
- for _, drv := range raidDiskInfo {
- if !utils.IsInStringArray(drv.Driver, raidDrivers) {
- raidDrivers = append(raidDrivers, drv.Driver)
- }
- }
- storageDriver = strings.Join(raidDrivers, ",")
- } else {
- storageDriver = baremetal.DISK_DRIVER_LINUX
- }
- ipmiEnable, err := isIPMIEnable(cli)
- if err != nil {
- return nil, err
- }
- ipmiInfo := task.baremetal.GetRawIPMIConfig()
- if ipmiInfo == nil {
- ipmiInfo = &types.SIPMIInfo{}
- }
- if !ipmiInfo.Verified && !ipmiInfo.Present && ipmiEnable {
- ipmiInfo.Present = true
- ipmiInfo.Verified = false
- }
- prepareInfo := &baremetalPrepareInfo{
- architecture: arch,
- 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(ctx context.Context, cli *ssh.Client, i *baremetalPrepareInfo) error {
- if !i.ipmiInfo.Present {
- return nil
- }
- // if verified, skip ipmi config
- if i.ipmiInfo.Verified {
- return nil
- }
- var (
- sysInfo = i.sysInfo
- ipmiInfo = i.ipmiInfo
- )
- sshIPMI := ipmitool.NewSSHIPMI(cli)
- setIPMILanPortShared(sshIPMI, sysInfo)
- profile, err := profiles.GetProfile(ctx, sysInfo)
- if err != nil {
- return errors.Wrap(err, "GetProfile")
- }
- ipmiUser, ipmiPasswd, ipmiIpAddr := task.getIPMIUserPasswd(i.ipmiInfo, profile)
- ipmiInfo.Username = ipmiUser
- ipmiInfo.Password = ipmiPasswd
- var ipmiLanChannel uint8 = 0
- for _, lanChannel := range profile.LanChannels {
- log.Infof("Try lan channel %d ...", lanChannel)
- conf, err := ipmitool.GetLanConfig(sshIPMI, lanChannel)
- if err != nil {
- log.Errorf("Get lan channel %d config error: %v", lanChannel, err)
- continue
- }
- if conf.Mac == nil {
- log.Errorf("Lan channel %d MAC address is empty", lanChannel)
- continue
- }
- ipmiNic := &types.SNicDevInfo{
- Mac: conf.Mac,
- Speed: 100,
- Mtu: 1500,
- }
- if err := task.sendNicInfo(ctx, ipmiNic, -1, api.NIC_TYPE_IPMI, true, "", false); err != nil {
- // ignore the error
- log.Errorf("Send IPMI nic %#v info: %v", ipmiNic, err)
- }
- rootId := profile.RootId
- err = ipmitool.CreateOrSetAdminUser(sshIPMI, lanChannel, rootId, ipmiUser, ipmiPasswd)
- if err != nil {
- // ignore the error
- log.Errorf("Lan channel %d set user password error: %v", lanChannel, err)
- }
- err = ipmitool.EnableLanAccess(sshIPMI, lanChannel)
- if err != nil {
- // ignore the error
- log.Errorf("Lan channel %d enable lan access error: %v", lanChannel, err)
- }
- tryAddrs := make([]string, 0)
- if ipmiIpAddr != "" {
- tryAddrs = append(tryAddrs, ipmiIpAddr)
- }
- if conf.IPAddr != "" && conf.IPAddr != ipmiIpAddr {
- tryAddrs = append(tryAddrs, conf.IPAddr)
- }
- if len(tryAddrs) > 0 && !o.Options.ForceDhcpProbeIpmi {
- for _, tryAddr := range tryAddrs {
- tryResult := task.tryLocalIpmiAddr(ctx, sshIPMI, ipmiNic, lanChannel,
- ipmiUser, ipmiPasswd, tryAddr)
- if tryResult {
- ipmiInfo.IpAddr = tryAddr
- ipmiLanChannel = lanChannel
- break
- }
- }
- if ipmiLanChannel > 0 {
- // found and set config on lanChannel
- break
- }
- }
- if len(tryAddrs) > 0 {
- task.baremetal.SetExistingIPMIIPAddr(tryAddrs[0])
- }
- err = ipmitool.SetLanDHCP(sshIPMI, lanChannel)
- if err != nil {
- // ignore error
- log.Errorf("Set lan channel %d dhcp error: %v", lanChannel, err)
- }
- time.Sleep(2 * time.Second)
- nic := task.baremetal.GetIPMINic(conf.Mac)
- maxTries := 180 // wait 3 minutes
- for tried := 0; nic != nil && nic.IpAddr == "" && tried < maxTries; tried++ {
- nic = task.baremetal.GetIPMINic(conf.Mac)
- }
- if len(nic.IpAddr) == 0 {
- err = ipmitool.DoBMCReset(sshIPMI) // do BMC reset to force DHCP request
- if err != nil {
- log.Errorf("Do BMC reset error: %v", err)
- }
- time.Sleep(1 * time.Second)
- }
- for tried := 0; nic != nil && nic.IpAddr == "" && tried < maxTries; tried++ {
- nic = task.baremetal.GetIPMINic(conf.Mac)
- time.Sleep(1 * time.Second)
- }
- if nic != nil && len(nic.IpAddr) == 0 {
- log.Errorf("DHCP wait IPMI address fail, retry ...")
- continue
- }
- log.Infof("DHCP get IPMI address succ, wait 2 seconds ...")
- var tried int = 0
- for tried < maxTries {
- time.Sleep(2 * time.Second)
- lanConf, err := ipmitool.GetLanConfig(sshIPMI, lanChannel)
- if err != nil {
- log.Errorf("Get lan config at channel %d error: %v", lanChannel, err)
- tried += 2
- continue
- }
- if lanConf.IPAddr == nic.IpAddr {
- break
- }
- log.Infof("waiting IPMI DHCP address old:%s expect:%s", lanConf.IPAddr, nic.IpAddr)
- tried += 2
- }
- if tried >= maxTries {
- continue
- }
- err = ipmitool.SetLanStatic(
- sshIPMI,
- lanChannel,
- nic.IpAddr,
- nic.GetNetMask(),
- nic.Gateway,
- )
- if err != nil {
- log.Errorf("Set lanChannel %d static net %#v error: %v", lanChannel, nic, err)
- continue
- }
- ipmiInfo.IpAddr = nic.IpAddr
- ipmiLanChannel = lanChannel
- }
- if ipmiLanChannel == 0 {
- return fmt.Errorf("Fail to get IPMI address from DHCP")
- }
- ipmiInfo.LanChannel = ipmiLanChannel
- ipmiInfo.Verified = true
- return nil
- }
- func (task *sBaremetalPrepareTask) DoPrepare(ctx context.Context, cli *ssh.Client) error {
- infos, err := task.prepareBaremetalInfo(cli)
- if err != nil {
- logclient.AddActionLogWithStartable(task, task.baremetal, logclient.ACT_PREPARE, err, task.userCred, false)
- return err
- }
- // set ipmi nic address and user password
- if err = task.configIPMISetting(ctx, cli, infos); err != nil {
- logclient.AddActionLogWithStartable(task, task.baremetal, logclient.ACT_PREPARE, err, task.userCred, false)
- return errors.Wrap(err, "Config IPMI setting")
- }
- if err = task.updateBmInfo(ctx, cli, infos); err != nil {
- logclient.AddActionLogWithStartable(task, task.baremetal, logclient.ACT_PREPARE, err, task.userCred, false)
- return err
- }
- // set NTP
- if err = task.baremetal.DoNTPConfig(); err != nil {
- // ignore error
- log.Errorf("SetNTP fail: %s", err)
- }
- if err = AdjustUEFIBootOrder(ctx, 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")
- }
- logclient.AddActionLogWithStartable(task, task.baremetal, logclient.ACT_PREPARE, infos.sysInfo, task.userCred, true)
- log.Infof("Prepare complete")
- return nil
- }
- func (task *sBaremetalPrepareTask) findAdminNic(cli *ssh.Client, nicsInfo []*types.SNicDevInfo) (int, *types.SNicDevInfo, error) {
- accessIp := cli.GetConfig().Host
- for idx := range nicsInfo {
- nic := nicsInfo[idx]
- output, err := cli.Run("/sbin/ifconfig " + nic.Dev)
- if err != nil {
- log.Errorf("ifconfig %s fail: %s", nic.Dev, err)
- continue
- }
- isAdmin := false
- for _, l := range output {
- if strings.Contains(l, accessIp) {
- isAdmin = true
- break
- }
- }
- if isAdmin {
- return idx, nic, nil
- }
- }
- return -1, nil, errors.Error("admin nic not found???")
- }
- func (task *sBaremetalPrepareTask) doUpdateBmInfo(
- ctx context.Context, cli *ssh.Client, i *baremetalPrepareInfo,
- bmName, accessIp, accessMac string,
- ) error {
- updateInfo := make(map[string]interface{})
- if bmName != "" {
- updateInfo["name"] = bmName
- }
- updateInfo["access_ip"] = accessIp
- if accessMac != "" {
- updateInfo["access_mac"] = accessMac
- }
- updateInfo["cpu_architecture"] = i.architecture
- updateInfo["cpu_count"] = i.cpuInfo.Count
- updateInfo["node_count"] = i.dmiCpuInfo.Nodes
- updateInfo["cpu_desc"] = i.cpuInfo.Model
- updateInfo["cpu_mhz"] = i.cpuInfo.Freq
- updateInfo["cpu_cache"] = i.cpuInfo.Cache
- updateInfo["mem_size"] = i.memInfo.Total
- updateInfo["storage_driver"] = i.storageDriver
- updateInfo["storage_info"] = i.diskInfo
- updateInfo["sys_info"] = i.sysInfo
- updateInfo["sn"] = i.sysInfo.SN
- size, diskType := task.collectDiskInfo(i.diskInfo)
- updateInfo["storage_size"] = size
- updateInfo["storage_type"] = diskType
- updateInfo["boot_mode"] = getBootMode(cli)
- updateInfo["uuid"] = getSystemGuid(cli)
- updateData := jsonutils.Marshal(updateInfo)
- updateData.(*jsonutils.JSONDict).Update(i.ipmiInfo.ToPrepareParams())
- _, err := modules.Hosts.Update(task.getClientSession(), task.baremetal.GetId(), updateData)
- if err != nil {
- log.Errorf("Update baremetal info error: %v", err)
- return errors.Wrap(err, "Hosts.Update")
- }
- if err := task.sendStorageInfo(size); err != nil {
- log.Errorf("sendStorageInfo error: %v", err)
- return errors.Wrap(err, "task.sendStorageInfo")
- }
- if len(i.isolatedDevicesInfo) > 0 {
- err = task.sendIsolatedDevicesInfo(task.getClientSession(), i.isolatedDevicesInfo)
- if err != nil {
- return errors.Wrap(err, "send isolated devices info")
- }
- }
- removedMacs := task.removeObsoleteNics(i)
- for idx := range removedMacs {
- err = task.removeNicInfo(ctx, removedMacs[idx])
- if err != nil {
- log.Errorf("Fail to remove Netif %s: %s", removedMacs[idx], err)
- return errors.Wrap(err, "task.removeNicInfo")
- }
- }
- for idx := range i.nicsInfo {
- err = task.sendNicInfo(ctx, i.nicsInfo[idx], idx, "", false, "", false)
- if err != nil {
- log.Errorf("Send nicinfo idx: %d, %#v error: %v", idx, i.nicsInfo[idx], err)
- return errors.Wrap(err, "task.sendNicInfo")
- }
- }
- return nil
- }
- func (task *sBaremetalPrepareTask) updateBmInfo(ctx context.Context, cli *ssh.Client, i *baremetalPrepareInfo) error {
- adminNic := task.baremetal.GetAdminNic()
- if adminNic == nil || (adminNic != nil && !adminNic.LinkUp) {
- adminIdx, adminNicDev, err := task.findAdminNic(cli, i.nicsInfo)
- if err != nil {
- return errors.Wrap(err, "task.findAdminNic")
- }
- accessIp := cli.GetConfig().Host
- err = task.sendNicInfo(ctx, adminNicDev, adminIdx, api.NIC_TYPE_ADMIN, false, accessIp, true)
- if err != nil {
- return errors.Wrap(err, "send Admin Nic Info")
- }
- adminNic = task.baremetal.GetNicByMac(adminNicDev.Mac)
- }
- oname := fmt.Sprintf("BM%s", strings.Replace(adminNic.Mac, ":", "", -1))
- if task.baremetal.GetName() != oname {
- oname = ""
- }
- err := task.doUpdateBmInfo(ctx, cli, i, oname, adminNic.IpAddr, adminNic.Mac)
- if err != nil {
- return err
- }
- if o.Options.EnablePxeBoot && task.baremetal.EnablePxeBoot() {
- for _, nicInfo := range i.nicsInfo {
- if nicInfo.Mac.String() != adminNic.GetMac().String() && nicInfo.Up != nil && *nicInfo.Up {
- err = task.doNicWireProbe(cli, nicInfo)
- if err != nil {
- // ignore the error
- log.Errorf("doNicWireProbe nic %#v error: %v", nicInfo, err)
- }
- }
- }
- }
- return nil
- }
- func (task *sBaremetalPrepareTask) removeObsoleteNics(i *baremetalPrepareInfo) []string {
- removes := make([]string, 0)
- existNics := task.baremetal.GetNics()
- log.Debugf("Existing nics: %s", jsonutils.Marshal(existNics))
- for idx := range existNics {
- if existNics[idx].Type != api.NIC_TYPE_NORMAL {
- continue
- }
- find := false
- for j := range i.nicsInfo {
- if existNics[idx].Mac == i.nicsInfo[j].Mac.String() {
- find = true
- break
- }
- }
- if !find {
- removes = append(removes, existNics[idx].Mac)
- }
- }
- return removes
- }
- func (task *sBaremetalPrepareTask) tryLocalIpmiAddr(ctx context.Context, sshIPMI *ipmitool.SSHIPMI, ipmiNic *types.SNicDevInfo, lanChannel uint8, ipmiUser, ipmiPasswd, tryAddr string) bool {
- log.Infof("IP addr found in IPMI config, try use %s as IPMI address", tryAddr)
- ipConf, err := task.getIPMIIPConfig(tryAddr)
- if err != nil {
- log.Errorf("Failed to get IPMI ipconfig for %s", tryAddr)
- return false
- }
- err = ipmitool.SetLanStatic(sshIPMI, lanChannel, ipConf.IPAddr, ipConf.Netmask, ipConf.Gateway)
- if err != nil {
- log.Errorf("Failed to set IPMI static net config %#v for %s", *ipConf, tryAddr)
- return false
- }
- var conf *types.SIPMILanConfig
- tried := 0
- maxTries := 5
- time.Sleep(2 * time.Second)
- for tried = 0; tried < maxTries; tried += 1 {
- conf, err = ipmitool.GetLanConfig(sshIPMI, lanChannel)
- if err != nil {
- log.Errorf("Failed to get lan config after set static network: %v", err)
- continue
- }
- log.Infof("Get lan config %#v", *conf)
- if conf.IPAddr == "" || conf.IPAddr != tryAddr {
- log.Errorf("Failed to set ipmi lan channel %d static ipaddr", lanChannel)
- continue
- }
- break
- }
- if tried >= maxTries {
- log.Errorf("Failed to get lan config after %d tries", tried)
- return false
- }
- rmcpIPMI := ipmitool.NewLanPlusIPMI(tryAddr, ipmiUser, ipmiPasswd)
- for tried = 0; tried < maxTries; tried += 1 {
- conf2, err := ipmitool.GetLanConfig(rmcpIPMI, lanChannel)
- if err != nil {
- log.Errorf("Failed to get lan channel %d config use RMCP mode: %v", lanChannel, err)
- continue
- }
- if len(conf2.Mac) != 0 &&
- conf2.Mac.String() == conf.Mac.String() &&
- conf2.IPAddr != "" && conf2.IPAddr == tryAddr {
- break
- } else {
- log.Errorf("fail to rmcp get IPMI ip config %v", conf2)
- time.Sleep(5 * time.Second)
- }
- }
- if tried < maxTries {
- // make sure the ipaddr is a IPMI address
- // enable the netif
- err := task.sendNicInfo(ctx, ipmiNic, -1, api.NIC_TYPE_IPMI, false, tryAddr, true)
- if err != nil {
- log.Errorf("Fail to set existing BMC IP address to %s", tryAddr)
- } else {
- return true
- }
- }
- return false
- }
- func (task *sBaremetalPrepareTask) getIPMIUserPasswd(oldIPMIConf *types.SIPMIInfo, profile *baremetalapi.BaremetalProfileSpec) (string, string, string) {
- var (
- ipmiUser string
- ipmiPasswd string
- ipmiIpAddr string
- )
- ipmiUser = profile.RootName
- isStrongPass := profile.StrongPass
- if !isStrongPass && o.Options.DefaultIpmiPassword != "" {
- ipmiPasswd = o.Options.DefaultIpmiPassword
- } else if isStrongPass && o.Options.DefaultStrongIpmiPassword != "" {
- ipmiPasswd = o.Options.DefaultStrongIpmiPassword
- } else if isStrongPass && o.Options.DefaultIpmiPassword != "" {
- ipmiPasswd = o.Options.DefaultIpmiPassword
- } else {
- ipmiPasswd = seclib.RandomPassword(20)
- }
- if oldIPMIConf.Username != "" {
- ipmiUser = oldIPMIConf.Username
- }
- if oldIPMIConf.Password != "" {
- ipmiPasswd = oldIPMIConf.Password
- }
- if oldIPMIConf.IpAddr != "" {
- ipmiIpAddr = oldIPMIConf.IpAddr
- }
- return ipmiUser, ipmiPasswd, ipmiIpAddr
- }
- type ipmiIPConfig struct {
- IPAddr string
- Netmask string
- Gateway string
- }
- func (task *sBaremetalPrepareTask) getIPMIIPConfig(ipAddr string) (*ipmiIPConfig, error) {
- params := jsonutils.NewDict()
- params.Add(jsonutils.NewString(ipAddr), "ip")
- params.Add(jsonutils.NewString("system"), "scope")
- params.Add(jsonutils.JSONTrue, "is_classic")
- listRet, err := modules.Networks.List(task.getClientSession(), params)
- if err != nil {
- return nil, err
- }
- if len(listRet.Data) != 1 {
- return nil, fmt.Errorf("Invalid network list count: %d", len(listRet.Data))
- }
- netObj := listRet.Data[0]
- config := &ipmiIPConfig{}
- config.IPAddr = ipAddr
- maskLen, _ := netObj.Int("guest_ip_mask")
- config.Netmask = netutils.Masklen2Mask(int8(maskLen)).String()
- config.Gateway, _ = netObj.GetString("guest_gateway")
- return config, nil
- }
- func (task *sBaremetalPrepareTask) getClientSession() *mcclient.ClientSession {
- return task.baremetal.GetClientSession()
- }
- func getArchitecture(cli *ssh.Client) (string, error) {
- ret, err := cli.Run("/bin/uname -m")
- if err != nil {
- return "", err
- }
- if len(ret) == 0 {
- return "", errors.Errorf("/bin/uname not output")
- }
- arch := strings.ToLower(ret[0])
- switch arch {
- case apis.OS_ARCH_AARCH64:
- return apis.OS_ARCH_AARCH64, nil
- case apis.OS_ARCH_X86_64:
- return apis.OS_ARCH_X86_64, nil
- default:
- return arch, nil
- }
- }
- func getDMISysinfo(cli *ssh.Client) (*types.SSystemInfo, error) {
- ret, err := cli.Run("/usr/sbin/dmidecode -t 1")
- if err != nil {
- return nil, err
- }
- return sysutils.ParseDMISysinfo(ret)
- }
- func getCPUInfo(cli *ssh.Client) (*types.SCPUInfo, error) {
- ret, err := cli.Run("cat /proc/cpuinfo")
- if err != nil {
- return nil, err
- }
- return sysutils.ParseCPUInfo(ret)
- }
- func getBootMode(cli *ssh.Client) string {
- lines, err := cli.Run("cat /proc/cmdline")
- if err != nil {
- return api.BOOT_MODE_PXE
- }
- const (
- key = "bootmode="
- )
- for _, line := range lines {
- pos := strings.Index(line, key)
- if pos >= 0 {
- if strings.HasPrefix(line[pos+len(key):], api.BOOT_MODE_ISO) {
- return api.BOOT_MODE_ISO
- }
- }
- }
- return api.BOOT_MODE_PXE
- }
- func getSystemGuid(cli *ssh.Client) string {
- lines, err := cli.Run("/usr/sbin/dmidecode -s system-uuid")
- if err != nil {
- return ""
- }
- for _, line := range lines {
- line = strings.TrimSpace(line)
- if len(line) > 0 {
- return sysutils.NormalizeUuid(line)
- }
- }
- return ""
- }
- func getDMICPUInfo(cli *ssh.Client) (*types.SDMICPUInfo, error) {
- ret, err := cli.Run("/usr/sbin/dmidecode -t 4")
- if err != nil {
- return nil, err
- }
- return sysutils.ParseDMICPUInfo(ret), nil
- }
- func getDMIMemInfo(cli *ssh.Client) (*types.SDMIMemInfo, error) {
- ret, err := cli.Run("/usr/sbin/dmidecode -t 17")
- if err != nil {
- return nil, err
- }
- return sysutils.ParseDMIMemInfo(ret), nil
- }
- func GetNicsInfo(cli *ssh.Client) ([]*types.SNicDevInfo, error) {
- return getNicsInfo(cli)
- }
- func getNicsInfo(cli *ssh.Client) ([]*types.SNicDevInfo, error) {
- ret, err := cli.Run("/lib/mos/lsnic")
- if err != nil {
- return nil, fmt.Errorf("Failed to retrieve NIC info: %v", err)
- }
- return sysutils.ParseNicInfo(ret), nil
- }
- func getIsolatedDevicesInfo(cli *ssh.Client, ip net.IP) ([]*isolated_device.PCIDevice, error) {
- // fetch pci.ids from baremetal agent
- var updatedPciids bool
- if ip != nil {
- out, err := cli.Run(fmt.Sprintf("tftp -g -r pci.ids %s -l /pci.ids", ip))
- if err != nil {
- log.Errorf("tftp failed download pciids %s %s", err, out)
- } else {
- updatedPciids = true
- }
- }
- var bootVgaPath = []string{}
- lines, err := cli.Run("ls /sys/bus/pci/devices/*/boot_vga")
- if err != nil {
- log.Errorf("failed find boot vga %s", err)
- }
- for i := 0; i < len(lines); i++ {
- bootVgaPath = append(bootVgaPath, strings.TrimSpace(lines[i]))
- }
- cmd := "lspci -nnmm"
- if updatedPciids {
- cmd = "lspci -i /pci.ids -nnmm"
- }
- lines, err = cli.Run(cmd)
- if err != nil {
- return nil, errors.Wrapf(err, "run %s", cmd)
- }
- devs := []*isolated_device.PCIDevice{}
- for _, line := range lines {
- if len(line) > 0 {
- dev := isolated_device.NewPCIDevice2(line, cli)
- if len(dev.Addr) > 0 && utils.IsInArray(dev.ClassCode, isolated_device.GpuClassCodes) && !isBootVga(cli, dev, bootVgaPath) {
- devs = append(devs, dev)
- }
- }
- }
- return devs, nil
- }
- func isBootVga(cli *ssh.Client, dev *isolated_device.PCIDevice, bootVgaPath []string) bool {
- for i := 0; i < len(bootVgaPath); i++ {
- if strings.Contains(bootVgaPath[i], dev.Addr) {
- out, err := cli.RawRun(fmt.Sprintf("cat %s", bootVgaPath[i]))
- if err != nil {
- log.Errorf("cat boot_vga %s failed %s", bootVgaPath[i], err)
- return false
- } else if len(out) > 0 {
- if strings.HasPrefix(out[0], "1") {
- log.Infof("device %s is boot vga", bootVgaPath[i])
- return true
- } else {
- return false
- }
- }
- break
- }
- }
- return false
- }
- func isIPMIEnable(cli *ssh.Client) (bool, error) {
- ret, err := cli.Run("/usr/sbin/dmidecode -t 38")
- if err != nil {
- return false, fmt.Errorf("Failed to retrieve IPMI info: %v", err)
- }
- return sysutils.ParseDMIIPMIInfo(ret), nil
- }
- func (task *sBaremetalPrepareTask) removeNicInfo(ctx context.Context, mac string) error {
- params := jsonutils.NewDict()
- params.Add(jsonutils.NewString(mac), "mac")
- resp, err := modules.Hosts.PerformAction(
- task.getClientSession(),
- task.baremetal.GetId(),
- "remove-netif",
- params,
- )
- if err != nil {
- return err
- }
- return task.baremetal.SaveDesc(ctx, resp)
- }
- func (task *sBaremetalPrepareTask) sendNicInfo(ctx context.Context,
- nic *types.SNicDevInfo, idx int, nicType compute.TNicType, reset bool, ipAddr string, reserve bool,
- ) error {
- return task.baremetal.SendNicInfo(ctx, nic, idx, nicType, reset, ipAddr, reserve)
- }
- func (task *sBaremetalPrepareTask) sendStorageInfo(size int64) error {
- params := jsonutils.NewDict()
- params.Add(jsonutils.NewInt(size), "capacity")
- params.Add(jsonutils.NewString(task.baremetal.GetZoneId()), "zone_id")
- params.Add(jsonutils.NewString(task.baremetal.GetStorageCacheId()), "storagecache_id")
- _, err := modules.Hosts.PerformAction(task.getClientSession(), task.baremetal.GetId(), "update-storage", params)
- return err
- }
- func (task *sBaremetalPrepareTask) getCloudIsolatedDevices(
- session *mcclient.ClientSession,
- ) ([]jsonutils.JSONObject, error) {
- params := jsonutils.NewDict()
- params.Set("details", jsonutils.JSONTrue)
- params.Set("limit", jsonutils.NewInt(0))
- params.Set("host", jsonutils.NewString(task.baremetal.GetId()))
- params.Set("scope", jsonutils.NewString("system"))
- params.Set("show_baremetal_isolated_devices", jsonutils.JSONTrue)
- res, err := modules.IsolatedDevices.List(session, params)
- if err != nil {
- return nil, err
- }
- return res.Data, nil
- }
- func (task *sBaremetalPrepareTask) sendIsolatedDevicesInfo(
- session *mcclient.ClientSession, devs []*isolated_device.PCIDevice,
- ) error {
- objs, err := task.getCloudIsolatedDevices(session)
- if err != nil {
- return errors.Wrap(err, "get cloud isolated devices")
- }
- gpuDevs := make([]isolated_device.IDevice, len(devs))
- for i := 0; i < len(devs); i++ {
- gpuDevs[i] = isolated_device.NewGPUHPCDevice(devs[i])
- }
- for _, obj := range objs {
- var notFound = true
- info := isolated_device.CloudDeviceInfo{}
- if err := obj.Unmarshal(&info); err != nil {
- return errors.Wrap(err, "unmarshal isolated device to cloud device info failed")
- }
- for i := 0; i < len(gpuDevs); i++ {
- if gpuDevs[i].GetAddr() == info.Addr && gpuDevs[i].GetVendorDeviceId() == info.VendorDeviceId {
- gpuDevs[i].SetDeviceInfo(info)
- notFound = false
- break
- }
- }
- if notFound {
- _, err := modules.IsolatedDevices.PerformAction(session, info.Id, "purge", nil)
- if err != nil {
- return errors.Wrap(err, "purge unknown isolated devices")
- }
- }
- }
- for i := 0; i < len(gpuDevs); i++ {
- if _, err := isolated_device.SyncDeviceInfo(session, task.baremetal.GetId(), gpuDevs[i], true); err != nil {
- return errors.Wrap(err, "sync device info")
- }
- }
- return nil
- }
- func (task *sBaremetalPrepareTask) doNicWireProbe(cli *ssh.Client, nic *types.SNicDevInfo) error {
- maxTries := 6
- for tried := 0; tried < maxTries; tried++ {
- log.Infof("doNicWireProbe %v", nic)
- _, err := cli.Run(fmt.Sprintf("/sbin/udhcpc -t 1 -T 3 -n -i %s", nic.Dev))
- if err != nil {
- log.Errorf("/sbin/udhcpc error: %v", err)
- }
- nicInfo := task.baremetal.GetNicByMac(nic.Mac)
- if nicInfo != nil && nicInfo.WireId != "" {
- log.Infof("doNicWireProbe success, get result %#v", nicInfo)
- break
- }
- }
- return nil
- }
- func (task *sBaremetalPrepareTask) collectDiskInfo(diskInfo []*baremetal.BaremetalStorage) (int64, string) {
- cnt := 0
- rotateCnt := 0
- var size int64 = 0
- var diskType string
- for _, d := range diskInfo {
- if d.Rotate {
- rotateCnt += 1
- }
- size += d.Size
- cnt += 1
- }
- if rotateCnt == cnt {
- diskType = "rotate"
- } else if rotateCnt == 0 {
- diskType = "ssd"
- } else {
- diskType = "hybrid"
- }
- return size, diskType
- }
- func setIPMILanPortShared(cli ipmitool.IPMIExecutor, sysInfo *types.SSystemInfo) {
- if !o.Options.IpmiLanPortShared {
- return
- }
- oemName := strings.ToLower(sysInfo.Manufacture)
- var err error
- switch sysInfo.OemName {
- case types.OEM_NAME_HUAWEI:
- err = ipmitool.SetHuaweiIPMILanPortShared(cli)
- case types.OEM_NAME_DELL:
- err = ipmitool.SetDellIPMILanPortShared(cli)
- }
- if err != nil {
- log.Errorf("Set %s ipmi lan port shared failed: %v", oemName, err)
- }
- }
|