| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229 |
- // 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 baremetal
- import (
- "context"
- "fmt"
- "io/fs"
- "io/ioutil"
- "net"
- "net/http"
- "net/url"
- "os"
- "path/filepath"
- "reflect"
- "strconv"
- "strings"
- "sync"
- "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/httputils"
- "yunion.io/x/pkg/util/netutils"
- "yunion.io/x/pkg/util/regutils"
- "yunion.io/x/pkg/util/seclib"
- "yunion.io/x/pkg/util/sets"
- "yunion.io/x/pkg/util/workqueue"
- "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"
- apiidenty "yunion.io/x/onecloud/pkg/apis/identity"
- o "yunion.io/x/onecloud/pkg/baremetal/options"
- "yunion.io/x/onecloud/pkg/baremetal/profiles"
- "yunion.io/x/onecloud/pkg/baremetal/pxe"
- baremetalstatus "yunion.io/x/onecloud/pkg/baremetal/status"
- "yunion.io/x/onecloud/pkg/baremetal/tasks"
- baremetaltypes "yunion.io/x/onecloud/pkg/baremetal/types"
- "yunion.io/x/onecloud/pkg/baremetal/utils/detect_storages"
- "yunion.io/x/onecloud/pkg/baremetal/utils/disktool"
- "yunion.io/x/onecloud/pkg/baremetal/utils/grub"
- "yunion.io/x/onecloud/pkg/baremetal/utils/ipmitool"
- raid2 "yunion.io/x/onecloud/pkg/baremetal/utils/raid"
- raiddrivers "yunion.io/x/onecloud/pkg/baremetal/utils/raid/drivers"
- "yunion.io/x/onecloud/pkg/baremetal/utils/raid/mdadm"
- "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"
- "yunion.io/x/onecloud/pkg/hostman/guestfs/sshpart"
- deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient"
- "yunion.io/x/onecloud/pkg/mcclient/auth"
- modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
- "yunion.io/x/onecloud/pkg/util/dhcp"
- "yunion.io/x/onecloud/pkg/util/fileutils2"
- "yunion.io/x/onecloud/pkg/util/influxdb"
- "yunion.io/x/onecloud/pkg/util/procutils"
- "yunion.io/x/onecloud/pkg/util/redfish"
- "yunion.io/x/onecloud/pkg/util/redfish/bmconsole"
- "yunion.io/x/onecloud/pkg/util/ssh"
- "yunion.io/x/onecloud/pkg/util/sysutils"
- )
- type SBaremetalManager struct {
- Agent *SBaremetalAgent
- configPath string
- baremetals *sBaremetalMap
- }
- func NewBaremetalManager(agent *SBaremetalAgent) (*SBaremetalManager, error) {
- bmPaths := o.Options.BaremetalsPath
- err := os.MkdirAll(bmPaths, 0755)
- if err != nil {
- return nil, err
- }
- return &SBaremetalManager{
- Agent: agent,
- configPath: bmPaths,
- baremetals: newBaremetalMap(),
- }, nil
- }
- func (m *SBaremetalManager) killAllIPMITool() {
- procutils.NewCommand("killall", "-9", "ipmitool").Run()
- }
- func (m *SBaremetalManager) GetClientSession() *mcclient.ClientSession {
- return m.Agent.GetAdminSession()
- }
- func (m *SBaremetalManager) GetPublicClientSession() *mcclient.ClientSession {
- return m.Agent.GetPublicAdminSession()
- }
- func (m *SBaremetalManager) GetZoneId() string {
- return m.Agent.Zone.Id
- }
- func (m *SBaremetalManager) GetZoneName() string {
- return m.Agent.Zone.Name
- }
- func (m *SBaremetalManager) loadConfigs() ([]fs.DirEntry, error) {
- m.killAllIPMITool()
- files, err := os.ReadDir(m.configPath)
- if err != nil {
- return nil, err
- }
- return files, nil
- }
- func (m *SBaremetalManager) initBaremetals(ctx context.Context, files []fs.DirEntry) error {
- bmIds := make([]string, 0)
- for _, file := range files {
- if file.IsDir() && regutils.MatchUUID(file.Name()) {
- bmIds = append(bmIds, file.Name())
- }
- }
- errsChannel := make(chan error, len(bmIds))
- initBaremetal := func(i int) {
- bmId := bmIds[i]
- err := m.InitBaremetal(ctx, bmId, true)
- if err != nil {
- errsChannel <- err
- return
- }
- }
- workqueue.Parallelize(4, len(bmIds), initBaremetal)
- errs := make([]error, 0)
- if len(errsChannel) > 0 {
- length := len(errsChannel)
- for ; length > 0; length-- {
- errs = append(errs, <-errsChannel)
- }
- }
- return errors.NewAggregate(errs)
- }
- func (m *SBaremetalManager) InitBaremetal(ctx context.Context, bmId string, update bool) error {
- session := m.GetClientSession()
- var err error
- var desc jsonutils.JSONObject
- if update {
- desc, err = m.updateBaremetal(session, bmId)
- } else {
- desc, err = m.fetchBaremetal(session, bmId)
- }
- if err != nil {
- return err
- }
- isBaremetal, _ := desc.Bool("is_baremetal")
- if !isBaremetal {
- return errors.Error("not a baremetal???")
- }
- bmInstance, err := m.AddBaremetal(ctx, desc)
- if err != nil {
- return err
- }
- if update {
- bmObj := bmInstance.(*SBaremetalInstance)
- if !sets.NewString(INIT, PREPARE, UNKNOWN).Has(bmObj.GetStatus()) {
- if !bmObj.IsHypervisorHost() {
- bmObj.SyncStatusBackground()
- }
- }
- }
- return nil
- }
- func (m *SBaremetalManager) CleanBaremetal(bmId string) {
- bm := m.baremetals.Pop(bmId)
- if bm != nil {
- bm.Stop()
- }
- bm.clearBootIsoImage()
- path := bm.GetDir()
- procutils.NewCommand("rm", "-fr", path).Run()
- }
- func (m *SBaremetalManager) updateBaremetal(session *mcclient.ClientSession, bmId string) (jsonutils.JSONObject, error) {
- params := jsonutils.NewDict()
- params.Add(jsonutils.JSONTrue, "is_baremetal")
- params.Add(jsonutils.JSONTrue, "not_sync_config")
- obj, err := modules.Hosts.Put(session, bmId, params)
- if err != nil {
- return nil, err
- }
- log.Infof("Baremetal %s update success", bmId)
- return obj, nil
- }
- func (m *SBaremetalManager) fetchBaremetal(session *mcclient.ClientSession, bmId string) (jsonutils.JSONObject, error) {
- obj, err := modules.Hosts.Get(session, bmId, nil)
- if err != nil {
- return nil, err
- }
- log.Infof("Baremetal %s update success", bmId)
- return obj, nil
- }
- func (m *SBaremetalManager) AddBaremetal(ctx context.Context, desc jsonutils.JSONObject) (pxe.IBaremetalInstance, error) {
- id, err := desc.GetString("id")
- if err != nil {
- return nil, fmt.Errorf("Not found baremetal id in desc %s", desc)
- }
- if instance, ok := m.baremetals.Get(id); ok {
- return instance, instance.SaveDesc(ctx, desc)
- }
- bm, err := newBaremetalInstance(ctx, m, desc)
- if err != nil {
- return nil, err
- }
- m.baremetals.Add(bm)
- return bm, nil
- }
- func (m *SBaremetalManager) GetBaremetals() []*SBaremetalInstance {
- objs := make([]*SBaremetalInstance, 0)
- getter := func(key, val interface{}) bool {
- objs = append(objs, val.(*SBaremetalInstance))
- return true
- }
- m.baremetals.Range(getter)
- return objs
- }
- func (m *SBaremetalManager) GetBaremetalById(bmId string) *SBaremetalInstance {
- obj, _ := m.baremetals.Get(bmId)
- return obj
- }
- func (m *SBaremetalManager) GetBaremetalByMac(mac net.HardwareAddr) pxe.IBaremetalInstance {
- var obj pxe.IBaremetalInstance
- getter := func(key, val interface{}) bool {
- instance := val.(*SBaremetalInstance)
- if instance.GetNicByMac(mac) != nil {
- obj = instance
- // stop the iteration
- return false
- }
- // not found, continue iteration
- return true
- }
- m.baremetals.Range(getter)
- return obj
- }
- type BmRegisterInput struct {
- // context with timeout
- Ctx context.Context
- R *http.Request
- W http.ResponseWriter
- // For notify web server close this connection
- C chan struct{}
- // remote server ssh info
- SshPort int
- SshPasswd string
- Hostname string
- RemoteIp string
- // ipmi info
- Username string
- Password string
- IpAddr string
- }
- func (i *BmRegisterInput) responseSucc(bmId string) {
- fmt.Fprintf(i.W, "%s", bmId)
- close(i.C)
- }
- func (i *BmRegisterInput) responseErr(ctx context.Context, err error) {
- httperrors.GeneralServerError(ctx, i.W, err)
- close(i.C)
- }
- func (i *BmRegisterInput) isTimeout() bool {
- select {
- case <-i.Ctx.Done():
- return true
- default:
- return false
- }
- }
- // delay task
- func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mcclient.TokenCredential, input *BmRegisterInput) {
- adminWire, err := m.checkNetworkFromIp(input.RemoteIp)
- if input.isTimeout() {
- return
- } else if err != nil {
- input.responseErr(ctx, httperrors.NewBadRequestError("Verify network failed: %s", err))
- return
- }
- sshCli, err := m.checkSshInfo(input)
- if input.isTimeout() {
- return
- } else if err != nil {
- input.responseErr(ctx, httperrors.NewBadRequestError("SSH verify failed: %s", err))
- return
- }
- isIpv6Addr := false
- if strings.Contains(input.RemoteIp, ":") {
- isIpv6Addr = true
- }
- input.IpAddr, err = m.fetchIpmiIp(sshCli, isIpv6Addr)
- log.Infof("find ipmi addr %s", input.IpAddr)
- if input.isTimeout() {
- return
- } else if err != nil {
- input.responseErr(ctx, httperrors.NewBadRequestError("Fetch ipmi address failed: %s", err))
- return
- }
- log.Infof("Find ipmi address %s", input.IpAddr)
- ipmiWire, err := m.checkNetworkFromIp(input.IpAddr)
- if input.isTimeout() {
- return
- } else if err != nil {
- input.responseErr(ctx, httperrors.NewBadRequestError("Verify network failed: %s", err))
- return
- }
- ipmiLanChannel, ipmiMac, err := m.checkIpmiInfo(ctx, input.Username, input.Password, input.IpAddr)
- if input.isTimeout() {
- return
- } else if err != nil {
- input.responseErr(ctx, httperrors.NewBadRequestError("IPMI login info not correct: %s", err))
- return
- }
- err, registered := m.verifyMacAddr(sshCli)
- if input.isTimeout() {
- return
- } else if err != nil {
- input.responseErr(ctx, httperrors.NewBadRequestError("Verify mac address failed: %s", err))
- return
- }
- registerTask := tasks.NewBaremetalRegisterTask(
- userCred, m, sshCli, input.Hostname, input.RemoteIp,
- input.Username, input.Password, input.IpAddr,
- ipmiMac, ipmiLanChannel, adminWire, ipmiWire,
- )
- var bmId string
- if !registered {
- bmId, err = registerTask.CreateBaremetal(ctx)
- } else {
- bmId, err = registerTask.UpdateBaremetal(ctx)
- }
- if err != nil {
- input.responseErr(ctx, httperrors.NewInternalServerError("%v", err))
- return
- }
- input.responseSucc(bmId)
- registerTask.DoPrepare(ctx, sshCli, registered)
- }
- func (m *SBaremetalManager) fetchIpmiIp(sshCli *ssh.Client, isIpv6Addr bool) (string, error) {
- if !isIpv6Addr {
- res, err := sshCli.RawRun(`/usr/bin/ipmitool lan print | grep "IP Address "`)
- if err != nil {
- return "", err
- }
- if len(res) == 1 {
- segs := strings.Fields(res[0])
- if len(segs) == 4 {
- return strings.TrimSpace(segs[3]), nil
- }
- }
- } else {
- res, err := sshCli.Run(`/usr/bin/ipmitool lan6 print`)
- if err != nil {
- return "", err
- }
- for i, line := range res {
- if strings.HasPrefix(line, "IPv6 Static Address") || strings.HasPrefix(line, "IPv6 Dynamic Address") {
- if len(res)-i > 3 {
- enabledSegs := strings.Fields(res[i+1])
- log.Infof("enabled segs %#v", enabledSegs)
- if len(enabledSegs) != 2 || enabledSegs[0] != "Enabled:" || enabledSegs[1] != "yes" {
- continue
- }
- statusSegs := strings.Fields(res[i+3])
- log.Infof("status segs %#v", statusSegs)
- if len(enabledSegs) != 2 || statusSegs[0] != "Status:" || statusSegs[1] != "active" {
- continue
- }
- addrSegs := strings.Fields(res[i+2])
- if len(addrSegs) != 2 || addrSegs[0] != "Address:" {
- continue
- }
- ipv6Addr := strings.Split(addrSegs[1], "/")
- return ipv6Addr[0], nil
- }
- }
- }
- }
- return "", fmt.Errorf("Failed to find ipmi ip address")
- }
- func (m *SBaremetalManager) checkNetworkFromIp(ip string) (string, error) {
- params := jsonutils.NewDict()
- params.Set("ip", jsonutils.NewString(ip))
- params.Set("scope", jsonutils.NewString("system"))
- params.Set("is_classic", jsonutils.JSONTrue)
- params.Set("provider", jsonutils.NewString(api.CLOUD_PROVIDER_ONECLOUD))
- params.Set("limit", jsonutils.NewInt(0))
- // use default vpc
- params.Set("vpc", jsonutils.NewString(api.DEFAULT_VPC_ID))
- res, err := modules.Networks.List(m.GetClientSession(), params)
- if err != nil {
- return "", fmt.Errorf("Fetch network by ip %s failed: %s", ip, err)
- }
- if len(res.Data) != 1 {
- return "", fmt.Errorf("Can't find network from ip %s", ip)
- }
- return res.Data[0].GetString("wire_id")
- }
- func (m *SBaremetalManager) verifyMacAddr(sshCli *ssh.Client) (error, bool) {
- output, err := sshCli.Run("/lib/mos/lsnic")
- if err != nil {
- return err, false
- }
- nicinfo := sysutils.ParseNicInfo(output)
- if len(nicinfo) == 0 {
- return fmt.Errorf("Can't get nic info"), false
- }
- var registered bool
- params := jsonutils.NewDict()
- for _, nic := range nicinfo {
- if len(nic.Mac) > 0 {
- params.Set("any_mac", jsonutils.NewString(nic.Mac.String()))
- params.Set("scope", jsonutils.NewString("system"))
- res, err := modules.Hosts.List(m.GetClientSession(), params)
- if err != nil {
- return fmt.Errorf("Get hosts info failed: %s", err), false
- }
- if len(res.Data) > 0 {
- registered = true
- }
- }
- }
- return nil, registered
- }
- func (m *SBaremetalManager) checkSshInfo(input *BmRegisterInput) (*ssh.Client, error) {
- sshCLi, err := ssh.NewClient(input.RemoteIp, input.SshPort, "root", input.SshPasswd, "")
- if err != nil {
- return nil, fmt.Errorf("Ssh connect failed: %s", err)
- }
- var RETRY, MAX_TRIES = 0, 3
- for RETRY = 0; RETRY < MAX_TRIES; RETRY++ {
- _, err := sshCLi.Run("/bin/ls")
- if err != nil {
- log.Errorf("Exec remote command failed: %s", err)
- time.Sleep(time.Second * 1)
- } else {
- break
- }
- }
- if RETRY >= MAX_TRIES {
- return nil, fmt.Errorf("SSH login info not correct??")
- }
- return sshCLi, nil
- }
- func (m *SBaremetalManager) checkIpmiInfo(ctx context.Context, username, password, ipAddr string) (uint8, net.HardwareAddr, error) {
- lanPlusTool := ipmitool.NewLanPlusIPMI(ipAddr, username, password)
- sysInfo, err := ipmitool.GetSysInfo(lanPlusTool)
- if err != nil {
- return 0, nil, errors.Wrap(err, "GetSysInfo")
- }
- profile, err := profiles.GetProfile(ctx, sysInfo)
- if err != nil {
- return 0, nil, errors.Wrap(err, "GetProfile")
- }
- for _, lanChannel := range profile.LanChannels {
- config, err := ipmitool.GetLanConfig(lanPlusTool, lanChannel)
- if err != nil {
- log.Errorf("GetLanConfig failed %s", err)
- continue
- }
- if len(config.Mac) == 0 {
- continue
- }
- return lanChannel, config.Mac, nil
- }
- return 0, nil, fmt.Errorf("Ipmi can't fetch lan config")
- }
- func (m *SBaremetalManager) Stop() {
- for _, bm := range m.GetBaremetals() {
- bm.Stop()
- }
- }
- type sBaremetalMap struct {
- *sync.Map
- }
- func newBaremetalMap() *sBaremetalMap {
- return &sBaremetalMap{
- Map: new(sync.Map),
- }
- }
- func (m *sBaremetalMap) Add(bm *SBaremetalInstance) {
- m.Store(bm.GetId(), bm)
- }
- func (m *sBaremetalMap) Get(id string) (*SBaremetalInstance, bool) {
- obj, ok := m.Load(id)
- if !ok {
- return nil, false
- }
- return obj.(*SBaremetalInstance), true
- }
- func (m *sBaremetalMap) Delete(id string) {
- m.Map.Delete(id)
- }
- func (m *sBaremetalMap) Pop(id string) *SBaremetalInstance {
- obj, exist := m.Get(id)
- if exist {
- m.Delete(id)
- }
- return obj
- }
- type SBaremetalInstance struct {
- manager *SBaremetalManager
- desc *jsonutils.JSONDict
- descLock *sync.Mutex
- taskQueue *tasks.TaskQueue
- server baremetaltypes.IBaremetalServer
- serverLock *sync.Mutex
- profile *baremetalapi.BaremetalProfileSpec
- cronJobs []IBaremetalCronJob
- }
- func newBaremetalInstance(ctx context.Context, man *SBaremetalManager, desc jsonutils.JSONObject) (*SBaremetalInstance, error) {
- bm := &SBaremetalInstance{
- manager: man,
- desc: desc.(*jsonutils.JSONDict),
- descLock: new(sync.Mutex),
- taskQueue: tasks.NewTaskQueue(),
- serverLock: new(sync.Mutex),
- }
- bm.cronJobs = []IBaremetalCronJob{
- NewLogFetchJob(bm, time.Duration(o.Options.LogFetchIntervalSeconds)*time.Second),
- NewSendMetricsJob(bm, time.Duration(o.Options.SendMetricsIntervalSeconds)*time.Second),
- NewStatusProbeJob(bm, time.Duration(o.Options.StatusProbeIntervalSeconds)*time.Second),
- }
- err := os.MkdirAll(bm.GetDir(), 0755)
- if err != nil {
- return nil, err
- }
- err = bm.SaveDesc(ctx, desc)
- if err != nil {
- return nil, err
- }
- bm.loadServer()
- return bm, nil
- }
- func (b *SBaremetalInstance) IsHypervisorHost() bool {
- hostType, _ := b.desc.GetString("host_type")
- return utils.IsInStringArray(hostType, []string{api.HOST_TYPE_KVM, api.HOST_TYPE_HYPERVISOR})
- }
- func (b *SBaremetalInstance) GetDHCPServerIP() (net.IP, error) {
- return b.manager.Agent.GetDHCPServerIP()
- }
- func (b *SBaremetalInstance) GetClientSession() *mcclient.ClientSession {
- return b.manager.GetClientSession()
- }
- func (b *SBaremetalInstance) GetPublicClientSession() *mcclient.ClientSession {
- return b.manager.GetPublicClientSession()
- }
- func (b *SBaremetalInstance) Keyword() string {
- return "host"
- }
- func (b *SBaremetalInstance) GetId() string {
- id, err := b.desc.GetString("id")
- if err != nil {
- log.Errorf("Get id from desc %s error: %v", b.desc.String(), err)
- }
- return id
- }
- func (b *SBaremetalInstance) GetName() string {
- id, err := b.desc.GetString("name")
- if err != nil {
- log.Fatalf("Get name from desc %s error: %v", b.desc.String(), err)
- }
- return id
- }
- func (b *SBaremetalInstance) Stop() {
- // TODO:
- }
- func (b *SBaremetalInstance) GetDir() string {
- return filepath.Join(b.manager.configPath, b.GetId())
- }
- func (b *SBaremetalInstance) GetDescFilePath() string {
- return filepath.Join(b.GetDir(), "desc")
- }
- func (b *SBaremetalInstance) GetServerDescFilePath() string {
- return filepath.Join(b.GetDir(), "server")
- }
- func (b *SBaremetalInstance) GetSSHConfigFilePath() string {
- return filepath.Join(b.GetDir(), "ssh")
- }
- func (b *SBaremetalInstance) GetStatus() string {
- status, err := b.desc.GetString("status")
- if err != nil {
- log.Fatalf("Get status from desc error: %v", err)
- }
- return status
- }
- func (b *SBaremetalInstance) AutoSaveDesc(ctx context.Context) error {
- return b.SaveDesc(ctx, nil)
- }
- func (b *SBaremetalInstance) SaveDesc(ctx context.Context, desc jsonutils.JSONObject) error {
- b.descLock.Lock()
- defer b.descLock.Unlock()
- if desc != nil {
- if b.desc != nil && b.desc.Contains("server_id") && !desc.Contains("server_id") {
- if b.server != nil {
- desc.(*jsonutils.JSONDict).Set("server_id", jsonutils.NewString(b.server.GetId()))
- }
- }
- b.desc = desc.(*jsonutils.JSONDict)
- if b.desc.Contains("sys_info") {
- sysInfo := types.SSystemInfo{}
- err := b.desc.Unmarshal(&sysInfo, "sys_info")
- if err != nil {
- return errors.Wrap(err, "Unmarshal sys_info")
- }
- b.profile, err = profiles.GetProfile(ctx, &sysInfo)
- if err != nil {
- return errors.Wrap(err, "GetProfile")
- }
- }
- }
- return os.WriteFile(b.GetDescFilePath(), []byte(b.desc.String()), 0644)
- }
- func (b *SBaremetalInstance) loadServer() {
- b.serverLock.Lock()
- defer b.serverLock.Unlock()
- if !b.desc.Contains("server_id") {
- return
- }
- descPath := b.GetServerDescFilePath()
- desc, err := os.ReadFile(descPath)
- if err != nil {
- log.Errorf("Failed to read server desc %s: %v", descPath, err)
- return
- }
- descObj, err := jsonutils.Parse(desc)
- if err != nil {
- log.Errorf("Failed to parse server json string: %v", err)
- return
- }
- srv, err := newBaremetalServer(b, descObj.(*jsonutils.JSONDict))
- if err != nil {
- log.Errorf("New server error: %v", err)
- return
- }
- if bmSrvId, _ := b.desc.GetString("server_id"); srv.GetId() != bmSrvId {
- log.Errorf("Server id %q not equal baremetal %q server id %q", srv.GetId(), b.GetName(), bmSrvId)
- return
- }
- b.server = srv
- }
- func (b *SBaremetalInstance) SaveSSHConfig(remoteAddr string, key string) error {
- var err error
- key, err = utils.EncryptAESBase64(b.GetId(), key)
- if err != nil {
- return err
- }
- sshConf := types.SSHConfig{
- Username: "root",
- Password: key,
- RemoteIP: remoteAddr,
- }
- conf := jsonutils.Marshal(sshConf)
- err = os.WriteFile(b.GetSSHConfigFilePath(), []byte(conf.String()), 0644)
- if err != nil {
- return err
- }
- b.SyncSSHConfig(sshConf)
- b.clearBootIso()
- return err
- }
- func (b *SBaremetalInstance) GetSSHConfig() (*types.SSHConfig, error) {
- path := b.GetSSHConfigFilePath()
- content, err := os.ReadFile(path)
- if err != nil {
- if os.IsNotExist(err) {
- return nil, nil
- }
- return nil, err
- }
- conf := types.SSHConfig{}
- obj, err := jsonutils.Parse(content)
- if err != nil {
- return nil, err
- }
- err = obj.Unmarshal(&conf)
- if err != nil {
- return nil, err
- }
- if len(conf.RemoteIP) == 0 {
- return nil, nil
- }
- conf.Password, err = utils.DescryptAESBase64(b.GetId(), conf.Password)
- if err != nil {
- return nil, err
- }
- return &conf, nil
- }
- func (b *SBaremetalInstance) TestSSHConfig() bool {
- conf, err := b.GetSSHConfig()
- if err != nil {
- return false
- }
- if conf == nil {
- return false
- }
- sshCli, err := ssh.NewClient(conf.RemoteIP, 22, "root", conf.Password, "")
- if err != nil {
- return false
- }
- ret, err := sshCli.Run("whoami")
- if err != nil {
- return false
- }
- if strings.Contains(strings.Join(ret, ""), "root") {
- return true
- }
- return false
- }
- func (b *SBaremetalInstance) ClearSSHConfig() {
- path := b.GetSSHConfigFilePath()
- err := os.Remove(path)
- if err != nil {
- log.V(2).Warningf("Clear ssh config %s error: %v", path, err)
- }
- emptyConfig := types.SSHConfig{
- Username: "None",
- Password: "None",
- RemoteIP: "None",
- }
- err = b.SyncSSHConfig(emptyConfig)
- if err != nil {
- log.Errorf("Sync emtpy SSH config error: %v", err)
- }
- }
- func (b *SBaremetalInstance) SyncSSHConfig(conf types.SSHConfig) error {
- session := b.manager.GetClientSession()
- var info *api.HostLoginInfo
- if len(conf.RemoteIP) > 0 {
- var err error
- // encrypt twice
- conf.Password, err = utils.EncryptAESBase64(b.GetId(), conf.Password)
- if err != nil {
- return err
- }
- info = &api.HostLoginInfo{
- Username: conf.Username,
- Password: conf.Password,
- Ip: conf.RemoteIP,
- }
- } else {
- info = &api.HostLoginInfo{
- Username: "None",
- Password: "None",
- Ip: "None",
- }
- }
- data := info.JSON(info)
- _, err := modules.Hosts.SetMetadata(session, b.GetId(), data)
- return err
- }
- func (b *SBaremetalInstance) SyncStatusBackground() {
- go func() {
- b.AutoSyncAllStatus(context.Background())
- }()
- }
- func (b *SBaremetalInstance) InitializeServer(s *mcclient.ClientSession, name string) error {
- params := jsonutils.NewDict()
- params.Set("name", jsonutils.NewString(name))
- _, err := modules.Hosts.PerformAction(s, b.GetId(), "initialize", params)
- return err
- }
- func (b *SBaremetalInstance) ServerLoadDesc(ctx context.Context) error {
- res, err := modules.Hosts.Get(b.manager.GetClientSession(), b.GetId(), nil)
- if err != nil {
- return err
- }
- b.SaveDesc(ctx, res)
- sid, err := res.GetString("server_id")
- if err == nil {
- sDesc := jsonutils.NewDict()
- sDesc.Set("uuid", jsonutils.NewString(sid))
- b.server, err = newBaremetalServer(b, sDesc)
- return err
- } else {
- return nil
- }
- }
- func PowerStatusToBaremetalStatus(status types.PowerStatus) string {
- switch status {
- case types.POWER_STATUS_ON:
- return baremetalstatus.RUNNING
- case types.POWER_STATUS_OFF:
- return baremetalstatus.READY
- }
- return baremetalstatus.UNKNOWN
- }
- func PowerStatusToServerStatus(bm *SBaremetalInstance, status types.PowerStatus) string {
- switch status {
- case types.POWER_STATUS_ON:
- if conf, _ := bm.GetSSHConfig(); conf == nil {
- return baremetalstatus.SERVER_RUNNING
- } else {
- if !bm.HasBMC() && !bm.IsMaintenance() {
- return baremetalstatus.SERVER_READY
- } else {
- return baremetalstatus.SERVER_ADMIN
- }
- }
- case types.POWER_STATUS_OFF:
- return baremetalstatus.SERVER_READY
- }
- return baremetalstatus.UNKNOWN
- }
- func (b *SBaremetalInstance) AutoSyncStatus(ctx context.Context) {
- b.SyncStatus(ctx, "", "")
- }
- func (b *SBaremetalInstance) SyncStatus(ctx context.Context, status string, reason string) {
- if status == "" {
- powerStatus, err := b.GetPowerStatus()
- if err != nil {
- log.Errorf("Get power status error: %v", err)
- }
- status = PowerStatusToBaremetalStatus(powerStatus)
- }
- b.desc.Set("status", jsonutils.NewString(status))
- b.AutoSaveDesc(ctx)
- params := jsonutils.NewDict()
- params.Add(jsonutils.NewString(status), "status")
- if reason != "" {
- params.Add(jsonutils.NewString(reason), "reason")
- }
- _, err := modules.Hosts.PerformAction(b.GetClientSession(), b.GetId(), "status", params)
- if err != nil {
- log.Errorf("Update baremetal %s status %s error: %v", b.GetId(), status, err)
- return
- }
- log.Infof("Update baremetal %s to status %s", b.GetId(), status)
- }
- func (b *SBaremetalInstance) AutoSyncAllStatus(ctx context.Context) {
- b.SyncAllStatus(ctx, "")
- }
- func (b *SBaremetalInstance) DelayedSyncStatus(ctx context.Context, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- b.AutoSyncAllStatus(ctx)
- return nil, nil
- }
- func (b *SBaremetalInstance) SyncAllStatus(ctx context.Context, status types.PowerStatus) {
- var err error
- if status == "" {
- status, err = b.GetPowerStatus()
- if err != nil {
- log.Errorf("Get power status error: %v", err)
- }
- }
- b.SyncStatus(ctx, PowerStatusToBaremetalStatus(status), "SyncAllStatus by baremetal-agent")
- b.SyncServerStatus(status)
- }
- func (b *SBaremetalInstance) SyncServerStatus(powerStatus types.PowerStatus) {
- if b.GetServerId() == "" {
- return
- }
- status := PowerStatusToServerStatus(b, powerStatus)
- if powerStatus == "" {
- powerStatus, err := b.GetPowerStatus()
- if err != nil {
- log.Errorf("Get power status error: %v", err)
- }
- status = PowerStatusToServerStatus(b, powerStatus)
- }
- params := &api.ServerPerformStatusInput{}
- params.Status = status
- params.PowerStates = string(powerStatus)
- _, err := modules.Servers.PerformAction(b.GetClientSession(), b.GetServerId(), "status", jsonutils.Marshal(params))
- if err != nil {
- log.Errorf("Update server %s status %s error: %v", b.GetServerName(), status, err)
- return
- }
- log.Infof("Update server %s to status %s", b.GetServerName(), status)
- }
- func (b *SBaremetalInstance) GetNics() []types.SNic {
- nics := []types.SNic{}
- err := b.desc.Unmarshal(&nics, "nic_info")
- if err != nil {
- log.Errorf("Unmarshal desc to get nics error: %v", err)
- return nil
- }
- return nics
- }
- func (b *SBaremetalInstance) getNicByType(nicType compute.TNicType) *types.SNic {
- nics := b.GetNics()
- if len(nics) == 0 {
- return nil
- }
- for i := range nics {
- if nics[i].Type == nicType {
- return &nics[i]
- }
- }
- return nil
- }
- func (b *SBaremetalInstance) GetNicByMac(mac net.HardwareAddr) *types.SNic {
- nics := b.GetNics()
- if len(nics) == 0 {
- return nil
- }
- for _, nic := range nics {
- tmp := nic
- if tmp.Mac == mac.String() {
- return &tmp
- }
- }
- return nil
- }
- func (b *SBaremetalInstance) GetAdminNic() *types.SNic {
- return b.getNicByType(api.NIC_TYPE_ADMIN)
- }
- func (b *SBaremetalInstance) NeedPXEBoot() bool {
- task := b.GetTask()
- taskName := "nil"
- serverId := b.GetServerId()
- if task != nil {
- taskName = task.GetName()
- }
- taskNeedPXEBoot := false
- if task != nil && task.NeedPXEBoot() {
- taskNeedPXEBoot = true
- }
- ret := false
- reason := ""
- if taskNeedPXEBoot {
- reason = fmt.Sprintf("Task %s need PXE boot", taskName)
- }
- emptyBmNoTask := false
- if task == nil && len(serverId) == 0 && b.GetHostType() == "baremetal" {
- emptyBmNoTask = true
- reason = fmt.Sprintf("Baremetal %s is empty and no task executing", b.GetName())
- }
- noTaskInMaintenance := false
- if task == nil && b.IsMaintenance() {
- noTaskInMaintenance = true
- reason = fmt.Sprintf("Baremetal %s no task executing but in maintenance", b.GetName())
- }
- if taskNeedPXEBoot || emptyBmNoTask || noTaskInMaintenance {
- ret = true
- }
- log.Infof("Check task %s, server %s NeedPXEBoot: %v(%s)", taskName, serverId, ret, reason)
- return ret
- }
- func (b *SBaremetalInstance) IsMaintenance() bool {
- isMt, _ := b.desc.Bool("is_maintenance")
- return isMt
- }
- func (b *SBaremetalInstance) GetArch() (string, error) {
- cpuArch, err := b.desc.GetString("cpu_architecture")
- if err != nil {
- return "", errors.Wrap(err, "Get cpu_architecture from desc")
- }
- if cpuArch == "" {
- return "", errors.Errorf("cpu_architecture is empty")
- }
- return cpuArch, nil
- }
- func (b *SBaremetalInstance) GetHostType() string {
- hostType, _ := b.desc.GetString("host_type")
- return hostType
- }
- func (b *SBaremetalInstance) GetIPMINic(cliMac net.HardwareAddr) *types.SNic {
- nic := b.getNicByType(api.NIC_TYPE_IPMI)
- if nic == nil {
- return nil
- }
- if nic.Mac == cliMac.String() {
- return nic
- }
- return nil
- }
- func (b *SBaremetalInstance) GetIPMINicIPAddr() string {
- nic := b.getNicByType(api.NIC_TYPE_IPMI)
- if nic == nil {
- return ""
- }
- return nic.IpAddr
- }
- func (b *SBaremetalInstance) GetDHCPConfig(cliMac net.HardwareAddr) (*dhcp.ResponseConfig, error) {
- var nic *types.SNic
- var hostname string
- var osName string
- if b.GetServer() != nil && (b.GetTask() == nil || !b.GetTask().NeedPXEBoot()) {
- nic = b.GetServer().GetNicByMac(cliMac)
- hostname = b.GetServer().GetHostName()
- osName = b.GetServer().GetOsName()
- } else {
- nic = b.GetNicByMac(cliMac)
- }
- if nic == nil {
- return nil, fmt.Errorf("GetNicDHCPConfig no nic found by mac: %s", cliMac)
- }
- return b.getDHCPConfig(nic, hostname, false, 0, osName)
- }
- func (b *SBaremetalInstance) GetPXEDHCPConfig(arch uint16) (*dhcp.ResponseConfig, error) {
- return b.getDHCPConfig(b.GetAdminNic(), "", true, arch, "Linux")
- }
- func (b *SBaremetalInstance) getDHCPConfig(
- nic *types.SNic,
- hostName string,
- isPxe bool,
- arch uint16,
- osName string,
- ) (*dhcp.ResponseConfig, error) {
- if hostName == "" {
- hostName = b.GetName()
- }
- if osName == "" {
- osName = "Linux"
- }
- serverIP, err := b.manager.Agent.GetDHCPServerIP()
- if err != nil {
- return nil, err
- }
- if o.Options.BootLoader == o.BOOT_LOADER_SYSLINUX && arch != dhcp.CLIENT_ARCH_EFI_ARM64 {
- if isPxe && dhcp.IsUEFIPxeArch(arch) && !b.NeedPXEBoot() {
- // TODO: use chainloader boot UEFI firmware,
- // currently not response PXE request,
- // and let BIOS detect bootable device
- b.ClearSSHConfig()
- return nil, errors.Errorf("Baremetal %s not need UEFI PXE boot", b.GetName())
- }
- }
- return GetNicDHCPConfig(nic, serverIP, b.manager.Agent.ListenInterface.HardwareAddr, hostName, isPxe, arch, osName)
- }
- func (b *SBaremetalInstance) GetNotifyUrl() string {
- return fmt.Sprintf("%s/baremetals/%s/notify", b.manager.Agent.GetListenUri(), b.GetId())
- }
- func (b *SBaremetalInstance) getHTTPEndpoint() (string, error) {
- serverIP, err := b.manager.Agent.GetDHCPServerIP()
- if err != nil {
- return "", errors.Wrap(err, "GetDHCPServerIP")
- }
- return fmt.Sprintf("%s:%d", serverIP, o.Options.Port+1000), nil
- }
- func (b *SBaremetalInstance) getHTTPFileUrl(filename string) string {
- endpoint, err := b.getHTTPEndpoint()
- if err != nil {
- log.Errorf("Get http file server endpoint: %v", err)
- return filename
- }
- return fmt.Sprintf("http://%s/tftp/%s", endpoint, filename)
- }
- func (b *SBaremetalInstance) GetImageUrl(disableImageCache bool) string {
- if disableImageCache {
- url, err := b.GetPublicClientSession().GetServiceURL(apis.SERVICE_TYPE_IMAGE, apiidenty.EndpointInterfacePublic, httputils.GET)
- if err != nil {
- log.Errorf("Get image public url: %v", err)
- return ""
- }
- return url
- }
- serverIP, err := b.manager.Agent.GetDHCPServerIP()
- if err != nil {
- log.Errorf("Get http file server: %v", err)
- return ""
- }
- // no /images/, rootcreate.sh will add this
- return fmt.Sprintf("http://%s:%d", serverIP, o.Options.Port+1000)
- }
- func (b *SBaremetalInstance) getBootIsoUrl() string {
- serverIP, err := b.manager.Agent.GetDHCPServerIP()
- if err != nil {
- log.Errorf("Get http file server: %v", err)
- return ""
- }
- // no /images/, rootcreate.sh will add this
- return fmt.Sprintf("http://%s:%d/bootiso/%s.iso", serverIP, o.Options.Port+1000, b.GetId())
- }
- func (b *SBaremetalInstance) GetTFTPResponse() string {
- arch, err := b.GetArch()
- if err != nil {
- log.Errorf("get arch error: %v", err)
- }
- if o.Options.BootLoader == o.BOOT_LOADER_SYSLINUX && arch != apis.OS_ARCH_AARCH64 {
- return b.getSyslinuxConf(true)
- }
- return b.getGrubPXEConf(true)
- }
- func (b *SBaremetalInstance) getIsolinuxConf() string {
- return b.getSyslinuxConf(false)
- }
- func (b *SBaremetalInstance) getSyslinuxPath(filename string, isTftp bool) string {
- if isTftp {
- return b.getHTTPFileUrl(filename)
- } else {
- return filename
- }
- }
- func (b *SBaremetalInstance) findAccessNetwork(accessIp string) (*types.SNetworkConfig, error) {
- params := jsonutils.NewDict()
- params.Add(jsonutils.NewString(accessIp), "ip")
- params.Add(jsonutils.NewString("system"), "scope")
- params.Add(jsonutils.JSONTrue, "is_classic")
- session := b.manager.GetClientSession()
- ret, err := modules.Networks.List(session, params)
- if err != nil {
- return nil, err
- }
- if len(ret.Data) == 0 {
- return nil, errors.Wrapf(httperrors.ErrNotFound, "accessIp %s", accessIp)
- }
- network := types.SNetworkConfig{}
- err = ret.Data[0].Unmarshal(&network)
- return &network, err
- }
- func (b *SBaremetalInstance) getKernelArgs(isTftp bool, initramfs string) string {
- args := []string{
- fmt.Sprintf("token=%s", auth.GetTokenString()),
- fmt.Sprintf("url=%s", b.GetNotifyUrl()),
- }
- bootmode := api.BOOT_MODE_PXE
- if !isTftp {
- adminNic := b.GetAdminNic()
- var mac string
- var addr string
- var mask string
- var gateway string
- if adminNic != nil {
- mac = adminNic.GetMac().String()
- addr = adminNic.IpAddr
- mask = adminNic.GetNetMask()
- gateway = adminNic.Gateway
- } else {
- accessIp := b.GetAccessIp()
- accessNet, _ := b.findAccessNetwork(accessIp)
- if accessNet != nil {
- addr = accessIp
- mask = netutils.Masklen2Mask(int8(accessNet.GuestIpMask)).String()
- gateway = accessNet.GuestGateway
- }
- }
- serverIP, _ := b.manager.Agent.GetDHCPServerIP()
- args = append(args, fmt.Sprintf("mac=%s", mac))
- args = append(args, fmt.Sprintf("dest=%s", serverIP))
- args = append(args, fmt.Sprintf("gateway=%s", gateway))
- args = append(args, fmt.Sprintf("addr=%s", addr))
- args = append(args, fmt.Sprintf("mask=%s", mask))
- bootmode = api.BOOT_MODE_ISO
- }
- args = append(args, fmt.Sprintf("bootmod=%s", bootmode))
- return strings.Join(args, " ")
- }
- func (b *SBaremetalInstance) getGrubPXEConf(isTftp bool) string {
- arch, err := b.GetArch()
- if err != nil {
- log.Warningf("Get baremetal %s architecture error: %v", b.GetName(), err)
- arch = apis.OS_ARCH_X86_64
- }
- kernel := "kernel"
- initrd := "initramfs"
- if arch == apis.OS_ARCH_AARCH64 {
- kernel = "kernel_aarch64"
- initrd = "initramfs_aarch64"
- }
- // TODO: support not tftp situation
- kernelArgs := b.getKernelArgs(isTftp, initrd)
- if len(o.Options.NfsBootRootfs) > 0 {
- kernelArgs = fmt.Sprintf("root=/dev/nfs nfsroot=%s rw", o.Options.NfsBootRootfs)
- }
- var resp string
- endpoint, err := b.getHTTPEndpoint()
- if err != nil {
- log.Fatalf("getHTTPEndpoint %s", err)
- }
- if b.NeedPXEBoot() {
- resp = grub.GetYunionOSConfig(3, endpoint, kernel, kernelArgs, initrd, o.Options.EnableGrubTftpDownload)
- } else {
- resp = grub.GetAutoFindConfig()
- b.ClearSSHConfig()
- }
- return resp
- }
- func (b *SBaremetalInstance) getSyslinuxConf(isTftp bool) string {
- resp := `DEFAULT start
- serial 1 115200
- LABEL start
- MENU LABEL ^Start
- MENU default
- `
- if b.NeedPXEBoot() {
- kernel := "vmlinuz"
- initramfs := "initrd.img"
- if isTftp {
- kernel = b.getHTTPFileUrl("kernel")
- initramfs = b.getHTTPFileUrl("initramfs")
- }
- resp += fmt.Sprintf(" kernel %s\n", kernel)
- args := []string{
- fmt.Sprintf("initrd=%s", initramfs),
- fmt.Sprintf("token=%s", auth.GetTokenString()),
- fmt.Sprintf("url=%s", b.GetNotifyUrl()),
- }
- bootmode := api.BOOT_MODE_PXE
- if !isTftp {
- adminNic := b.GetAdminNic()
- var mac string
- var addr string
- var mask string
- var gateway string
- if adminNic != nil {
- mac = adminNic.GetMac().String()
- addr = adminNic.IpAddr
- mask = adminNic.GetNetMask()
- gateway = adminNic.Gateway
- } else {
- accessIp := b.GetAccessIp()
- accessNet, _ := b.findAccessNetwork(accessIp)
- if accessNet != nil {
- addr = accessIp
- mask = netutils.Masklen2Mask(int8(accessNet.GuestIpMask)).String()
- gateway = accessNet.GuestGateway
- }
- }
- serverIP, _ := b.manager.Agent.GetDHCPServerIP()
- args = append(args, fmt.Sprintf("mac=%s", mac))
- args = append(args, fmt.Sprintf("dest=%s", serverIP))
- args = append(args, fmt.Sprintf("gateway=%s", gateway))
- args = append(args, fmt.Sprintf("addr=%s", addr))
- args = append(args, fmt.Sprintf("mask=%s", mask))
- bootmode = api.BOOT_MODE_ISO
- }
- args = append(args, fmt.Sprintf("bootmod=%s", bootmode))
- resp += fmt.Sprintf(" append %s\n", strings.Join(args, " "))
- } else {
- resp += fmt.Sprintf(" COM32 %s\n", b.getSyslinuxPath("chain.c32", isTftp))
- resp += " APPEND hd0 0\n"
- b.ClearSSHConfig()
- }
- // log.Debugf("[SysLinux config]: \n%s", resp)
- return resp
- }
- func (b *SBaremetalInstance) GetTaskQueue() *tasks.TaskQueue {
- return b.taskQueue
- }
- func (b *SBaremetalInstance) GetTask() tasks.ITask {
- return b.taskQueue.GetTask()
- }
- func (b *SBaremetalInstance) SetTask(task tasks.ITask) {
- // hack: clear exist tasks if task is server destroy task
- if task.GetName() == tasks.BAREMETAL_SERVER_DESTROY_TASK {
- log.Infof("clear tasks of baremetal %s before executing %s", b.GetName(), task.GetName())
- b.taskQueue.ClearTasks()
- }
- b.taskQueue.AppendTask(task)
- if reflect.DeepEqual(task, b.taskQueue.GetTask()) {
- log.Infof("Execute task %s of baremetal %s", task.GetName(), b.GetName())
- tasks.ExecuteTask(task, nil)
- } else {
- log.Warningf("Append task %s of baremetal %s before executing %s", task.GetName(), b.GetName(), b.taskQueue.DebugString())
- }
- }
- func (b *SBaremetalInstance) InitAdminNetif(
- ctx context.Context,
- cliMac net.HardwareAddr,
- wireId string,
- nicType compute.TNicType,
- netType api.TNetworkType,
- isDoImport bool,
- importIpAddr string,
- ) error {
- // start prepare task
- // sync status to PREPARE
- if !isDoImport && nicType == api.NIC_TYPE_ADMIN &&
- utils.IsInStringArray(b.GetStatus(),
- []string{baremetalstatus.INIT,
- baremetalstatus.PREPARE,
- baremetalstatus.PREPARE_FAIL,
- baremetalstatus.UNKNOWN}) &&
- b.GetTask() == nil && b.GetServer() == nil {
- b.SetTask(tasks.NewBaremetalServerPrepareTask(b))
- b.SyncStatus(ctx, baremetalstatus.PREPARE, "")
- }
- nic := b.GetNicByMac(cliMac)
- if nic == nil || nic.WireId == "" {
- _, err := b.attachWire(cliMac, wireId, nicType)
- if err != nil {
- return err
- }
- return b.postAttachWire(ctx, cliMac, nicType, netType, importIpAddr)
- } else if nic.IpAddr == "" {
- return b.postAttachWire(ctx, cliMac, nicType, netType, importIpAddr)
- }
- return nil
- }
- func (b *SBaremetalInstance) RegisterNetif(ctx context.Context, cliMac net.HardwareAddr, wireId string) error {
- var nicType compute.TNicType
- nic := b.GetNicByMac(cliMac)
- if nic != nil {
- nicType = nic.Type
- }
- if nic == nil || nic.WireId == "" || nic.WireId != wireId {
- desc, err := b.attachWire(cliMac, wireId, nicType)
- if err != nil {
- return err
- }
- return b.SaveDesc(ctx, desc)
- }
- return nil
- }
- func (b *SBaremetalInstance) attachWire(mac net.HardwareAddr, wireId string, nicType compute.TNicType) (jsonutils.JSONObject, error) {
- session := b.manager.GetClientSession()
- params := jsonutils.NewDict()
- params.Add(jsonutils.NewString(mac.String()), "mac")
- if nicType != "" {
- params.Add(jsonutils.NewString(string(nicType)), "nic_type")
- }
- params.Add(jsonutils.NewString(wireId), "wire")
- params.Add(jsonutils.NewInt(-1), "index")
- params.Add(jsonutils.JSONTrue, "link_up")
- return modules.Hosts.PerformAction(session, b.GetId(), "add-netif", params)
- }
- func (b *SBaremetalInstance) postAttachWire(ctx context.Context, mac net.HardwareAddr, nicType compute.TNicType, netType api.TNetworkType, ipAddr string) error {
- if ipAddr == "" {
- switch nicType {
- case api.NIC_TYPE_IPMI:
- oldIPMIConf := b.GetRawIPMIConfig()
- if oldIPMIConf != nil && oldIPMIConf.IpAddr != "" {
- ipAddr = oldIPMIConf.IpAddr
- }
- case api.NIC_TYPE_ADMIN:
- accessIp := b.GetAccessIp()
- if accessIp != "" {
- ipAddr = accessIp
- }
- }
- }
- desc, err := b.enableWire(mac, ipAddr, nicType, netType)
- if err != nil {
- return err
- }
- return b.SaveDesc(ctx, desc)
- }
- func (b *SBaremetalInstance) enableWire(mac net.HardwareAddr, ipAddr string, nicType compute.TNicType, netType api.TNetworkType) (jsonutils.JSONObject, error) {
- session := b.manager.GetClientSession()
- params := jsonutils.NewDict()
- params.Add(jsonutils.NewString(mac.String()), "mac")
- if nicType != "" {
- params.Add(jsonutils.NewString(string(nicType)), "nic_type")
- }
- if ipAddr != "" {
- params.Add(jsonutils.NewString(ipAddr), "ip_addr")
- params.Add(jsonutils.JSONTrue, "reserve")
- }
- if nicType == api.NIC_TYPE_IPMI {
- params.Add(jsonutils.NewString("stepup"), "alloc_dir") // alloc bottom up
- }
- if len(netType) > 0 {
- params.Add(jsonutils.NewString(string(netType)), "net_type")
- }
- log.Infof("enable net if params: %s", params.String())
- return modules.Hosts.PerformAction(session, b.GetId(), "enable-netif", params)
- }
- func (b *SBaremetalInstance) GetIPMIConfig() *types.SIPMIInfo {
- conf := b.GetRawIPMIConfig()
- if conf == nil {
- log.Debugf("GetIPMIConfig conf is nil")
- return nil
- }
- if conf.Password == "" {
- log.Debugf("GetIPMIConfig password is nil")
- return nil
- }
- if conf.Username == "" && b.profile != nil {
- conf.Username = b.profile.RootName
- }
- if conf.IpAddr == "" {
- nicIPAddr := b.GetIPMINicIPAddr()
- if nicIPAddr != "" {
- conf.IpAddr = nicIPAddr
- }
- }
- conf.Password = utils.Unquote(conf.Password) // XXX: remove quotes!!!
- if conf.IpAddr == "" {
- log.Debugf("GetIPMIConfig ipaddr s nil")
- return nil
- }
- return conf
- }
- func (b *SBaremetalInstance) GetRawIPMIConfig() *types.SIPMIInfo {
- ipmiInfo := types.SIPMIInfo{}
- err := b.desc.Unmarshal(&ipmiInfo, "ipmi_info")
- if err != nil {
- log.Errorf("Unmarshal IPMIInfo error: %v", err)
- return nil
- }
- if ipmiInfo.Password != "" {
- ipmiInfo.Password, err = utils.DescryptAESBase64(b.GetId(), ipmiInfo.Password)
- if err != nil {
- log.Errorf("DescryptAESBase64 IPMI password error: %v", err)
- return nil
- }
- }
- 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
- }
- func (b *SBaremetalInstance) GetAccessMac() string {
- accessMac, _ := b.desc.GetString("access_mac")
- return accessMac
- }
- func (b *SBaremetalInstance) GetServer() baremetaltypes.IBaremetalServer {
- b.serverLock.Lock()
- defer b.serverLock.Unlock()
- if !b.desc.Contains("server_id") && b.server != nil {
- log.Warningf("baremetal %s server_id not present, remove server %q", b.GetName(), b.server.GetName())
- b.removeServer()
- return nil
- }
- return b.server
- }
- func (b *SBaremetalInstance) GetServerId() string {
- srv := b.GetServer()
- if srv == nil {
- return ""
- }
- return srv.GetId()
- }
- func (b *SBaremetalInstance) GetServerName() string {
- srv := b.GetServer()
- if srv == nil {
- return ""
- }
- return srv.GetName()
- }
- func (b *SBaremetalInstance) RemoveServer() {
- b.serverLock.Lock()
- defer b.serverLock.Unlock()
- b.removeServer()
- }
- func (b *SBaremetalInstance) removeServer() {
- if b.server != nil {
- b.server.RemoveDesc()
- b.server = nil
- }
- }
- func (b *SBaremetalInstance) SetExistingIPMIIPAddr(ipAddr string) {
- info, _ := b.desc.Get("ipmi_info")
- if info == nil {
- info = jsonutils.NewDict()
- }
- oIPAddr, _ := info.GetString("ip_addr")
- if oIPAddr == "" {
- info.(*jsonutils.JSONDict).Add(jsonutils.NewString(ipAddr), "ip_addr")
- }
- b.desc.Set("ipmi_info", info)
- }
- func (b *SBaremetalInstance) HasBMC() bool {
- conf := b.GetIPMIConfig()
- if conf == nil {
- return false
- }
- return true
- }
- func (b *SBaremetalInstance) GetHostSSHClient() (*ssh.Client, error) {
- conf, err := b.GetSSHConfig()
- if err != nil {
- return nil, errors.Wrap(err, "Get host ssh config")
- }
- if conf == nil {
- return nil, errors.Errorf("Host ssh config is empty")
- }
- sshCli, err := ssh.NewClient(conf.RemoteIP, 22, "root", conf.Password, "")
- if err != nil {
- return nil, errors.Wrap(err, "New ssh client")
- }
- return sshCli, nil
- }
- func (b *SBaremetalInstance) GetServerSSHClient() (*ssh.Client, error) {
- s := b.GetServer()
- if s == nil {
- return nil, errors.Error("No server")
- }
- privateKey, err := modules.Sshkeypairs.FetchPrivateKey(context.TODO(), auth.AdminCredential())
- if err != nil {
- return nil, errors.Wrapf(err, "Get server %s login info", s.GetId())
- }
- nics := s.GetNics()
- var errs []error
- for idx, nic := range nics {
- if nic.Ip != "" {
- for _, user := range []string{"cloudroot", "root"} {
- sshCli, err := ssh.NewClient(nic.Ip, 22, user, "", privateKey)
- if err != nil {
- err = errors.Wrapf(err, "New server %s ssh client %s@%s", s.GetName(), user, nic.Ip)
- errs = append(errs, err)
- } else {
- return sshCli, nil
- }
- }
- } else {
- errs = append(errs, errors.Errorf("nic %d link_up: %v, ip: %q", idx, nic.LinkUp, nic.Ip))
- }
- }
- return nil, errors.NewAggregate(errs)
- }
- func (b *SBaremetalInstance) SSHReachable() (bool, error) {
- var errs []error
- if cli, err := b.GetHostSSHClient(); err != nil {
- errs = append(errs, err)
- } else {
- // host ssh reachable
- cli.Close()
- return true, nil
- }
- if cli, err := b.GetServerSSHClient(); err != nil {
- errs = append(errs, err)
- } else {
- // server ssh reachable
- cli.Close()
- return true, nil
- }
- return false, errors.NewAggregate(errs)
- }
- 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 hostRun(hostCli)
- }
- }
- serverCli, err := b.GetServerSSHClient()
- if err != nil {
- return nil, errors.Wrapf(err, "Get baremetal %s server ssh client", b.GetName())
- }
- 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(ctx context.Context, 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 b.CleanUEFIInfo(ctx)
- }
- return f()
- }
- func (b *SBaremetalInstance) AdjustUEFICurrentBootOrder(ctx context.Context, hostCli *ssh.Client) error {
- return b.adjustUEFIWrapper(ctx, 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(ctx, mgr)
- })
- }
- func (b *SBaremetalInstance) updateUEFIInfo(ctx context.Context, uefiData jsonutils.JSONObject) error {
- desc := b.desc
- desc.Add(uefiData, "uefi_info")
- if err := b.SaveDesc(ctx, 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) CleanUEFIInfo(ctx context.Context) error {
- if err := b.updateUEFIInfo(ctx, jsonutils.NewDict()); err != nil {
- return errors.Wrap(err, "CleanUEFIInfo")
- }
- return nil
- }
- func (b *SBaremetalInstance) SendUEFIInfo(ctx context.Context, mgr *uefi.BootMgr) error {
- info, err := mgr.ToEFIBootMgrInfo()
- if err != nil {
- return err
- }
- if err := b.updateUEFIInfo(ctx, jsonutils.Marshal(info)); err != nil {
- return errors.Wrap(err, "SendUEFIInfo")
- }
- return nil
- }
- func (b *SBaremetalInstance) adjustServerUEFIBootOrder(ctx context.Context, srvCli *ssh.Client) error {
- return b.adjustUEFIWrapper(ctx, 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(ctx context.Context) error {
- _, err := b.sshRunWrapper(
- func(hostCli *ssh.Client) ([]string, error) {
- return nil, b.AdjustUEFICurrentBootOrder(ctx, hostCli)
- },
- func(srvCli *ssh.Client) ([]string, error) {
- return nil, b.adjustServerUEFIBootOrder(ctx, srvCli)
- },
- )
- return err
- }
- func (b *SBaremetalInstance) SSHReboot(ctx context.Context) error {
- if !b.HasBMC() {
- // try adjust uefi boot order before reboot
- if err := b.AdjustUEFIBootOrder(ctx); 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")
- }
- }
- b.ClearSSHConfig()
- return nil
- }
- func (b *SBaremetalInstance) SSHShutdown() error {
- if _, err := b.sshRun("/sbin/poweroff", "sudo shutdown -h now && exit"); err != nil {
- if ssh.IsExitMissingError(err) {
- return nil
- }
- return errors.Wrap(err, "Try poweroff")
- }
- return nil
- }
- func (b *SBaremetalInstance) GetIPMITool() *ipmitool.LanPlusIPMI {
- conf := b.GetIPMIConfig()
- if conf == nil {
- log.Debugf("GetIPMIConfig is nil")
- return nil
- }
- return ipmitool.NewLanPlusIPMI(conf.IpAddr, conf.Username, conf.Password)
- }
- func (b *SBaremetalInstance) isRedfishCapable() bool {
- conf := b.GetIPMIConfig()
- if conf == nil {
- return false
- }
- if !conf.Verified {
- return false
- }
- if !conf.RedfishApi {
- return false
- }
- return true
- }
- func (b *SBaremetalInstance) GetRedfishCli(ctx context.Context) redfish.IRedfishDriver {
- if !b.isRedfishCapable() {
- return nil
- }
- conf := b.GetIPMIConfig()
- var endpoint = "https://" + conf.IpAddr
- if strings.Contains(conf.IpAddr, ":") {
- endpoint = fmt.Sprintf("https://[%s]", conf.IpAddr)
- }
- return redfish.NewRedfishDriver(ctx, endpoint, conf.Username, conf.Password, false)
- }
- func (b *SBaremetalInstance) GetIPMILanChannel() uint8 {
- conf := b.GetIPMIConfig()
- if conf == nil {
- return 0
- }
- return conf.LanChannel
- }
- func (b *SBaremetalInstance) DoPXEBoot() error {
- log.Infof("Do PXE Boot ........., wait")
- b.ClearSSHConfig()
- ipmiCli := b.GetIPMITool()
- if ipmiCli != nil {
- return ipmitool.DoRebootToPXE(ipmiCli)
- }
- return fmt.Errorf("Baremetal %s ipmitool is nil", b.GetId())
- }
- func (b *SBaremetalInstance) doRedfishPowerOn() error {
- log.Infof("Do Redfish PowerOn ........., wait")
- ctx := context.Background()
- b.ClearSSHConfig()
- redfishApi := b.GetRedfishCli(ctx)
- if redfishApi != nil {
- err := redfishApi.Reset(ctx, "On")
- if err != nil {
- if httputils.ErrorCode(err) == 409 {
- return errors.Wrap(err, "redfishApi.Reset On fail, code 409")
- } else {
- return errors.Wrap(err, "redfishApi.Reset On")
- }
- }
- return nil
- }
- return fmt.Errorf("Baremetal %s redfishApi is nil", b.GetId())
- }
- func (b *SBaremetalInstance) DoRedfishPowerOn() error {
- err := b.doRedfishPowerOn()
- if err == nil {
- return nil
- }
- var errs = []error{err}
- log.Warningf("Do redfish power on error: %v, try use fallback IPMI way", err)
- ipmiCli := b.GetIPMITool()
- if err := ipmitool.DoReboot(ipmiCli); err != nil {
- errs = append(errs, errors.Wrap(err, "Fallback to use ipmitool reboot"))
- } else {
- return nil
- }
- return errors.NewAggregate(errs)
- }
- /*
- func (b *SBaremetalInstance) DoDiskBoot() error {
- log.Infof("Do DISK Boot ........., wait")
- b.ClearSSHConfig()
- ipmiCli := b.GetIPMITool()
- if ipmiCli != nil {
- return ipmitool.DoRebootToDisk(ipmiCli)
- }
- return fmt.Errorf("Baremetal %s ipmitool is nil", b.GetId())
- }
- */
- func (b *SBaremetalInstance) GetPowerStatus() (types.PowerStatus, error) {
- status, err := b.getPowerStatus()
- if err != nil {
- if errors.Cause(err) != types.ErrIPMIToolNull {
- return "", errors.Wrap(err, "GetPowerStatus")
- } else if b.HasBMC() {
- return "", errors.Wrap(err, "GetPowerStatus from ipmi")
- }
- }
- return status, nil
- }
- func (b *SBaremetalInstance) getPowerStatus() (types.PowerStatus, error) {
- ipmiCli := b.GetIPMITool()
- if ipmiCli == nil {
- if cli, err := b.GetHostSSHClient(); err == nil {
- cli.Close()
- return types.POWER_STATUS_ON, nil
- } else {
- log.Warningf("Use host %s ssh client get powerstatus: %v", b.GetName(), err)
- }
- if cli, err := b.GetServerSSHClient(); err == nil {
- cli.Close()
- b.ClearSSHConfig()
- return types.POWER_STATUS_ON, nil
- } else {
- log.Warningf("Use server %s ssh client get powerstatus: %v", b.GetServerName(), err)
- }
- return "", errors.Wrapf(types.ErrIPMIToolNull, "Baremetal %s", b.GetId())
- }
- cps, err := ipmitool.GetChassisPowerStatus(ipmiCli)
- if err != nil {
- return "", errors.Wrap(err, "ipmitool.GetChassisPowerStatus")
- }
- return types.PowerStatus(cps), nil
- }
- func (b *SBaremetalInstance) DoPowerShutdown(soft bool) error {
- b.ClearSSHConfig()
- ipmiCli := b.GetIPMITool()
- if ipmiCli != nil {
- if soft {
- return ipmitool.DoSoftShutdown(ipmiCli)
- }
- return ipmitool.DoHardShutdown(ipmiCli)
- }
- return fmt.Errorf("Baremetal %s ipmitool is nil", b.GetId())
- }
- func (b *SBaremetalInstance) GetStorageDriver() string {
- driver, _ := b.desc.GetString("storage_driver")
- return driver
- }
- func (b *SBaremetalInstance) GetZoneId() string {
- return b.manager.GetZoneId()
- }
- func (b *SBaremetalInstance) GetZoneName() string {
- return b.manager.GetZoneName()
- }
- func (b *SBaremetalInstance) GetStorageCacheId() string {
- return b.manager.Agent.CacheManager.GetId()
- }
- func (b *SBaremetalInstance) GetBootMode() string {
- bootMode, _ := b.desc.GetString("boot_mode")
- if len(bootMode) == 0 {
- bootMode = api.BOOT_MODE_PXE
- }
- return bootMode
- }
- func (b *SBaremetalInstance) GetRegion() string {
- r, _ := b.desc.GetString("region")
- return r
- }
- func (b *SBaremetalInstance) GetRegionId() string {
- r, _ := b.desc.GetString("region_id")
- return r
- }
- func (b *SBaremetalInstance) GetSerialNumber() string {
- r, _ := b.desc.GetString("sn")
- return r
- }
- func (b *SBaremetalInstance) GetManufacture() string {
- r, _ := b.desc.GetString("sys_info", "manufacture")
- return r
- }
- func (b *SBaremetalInstance) GetModel() string {
- r, _ := b.desc.GetString("sys_info", "model")
- return r
- }
- func (b *SBaremetalInstance) GetNodeCount() string {
- r, _ := b.desc.GetString("node_count")
- return r
- }
- func (b *SBaremetalInstance) GetMemGb() string {
- memMb, _ := b.desc.Int("mem_size")
- return strconv.FormatInt(memMb/1024, 10)
- }
- func (b *SBaremetalInstance) DelayedRemove(_ context.Context, _ jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- b.remove()
- return nil, nil
- }
- func (b *SBaremetalInstance) remove() {
- b.manager.CleanBaremetal(b.GetId())
- b.manager = nil
- b.desc = nil
- }
- func (b *SBaremetalInstance) StartNewTask(factory tasks.TaskFactory, userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) {
- go func() {
- task := factory(userCred, b, taskId, data)
- b.SetTask(task)
- }()
- }
- func (b *SBaremetalInstance) StartBaremetalMaintenanceTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) {
- if jsonutils.QueryBoolean(data, "force_reboot", false) {
- b.ClearSSHConfig()
- }
- if jsonutils.QueryBoolean(data, "guest_running", false) {
- data.(*jsonutils.JSONDict).Set("soft_reboot", jsonutils.JSONTrue)
- }
- b.StartNewTask(tasks.NewBaremetalMaintenanceTask, userCred, taskId, data)
- }
- func (b *SBaremetalInstance) StartBaremetalUnmaintenanceTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) {
- b.StartNewTask(tasks.NewBaremetalUnmaintenanceTask, userCred, taskId, data)
- }
- func (b *SBaremetalInstance) StartBaremetalReprepareTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) {
- b.StartNewTask(tasks.NewBaremetalReprepareTask, userCred, taskId, data)
- }
- func (b *SBaremetalInstance) StartBaremetalResetBMCTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
- b.StartNewTask(tasks.NewBaremetalResetBMCTask, userCred, taskId, data)
- return nil
- }
- func (b *SBaremetalInstance) StartBaremetalIpmiProbeTask(ctx context.Context, userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
- session := b.manager.GetClientSession()
- data, _ = b.manager.fetchBaremetal(session, b.GetId())
- if err := b.SaveDesc(ctx, data); err != nil {
- return err
- }
- b.StartNewTask(tasks.NewBaremetalIpmiProbeTask, userCred, taskId, data)
- return nil
- }
- func (b *SBaremetalInstance) StartBaremetalCdromTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
- b.StartNewTask(tasks.NewBaremetalCdromTask, userCred, taskId, data)
- return nil
- }
- func (b *SBaremetalInstance) DelayedServerReset(ctx context.Context, _ jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- err := b.DoPXEBoot()
- return nil, err
- }
- func (b *SBaremetalInstance) StartServerCreateTask(ctx context.Context, userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
- b.serverLock.Lock()
- defer b.serverLock.Unlock()
- if b.server != nil {
- return fmt.Errorf("Baremetal %s already have server %s", b.GetName(), b.server.GetName())
- }
- descData, err := data.Get("desc")
- if err != nil {
- return fmt.Errorf("Create data not found server desc: %v", err)
- }
- server, err := newBaremetalServer(b, descData.(*jsonutils.JSONDict))
- if err != nil {
- return fmt.Errorf("New server error: %v", err)
- }
- b.server = server
- b.desc.Set("server_id", jsonutils.NewString(b.server.GetId()))
- if err := b.AutoSaveDesc(ctx); err != nil {
- return err
- }
- b.StartNewTask(tasks.NewBaremetalServerCreateTask, userCred, taskId, data)
- return nil
- }
- func (b *SBaremetalInstance) StartServerDeployTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
- desc, err := data.Get("desc")
- if err != nil {
- return fmt.Errorf("Not found desc in data")
- }
- if err := b.GetServer().SaveDesc(desc); err != nil {
- return fmt.Errorf("Save server desc: %v", err)
- }
- b.StartNewTask(tasks.NewBaremetalServerDeployTask, userCred, taskId, data)
- return nil
- }
- func (b *SBaremetalInstance) StartServerRebuildTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
- desc, err := data.Get("desc")
- if err != nil {
- return fmt.Errorf("Not found desc in data")
- }
- if err := b.GetServer().SaveDesc(desc); err != nil {
- return fmt.Errorf("Save server desc: %v", err)
- }
- b.StartNewTask(tasks.NewBaremetalServerRebuildTask, userCred, taskId, data)
- return nil
- }
- func (b *SBaremetalInstance) StartServerStartTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
- b.StartNewTask(tasks.NewBaremetalServerStartTask, userCred, taskId, data)
- return nil
- }
- func (b *SBaremetalInstance) StartServerStopTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) error {
- b.StartNewTask(tasks.NewBaremetalServerStopTask, userCred, taskId, data)
- return nil
- }
- func (b *SBaremetalInstance) StartServerDestroyTask(userCred mcclient.TokenCredential, taskId string, data jsonutils.JSONObject) {
- b.StartNewTask(tasks.NewBaremetalServerDestroyTask, userCred, taskId, data)
- }
- func (b *SBaremetalInstance) DelayedSyncIPMIInfo(ctx context.Context, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- ipmiCli := b.GetIPMITool()
- lanChannel := b.GetIPMILanChannel()
- sysInfo, err := ipmitool.GetSysInfo(ipmiCli)
- if err != nil {
- return nil, errors.Wrap(err, "GetSysInfo")
- }
- profile, err := profiles.GetProfile(ctx, sysInfo)
- if err != nil {
- return nil, errors.Wrap(err, "GetProfile")
- }
- if lanChannel <= 0 {
- if len(profile.LanChannels) == 0 {
- return nil, errors.Wrap(errors.ErrInvalidStatus, "baremetal profile not valid lan channel?")
- }
- lanChannel = profile.LanChannels[0]
- }
- retObj := make(map[string]string)
- if ipAddr, _ := data.GetString("ip_addr"); ipAddr != "" {
- err = ipmitool.SetLanStaticIP(ipmiCli, lanChannel, ipAddr)
- if err != nil {
- return nil, err
- }
- // TODO: netutils.wait_ip_alive(ipAddr, 120)
- retObj["ipmi_ip_addr"] = ipAddr
- }
- if passwd, _ := data.GetString("password"); passwd != "" {
- err = ipmitool.SetLanPasswd(ipmiCli, profile.RootId, passwd)
- if err != nil {
- return nil, err
- }
- retObj["ipmi_password"] = passwd
- }
- return jsonutils.Marshal(retObj), nil
- }
- func (b *SBaremetalInstance) DelayedSyncDesc(ctx context.Context, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if data == nil {
- session := b.manager.GetClientSession()
- data, _ = b.manager.fetchBaremetal(session, b.GetId())
- }
- err := b.SaveDesc(ctx, data)
- return nil, err
- }
- func (b *SBaremetalInstance) DelayedServerStatus(ctx context.Context, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- ps, err := b.GetPowerStatus()
- if err != nil {
- return nil, err
- }
- status := PowerStatusToServerStatus(b, ps)
- resp := jsonutils.NewDict()
- resp.Add(jsonutils.NewString(status), "status")
- return resp, err
- }
- func (b *SBaremetalInstance) SendNicInfo(ctx context.Context, nic *types.SNicDevInfo, idx int, nicType compute.TNicType, reset bool, ipAddr string, reserve bool) error {
- params := jsonutils.NewDict()
- params.Add(jsonutils.NewString(nic.Mac.String()), "mac")
- params.Add(jsonutils.NewInt(int64(nic.Speed)), "rate")
- if idx >= 0 {
- params.Add(jsonutils.NewInt(int64(idx)), "index")
- }
- if nicType != "" {
- params.Add(jsonutils.NewString(string(nicType)), "nic_type")
- }
- params.Add(jsonutils.NewInt(int64(nic.Mtu)), "mtu")
- if nic.Up != nil {
- params.Add(jsonutils.NewBool(*nic.Up), "link_up")
- }
- if reset {
- params.Add(jsonutils.JSONTrue, "reset")
- }
- if ipAddr != "" {
- params.Add(jsonutils.NewString(ipAddr), "ip_addr")
- params.Add(jsonutils.JSONTrue, "require_designated_ip")
- if reserve {
- params.Add(jsonutils.JSONTrue, "reserve")
- }
- }
- localNic := b.GetNicByMac(nic.Mac)
- if localNic != nil {
- params.Add(jsonutils.NewString(localNic.WireId), "wire_id")
- }
- resp, err := modules.Hosts.PerformAction(
- b.GetClientSession(),
- b.GetId(),
- "add-netif",
- params,
- )
- if err != nil {
- return err
- }
- return b.SaveDesc(ctx, resp)
- }
- func bindMount(src, dst string) error {
- err := procutils.NewCommand("touch", dst).Run()
- if err != nil {
- return errors.Wrapf(err, "touch %s", dst)
- }
- err = procutils.NewCommand("mount", "-o", "ro,bind", src, dst).Run()
- if err != nil {
- return errors.Wrapf(err, "mount %s %s", src, dst)
- }
- return nil
- }
- func unbindMount(dst string) error {
- err := procutils.NewCommand("umount", dst).Run()
- if err != nil {
- return errors.Wrapf(err, "umount %s", dst)
- }
- return nil
- }
- func (b *SBaremetalInstance) EnablePxeBoot() bool {
- return jsonutils.QueryBoolean(b.desc, "enable_pxe_boot", true)
- }
- func (b *SBaremetalInstance) GenerateBootISO() error {
- // precheck
- conf := b.GetRawIPMIConfig()
- if !conf.Verified {
- return errors.Error("GenerateBootISO: IPMI not supported")
- }
- if !conf.CdromBoot {
- return errors.Error("GenerateBootISO: cdrom boot not supported")
- }
- accessIp := b.GetAccessIp()
- if accessIp == "" {
- return errors.Error("GenerateBootISO: empty accessIp")
- }
- adminNic := b.GetAdminNic()
- if adminNic == nil {
- accessNet, _ := b.findAccessNetwork(accessIp)
- if accessNet == nil {
- return errors.Error("GenerateBootISO: Nil access Network")
- }
- }
- ctx := context.Background()
- redfishApi := b.GetRedfishCli(ctx)
- if redfishApi == nil {
- return errors.Wrap(httperrors.ErrNotSupported, "no valid redfishApi")
- }
- // generate ISO
- isoDir, err := ioutil.TempDir("", "bmiso")
- if err != nil {
- return errors.Wrap(err, "ioutil.TempDir")
- }
- defer os.RemoveAll(isoDir)
- isoLinDir := filepath.Join(isoDir, "isolinux")
- err = os.Mkdir(isoLinDir, os.FileMode(0766))
- if err != nil {
- return errors.Wrapf(err, "Mkdir %s", isoLinDir)
- }
- for _, f := range []string{
- "chain.c32", "ldlinux.c32", "libutil.c32", "libcom32.c32",
- } {
- err = bindMount(filepath.Join(o.Options.TftpRoot, f), filepath.Join(isoLinDir, f))
- if err != nil {
- return errors.Wrapf(err, "Link %s", f)
- }
- defer unbindMount(filepath.Join(isoLinDir, f))
- }
- for src, dst := range map[string]string{
- "kernel": "vmlinuz",
- "initramfs": "initrd.img",
- } {
- err = bindMount(filepath.Join(o.Options.TftpRoot, src), filepath.Join(isoLinDir, dst))
- if err != nil {
- return errors.Wrapf(err, "Link %s %s", src, dst)
- }
- defer unbindMount(filepath.Join(isoLinDir, dst))
- }
- for _, f := range []string{
- "isolinux.bin",
- } {
- err = procutils.NewCommand("cp", filepath.Join(o.Options.TftpRoot, f), filepath.Join(isoLinDir, f)).Run()
- if err != nil {
- return errors.Wrapf(err, "cp %s", f)
- }
- }
- cfgCont := b.getIsolinuxConf()
- err = fileutils2.FilePutContents(filepath.Join(isoLinDir, "isolinux.cfg"), cfgCont, false)
- if err != nil {
- return errors.Wrap(err, "fileutils.FilePutContent")
- }
- args := []string{
- "-quiet",
- "-J", "-R",
- "-input-charset", "utf-8",
- "-b", "isolinux/isolinux.bin",
- "-c", "isolinux/boot.cat",
- "-no-emul-boot",
- "-boot-load-size", "4",
- "-boot-info-table",
- "-o", b.getBootIsoImagePath(),
- isoDir,
- }
- err = procutils.NewCommand("mkisofs", args...).Run()
- if err != nil {
- return errors.Wrap(err, "procutils.NewCommand mkisofs")
- }
- // mount the virtual media
- err = redfish.MountVirtualCdrom(ctx, redfishApi, b.getBootIsoUrl(), true)
- if err != nil {
- return errors.Wrap(err, "redfish.MountVirtualCdrom")
- }
- return nil
- }
- func (b *SBaremetalInstance) clearBootIso() error {
- ctx := context.Background()
- redfishApi := b.GetRedfishCli(ctx)
- if redfishApi == nil {
- return errors.Wrap(httperrors.ErrNotSupported, "no valid redfishApi")
- }
- err := redfish.UmountVirtualCdrom(ctx, redfishApi)
- if err != nil {
- return errors.Wrap(err, "redfish.UmountVirtualCdrom")
- }
- return b.clearBootIsoImage()
- }
- func (b *SBaremetalInstance) clearBootIsoImage() error {
- path := b.getBootIsoImagePath()
- if fileutils2.Exists(path) {
- return os.Remove(path)
- }
- return nil
- }
- func (b *SBaremetalInstance) getBootIsoImagePath() string {
- return filepath.Join(o.Options.BootIsoPath, b.GetId()+".iso")
- }
- func (b *SBaremetalInstance) DoNTPConfig() error {
- var urls []string
- for _, ep := range []string{"internal", "public"} {
- urls, _ = auth.GetServiceURLs("ntp", o.Options.Region, "", ep, httputils.POST)
- if len(urls) > 0 {
- break
- }
- }
- if len(urls) == 0 {
- log.Warningf("NO ntp server specified, skip DoNTPConfig")
- return nil
- }
- for i := range urls {
- if strings.HasPrefix(urls[i], "ntp://") {
- urls[i] = urls[i][6:]
- }
- }
- log.Infof("Set NTP %s", urls)
- ntpConf := redfish.SNTPConf{}
- ntpConf.ProtocolEnabled = true
- ntpConf.TimeZone = o.Options.TimeZone
- ntpConf.NTPServers = urls
- ctx := context.Background()
- redfishApi := b.GetRedfishCli(ctx)
- if redfishApi == nil {
- return errors.Wrap(httperrors.ErrNotSupported, "no valid redfishApi")
- }
- err := redfishApi.SetNTPConf(ctx, ntpConf)
- if err != nil {
- return errors.Wrap(err, "redfishApi.SetNTPConf")
- }
- return nil
- }
- func (b *SBaremetalInstance) fetchLogs(ctx context.Context, logType string, since time.Time) ([]redfish.SEvent, error) {
- redfishApi := b.GetRedfishCli(ctx)
- if redfishApi == nil {
- // errors.Wrap(httperrors.ErrNotSupported, "no valid redfish api")
- return nil, nil
- }
- switch logType {
- case redfish.EVENT_TYPE_SYSTEM:
- return redfishApi.ReadSystemLogs(ctx, since)
- case redfish.EVENT_TYPE_MANAGER:
- return redfishApi.ReadManagerLogs(ctx, since)
- }
- return nil, errors.Wrap(httperrors.ErrNotSupported, logType)
- }
- func (b *SBaremetalInstance) clearLogs(ctx context.Context, logType string) error {
- redfishApi := b.GetRedfishCli(ctx)
- if redfishApi == nil {
- return errors.Wrap(httperrors.ErrNotSupported, "no valid redfish api")
- }
- switch logType {
- case redfish.EVENT_TYPE_SYSTEM:
- return redfishApi.ClearSystemLogs(ctx)
- case redfish.EVENT_TYPE_MANAGER:
- return redfishApi.ClearManagerLogs(ctx)
- }
- return errors.Wrap(httperrors.ErrNotSupported, logType)
- }
- func (b *SBaremetalInstance) doCronJobs(ctx context.Context) {
- for _, job := range b.cronJobs {
- now := time.Now().UTC()
- if job.NeedsToRun(now) {
- // log.Debugf("need to run %s", job.Name())
- func() {
- job.StartRun()
- defer job.StopRun()
- err := job.Do(ctx, now)
- if err != nil {
- log.Errorf("Baremetal %s do cronjob %s fail: %s", b.GetName(), job.Name(), err)
- }
- }()
- }
- }
- }
- func (b *SBaremetalInstance) fetchPowerThermalMetrics(ctx context.Context) ([]influxdb.SKeyValue, []influxdb.SKeyValue, error) {
- redfishApi := b.GetRedfishCli(ctx)
- if redfishApi == nil {
- return nil, nil, errors.Wrap(httperrors.ErrNotSupported, "no valid redfish api")
- }
- powers, err := redfishApi.GetPower(ctx)
- if err != nil {
- return nil, nil, errors.Wrap(err, "redfishApi.GetPower")
- }
- thermals, err := redfishApi.GetThermal(ctx)
- if err != nil {
- return nil, nil, errors.Wrap(err, "redfishApi.Thermal")
- }
- var powerMetrics []influxdb.SKeyValue
- if len(powers) > 0 {
- powerMetrics = powers[0].ToMetrics()
- }
- thermalMetrics := make([]influxdb.SKeyValue, 0)
- for _, t := range thermals {
- thermalMetrics = append(thermalMetrics, t.ToMetric())
- }
- return powerMetrics, thermalMetrics, nil
- }
- func (b *SBaremetalInstance) GetConsoleJNLP(ctx context.Context) (string, error) {
- cli := b.GetRedfishCli(ctx)
- if cli != nil {
- return cli.GetConsoleJNLP(ctx)
- }
- conf := b.GetIPMIConfig()
- bmc := bmconsole.NewBMCConsole(conf.IpAddr, conf.Username, conf.Password, false)
- manufacture := b.GetManufacture()
- switch strings.ToLower(manufacture) {
- case "hp", "hpe":
- return bmc.GetIloConsoleJNLP(ctx)
- case "dell", "dell inc.":
- return bmc.GetIdracConsoleJNLP(ctx, b.GetSerialNumber(), b.GetModel())
- case "supermicro":
- return bmc.GetSupermicroConsoleJNLP(ctx)
- case "lenovo":
- return bmc.GetLenovoConsoleJNLP(ctx)
- }
- return "", httperrors.NewNotImplementedError("Unsupported manufacture %s", manufacture)
- }
- func (b *SBaremetalInstance) getTags() []influxdb.SKeyValue {
- tags := []influxdb.SKeyValue{
- {
- Key: "id",
- Value: b.GetId(),
- },
- {
- Key: "name",
- Value: b.GetName(),
- },
- {
- Key: "zone_id",
- Value: b.GetZoneId(),
- },
- {
- Key: "zone",
- Value: b.GetZoneName(),
- },
- {
- Key: "boot_mode",
- Value: b.GetBootMode(),
- },
- {
- Key: "host_type",
- Value: "baremetal",
- },
- {
- Key: "region",
- Value: b.GetRegion(),
- },
- {
- Key: "region_id",
- Value: b.GetRegionId(),
- },
- {
- Key: "sn",
- Value: b.GetSerialNumber(),
- },
- {
- Key: "manufacture",
- Value: b.GetManufacture(),
- },
- {
- Key: "model",
- Value: b.GetModel(),
- },
- {
- Key: "status",
- Value: b.GetStatus(),
- },
- {
- Key: "ncpu",
- Value: b.GetNodeCount(),
- },
- {
- Key: "mem_gb",
- Value: b.GetMemGb(),
- },
- }
- srvId := b.GetServerId()
- if len(srvId) > 0 {
- tags = append(tags, influxdb.SKeyValue{
- Key: "server_id",
- Value: srvId,
- })
- tags = append(tags, influxdb.SKeyValue{
- Key: "server",
- Value: b.GetServerName(),
- })
- }
- return tags
- }
- type SBaremetalServer struct {
- baremetal *SBaremetalInstance
- desc *jsonutils.JSONDict
- }
- func newBaremetalServer(baremetal *SBaremetalInstance, desc *jsonutils.JSONDict) (*SBaremetalServer, error) {
- server := &SBaremetalServer{
- baremetal: baremetal,
- desc: desc,
- }
- err := server.SaveDesc(desc)
- return server, err
- }
- func (server *SBaremetalServer) GetId() string {
- id, err := server.desc.GetString("uuid")
- if err != nil {
- log.Fatalf("Get id from desc error: %v", err)
- }
- return id
- }
- func (server *SBaremetalServer) GetName() string {
- id, err := server.desc.GetString("name")
- if err != nil {
- log.Errorf("Get name from desc %s error: %v", server.desc.String(), err)
- }
- return id
- }
- func (server *SBaremetalServer) GetHostName() string {
- hostname, err := server.desc.GetString("hostname")
- if err != nil {
- log.Errorf("Get hostname from desc %s error: %v", server.desc.String(), err)
- }
- return hostname
- }
- func (server *SBaremetalServer) GetOsName() string {
- osName, err := server.desc.GetString("os_name")
- if err != nil {
- log.Errorf("Get os name from desc %s error: %v", server.desc.String(), err)
- }
- return osName
- }
- func (server *SBaremetalServer) SaveDesc(desc jsonutils.JSONObject) error {
- if desc != nil {
- server.desc = desc.(*jsonutils.JSONDict)
- }
- return ioutil.WriteFile(server.baremetal.GetServerDescFilePath(), []byte(server.desc.String()), 0644)
- }
- func (s *SBaremetalServer) RemoveDesc() {
- os.Remove(s.baremetal.GetServerDescFilePath())
- s.desc = nil
- s.baremetal = nil
- }
- func (s *SBaremetalServer) GetRootTemplateId() string {
- rootDisk, err := s.desc.GetAt(0, "disks")
- if err != nil {
- log.Errorf("Can't found root disk")
- return ""
- }
- id, _ := rootDisk.GetString("template_id")
- return id
- }
- func (s *SBaremetalServer) GetMetadata() (*jsonutils.JSONDict, error) {
- metadata, err := s.desc.Get("metadata")
- if err != nil {
- return nil, errors.Wrap(err, "get desc.metadata")
- }
- return metadata.(*jsonutils.JSONDict), nil
- }
- func (s *SBaremetalServer) GetRootDiskMatcher() (*api.BaremetalRootDiskMatcher, error) {
- matcher, err := s.getRootDiskMatcher()
- if err != nil && errors.Cause(err) != errors.ErrNotFound {
- return nil, errors.Wrap(err, "getRootDiskMatcher")
- }
- if matcher == nil {
- matcher = &api.BaremetalRootDiskMatcher{}
- }
- rootDiskObj, err := s.GetRootDiskObj()
- if err != nil {
- return nil, errors.Wrap(err, "GetRootDiskObj")
- }
- pciPath, _ := rootDiskObj.GetString("pci_path")
- if pciPath != "" {
- matcher.PCIPath = pciPath
- }
- return matcher, nil
- }
- func (s *SBaremetalServer) getRootDiskMatcher() (*api.BaremetalRootDiskMatcher, error) {
- metadata, err := s.GetMetadata()
- if err != nil {
- return nil, errors.Wrap(err, "get metadata")
- }
- if !metadata.Contains(api.BAREMETAL_SERVER_METATA_ROOT_DISK_MATCHER) {
- return nil, errors.Wrapf(errors.ErrNotFound, "not found %s in metadata", api.BAREMETAL_SERVER_METATA_ROOT_DISK_MATCHER)
- }
- jStr, _ := metadata.GetString(api.BAREMETAL_SERVER_METATA_ROOT_DISK_MATCHER)
- jObj, err := jsonutils.ParseString(jStr)
- if err != nil {
- return nil, errors.Wrapf(err, "parse json string: %s", jStr)
- }
- matcher := new(api.BaremetalRootDiskMatcher)
- if err := jObj.Unmarshal(matcher); err != nil {
- return nil, errors.Wrapf(err, "unmarshal to matcher")
- }
- return matcher, nil
- }
- func (s *SBaremetalServer) GetDiskConfig() ([]*api.BaremetalDiskConfig, error) {
- layouts := make([]baremetal.Layout, 0)
- err := s.desc.Unmarshal(&layouts, "disk_config")
- if err != nil {
- return nil, err
- }
- if len(layouts) != 0 {
- firstDisk := layouts[0]
- // convert to normal order if first disk is Linux or PCIE driver
- driver := firstDisk.Conf.Driver
- if utils.IsInStringArray(driver, []string{baremetal.DISK_DRIVER_LINUX, baremetal.DISK_DRIVER_PCIE}) {
- return baremetal.GetLayoutDiskConfig(layouts), nil
- }
- }
- return baremetal.GetLayoutRaidConfig(layouts), nil
- }
- func (s *SBaremetalServer) GetRootDiskObj() (*jsonutils.JSONDict, error) {
- disks, _ := s.desc.GetArray("disks")
- if len(disks) == 0 {
- return nil, errors.Error("Empty disks in desc")
- }
- return disks[0].(*jsonutils.JSONDict), nil
- }
- func (s *SBaremetalServer) NewConfigedSSHPartitionTool(term *ssh.Client) (*disktool.SSHPartitionTool, error) {
- raid, nonRaid, pcie, err := detect_storages.DetectStorageInfo(term, false)
- if err != nil {
- return nil, errors.Wrap(err, "DetectStorageInfo")
- }
- storages := make([]*baremetal.BaremetalStorage, 0)
- storages = append(storages, raid...)
- storages = append(storages, nonRaid...)
- storages = append(storages, pcie...)
- confs, err := s.GetDiskConfig()
- if err != nil {
- return nil, err
- }
- layouts, err := baremetal.CalculateLayout(confs, storages)
- if err != nil {
- return nil, fmt.Errorf("CalculateLayout: %v", err)
- }
- log.Errorf("NewConfigedSSHPartitionTool layouts: %s", jsonutils.Marshal(layouts))
- diskConfs := baremetal.GroupLayoutResultsByDriverAdapter(layouts)
- for _, dConf := range diskConfs {
- driver := dConf.Driver
- adapter := dConf.Adapter
- isSoftRaid := baremetal.DISK_DRIVERS_SOFT_RAID.Has(driver)
- raidDrv := raiddrivers.GetDriver(driver, term)
- if raidDrv != nil {
- if err := raidDrv.ParsePhyDevs(); err != nil {
- return nil, fmt.Errorf("RaidDriver %s parse physical devices: %v", raidDrv.GetName(), err)
- }
- if isSoftRaid {
- devs := make([]*baremetal.BaremetalStorage, 0)
- for _, layout := range layouts {
- if len(layout.Disks) > 0 && layout.Disks[0].Driver == driver && layout.Disks[0].Adapter == dConf.Adapter {
- devs = append(devs, layout.Disks...)
- }
- }
- log.Infof("SetDevicesForAdapter %v", jsonutils.Marshal(devs))
- if mdadmDrver, ok := raidDrv.(raid2.IRaidDeviceSetter); ok {
- mdadmDrver.SetDevicesForAdapter(dConf.Adapter, devs)
- }
- }
- if err := raiddrivers.PostBuildRaid(raidDrv, adapter); err != nil {
- return nil, fmt.Errorf("Build %s raid failed: %v", raidDrv.GetName(), err)
- }
- time.Sleep(10 * time.Second) // wait 10 seconds for raid status OK
- }
- }
- matcher, err := s.GetRootDiskMatcher()
- if errors.Cause(err) != errors.ErrNotFound {
- log.Errorf("GetRootDiskMatcher: %v", err)
- }
- tool, err := disktool.NewSSHPartitionTool(term, layouts, matcher)
- if err != nil {
- return nil, errors.Wrap(err, "NewSSHPartitionTool")
- }
- return tool, nil
- }
- func (s *SBaremetalServer) DoDiskConfig(term *ssh.Client) (*disktool.SSHPartitionTool, error) {
- raid, nonRaid, pcie, err := detect_storages.DetectStorageInfo(term, true)
- if err != nil {
- return nil, errors.Wrap(err, "DetectStorageInfo")
- }
- storages := make([]*baremetal.BaremetalStorage, 0)
- storages = append(storages, raid...)
- storages = append(storages, nonRaid...)
- storages = append(storages, pcie...)
- confs, err := s.GetDiskConfig()
- if err != nil {
- return nil, err
- }
- layouts, err := baremetal.CalculateLayout(confs, storages)
- if err != nil {
- return nil, fmt.Errorf("CalculateLayout: %v", err)
- }
- diskConfs := baremetal.GroupLayoutResultsByDriverAdapter(layouts)
- log.Errorf("%s layouts: %s, diskConfs: %s", s.GetName(), jsonutils.Marshal(layouts).PrettyString(), jsonutils.Marshal(diskConfs).PrettyString())
- for _, dConf := range diskConfs {
- driver := dConf.Driver
- raidDrv := raiddrivers.GetDriver(driver, term)
- if raidDrv != nil {
- if err := raidDrv.ParsePhyDevs(); err != nil {
- return nil, fmt.Errorf("RaidDriver %s parse physical devices: %v", raidDrv.GetName(), err)
- }
- raidDrv.CleanRaid()
- }
- }
- for _, dConf := range diskConfs {
- driver := dConf.Driver
- adapter := dConf.Adapter
- isSoftRaid := baremetal.DISK_DRIVERS_SOFT_RAID.Has(driver)
- raidDrv := raiddrivers.GetDriver(driver, term)
- if raidDrv != nil {
- if err := raidDrv.ParsePhyDevs(); err != nil {
- return nil, fmt.Errorf("RaidDriver %s parse physical devices: %v", raidDrv.GetName(), err)
- }
- if isSoftRaid {
- devs := make([]*baremetal.BaremetalStorage, 0)
- for _, layout := range layouts {
- if len(layout.Disks) > 0 && layout.Disks[0].Driver == driver && layout.Disks[0].Adapter == dConf.Adapter {
- devs = append(devs, layout.Disks...)
- }
- }
- log.Infof("SetDevicesForAdapter %v", jsonutils.Marshal(devs))
- if mdadmDriver, ok := raidDrv.(raid2.IRaidDeviceSetter); ok {
- mdadmDriver.SetDevicesForAdapter(dConf.Adapter, devs)
- }
- }
- if err := raiddrivers.BuildRaid(raidDrv, dConf.Configs, adapter); err != nil {
- return nil, fmt.Errorf("Build %s raid failed: %v", raidDrv.GetName(), err)
- }
- time.Sleep(10 * time.Second) // wait 10 seconds for raid status OK
- }
- }
- matcher, err := s.GetRootDiskMatcher()
- if errors.Cause(err) != errors.ErrNotFound {
- log.Errorf("GetRootDiskMatcher: %v", err)
- }
- tool, err := disktool.NewSSHPartitionTool(term, layouts, matcher)
- if err != nil {
- return nil, errors.Wrap(err, "NewSSHPartitionTool")
- }
- maxTries := 60
- for tried := 0; !tool.IsAllDisksReady() && tried < maxTries; tried++ {
- time.Sleep(5 * time.Second)
- tool.RetrieveDiskInfo(matcher)
- log.Warningf("disktool not ready string: %s", tool.DebugString())
- }
- if !tool.IsAllDisksReady() {
- return nil, fmt.Errorf("Raid disks are not ready???")
- }
- return tool, nil
- }
- func (s *SBaremetalServer) DoDiskUnconfig(term *ssh.Client) error {
- // tear down raid
- driver := s.baremetal.GetStorageDriver()
- raidDrv := raiddrivers.GetDriver(driver, term)
- if raidDrv != nil {
- if err := raidDrv.ParsePhyDevs(); err != nil {
- return err
- }
- raidDrv.CleanRaid()
- }
- return nil
- }
- func (s *SBaremetalServer) DoEraseDisk(term *ssh.Client) error {
- // soft raid should stop mdadm first
- if err := mdadm.CleanRaid(term); err != nil {
- return err
- }
- cmd := "/lib/mos/partdestroy.sh"
- _, err := term.Run(cmd)
- return err
- }
- func replaceHostAddr(urlStr string, addr string) string {
- urlComp, _ := url.Parse(urlStr)
- commaPos := strings.IndexByte(urlComp.Host, ':')
- if commaPos >= 0 {
- urlComp.Host = addr + urlComp.Host[commaPos:]
- } else {
- urlComp.Host = addr
- }
- return urlComp.String()
- }
- func (s *SBaremetalServer) doCreateRoot(term *ssh.Client, devName string, disableImageCache bool) error {
- session := s.baremetal.GetClientSession()
- token := session.GetToken().GetTokenString()
- urlStr := s.baremetal.GetImageUrl(disableImageCache)
- imageId := s.GetRootTemplateId()
- cmd := fmt.Sprintf("/lib/mos/rootcreate.sh %s %s %s %s", token, urlStr, imageId, devName)
- log.Infof("rootcreate cmd: %q", cmd)
- if _, err := term.Run(cmd); err != nil {
- return fmt.Errorf("Root create fail: %v", err)
- }
- return nil
- }
- func (s *SBaremetalServer) DoPartitionDisk(tool *disktool.SSHPartitionTool, term *ssh.Client, disableImageCache bool) (*disktool.DiskPartitions, []*disktool.Partition, error) {
- raid, nonRaid, pcie, err := detect_storages.DetectStorageInfo(term, false)
- if err != nil {
- return nil, nil, errors.Wrap(err, "DetectStorageInfo")
- }
- storages := make([]*baremetal.BaremetalStorage, 0)
- storages = append(storages, raid...)
- storages = append(storages, nonRaid...)
- storages = append(storages, pcie...)
- // confs, err := s.GetDiskConfig()
- // if err != nil {
- // return nil, errors.Wrapf(err, "do disk config")
- // }
- // layouts, err := baremetal.CalculateLayout(confs, storages)
- // if err != nil {
- // return nil, errors.Wrapf(err, "CalculateLayout")
- // }
- //
- // tool, err := disktool.NewSSHPartitionTool(term, layouts)
- // if err != nil {
- // return nil, errors.Wrapf(err, "NewSSHPartitionTool")
- // }
- disks, _ := s.desc.GetArray("disks")
- if len(disks) == 0 {
- return nil, nil, errors.Error("Empty disks in desc")
- }
- rootImageId := s.GetRootTemplateId()
- diskOffset := 0
- rootDisk := tool.GetRootDisk()
- log.Infof("root disk name %s", rootDisk.GetDevName())
- if len(rootImageId) > 0 {
- rootDiskObj := disks[0]
- rootSize, _ := rootDiskObj.Int("size")
- err = s.doCreateRoot(term, rootDisk.GetDevName(), disableImageCache)
- if err != nil {
- return rootDisk, nil, errors.Wrap(err, "Failed to create root")
- }
- tool.RetrievePartitionInfo()
- parts := tool.GetPartitions()
- if len(parts) == 0 {
- return rootDisk, nil, errors.Error("Root disk create failed, no partitions")
- }
- log.Infof("Resize root to %d MB", rootSize)
- if err := tool.ResizePartition(0, rootSize); err != nil {
- return rootDisk, nil, errors.Wrapf(err, "Fail to resize root to %d", rootSize)
- }
- diskOffset = 1
- } else {
- tool.RetrievePartitionInfo()
- parts := tool.GetPartitions()
- if len(parts) > 0 {
- return rootDisk, nil, errors.Error("should no partition!!!")
- }
- }
- if len(disks) > diskOffset {
- for _, disk := range disks[diskOffset:] {
- sz, err := disk.Int("size")
- if err != nil {
- sz = -1
- }
- fs, _ := disk.GetString("fs")
- uuid, _ := disk.GetString("disk_id")
- driver, _ := disk.GetString("driver")
- log.Infof("Create partition %d %s", sz, fs)
- if err := tool.CreatePartition(-1, sz, fs, true, driver, uuid); err != nil {
- return rootDisk, nil, errors.Wrapf(err, "Fail to create disk %s", disk.String())
- }
- }
- }
- log.Infof("Finish create partitions")
- return rootDisk, tool.GetPartitions(), nil
- }
- func (s *SBaremetalServer) DoRebuildRootDisk(tool *disktool.SSHPartitionTool, term *ssh.Client, disableImageCache bool) (*disktool.DiskPartitions, []*disktool.Partition, error) {
- // raid, nonRaid, pcie, err := detect_storages.DetectStorageInfo(term, false)
- // if err != nil {
- // return nil, err
- // }
- // storages := make([]*baremetal.BaremetalStorage, 0)
- // storages = append(storages, raid...)
- // storages = append(storages, nonRaid...)
- // storages = append(storages, pcie...)
- // confs, err := s.GetDiskConfig()
- // if err != nil {
- // return nil, err
- // }
- // layouts, err := baremetal.CalculateLayout(confs, storages)
- // if err != nil {
- // return nil, err
- // }
- //
- // tool, err := disktool.NewSSHPartitionTool(term, layouts)
- // if err != nil {
- // return nil, err
- // }
- disks, _ := s.desc.GetArray("disks")
- if len(disks) == 0 {
- return nil, nil, fmt.Errorf("Empty disks in desc")
- }
- rootDisk := disks[0]
- rootSize, _ := rootDisk.Int("size")
- rd := tool.GetRootDisk()
- err := s.doCreateRoot(term, rd.GetDevName(), disableImageCache)
- if err != nil {
- return rd, nil, fmt.Errorf("Failed to create root: %v", err)
- }
- tool.RetrievePartitionInfo()
- if err := rd.ReInitInfo(); err != nil {
- return rd, nil, errors.Wrap(err, "Reinit root disk after create root")
- }
- log.Infof("Resize root to %d MB", rootSize)
- if err := rd.ResizePartition(rootSize); err != nil {
- return rd, nil, fmt.Errorf("Fail to resize root to %d, err: %v", rootSize, err)
- }
- if len(disks) > 1 {
- for _, disk := range disks[1:] {
- sz, err := disk.Int("size")
- if err != nil {
- sz = -1
- }
- fs, _ := disk.GetString("fs")
- uuid, _ := disk.GetString("disk_id")
- log.Infof("Create partition %d %s", sz, fs)
- if err := rd.CreatePartition(sz, fs, false, uuid); err != nil {
- log.Errorf("Rebuild root create (%s, %d, %s) partition error: %v", uuid, sz, fs, err)
- break
- }
- }
- }
- log.Infof("Finish create partitions")
- parts := rd.GetPartitions()
- restDisks := tool.Disks()
- if len(restDisks) > 1 {
- restDisks = restDisks[1:]
- }
- for _, d := range restDisks {
- parts = append(parts, d.GetPartitions()...)
- }
- return rd, parts, nil
- }
- func (s *SBaremetalServer) SyncPartitionSize(term *ssh.Client, rootDisk *disktool.DiskPartitions, parts []*disktool.Partition) ([]jsonutils.JSONObject, error) {
- disks, _ := s.desc.GetArray("disks")
- // calculate root partitions count
- rootPartsCnt := len(parts) - len(disks) + 1
- if len(parts) < len(disks) {
- // HACK: rebuild root disk
- rootPartsCnt = len(parts)
- }
- rootParts := parts[0:rootPartsCnt]
- dataParts := parts[rootPartsCnt:]
- idx := 0
- // set root disk attributes that returns to region service
- size := (rootParts[len(rootParts)-1].GetEnd() + 1) * 512 / 1024 / 1024
- rootDiskObj := disks[idx].(*jsonutils.JSONDict)
- rootDiskObj.Set("size", jsonutils.NewInt(int64(size)))
- rootDiskObj.Set("pci_path", jsonutils.NewString(rootDisk.GetPCIPath()))
- idx += 1
- for _, p := range dataParts {
- sizeMB, err := p.GetSizeMB()
- if err != nil {
- return nil, errors.Wrap(err, "GetSizeMB")
- }
- disks[idx].(*jsonutils.JSONDict).Set("size", jsonutils.NewInt(int64(sizeMB)))
- disks[idx].(*jsonutils.JSONDict).Set("dev", jsonutils.NewString(p.GetDev()))
- idx++
- }
- s.desc.Set("disks", jsonutils.NewArray(disks...))
- return disks, nil
- }
- func (s *SBaremetalServer) DoDeploy(tool *disktool.SSHPartitionTool, term *ssh.Client, data jsonutils.JSONObject, isInit bool) (jsonutils.JSONObject, error) {
- publicKey := deployapi.GetKeys(data)
- isRandomPassword := false
- password, _ := data.GetString("password")
- resetPassword := jsonutils.QueryBoolean(data, "reset_password", false)
- if resetPassword && len(password) == 0 {
- password = seclib.RandomPassword(12)
- isRandomPassword = true
- }
- deployArray := make([]*deployapi.DeployContent, 0)
- if data.Contains("deploys") {
- err := data.Unmarshal(&deployArray, "deploys")
- if err != nil {
- return nil, errors.Wrapf(err, "unmarshal to array of deployapi.DeployContent")
- }
- }
- userData, _ := s.desc.GetString("user_data")
- deployInfo := deployapi.NewDeployInfo(publicKey, deployArray,
- password, isRandomPassword, isInit, true, o.Options.LinuxDefaultRootUser, o.Options.WindowsDefaultAdminUser, false, "",
- false, "",
- userData,
- )
- return s.deployFs(tool, term, deployInfo)
- }
- func (s *SBaremetalServer) deployFs(tool *disktool.SSHPartitionTool, term *ssh.Client, deployInfo *deployapi.DeployInfo) (jsonutils.JSONObject, error) {
- raid, nonRaid, pcie, err := detect_storages.DetectStorageInfo(term, false)
- if err != nil {
- return nil, err
- }
- storages := make([]*baremetal.BaremetalStorage, 0)
- storages = append(storages, raid...)
- storages = append(storages, nonRaid...)
- storages = append(storages, pcie...)
- confs, err := s.GetDiskConfig()
- if err != nil {
- return nil, err
- }
- layouts, err := baremetal.CalculateLayout(confs, storages)
- if err != nil {
- return nil, err
- }
- rootDev, rootfs, err := sshpart.MountSSHRootfs(tool, term, layouts)
- if err != nil {
- return nil, fmt.Errorf("Find rootfs error: %s", err)
- }
- defer func() {
- rootDev.Umount()
- }()
- if strings.ToLower(rootfs.GetOs()) == "windows" {
- return nil, fmt.Errorf("Unsupported OS: %s", rootfs.GetOs())
- }
- deployDesc, err := deployapi.GuestJsonDescToDeployDesc(s.desc)
- if err != nil {
- return nil, errors.Wrap(err, "To deploy desc fail")
- }
- deployDesc.Hypervisor = api.HYPERVISOR_BAREMETAL
- deployDesc, err = s.reIndexDescNics(term, deployDesc)
- if err != nil {
- return nil, errors.Wrap(err, "reIndexDescNics")
- }
- return guestfs.DeployGuestFs(rootfs, deployDesc, deployInfo)
- }
- func (s *SBaremetalServer) reIndexDescNics(term *ssh.Client, desc *deployapi.GuestDesc) (*deployapi.GuestDesc, error) {
- rNics, err := tasks.GetNicsInfo(term)
- if err != nil {
- return nil, errors.Wrapf(err, "Get server %s remote nics", s.GetName())
- }
- findRemoteNic := func(mac string) (int, *types.SNicDevInfo) {
- for idx, nic := range rNics {
- if nic.Mac.String() == mac {
- return idx, rNics[idx]
- }
- }
- return -1, nil
- }
- reIndexNics := func(nics []*deployapi.Nic) ([]*deployapi.Nic, error) {
- for idx, nic := range nics {
- if nic.GetNicType() == string(api.NIC_TYPE_IPMI) || nic.GetIndex() >= 0 {
- continue
- }
- rIdx, rNic := findRemoteNic(nic.GetMac())
- if rNic == nil {
- return nil, errors.Errorf("Not found remote nic by mac %q", nic.GetMac())
- }
- if nics[idx].Index != int32(rIdx) {
- log.Infof("Reindex nic %s index %d to %d", nics[idx].GetMac(), nics[idx].Index, rIdx)
- nics[idx].Index = int32(rIdx)
- }
- }
- return nics, nil
- }
- nics, err := reIndexNics(desc.Nics)
- if err != nil {
- return nil, errors.Wrap(err, "Reindex nics")
- }
- desc.Nics = nics
- sNics, err := reIndexNics(desc.NicsStandby)
- if err != nil {
- return nil, errors.Wrap(err, "Reindex standby nics")
- }
- desc.NicsStandby = sNics
- return desc, nil
- }
- func (s *SBaremetalServer) GetNics() []types.SServerNic {
- nics := []types.SServerNic{}
- err := s.desc.Unmarshal(&nics, "nics")
- if err != nil {
- log.Errorf("Unmarshal desc to get server nics error: %v", err)
- return nil
- }
- return nics
- }
- func (s *SBaremetalServer) GetNicByMac(mac net.HardwareAddr) *types.SNic {
- for _, n := range s.GetNics() {
- if n.GetMac().String() == mac.String() {
- nic := n.ToNic()
- return &nic
- }
- }
- return nil
- }
|