| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182 |
- // 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 models
- import (
- "context"
- "database/sql"
- "fmt"
- "net"
- "net/http"
- "net/url"
- "sort"
- "strconv"
- "strings"
- "sync"
- "time"
- "golang.org/x/sync/errgroup"
- v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "yunion.io/x/cloudmux/pkg/apis/compute"
- "yunion.io/x/cloudmux/pkg/cloudprovider"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/gotypes"
- "yunion.io/x/pkg/tristate"
- "yunion.io/x/pkg/util/compare"
- "yunion.io/x/pkg/util/fileutils"
- "yunion.io/x/pkg/util/httputils"
- "yunion.io/x/pkg/util/netutils"
- "yunion.io/x/pkg/util/rbacscope"
- "yunion.io/x/pkg/util/regutils"
- "yunion.io/x/pkg/util/sets"
- "yunion.io/x/pkg/utils"
- "yunion.io/x/sqlchemy"
- "yunion.io/x/onecloud/pkg/apis"
- baremetalapi "yunion.io/x/onecloud/pkg/apis/baremetal"
- billing_api "yunion.io/x/onecloud/pkg/apis/billing"
- api "yunion.io/x/onecloud/pkg/apis/compute"
- computeapi "yunion.io/x/onecloud/pkg/apis/compute"
- hostapi "yunion.io/x/onecloud/pkg/apis/host"
- napi "yunion.io/x/onecloud/pkg/apis/notify"
- "yunion.io/x/onecloud/pkg/appsrv"
- "yunion.io/x/onecloud/pkg/cloudcommon/consts"
- "yunion.io/x/onecloud/pkg/cloudcommon/db"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
- "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
- "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
- "yunion.io/x/onecloud/pkg/cloudcommon/types"
- "yunion.io/x/onecloud/pkg/compute/baremetal"
- "yunion.io/x/onecloud/pkg/compute/options"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient"
- "yunion.io/x/onecloud/pkg/mcclient/auth"
- "yunion.io/x/onecloud/pkg/mcclient/modules/scheduler"
- "yunion.io/x/onecloud/pkg/util/cgrouputils/cpuset"
- "yunion.io/x/onecloud/pkg/util/k8s/tokens"
- "yunion.io/x/onecloud/pkg/util/logclient"
- "yunion.io/x/onecloud/pkg/util/rbacutils"
- "yunion.io/x/onecloud/pkg/util/stringutils2"
- )
- type SHostManager struct {
- db.SEnabledStatusInfrasResourceBaseManager
- db.SExternalizedResourceBaseManager
- SZoneResourceBaseManager
- SManagedResourceBaseManager
- SHostnameResourceBaseManager
- SBackupstorageResourceBaseManager
- }
- var HostManager *SHostManager
- func init() {
- HostManager = &SHostManager{
- SEnabledStatusInfrasResourceBaseManager: db.NewEnabledStatusInfrasResourceBaseManager(
- SHost{},
- "hosts_tbl",
- "host",
- "hosts",
- ),
- }
- HostManager.SetVirtualObject(HostManager)
- HostManager.SetAlias("baremetal", "baremetals")
- notifyclient.AddNotifyDBHookResources(HostManager.KeywordPlural(), HostManager.AliasPlural())
- GuestManager.NameRequireAscii = false
- }
- type SHost struct {
- db.SEnabledStatusInfrasResourceBase
- db.SExternalizedResourceBase
- SZoneResourceBase `update:""`
- SManagedResourceBase
- SBillingResourceBase
- SHostnameResourceBase
- // 机架
- Rack string `width:"16" charset:"ascii" nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
- // 机位
- Slots string `width:"16" charset:"ascii" nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
- // 管理口MAC
- AccessMac string `width:"32" charset:"ascii" nullable:"true" index:"true" list:"domain" update:"domain"`
- // 管理口Ip地址
- AccessIp string `width:"64" charset:"ascii" nullable:"true" list:"domain" update:"domain"`
- // 管理地址
- ManagerUri string `width:"256" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- // 系统信息
- SysInfo jsonutils.JSONObject `length:"long" nullable:"true" search:"domain" list:"domain" update:"domain" create:"domain_optional"`
- // 物理机序列号信息
- SN string `width:"128" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- // CPU核数
- CpuCount int `nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- // 物理CPU颗数
- NodeCount int8 `nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- // CPU描述信息
- CpuDesc string `width:"128" charset:"ascii" nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
- // CPU频率
- CpuMhz int `nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
- // CPU缓存大小,单位KB
- CpuCache int `nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
- // 预留CPU大小
- CpuReserved int `nullable:"true" default:"0" list:"domain" update:"domain" create:"domain_optional"`
- // CPU超分比
- CpuCmtbound float32 `nullable:"true" list:"domain" create:"domain_optional"`
- // CPUMicrocode
- CpuMicrocode string `width:"64" charset:"ascii" nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
- // CPU架构
- CpuArchitecture string `width:"16" charset:"ascii" nullable:"true" get:"domain" list:"domain" update:"domain" create:"domain_optional"`
- // KVM CAP VCPU MAX
- KvmCapMaxVcpu int `nullable:"true" get:"domain" list:"domain" update:"domain" create:"domain_optional"`
- // 内存大小,单位Mb
- MemSize int `nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- // 预留内存大小
- MemReserved int `nullable:"true" default:"0" list:"domain" update:"domain" create:"domain_optional"`
- // 内存超分比
- MemCmtbound float32 `nullable:"true" list:"domain" create:"domain_optional"`
- // 页大小
- PageSizeKB int `nullable:"false" default:"4" list:"domain" update:"domain" create:"domain_optional"`
- // scheduler cpu-node/numa allocate
- EnableNumaAllocate bool `nullable:"true" default:"false" list:"domain" update:"domain" create:"domain_optional"`
- // 存储大小,单位Mb
- StorageSize int64 `nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- // 存储类型
- StorageType string `width:"20" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- // 存储驱动类型
- StorageDriver string `width:"20" charset:"ascii" nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
- // 存储详情
- StorageInfo jsonutils.JSONObject `nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
- RootPartitionUsedCapacityMb int `nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- MemoryUsedMb int `nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- CpuUsagePercent float64 `nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- // IPMI地址
- IpmiIp string `width:"16" charset:"ascii" nullable:"true" list:"domain"`
- // IPMI详情
- IpmiInfo jsonutils.JSONObject `nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
- // 宿主机状态
- // example: online
- HostStatus string `width:"16" charset:"ascii" nullable:"false" default:"offline" list:"domain"`
- // 宿主机类型
- HostType string `width:"36" charset:"ascii" nullable:"false" list:"domain" update:"domain" create:"domain_required"`
- // host服务软件版本
- Version string `width:"128" charset:"ascii" list:"domain" update:"domain" create:"domain_optional"`
- // OVN软件版本
- OvnVersion string `width:"64" charset:"ascii" list:"domain" update:"domain" create:"domain_optional"`
- IsBaremetal bool `nullable:"true" default:"false" list:"domain" update:"domain" create:"domain_optional"`
- // 是否处于维护状态
- IsMaintenance bool `nullable:"true" default:"false" list:"domain"`
- LastPingAt time.Time ``
- // health check enabled by host agent online
- EnableHealthCheck bool `nullable:"true" default:"false"`
- ResourceType string `width:"36" charset:"ascii" nullable:"false" list:"domain" update:"domain" create:"domain_optional" default:"shared"`
- RealExternalId string `width:"256" charset:"utf8" get:"domain"`
- // 是否为导入的宿主机
- IsImport bool `nullable:"true" default:"false" list:"domain" create:"domain_optional"`
- // 是否允许PXE启动
- EnablePxeBoot tristate.TriState `default:"true" list:"domain" create:"domain_optional" update:"domain"`
- // 主机UUID
- Uuid string `width:"64" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- // 主机启动模式, 可能值为PXE和ISO
- BootMode string `width:"8" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
- // IPv4地址,作为私有云vpc访问外网时的网关
- OvnMappedIpAddr string `width:"16" charset:"ascii" nullable:"true" list:"user"`
- // IPv6地址,作为私有云vpc访问外网时的网关
- OvnMappedIp6Addr string `width:"64" charset:"ascii" nullable:"true" list:"user"`
- // UEFI详情
- UefiInfo jsonutils.JSONObject `nullable:"true" get:"domain" update:"domain" create:"domain_optional"`
- // 公网Ip地址
- PublicIp string `width:"128" charset:"ascii" nullable:"true" list:"domain" update:"domain"`
- }
- func (manager *SHostManager) GetContextManagers() [][]db.IModelManager {
- return [][]db.IModelManager{
- {ZoneManager},
- }
- }
- // 宿主机/物理机列表
- func (manager *SHostManager) ListItemFilter(
- ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- query api.HostListInput,
- ) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
- }
- q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
- }
- q, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ZonalFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter")
- }
- resType := query.ResourceType
- if len(resType) > 0 {
- switch resType {
- case api.HostResourceTypeShared:
- q = q.Filter(
- sqlchemy.OR(
- sqlchemy.IsNullOrEmpty(q.Field("resource_type")),
- sqlchemy.Equals(q.Field("resource_type"), api.HostResourceTypeShared),
- ),
- )
- default:
- q = q.Equals("resource_type", resType)
- }
- }
- q, err = manager.SEnabledStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.EnabledStatusInfrasResourceBaseListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ListItemFilter")
- }
- if len(query.AnyMac) > 0 {
- anyMac := netutils.FormatMacAddr(query.AnyMac)
- if len(anyMac) == 0 {
- return nil, errors.Wrapf(httperrors.ErrInputParameter, "invalid any_mac address %s", query.AnyMac)
- }
- netifs, _ := NetInterfaceManager.FetchByMac(anyMac)
- var bmIds []string
- for i := range netifs {
- if !utils.IsInArray(netifs[i].BaremetalId, bmIds) {
- bmIds = append(bmIds, netifs[i].BaremetalId)
- }
- }
- if len(bmIds) > 0 {
- q = q.In("id", bmIds)
- } else {
- q = q.Equals("access_mac", anyMac)
- }
- }
- if len(query.AnyIp) > 0 {
- cmpFunc := sqlchemy.Equals
- if len(query.AnyIp) == 1 {
- cmpFunc = func(f sqlchemy.IQueryField, v interface{}) sqlchemy.ICondition {
- return sqlchemy.Regexp(f, v.(string))
- }
- }
- hnQ := HostnetworkManager.Query("baremetal_id") //.Contains("ip_addr", query.AnyIp).SubQuery()
- conditions := []sqlchemy.ICondition{}
- for _, ip := range query.AnyIp {
- conditions = append(conditions, cmpFunc(hnQ.Field("ip_addr"), ip))
- }
- hn := hnQ.Filter(
- sqlchemy.OR(conditions...),
- )
- conditions = []sqlchemy.ICondition{}
- for _, ip := range query.AnyIp {
- conditions = append(conditions, cmpFunc(q.Field("access_ip"), ip))
- conditions = append(conditions, cmpFunc(q.Field("ipmi_ip"), ip))
- }
- conditions = append(conditions, sqlchemy.In(q.Field("id"), hn))
- q = q.Filter(sqlchemy.OR(
- conditions...,
- ))
- }
- schedTagStr := query.SchedtagId
- if len(schedTagStr) > 0 {
- schedTag, _ := SchedtagManager.FetchByIdOrName(ctx, nil, schedTagStr)
- if schedTag == nil {
- return nil, httperrors.NewResourceNotFoundError("Schedtag %s not found", schedTagStr)
- }
- hostschedtags := HostschedtagManager.Query().SubQuery()
- scopeQuery := hostschedtags.Query(hostschedtags.Field("host_id")).Equals("schedtag_id", schedTag.GetId()).SubQuery()
- q = q.In("id", scopeQuery)
- }
- wireStr := query.WireId
- if len(wireStr) > 0 {
- wire, _ := WireManager.FetchByIdOrName(ctx, nil, wireStr)
- if wire == nil {
- return nil, httperrors.NewResourceNotFoundError("Wire %s not found", wireStr)
- }
- hostwires := NetInterfaceManager.Query().SubQuery()
- scopeQuery := hostwires.Query(hostwires.Field("baremetal_id")).Equals("wire_id", wire.GetId()).SubQuery()
- q = q.In("id", scopeQuery)
- }
- storageStr := query.StorageId
- if len(storageStr) > 0 {
- storage, _ := StorageManager.FetchByIdOrName(ctx, nil, storageStr)
- if storage == nil {
- return nil, httperrors.NewResourceNotFoundError("Storage %s not found", storageStr)
- }
- hoststorages := HoststorageManager.Query().SubQuery()
- scopeQuery := hoststorages.Query(hoststorages.Field("host_id")).Equals("storage_id", storage.GetId()).SubQuery()
- notAttached := (query.StorageNotAttached != nil && *query.StorageNotAttached)
- if !notAttached {
- q = q.In("id", scopeQuery)
- } else {
- q = q.NotIn("id", scopeQuery)
- }
- }
- if len(query.BackupstorageId) > 0 {
- hbsQ := HostBackupstorageManager.Query("host_id", "backupstorage_id")
- hbsQ, err = manager.SBackupstorageResourceBaseManager.ListItemFilter(ctx, hbsQ, userCred, query.BackupstorageFilterListInput)
- if err != nil {
- return q, errors.Wrap(err, "SBackupStorageResouceBaseManager.ListItemFiled")
- }
- hbsSubQ := hbsQ.SubQuery()
- q = q.LeftJoin(hbsSubQ, sqlchemy.Equals(q.Field("id"), hbsSubQ.Field("host_id")))
- notAttached := (query.StorageNotAttached != nil && *query.StorageNotAttached)
- if !notAttached {
- q = q.Filter(sqlchemy.IsNotNull(hbsSubQ.Field("backupstorage_id")))
- } else {
- q = q.Filter(sqlchemy.IsNull(hbsSubQ.Field("backupstorage_id")))
- }
- }
- hostStorageType := query.HostStorageType
- if len(hostStorageType) > 0 {
- hoststorages := HoststorageManager.Query()
- storages := StorageManager.Query().In("storage_type", hostStorageType).SubQuery()
- hq := hoststorages.Join(storages, sqlchemy.Equals(hoststorages.Field("storage_id"), storages.Field("id"))).SubQuery()
- scopeQuery := hq.Query(hq.Field("host_id")).SubQuery()
- q = q.In("id", scopeQuery)
- }
- hypervisorStr := query.Hypervisor
- if len(hypervisorStr) > 0 {
- q = q.Filter(sqlchemy.In(q.Field("host_type"), Hypervisors2HostTypes([]string{query.Hypervisor})))
- }
- usable := (query.Usable != nil && *query.Usable)
- if usable {
- hosts := HostManager.Query().SubQuery()
- netifs := NetInterfaceManager.Query().SubQuery()
- networks := NetworkManager.Query().SubQuery()
- providers := usableCloudProviders().SubQuery()
- hostQ1 := hosts.Query(hosts.Field("id"))
- hostQ1 = hostQ1.Join(providers, sqlchemy.Equals(hosts.Field("manager_id"), providers.Field("id")))
- hostQ1 = hostQ1.Join(netifs, sqlchemy.Equals(hosts.Field("id"), netifs.Field("baremetal_id")))
- hostQ1 = hostQ1.Join(networks, sqlchemy.Equals(netifs.Field("wire_id"), networks.Field("wire_id")))
- hostQ1 = hostQ1.Filter(sqlchemy.Equals(networks.Field("status"), api.NETWORK_STATUS_AVAILABLE))
- hostQ1 = hostQ1.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
- hostQ2 := hosts.Query(hosts.Field("id"))
- hostQ2 = hostQ2.Join(netifs, sqlchemy.Equals(hosts.Field("id"), netifs.Field("baremetal_id")))
- hostQ2 = hostQ2.Join(networks, sqlchemy.Equals(netifs.Field("wire_id"), networks.Field("wire_id")))
- hostQ2 = hostQ2.Filter(sqlchemy.IsNullOrEmpty(hosts.Field("manager_id")))
- hostQ2 = hostQ2.Filter(sqlchemy.Equals(networks.Field("status"), api.NETWORK_STATUS_AVAILABLE))
- hostQ2 = hostQ2.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
- q = q.Filter(sqlchemy.OR(
- sqlchemy.In(q.Field("id"), hostQ1.SubQuery()),
- sqlchemy.In(q.Field("id"), hostQ2.SubQuery()),
- ))
- zones := ZoneManager.Query().SubQuery()
- q = q.Join(zones, sqlchemy.Equals(q.Field("zone_id"), zones.Field("id"))).
- Filter(sqlchemy.Equals(zones.Field("status"), api.ZONE_ENABLE))
- q = q.In("status", []string{api.HOST_STATUS_RUNNING, api.HOST_STATUS_READY})
- q = q.Filter(
- sqlchemy.OR(
- sqlchemy.AND(
- sqlchemy.NotEquals(q.Field("host_type"), api.HOST_TYPE_BAREMETAL),
- sqlchemy.Equals(q.Field("host_status"), api.HOST_ONLINE),
- ),
- sqlchemy.Equals(q.Field("host_type"), api.HOST_TYPE_BAREMETAL),
- ),
- )
- }
- if query.IsEmpty != nil {
- isEmpty := *query.IsEmpty
- sq := GuestManager.Query("host_id").IsNotEmpty("host_id").GroupBy("host_id").SubQuery()
- if isEmpty {
- q = q.NotIn("id", sq)
- } else {
- q = q.In("id", sq)
- }
- }
- if query.Baremetal != nil {
- isBaremetal := *query.Baremetal
- if isBaremetal {
- q = q.Equals("host_type", api.HOST_TYPE_BAREMETAL)
- } else {
- q = q.NotEquals("host_type", api.HOST_TYPE_BAREMETAL)
- }
- }
- fieldQueryMap := map[string][]string{
- "rack": query.Rack,
- "slots": query.Slots,
- "access_mac": query.AccessMac,
- "access_ip": query.AccessIp,
- "sn": query.SN,
- "storage_type": query.StorageType,
- "ipmi_ip": query.IpmiIp,
- "public_ip": query.PublicIp,
- "host_status": query.HostStatus,
- "host_type": query.HostType,
- "version": query.Version,
- "ovn_version": query.OvnVersion,
- "uuid": query.Uuid,
- "boot_mode": query.BootMode,
- "cpu_architecture": query.CpuArchitecture,
- }
- for f, vars := range fieldQueryMap {
- vars = stringutils2.FilterEmpty(vars)
- if len(vars) > 1 {
- q = q.In(f, vars)
- } else if len(vars) == 1 {
- q = q.Regexp(f, vars[0])
- }
- }
- if len(query.CpuCount) > 0 {
- q = q.In("cpu_count", query.CpuCount)
- }
- if len(query.MemSize) > 0 {
- q = q.In("mem_size", query.MemSize)
- }
- if query.IsMaintenance != nil {
- if *query.IsMaintenance {
- q = q.IsTrue("is_maintenance")
- } else {
- q = q.IsFalse("is_maintenance")
- }
- }
- if query.IsImport != nil {
- if *query.IsImport {
- q = q.IsTrue("is_import")
- } else {
- q = q.IsFalse("is_import")
- }
- }
- if query.EnablePxeBoot != nil {
- if *query.EnablePxeBoot {
- q = q.IsTrue("enable_pxe_boot")
- } else {
- q = q.IsFalse("enable_pxe_boot")
- }
- }
- if len(query.OsArch) > 0 {
- q = db.ListQueryByArchitecture(q, "cpu_architecture", query.OsArch)
- }
- // for provider onecloud
- if len(query.ServerIdForNetwork) > 0 {
- guest := GuestManager.FetchGuestById(query.ServerIdForNetwork)
- if guest != nil && guest.GetHypervisor() == api.HYPERVISOR_KVM {
- nets, _ := guest.GetNetworks("")
- if len(nets) > 0 {
- wires := []string{}
- for i := 0; i < len(nets); i++ {
- net, _ := nets[i].GetNetwork()
- if net == nil {
- continue
- }
- vpc, _ := net.GetVpc()
- if vpc.Id != api.DEFAULT_VPC_ID {
- q = q.IsNotEmpty("ovn_version")
- } else {
- if !utils.IsInStringArray(net.WireId, wires) {
- wires = append(wires, net.WireId)
- netifs := NetInterfaceManager.Query().SubQuery()
- scopeQuery := netifs.Query(netifs.Field("baremetal_id")).Equals("wire_id", net.WireId).SubQuery()
- q = q.In("id", scopeQuery)
- }
- }
- }
- }
- }
- }
- return q, nil
- }
- func (manager *SHostManager) OrderByExtraFields(
- ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- query api.HostListInput,
- ) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.EnabledStatusInfrasResourceBaseListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.OrderByExtraFields")
- }
- q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields")
- }
- q, err = manager.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ZonalFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields")
- }
- if db.NeedOrderQuery([]string{query.OrderByServerCount}) {
- guests := GuestManager.Query().SubQuery()
- guestCounts := guests.Query(
- guests.Field("host_id"),
- sqlchemy.COUNT("id").Label("guest_count"),
- ).GroupBy("host_id").SubQuery()
- q = q.LeftJoin(guestCounts, sqlchemy.Equals(q.Field("id"), guestCounts.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByServerCount}, []sqlchemy.IQueryField{guestCounts.Field("guest_count")})
- }
- if db.NeedOrderQuery([]string{query.OrderByCpuCommitRate}) {
- guestsQ := GuestManager.Query()
- if options.Options.IgnoreNonrunningGuests {
- guestsQ = guestsQ.Equals("status", api.VM_RUNNING)
- }
- guests := guestsQ.SubQuery()
- hosts := HostManager.Query().SubQuery()
- hostQ := hosts.Query(
- hosts.Field("id"),
- hosts.Field("cpu_count"),
- hosts.Field("cpu_reserved"),
- sqlchemy.SUM("guest_vcpu_count", guests.Field("vcpu_count")),
- ).LeftJoin(guests, sqlchemy.Equals(hosts.Field("id"), guests.Field("host_id")))
- hostSQ := hostQ.GroupBy(hostQ.Field("host_id")).SubQuery()
- divSQ := hostSQ.Query(
- hostSQ.Field("id"),
- sqlchemy.SUB("vcpu_count", hostSQ.Field("cpu_count"), hostSQ.Field("cpu_reserved")),
- hostSQ.Field("guest_vcpu_count"),
- ).SubQuery()
- sq := divSQ.Query(
- divSQ.Field("id").Label("host_id"),
- sqlchemy.DIV("cpu_commit_rate", divSQ.Field("guest_vcpu_count"), divSQ.Field("vcpu_count")),
- ).SubQuery()
- q = q.LeftJoin(sq, sqlchemy.Equals(q.Field("id"), sq.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByCpuCommitRate}, []sqlchemy.IQueryField{sq.Field("cpu_commit_rate")})
- }
- if db.NeedOrderQuery([]string{query.OrderByCpuCommit}) {
- guestsQ := GuestManager.Query()
- if options.Options.IgnoreNonrunningGuests {
- guestsQ = guestsQ.Equals("status", api.VM_RUNNING)
- }
- guests := guestsQ.SubQuery()
- guestQ := guests.Query(
- guests.Field("host_id"),
- sqlchemy.SUM("guest_vcpu_count", guests.Field("vcpu_count")),
- )
- guestSQ := guestQ.GroupBy(guestQ.Field("host_id")).SubQuery()
- q = q.LeftJoin(guestSQ, sqlchemy.Equals(q.Field("id"), guestSQ.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByCpuCommit}, []sqlchemy.IQueryField{q.Field("guest_vcpu_count")})
- }
- if db.NeedOrderQuery([]string{query.OrderByStorage}) {
- hoststorages := HoststorageManager.Query().SubQuery()
- storages := StorageManager.Query().IsTrue("enabled").In("storage_type", api.HOST_STORAGE_LOCAL_TYPES).SubQuery()
- hoststoragesQ := hoststorages.Query(
- hoststorages.Field("host_id"),
- sqlchemy.SUM("storage_capacity", storages.Field("capacity")),
- )
- hoststoragesQ = hoststoragesQ.LeftJoin(storages, sqlchemy.Equals(hoststoragesQ.Field("storage_id"), storages.Field("id")))
- hoststoragesSQ := hoststoragesQ.GroupBy(hoststoragesQ.Field("host_id")).SubQuery()
- q = q.LeftJoin(hoststoragesSQ, sqlchemy.Equals(q.Field("id"), hoststoragesSQ.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByStorage}, []sqlchemy.IQueryField{hoststoragesSQ.Field("storage_capacity")})
- }
- if db.NeedOrderQuery([]string{query.OrderByStorageCommitRate}) {
- hoststorages := HoststorageManager.Query().SubQuery()
- disks := DiskManager.Query().Equals("status", api.DISK_READY).SubQuery()
- storages := StorageManager.Query().IsTrue("enabled").In("storage_type", api.HOST_STORAGE_LOCAL_TYPES).SubQuery()
- disksQ := disks.Query(
- disks.Field("storage_id"),
- sqlchemy.SUM("disk_size", disks.Field("disk_size")),
- storages.Field("capacity"),
- storages.Field("reserved"),
- ).LeftJoin(storages, sqlchemy.Equals(disks.Field("storage_id"), storages.Field("id")))
- disksSQ := disksQ.GroupBy(disksQ.Field("storage_id")).SubQuery()
- divSQ := disksSQ.Query(
- disksSQ.Field("storage_id"),
- disksSQ.Field("disk_size"),
- sqlchemy.SUB("storage_capacity", disksSQ.Field("capacity"), disksSQ.Field("reserved")),
- ).SubQuery()
- hoststoragesQ := hoststorages.Query(
- hoststorages.Field("host_id"),
- sqlchemy.SUM("storage_used", divSQ.Field("disk_size")),
- sqlchemy.SUM("storage_capacity", divSQ.Field("storage_capacity")),
- )
- hoststoragesQ = hoststoragesQ.LeftJoin(divSQ, sqlchemy.Equals(hoststoragesQ.Field("storage_id"), divSQ.Field("storage_id")))
- hoststoragesSQ1 := hoststoragesQ.GroupBy(hoststoragesQ.Field("host_id")).SubQuery()
- hoststoragesSQ := hoststoragesSQ1.Query(
- hoststoragesSQ1.Field("host_id"),
- sqlchemy.DIV("storage_commit_rate",
- hoststoragesSQ1.Field("storage_used"),
- hoststoragesSQ1.Field("storage_capacity"),
- ),
- ).SubQuery()
- q = q.LeftJoin(hoststoragesSQ, sqlchemy.Equals(q.Field("id"), hoststoragesSQ.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByStorageCommitRate}, []sqlchemy.IQueryField{hoststoragesSQ.Field("storage_commit_rate")})
- }
- if db.NeedOrderQuery([]string{query.OrderByMemCommitRate}) {
- guestsQ := GuestManager.Query()
- if options.Options.IgnoreNonrunningGuests {
- guestsQ = guestsQ.Equals("status", api.VM_RUNNING)
- }
- guests := guestsQ.SubQuery()
- hosts := HostManager.Query().SubQuery()
- hostQ := hosts.Query(
- hosts.Field("id"),
- hosts.Field("mem_size"),
- hosts.Field("mem_reserved"),
- sqlchemy.SUM("guest_vmem_size", guests.Field("vmem_size")),
- ).LeftJoin(guests, sqlchemy.Equals(hosts.Field("id"), guests.Field("host_id")))
- hostSQ := hostQ.GroupBy(hostQ.Field("host_id")).SubQuery()
- divSQ := hostSQ.Query(
- hostSQ.Field("id"),
- sqlchemy.SUB("vmem_size", hostSQ.Field("mem_size"), hostSQ.Field("mem_reserved")),
- hostSQ.Field("guest_vmem_size"),
- ).SubQuery()
- sq := divSQ.Query(
- divSQ.Field("id").Label("host_id"),
- sqlchemy.DIV("mem_commit_rate", divSQ.Field("guest_vmem_size"), divSQ.Field("vmem_size")),
- ).SubQuery()
- q = q.LeftJoin(sq, sqlchemy.Equals(q.Field("id"), sq.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByMemCommitRate}, []sqlchemy.IQueryField{sq.Field("mem_commit_rate")})
- }
- if db.NeedOrderQuery([]string{query.OrderByMemCommit}) {
- guestsQ := GuestManager.Query()
- if options.Options.IgnoreNonrunningGuests {
- guestsQ = guestsQ.Equals("status", api.VM_RUNNING)
- }
- guests := guestsQ.SubQuery()
- guestQ := guests.Query(
- guests.Field("host_id"),
- sqlchemy.SUM("guest_vmem_size", guests.Field("vmem_size")),
- )
- guestSQ := guestQ.GroupBy(guestQ.Field("host_id")).SubQuery()
- q = q.LeftJoin(guestSQ, sqlchemy.Equals(q.Field("id"), guestSQ.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByMemCommit}, []sqlchemy.IQueryField{q.Field("guest_vmem_size")})
- }
- if db.NeedOrderQuery([]string{query.OrderByStorageUsed}) {
- disks := DiskManager.Query().Equals("status", api.DISK_READY).SubQuery()
- storages := StorageManager.Query().IsTrue("enabled").In("storage_type", api.HOST_STORAGE_LOCAL_TYPES).SubQuery()
- hs := HoststorageManager.Query()
- hoststorages := hs.Join(storages, sqlchemy.Equals(storages.Field("id"), hs.Field("storage_id"))).SubQuery()
- disksQ := disks.Query(
- disks.Field("storage_id"),
- sqlchemy.SUM("total_disk_size", disks.Field("disk_size")),
- )
- disksQ = disksQ.LeftJoin(storages, sqlchemy.Equals(disksQ.Field("storage_id"), storages.Field("id")))
- disksSQ := disksQ.GroupBy(disksQ.Field("storage_id")).SubQuery()
- hoststoragesQ := hoststorages.Query(
- hoststorages.Field("host_id"),
- sqlchemy.SUM("storage_used", disksSQ.Field("total_disk_size")),
- )
- hoststoragesQ = hoststoragesQ.Join(disksSQ, sqlchemy.Equals(hoststoragesQ.Field("storage_id"), disksSQ.Field("storage_id")))
- storageSQ := hoststoragesQ.GroupBy(hoststoragesQ.Field("host_id")).SubQuery()
- q = q.LeftJoin(storageSQ, sqlchemy.Equals(q.Field("id"), storageSQ.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByStorageUsed}, []sqlchemy.IQueryField{q.Field("storage_used")})
- }
- if db.NeedOrderQuery([]string{query.OrderByCpuUsage}) {
- db.OrderByFields(q, []string{query.OrderByCpuUsage}, []sqlchemy.IQueryField{q.Field("cpu_usage_percent")})
- }
- if db.NeedOrderQuery([]string{query.OrderByMemUsage}) {
- hosts := HostManager.Query().SubQuery()
- sq := hosts.Query(
- hosts.Field("id").Label("host_id"),
- sqlchemy.DIV("mem_usage", hosts.Field("memory_used_mb"), hosts.Field("mem_size")),
- ).SubQuery()
- q = q.LeftJoin(sq, sqlchemy.Equals(q.Field("id"), sq.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByMemUsage}, []sqlchemy.IQueryField{sq.Field("mem_usage")})
- }
- if db.NeedOrderQuery([]string{query.OrderByStorageUsage}) {
- hs := HoststorageManager.Query().SubQuery()
- storages := StorageManager.Query().IsTrue("enabled").NotEquals("storage_type", api.STORAGE_BAREMETAL).In("storage_type", api.HOST_STORAGE_LOCAL_TYPES).SubQuery()
- host := HostManager.Query().SubQuery()
- hsSQ := hs.Query(
- hs.Field("host_id"),
- sqlchemy.SUM("actual_storage_used", storages.Field("actual_capacity_used")),
- ).LeftJoin(storages, sqlchemy.Equals(hs.Field("storage_id"), storages.Field("id"))).GroupBy(hs.Field("host_id")).SubQuery()
- hsQ := hsSQ.Query(
- hsSQ.Field("host_id"),
- sqlchemy.DIV("storage_usage", hsSQ.Field("actual_storage_used"), host.Field("storage_size")),
- ).LeftJoin(host, sqlchemy.Equals(hsSQ.Field("host_id"), host.Field("id")))
- hsSSQ := hsQ.GroupBy(hsQ.Field("host_id")).SubQuery()
- q = q.LeftJoin(hsSSQ, sqlchemy.Equals(q.Field("id"), hsSSQ.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByStorageUsage}, []sqlchemy.IQueryField{hsSSQ.Field("storage_usage")})
- }
- if db.NeedOrderQuery([]string{query.OrderByVirtualMemUsage}) {
- guests := GuestManager.Query()
- if options.Options.IgnoreNonrunningGuests {
- guests = guests.Equals("status", api.VM_RUNNING)
- }
- sq := guests.SubQuery()
- guestSQ := sq.Query(
- sq.Field("host_id"),
- sqlchemy.SUM("mem_commit", sq.Field("vmem_size")),
- ).GroupBy(sq.Field("host_id")).SubQuery()
- host := HostManager.Query().SubQuery()
- vq := guestSQ.Query(
- guestSQ.Field("host_id"),
- guestSQ.Field("mem_commit"),
- sqlchemy.NewFunction(
- sqlchemy.NewCase().When(
- sqlchemy.GT(host.Field("mem_cmtbound"), 0),
- host.Field("mem_cmtbound"),
- ).Else(sqlchemy.NewConstField(options.Options.DefaultMemoryOvercommitBound)),
- "mem_cmtbound",
- true,
- ),
- sqlchemy.SUB("host_mem_size", host.Field("mem_size"), host.Field("mem_reserved")),
- ).LeftJoin(host, sqlchemy.Equals(guestSQ.Field("host_id"), host.Field("id"))).GroupBy(guestSQ.Field("host_id")).SubQuery()
- vsq := vq.Query(
- vq.Field("host_id"),
- sqlchemy.DIV("virtual_mem_usage", vq.Field("mem_commit"), sqlchemy.DIV("cmt_mem_size", vq.Field("mem_cmtbound"), vq.Field("host_mem_size"))),
- )
- vqq := vsq.GroupBy(vsq.Field("host_id")).SubQuery()
- q = q.LeftJoin(vqq, sqlchemy.Equals(q.Field("id"), vqq.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByVirtualMemUsage}, []sqlchemy.IQueryField{vqq.Field("virtual_mem_usage")})
- }
- if db.NeedOrderQuery([]string{query.OrderByVirtualCpuUsage}) {
- guests := GuestManager.Query()
- if options.Options.IgnoreNonrunningGuests {
- guests = guests.Equals("status", api.VM_RUNNING)
- }
- sq := guests.SubQuery()
- guestSQ := sq.Query(
- sq.Field("host_id"),
- sqlchemy.SUM("cpu_commit", sq.Field("vcpu_count")),
- ).GroupBy(sq.Field("host_id")).SubQuery()
- host := HostManager.Query().SubQuery()
- vq := guestSQ.Query(
- guestSQ.Field("host_id"),
- guestSQ.Field("cpu_commit"),
- sqlchemy.NewFunction(
- sqlchemy.NewCase().When(
- sqlchemy.GT(host.Field("cpu_cmtbound"), 0),
- host.Field("cpu_cmtbound"),
- ).Else(sqlchemy.NewConstField(options.Options.DefaultCPUOvercommitBound)),
- "cpu_cmtbound",
- true,
- ),
- sqlchemy.SUB("host_cpu_size", host.Field("cpu_count"), host.Field("cpu_reserved")),
- ).LeftJoin(host, sqlchemy.Equals(guestSQ.Field("host_id"), host.Field("id"))).GroupBy(guestSQ.Field("host_id")).SubQuery()
- vsq := vq.Query(
- vq.Field("host_id"),
- sqlchemy.DIV("virtual_cpu_usage", vq.Field("cpu_commit"), sqlchemy.DIV("cmt_cpu_size", vq.Field("cpu_cmtbound"), vq.Field("host_cpu_size"))),
- )
- vqq := vsq.GroupBy(vsq.Field("host_id")).SubQuery()
- q = q.LeftJoin(vqq, sqlchemy.Equals(q.Field("id"), vqq.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByVirtualCpuUsage}, []sqlchemy.IQueryField{vqq.Field("virtual_cpu_usage")})
- }
- if db.NeedOrderQuery([]string{query.OrderByVirtualStorageUsage}) {
- hoststorages := HoststorageManager.Query().SubQuery()
- storageQ := StorageManager.Query().IsTrue("enabled").NotEquals("storage_type", api.STORAGE_BAREMETAL).In("storage_type", api.HOST_STORAGE_LOCAL_TYPES).SubQuery()
- diskReadySQ := DiskManager.Query().Equals("status", api.DISK_READY).SubQuery()
- diskReadyQ := diskReadySQ.Query(sqlchemy.SUM("sum", diskReadySQ.Field("disk_size")).Label("used")).GroupBy(diskReadySQ.Field("storage_id"))
- readySQ := diskReadyQ.SubQuery()
- storageSQ := storageQ.Query(
- storageQ.Field("id"),
- sqlchemy.SUB("storage_capacity", storageQ.Field("capacity"), storageQ.Field("reserved")),
- hoststorages.Field("host_id"),
- sqlchemy.NewFunction(
- sqlchemy.NewCase().When(
- sqlchemy.GT(storageQ.Field("cmtbound"), 0),
- storageQ.Field("cmtbound"),
- ).Else(sqlchemy.NewConstField(1)),
- "cmtbound",
- true,
- ),
- readySQ.Field("used"),
- )
- storageSQ = storageSQ.Join(hoststorages, sqlchemy.Equals(storageSQ.Field("id"), hoststorages.Field("storage_id")))
- storageSQ = storageSQ.LeftJoin(readySQ, sqlchemy.Equals(readySQ.Field("storage_id"), storageSQ.Field("id")))
- sq := storageSQ.SubQuery()
- sqMul := sq.Query(
- sq.Field("host_id"),
- sq.Field("id"),
- sq.Field("used"),
- sqlchemy.MUL("virtual_storage_size", sq.Field("storage_capacity"), sq.Field("cmtbound")),
- ).SubQuery()
- sqSum := sqMul.Query(
- sqMul.Field("host_id"),
- sqMul.Field("id"),
- sqlchemy.SUM("total_used", sqMul.Field("used")),
- sqlchemy.SUM("total_virtual_storage_szie", sqMul.Field("virtual_storage_size")),
- ).GroupBy(sqMul.Field("host_id")).SubQuery()
- sqDiv := sqSum.Query(
- sqSum.Field("host_id"),
- sqlchemy.DIV("virtual_storage_usage", sqSum.Field("total_used"), sqSum.Field("total_virtual_storage_szie")),
- )
- usageSQ := sqDiv.GroupBy(sqDiv.Field("host_id")).SubQuery()
- q = q.LeftJoin(usageSQ, sqlchemy.Equals(q.Field("id"), usageSQ.Field("host_id")))
- db.OrderByFields(q, []string{query.OrderByVirtualStorageUsage}, []sqlchemy.IQueryField{usageSQ.Field("virtual_storage_usage")})
- }
- return q, nil
- }
- func (manager *SHostManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SEnabledStatusInfrasResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- q, err = manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- return q, httperrors.ErrNotFound
- }
- func (manager *SHostManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
- if err == nil {
- return q, nil
- }
- return q, httperrors.ErrNotFound
- }
- func (manager *SHostManager) CustomizeFilterList(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*db.CustomizeListFilters, error) {
- filters := db.NewCustomizeListFilters()
- if query.Contains("cdrom_boot") {
- cdromBoot := jsonutils.QueryBoolean(query, "cdrom_boot", false)
- cdromBootF := func(obj jsonutils.JSONObject) (bool, error) {
- id, err := obj.GetString("id")
- if err != nil {
- return false, err
- }
- host := manager.FetchHostById(id)
- ipmiInfo, err := host.GetIpmiInfo()
- if err != nil {
- return false, err
- }
- if cdromBoot && ipmiInfo.CdromBoot {
- return true, nil
- }
- if !cdromBoot && !ipmiInfo.CdromBoot {
- return true, nil
- }
- return false, nil
- }
- filters.Append(cdromBootF)
- }
- return filters, nil
- }
- func (hh *SHost) IsArmHost() bool {
- return hh.CpuArchitecture == apis.OS_ARCH_AARCH64
- }
- func (hh *SHost) IsRISCVHost() bool {
- return hh.CpuArchitecture == apis.OS_ARCH_RISCV64
- }
- func (hh *SHost) GetZone() (*SZone, error) {
- zone, err := ZoneManager.FetchById(hh.ZoneId)
- if err != nil {
- return nil, err
- }
- return zone.(*SZone), nil
- }
- func (hh *SHost) GetRegion() (*SCloudregion, error) {
- zones := ZoneManager.Query("cloudregion_id").Equals("id", hh.ZoneId).SubQuery()
- q := CloudregionManager.Query().In("id", zones)
- ret := &SCloudregion{}
- ret.SetModelManager(CloudregionManager, ret)
- err := q.First(ret)
- if err != nil {
- return nil, err
- }
- return ret, nil
- }
- func (hh *SHost) GetCpuCount() int {
- if hh.CpuReserved > 0 && hh.CpuReserved < hh.CpuCount {
- return int(hh.CpuCount - hh.CpuReserved)
- } else {
- return int(hh.CpuCount)
- }
- }
- func (hh *SHost) GetMemSize() int {
- if hh.MemReserved > 0 && hh.MemReserved < hh.MemSize {
- return hh.MemSize - hh.MemReserved
- } else {
- return hh.MemSize
- }
- }
- func (hh *SHost) IsHugePage() bool {
- return isHugePage(hh.PageSizeKB)
- }
- func isHugePage(pageSizeKb int) bool {
- return pageSizeKb > 4
- }
- func (hh *SHost) GetMemoryOvercommitBound() float32 {
- if hh.IsHugePage() {
- return 1.0
- }
- if hh.MemCmtbound > 0 {
- return hh.MemCmtbound
- }
- return options.Options.DefaultMemoryOvercommitBound
- }
- func (hh *SHost) GetVirtualMemorySize() float32 {
- return float32(hh.GetMemSize()) * hh.GetMemoryOvercommitBound()
- }
- func (hh *SHost) GetCPUOvercommitBound() float32 {
- if hh.CpuCmtbound > 0 {
- return hh.CpuCmtbound
- }
- return options.Options.DefaultCPUOvercommitBound
- }
- func (hh *SHost) GetVirtualCPUCount() float32 {
- return float32(hh.GetCpuCount()) * hh.GetCPUOvercommitBound()
- }
- func (hh *SHost) ValidateDeleteCondition(ctx context.Context, info api.HostDetails) error {
- if hh.IsBaremetal && hh.HostType != api.HOST_TYPE_BAREMETAL {
- return httperrors.NewInvalidStatusError("Host is a converted baremetal, should be unconverted before delete")
- }
- if hh.GetEnabled() {
- return httperrors.NewInvalidStatusError("Host is not disabled")
- }
- if info.Guests > 0 || info.BackupGuests > 0 {
- return httperrors.NewNotEmptyError("Not an empty host")
- }
- return hh.SEnabledStatusInfrasResourceBase.ValidateDeleteCondition(ctx, nil)
- }
- func (hh *SHost) validateDeleteCondition(ctx context.Context, purge bool) error {
- if !purge && hh.IsBaremetal && hh.HostType != api.HOST_TYPE_BAREMETAL {
- return httperrors.NewInvalidStatusError("Host is a converted baremetal, should be unconverted before delete")
- }
- if hh.GetEnabled() {
- return httperrors.NewInvalidStatusError("Host is not disabled")
- }
- cnt, err := hh.GetGuestCount()
- if err != nil {
- return httperrors.NewInternalServerError("getGuestCount fail %s", err)
- }
- if cnt > 0 {
- return httperrors.NewNotEmptyError("Not an empty host")
- }
- cnt, err = hh.GetBackupGuestCount()
- if err != nil {
- return httperrors.NewInternalServerError("GetBackupGuestCount fail %s", err)
- }
- if cnt > 0 {
- return httperrors.NewNotEmptyError("Not an empty host")
- }
- for _, hoststorage := range hh.GetHoststorages() {
- storage := hoststorage.GetStorage()
- if storage != nil && storage.IsLocal() {
- cnt, err := storage.GetDiskCount()
- if err != nil {
- return httperrors.NewInternalServerError("GetDiskCount fail %s", err)
- }
- if cnt > 0 {
- return httperrors.NewNotEmptyError("Local host storage is not empty???")
- }
- }
- }
- return hh.SEnabledStatusInfrasResourceBase.ValidateDeleteCondition(ctx, nil)
- }
- func (hh *SHost) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
- log.Infof("Host delete do nothing")
- return nil
- }
- func (hh *SHost) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
- if hh.IsBaremetal {
- return hh.StartDeleteBaremetalTask(ctx, userCred, "")
- }
- return hh.RealDelete(ctx, userCred)
- }
- func (hh *SHost) StartDeleteBaremetalTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- task, err := taskman.TaskManager.NewTask(ctx, "BaremetalDeleteTask", hh, userCred, nil, parentTaskId, "", nil)
- if err != nil {
- return err
- }
- return task.ScheduleRun(nil)
- }
- func (hh *SHost) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
- return hh.purge(ctx, userCred)
- }
- func (hh *SHost) GetLoadbalancerBackends() ([]SLoadbalancerBackend, error) {
- q := LoadbalancerBackendManager.Query().Equals("backend_id", hh.Id)
- ret := []SLoadbalancerBackend{}
- return ret, db.FetchModelObjects(LoadbalancerBackendManager, q, &ret)
- }
- func (hh *SHost) GetHoststoragesQuery() *sqlchemy.SQuery {
- return HoststorageManager.Query().Equals("host_id", hh.Id)
- }
- func (hh *SHost) GetStorageCount() (int, error) {
- return hh.GetHoststoragesQuery().CountWithError()
- }
- func (hh *SHost) GetHoststorages() []SHoststorage {
- hoststorages := make([]SHoststorage, 0)
- q := hh.GetHoststoragesQuery()
- err := db.FetchModelObjects(HoststorageManager, q, &hoststorages)
- if err != nil && errors.Cause(err) != sql.ErrNoRows {
- log.Errorf("GetHoststorages error %s", err)
- return nil
- }
- return hoststorages
- }
- func (hh *SHost) GetStorages() ([]SStorage, error) {
- sq := HoststorageManager.Query("storage_id").Equals("host_id", hh.Id).SubQuery()
- q := StorageManager.Query().In("id", sq)
- storages := []SStorage{}
- if err := db.FetchModelObjects(StorageManager, q, &storages); err != nil {
- return nil, err
- }
- return storages, nil
- }
- func (hh *SHost) GetHoststorageOfId(storageId string) *SHoststorage {
- hoststorage := SHoststorage{}
- hoststorage.SetModelManager(HoststorageManager, &hoststorage)
- err := hh.GetHoststoragesQuery().Equals("storage_id", storageId).First(&hoststorage)
- if err != nil {
- if errors.Cause(err) != sql.ErrNoRows {
- log.Errorf("GetHoststorageOfId fail %s", err)
- }
- return nil
- }
- return &hoststorage
- }
- func (hh *SHost) GetHoststorageByExternalId(extId string) *SHoststorage {
- hoststorage := SHoststorage{}
- hoststorage.SetModelManager(HoststorageManager, &hoststorage)
- hoststorages := HoststorageManager.Query().SubQuery()
- storages := StorageManager.Query().SubQuery()
- q := hoststorages.Query()
- q = q.Join(storages, sqlchemy.Equals(hoststorages.Field("storage_id"), storages.Field("id")))
- q = q.Filter(sqlchemy.Equals(hoststorages.Field("host_id"), hh.Id))
- q = q.Filter(sqlchemy.Equals(storages.Field("external_id"), extId))
- err := q.First(&hoststorage)
- if err != nil {
- if errors.Cause(err) != sql.ErrNoRows {
- log.Errorf("GetHoststorageByExternalId fail %s", err)
- }
- return nil
- }
- return &hoststorage
- }
- func (hh *SHost) GetStorageByFilePath(path string) *SStorage {
- hoststorages := hh.GetHoststorages()
- if hoststorages == nil {
- return nil
- }
- for i := 0; i < len(hoststorages); i += 1 {
- if len(hoststorages[i].MountPoint) > 0 && strings.HasPrefix(path, hoststorages[i].MountPoint) {
- return hoststorages[i].GetStorage()
- }
- }
- return nil
- }
- func (hh *SHost) GetBaremetalstorage() *SHoststorage {
- if !hh.IsBaremetal {
- return nil
- }
- hoststorages := HoststorageManager.Query().SubQuery()
- storages := StorageManager.Query().SubQuery()
- q := hoststorages.Query()
- q = q.Join(storages, sqlchemy.AND(sqlchemy.Equals(storages.Field("id"), hoststorages.Field("storage_id")),
- sqlchemy.IsFalse(storages.Field("deleted"))))
- q = q.Filter(sqlchemy.Equals(storages.Field("storage_type"), api.STORAGE_BAREMETAL))
- q = q.Filter(sqlchemy.Equals(hoststorages.Field("host_id"), hh.Id))
- cnt, err := q.CountWithError()
- if err != nil {
- return nil
- }
- if cnt == 1 {
- hs := SHoststorage{}
- hs.SetModelManager(HoststorageManager, &hs)
- err := q.First(&hs)
- if err != nil {
- log.Errorf("error %s", err)
- return nil
- }
- return &hs
- }
- // log.Errorf("Cannot find baremetalstorage??")
- return nil
- }
- func (hh *SHost) SaveCleanUpdates(doUpdate func() error) (map[string]sqlchemy.SUpdateDiff, error) {
- return hh.saveUpdates(doUpdate, true)
- }
- func (hh *SHost) SaveUpdates(doUpdate func() error) (map[string]sqlchemy.SUpdateDiff, error) {
- return hh.saveUpdates(doUpdate, false)
- }
- func (hh *SHost) saveUpdates(doUpdate func() error, doSchedClean bool) (map[string]sqlchemy.SUpdateDiff, error) {
- diff, err := db.Update(hh, doUpdate)
- if err != nil {
- return nil, err
- }
- if doSchedClean {
- hh.ClearSchedDescCache()
- }
- return diff, nil
- }
- func (hh *SHost) PerformSetCommitBound(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input api.HostSetCommitBoundInput,
- ) (jsonutils.JSONObject, error) {
- _, err := db.Update(hh, func() error {
- if input.CpuCmtbound != nil {
- hh.CpuCmtbound = *input.CpuCmtbound
- }
- if input.MemCmtbound != nil {
- hh.MemCmtbound = *input.MemCmtbound
- }
- return nil
- })
- if err != nil {
- return nil, err
- }
- db.OpsLog.LogEvent(hh, db.ACT_SET_COMMIT_BOUND, input, userCred)
- logclient.AddActionLogWithContext(ctx, hh, logclient.ACT_SET_COMMIT_BOUND, input, userCred, true)
- return nil, nil
- }
- func (hh *SHost) PerformUpdateStorage(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- data jsonutils.JSONObject,
- ) (jsonutils.JSONObject, error) {
- bs := hh.GetBaremetalstorage()
- capacity, _ := data.Int("capacity")
- zoneId, _ := data.GetString("zone_id")
- storageCacheId, _ := data.GetString("storagecache_id")
- if bs == nil {
- // 1. create storage
- storage := SStorage{}
- storage.Name = fmt.Sprintf("storage%s", hh.GetName())
- storage.Capacity = capacity
- storage.StorageType = api.STORAGE_BAREMETAL
- storage.MediumType = hh.StorageType
- storage.Cmtbound = 1.0
- storage.Status = api.STORAGE_ONLINE
- storage.Enabled = tristate.True
- storage.ZoneId = zoneId
- storage.StoragecacheId = storageCacheId
- storage.DomainId = hh.DomainId
- storage.DomainSrc = string(apis.OWNER_SOURCE_LOCAL)
- err := StorageManager.TableSpec().Insert(ctx, &storage)
- if err != nil {
- return nil, fmt.Errorf("Create baremetal storage error: %v", err)
- }
- storage.SetModelManager(StorageManager, &storage)
- db.OpsLog.LogEvent(&storage, db.ACT_CREATE, storage.GetShortDesc(ctx), userCred)
- // 2. create host storage
- bmStorage := SHoststorage{}
- bmStorage.HostId = hh.Id
- bmStorage.StorageId = storage.Id
- bmStorage.RealCapacity = capacity
- bmStorage.MountPoint = ""
- err = HoststorageManager.TableSpec().Insert(ctx, &bmStorage)
- if err != nil {
- return nil, fmt.Errorf("Create baremetal hostStorage error: %v", err)
- }
- bmStorage.SetModelManager(HoststorageManager, &bmStorage)
- db.OpsLog.LogAttachEvent(ctx, hh, &storage, userCred, bmStorage.GetShortDesc(ctx))
- bmStorage.syncLocalStorageShare(ctx, userCred)
- return nil, nil
- }
- storage := bs.GetStorage()
- //if capacity != int64(storage.Capacity) {
- diff, err := db.Update(storage, func() error {
- storage.Capacity = capacity
- storage.StoragecacheId = storageCacheId
- storage.Enabled = tristate.True
- storage.DomainId = hh.DomainId
- storage.DomainSrc = string(apis.OWNER_SOURCE_LOCAL)
- return nil
- })
- if err != nil {
- return nil, fmt.Errorf("Update baremetal storage error: %v", err)
- }
- db.OpsLog.LogEvent(storage, db.ACT_UPDATE, diff, userCred)
- bs.syncLocalStorageShare(ctx, userCred)
- //}
- return nil, nil
- }
- func (hh *SHost) GetFetchUrl(disableHttps bool) string {
- managerUrl, err := url.Parse(hh.ManagerUri)
- if err != nil {
- log.Errorf("GetFetchUrl fail to parse url: %s", err)
- }
- if disableHttps {
- managerUrl.Scheme = "http"
- }
- portStr := managerUrl.Port()
- var port int
- if len(portStr) > 0 {
- port, _ = strconv.Atoi(portStr)
- } else {
- if managerUrl.Scheme == "https" {
- port = 443
- } else if managerUrl.Scheme == "http" {
- port = 80
- }
- }
- return fmt.Sprintf("%s://%s", managerUrl.Scheme, net.JoinHostPort(managerUrl.Hostname(), strconv.Itoa(port+40000)))
- }
- func (hh *SHost) GetAttachedEnabledHostStorages(storageType []string) []SStorage {
- return hh._getAttachedStorages(tristate.False, tristate.True, storageType)
- }
- func (hh *SHost) _getAttachedStorages(isBaremetal tristate.TriState, enabled tristate.TriState, storageType []string) []SStorage {
- storages := StorageManager.Query().SubQuery()
- hoststorages := HoststorageManager.Query().SubQuery()
- q := storages.Query()
- q = q.Join(hoststorages, sqlchemy.Equals(storages.Field("id"), hoststorages.Field("storage_id")))
- if enabled.IsTrue() {
- q = q.IsTrue("enabled")
- } else if enabled.IsFalse() {
- q = q.IsFalse("enabled")
- }
- if isBaremetal.IsTrue() {
- q = q.Equals("storage_type", api.STORAGE_BAREMETAL)
- } else if isBaremetal.IsFalse() {
- q = q.NotEquals("storage_type", api.STORAGE_BAREMETAL)
- }
- if len(storageType) > 0 {
- q = q.In("storage_type", storageType)
- }
- q = q.Filter(sqlchemy.Equals(hoststorages.Field("host_id"), hh.Id))
- ret := make([]SStorage, 0)
- err := db.FetchModelObjects(StorageManager, q, &ret)
- if err != nil {
- log.Errorf("GetAttachedStorages fail %s", err)
- return nil
- }
- return ret
- }
- func (hh *SHost) SyncAttachedStorageStatus(ctx context.Context) {
- storages := hh.GetAttachedEnabledHostStorages(nil)
- if storages != nil {
- for _, storage := range storages {
- storage.SyncStatusWithHosts(ctx)
- }
- hh.ClearSchedDescCache()
- }
- }
- func (hh *SHostManager) IsNewNameUnique(name string, userCred mcclient.TokenCredential, kwargs *jsonutils.JSONDict) (bool, error) {
- q := hh.Query().Equals("name", name)
- if kwargs != nil && kwargs.Contains("zone_id") {
- zoneId, _ := kwargs.GetString("zone_id")
- q.Equals("zone_id", zoneId)
- }
- cnt, err := q.CountWithError()
- if err != nil {
- return false, err
- }
- return cnt == 0, nil
- }
- func (hh *SHostManager) GetPropertyK8sMasterNodeIps(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- cli, err := tokens.GetCoreClient()
- if err != nil {
- return nil, errors.Wrap(err, "get k8s client")
- }
- nodes, err := cli.Nodes().List(context.Background(), metav1.ListOptions{
- LabelSelector: "node-role.kubernetes.io/master",
- })
- if err != nil {
- return nil, errors.Wrap(err, "list master nodes")
- }
- ips := make([]string, 0)
- for i := range nodes.Items {
- for j := range nodes.Items[i].Status.Addresses {
- if nodes.Items[i].Status.Addresses[j].Type == v1.NodeInternalIP {
- ips = append(ips, nodes.Items[i].Status.Addresses[j].Address)
- }
- }
- }
- log.Infof("k8s master nodes ips %v", ips)
- res := jsonutils.NewDict()
- res.Set("ips", jsonutils.Marshal(ips))
- return res, nil
- }
- func (hh *SHostManager) GetPropertyBmStartRegisterScript(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- regionUri, err := auth.GetPublicServiceURL(consts.GetServiceType(), options.Options.Region, "", httputils.POST)
- if err != nil {
- return nil, err
- }
- var script string
- script += fmt.Sprintf("curl -k -fsSL -H 'X-Auth-Token: %s' %s/misc/bm-prepare-script", userCred.GetTokenString(), regionUri)
- res := jsonutils.NewDict()
- res.Add(jsonutils.NewString(script), "script")
- return res, nil
- }
- func (hh *SHostManager) GetPropertyNodeCount(ctx context.Context, userCred mcclient.TokenCredential, query api.HostListInput) (jsonutils.JSONObject, error) {
- hosts := hh.Query().SubQuery()
- q := hosts.Query(hosts.Field("host_type"), sqlchemy.SUM("node_count_total", hosts.Field("node_count")))
- return hh.getCount(ctx, userCred, q, query)
- }
- func (hh *SHostManager) getCount(ctx context.Context, userCred mcclient.TokenCredential, q *sqlchemy.SQuery, query api.HostListInput) (jsonutils.JSONObject, error) {
- filterAny := false
- if query.FilterAny != nil {
- filterAny = *query.FilterAny
- }
- q, err := db.ApplyListItemsGeneralFilters(hh, q, userCred, query.Filter, filterAny)
- if err != nil {
- return nil, err
- }
- q, err = hh.ListItemFilter(ctx, q, userCred, query)
- if err != nil {
- return nil, err
- }
- rows, err := q.GroupBy("host_type").Rows()
- if err != nil {
- return nil, err
- }
- ret := jsonutils.NewDict()
- defer rows.Close()
- for rows.Next() {
- var hostType string
- var count int64
- err = rows.Scan(&hostType, &count)
- if err != nil {
- log.Errorf("getCount scan err: %v", err)
- return ret, nil
- }
- ret.Add(jsonutils.NewInt(count), hostType)
- }
- return ret, nil
- }
- func (hh *SHostManager) GetPropertyHostTypeCount(ctx context.Context, userCred mcclient.TokenCredential, query api.HostListInput) (jsonutils.JSONObject, error) {
- hosts := hh.Query().SubQuery()
- // select host_type, (case host_type when 'huaweicloudstack' then count(DISTINCT external_id) else count(id) end) as count from hosts_tbl group by host_type;
- cs := sqlchemy.NewCase()
- hcso := sqlchemy.Equals(hosts.Field("host_type"), api.HOST_TYPE_HCSO)
- cs.When(hcso, sqlchemy.COUNT("", sqlchemy.DISTINCT("", hosts.Field("external_id"))))
- cs.Else(sqlchemy.COUNT("", hosts.Field("id")))
- q := hosts.Query(hosts.Field("host_type"), sqlchemy.NewFunction(cs, "count", true))
- return hh.getCount(ctx, userCred, q, query)
- }
- func (hh *SHostManager) ClearAllSchedDescCache() error {
- return hh.ClearSchedDescSessionCache("", "")
- }
- func (hh *SHostManager) ClearSchedDescCache(hostId string) error {
- return hh.ClearSchedDescSessionCache(hostId, "")
- }
- func (hh *SHostManager) ClearSchedDescSessionCache(hostId, sessionId string) error {
- s := auth.GetAdminSession(context.Background(), options.Options.Region)
- return scheduler.SchedManager.CleanCache(s, hostId, sessionId, false)
- }
- func (hh *SHost) ClearSchedDescCache() error {
- return hh.ClearSchedDescSessionCache("")
- }
- func (hh *SHost) ClearSchedDescSessionCache(sessionId string) error {
- return HostManager.ClearSchedDescSessionCache(hh.Id, sessionId)
- }
- // sync clear sched desc on scheduler side
- func (hh *SHostManager) SyncClearSchedDescSessionCache(hostId, sessionId string) error {
- s := auth.GetAdminSession(context.Background(), options.Options.Region)
- return scheduler.SchedManager.CleanCache(s, hostId, sessionId, true)
- }
- func (hh *SHost) SyncCleanSchedDescCache() error {
- return hh.SyncClearSchedDescSessionCache("")
- }
- func (hh *SHost) SyncClearSchedDescSessionCache(sessionId string) error {
- return HostManager.SyncClearSchedDescSessionCache(hh.Id, sessionId)
- }
- func (hh *SHost) GetDetailsSpec(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- return GetModelSpec(HostManager, hh)
- }
- func (man *SHostManager) GetSpecShouldCheckStatus(query *jsonutils.JSONDict) (bool, error) {
- statusCheck := true
- if query.Contains("is_empty") {
- isEmpty, err := query.Bool("is_empty")
- if err != nil {
- return statusCheck, err
- }
- if !isEmpty {
- statusCheck = false
- }
- }
- return statusCheck, nil
- }
- func (hh *SHost) GetSpec(statusCheck bool) *jsonutils.JSONDict {
- if statusCheck {
- if !hh.GetEnabled() {
- return nil
- }
- if !utils.IsInStringArray(hh.Status, []string{api.BAREMETAL_RUNNING, api.BAREMETAL_READY}) || hh.GetBaremetalServer() != nil || hh.IsMaintenance {
- return nil
- }
- if hh.MemSize == 0 || hh.CpuCount == 0 {
- return nil
- }
- if hh.ResourceType == api.HostResourceTypePrepaidRecycle {
- cnt, err := hh.GetGuestCount()
- if err != nil {
- return nil
- }
- if cnt > 0 {
- // occupied
- return nil
- }
- }
- if len(hh.ManagerId) > 0 {
- providerObj, _ := CloudproviderManager.FetchById(hh.ManagerId)
- if providerObj == nil {
- return nil
- }
- provider := providerObj.(*SCloudprovider)
- if !provider.IsAvailable() {
- return nil
- }
- }
- }
- spec := hh.GetHardwareSpecification()
- specInfo := new(api.HostSpec)
- if err := spec.Unmarshal(specInfo); err != nil {
- return spec
- }
- nifs := hh.GetAllNetInterfaces()
- var nicCount int
- for _, nif := range nifs {
- if nif.NicType != api.NIC_TYPE_IPMI {
- nicCount++
- }
- }
- specInfo.NicCount = nicCount
- var manufacture string
- var model string
- if hh.SysInfo != nil {
- manufacture, _ = hh.SysInfo.GetString("manufacture")
- model, _ = hh.SysInfo.GetString("model")
- }
- if manufacture == "" {
- manufacture = "Unknown"
- }
- if model == "" {
- model = "Unknown"
- }
- specInfo.Manufacture = strings.ReplaceAll(manufacture, " ", "_")
- specInfo.Model = strings.ReplaceAll(model, " ", "_")
- devices := IsolatedDeviceManager.FindByHost(hh.Id)
- if len(devices) > 0 {
- specInfo.IsolatedDevices = make([]api.IsolatedDeviceSpec, len(devices))
- for i := 0; i < len(devices); i++ {
- specInfo.IsolatedDevices[i].DevType = devices[i].DevType
- specInfo.IsolatedDevices[i].Model = devices[i].Model
- specInfo.IsolatedDevices[i].PciId = devices[i].VendorDeviceId
- specInfo.IsolatedDevices[i].Vendor = devices[i].getVendor()
- }
- }
- return specInfo.JSON(specInfo)
- }
- func (manager *SHostManager) GetSpecIdent(input *jsonutils.JSONDict) []string {
- spec := new(api.HostSpec)
- input.Unmarshal(spec)
- specKeys := []string{
- fmt.Sprintf("cpu:%d", spec.Cpu),
- fmt.Sprintf("mem:%dM", spec.Mem),
- fmt.Sprintf("nic:%d", spec.NicCount),
- fmt.Sprintf("manufacture:%s", spec.Manufacture),
- fmt.Sprintf("model:%s", spec.Model),
- }
- diskDriverSpec := spec.Disk
- if diskDriverSpec != nil {
- for driver, driverSpec := range diskDriverSpec {
- specKeys = append(specKeys, parseDiskDriverSpec(driver, driverSpec)...)
- }
- }
- sort.Strings(specKeys)
- return specKeys
- }
- func parseDiskDriverSpec(driver string, adapterSpecs api.DiskAdapterSpec) []string {
- ret := make([]string, 0)
- for adapterKey, adapterSpec := range adapterSpecs {
- for _, diskSpec := range adapterSpec {
- sizeGB, _ := utils.GetSizeGB(fmt.Sprintf("%d", diskSpec.Size), "M")
- diskKey := fmt.Sprintf("disk:%s_%s_%s_%dGx%d", driver, adapterKey, diskSpec.Type, sizeGB, diskSpec.Count)
- ret = append(ret, diskKey)
- }
- }
- return ret
- }
- func ConvertStorageInfo2BaremetalStorages(storageInfo jsonutils.JSONObject) []*baremetal.BaremetalStorage {
- if storageInfo == nil {
- return nil
- }
- storages := []baremetal.BaremetalStorage{}
- err := storageInfo.Unmarshal(&storages)
- if err != nil {
- log.Errorf("Unmarshal to baremetal storage error: %v", err)
- return nil
- }
- ret := make([]*baremetal.BaremetalStorage, len(storages))
- for i := range storages {
- ret[i] = &storages[i]
- }
- return ret
- }
- func GetDiskSpecV2(storageInfo jsonutils.JSONObject) api.DiskDriverSpec {
- refStorages := ConvertStorageInfo2BaremetalStorages(storageInfo)
- if refStorages == nil {
- return nil
- }
- return baremetal.GetDiskSpecV2(refStorages)
- }
- func (hh *SHost) GetHardwareSpecification() *jsonutils.JSONDict {
- spec := &api.HostSpec{
- Cpu: int(hh.CpuCount),
- Mem: hh.MemSize,
- }
- if hh.StorageInfo != nil {
- spec.Disk = GetDiskSpecV2(hh.StorageInfo)
- spec.Driver = hh.StorageDriver
- }
- ret := spec.JSON(spec)
- if hh.StorageInfo != nil {
- ret.Set("storage_info", hh.StorageInfo)
- }
- return ret
- }
- type SStorageCapacity struct {
- Capacity int64 `json:"capacity,omitzero"`
- Used int64 `json:"used_capacity,omitzero"`
- ActualUsed int64 `json:"real_time_used_capacity,omitzero"`
- Wasted int64 `json:"waste_capacity,omitzero"`
- VCapacity int64 `json:"virtual_capacity,omitzero"`
- }
- func (cap *SStorageCapacity) GetFree() int64 {
- return cap.VCapacity - cap.Used - cap.Wasted
- }
- func (cap *SStorageCapacity) GetCommitRate() float64 {
- if cap.Capacity > 0 {
- return float64(int(float64(cap.Used)*100.0/float64(cap.Capacity)+0.5)) / 100.0
- } else {
- return 0.0
- }
- }
- func (cap *SStorageCapacity) Add(cap2 SStorageCapacity) {
- cap.Capacity += cap2.Capacity
- cap.Used += cap2.Used
- cap.Wasted += cap2.Wasted
- cap.VCapacity += cap2.VCapacity
- cap.ActualUsed += cap2.ActualUsed
- }
- func (cap *SStorageCapacity) toCapacityInfo() api.SStorageCapacityInfo {
- info := api.SStorageCapacityInfo{}
- info.UsedCapacity = cap.Used
- info.WasteCapacity = cap.Wasted
- info.VirtualCapacity = cap.VCapacity
- info.CommitRate = cap.GetCommitRate()
- info.FreeCapacity = cap.GetFree()
- return info
- }
- func (hh *SHost) GetAttachedLocalStorageCapacity() SStorageCapacity {
- ret := SStorageCapacity{}
- storages := hh.GetAttachedEnabledHostStorages(api.HOST_STORAGE_LOCAL_TYPES)
- for _, s := range storages {
- ret.Add(s.getStorageCapacity())
- }
- return ret
- }
- func (hh *SHost) GetAttachedLocalStorages() []SStorage {
- return hh.GetAttachedEnabledHostStorages(api.HOST_STORAGE_LOCAL_TYPES)
- }
- func _getLeastUsedStorage(storages []SStorage, backends []string) *SStorage {
- var best *SStorage
- var bestCap int64
- for i := 0; i < len(storages); i++ {
- s := storages[i]
- if len(backends) > 0 {
- in, _ := utils.InStringArray(s.StorageType, backends)
- if !in {
- continue
- }
- }
- capa := s.GetFreeCapacity()
- if best == nil || bestCap < capa {
- bestCap = capa
- best = &s
- }
- }
- return best
- }
- func ChooseLeastUsedStorage(storages []SStorage, backend string) *SStorage {
- var backends []string
- if backend == api.STORAGE_LOCAL {
- backends = []string{api.STORAGE_NAS, api.STORAGE_LOCAL}
- } else if len(backend) > 0 {
- backends = []string{backend}
- } else {
- backends = []string{}
- }
- return _getLeastUsedStorage(storages, backends)
- }
- func (hh *SHost) GetLeastUsedStorage(backend string) *SStorage {
- storages := hh.GetAttachedEnabledHostStorages(nil)
- if storages != nil {
- return ChooseLeastUsedStorage(storages, backend)
- }
- return nil
- }
- /*func (hh *SHost) GetWiresQuery() *sqlchemy.SQuery {
- return Manager.Query().Equals("host_id", hh.Id)
- }
- func (hh *SHost) GetWireCount() (int, error) {
- return hh.GetWiresQuery().CountWithError()
- }
- func (hh *SHost) GetHostwires() []SHostwire {
- hw := make([]SHostwire, 0)
- q := hh.GetWiresQuery()
- err := db.FetchModelObjects(HostwireManager, q, &hw)
- if err != nil {
- log.Errorf("GetWires error %s", err)
- return nil
- }
- return hw
- }*/
- func (hh *SHost) getAttachedWires() []SWire {
- wires := WireManager.Query().SubQuery()
- netifs := NetInterfaceManager.Query().SubQuery()
- q := wires.Query()
- q = q.Join(netifs, sqlchemy.Equals(netifs.Field("wire_id"), wires.Field("id")))
- q = q.Filter(sqlchemy.Equals(netifs.Field("baremetal_id"), hh.Id))
- q = q.Distinct()
- ret := make([]SWire, 0)
- err := db.FetchModelObjects(WireManager, q, &ret)
- if err != nil {
- log.Errorf("%s", err)
- return nil
- }
- return ret
- }
- func (hh *SHostManager) GetEnabledKvmHostForBackupStorage(bs *SBackupStorage) (*SHost, error) {
- hbs, err := HostBackupstorageManager.GetBackupStoragesByBackup(bs.Id)
- if err != nil {
- return nil, errors.Wrap(err, "GetBackupStoragesByBackup")
- }
- candidates := make([]string, 0)
- for i := range hbs {
- candidates = append(candidates, hbs[i].HostId)
- }
- host, err := HostManager.GetEnabledKvmHost(candidates)
- if err != nil {
- return nil, errors.Wrap(err, "GetEnabledKvmHost")
- }
- return host, nil
- }
- func (hh *SHostManager) GetEnabledKvmHostForDiskBackup(backup *SDiskBackup) (*SHost, error) {
- hbsCandidates := stringutils2.NewSortedStrings(nil)
- hssCandidates := stringutils2.NewSortedStrings(nil)
- var candidates []string
- {
- bs, err := backup.GetBackupStorage()
- if err != nil {
- return nil, errors.Wrap(err, "unable to get backupStorage")
- }
- hbs, err := HostBackupstorageManager.GetBackupStoragesByBackup(bs.Id)
- if err != nil {
- return nil, errors.Wrap(err, "HostBackupstorageManager.GetBackupStoragesByBackup")
- }
- for i := range hbs {
- hbsCandidates = hbsCandidates.Append(hbs[i].HostId)
- }
- }
- if len(backup.StorageId) > 0 {
- storage, err := backup.GetStorage()
- if err != nil {
- return nil, errors.Wrap(err, "unable to get storage of diskbackup")
- }
- hss, err := HoststorageManager.GetHostStoragesByStorageId(storage.Id)
- if err != nil {
- return nil, errors.Wrap(err, "HoststorageManager.GetStorages")
- }
- for i := range hss {
- hssCandidates = hssCandidates.Append(hss[i].HostId)
- }
- if len(hbsCandidates) == 0 {
- candidates = []string(hssCandidates)
- } else {
- candidates = []string(stringutils2.Intersect(hbsCandidates, hssCandidates))
- }
- } else {
- candidates = []string(hbsCandidates)
- }
- host, err := HostManager.GetEnabledKvmHost(candidates)
- if err != nil {
- return nil, errors.Wrap(err, "GetEnabledKvmHost")
- }
- return host, nil
- }
- func (hh *SHostManager) GetEnabledKvmHost(candidates []string) (*SHost, error) {
- hostq := HostManager.Query().IsTrue("enabled")
- hostq = hostq.Equals("host_status", api.HOST_ONLINE)
- hostq = hostq.In("host_type", []string{api.HOST_TYPE_HYPERVISOR, api.HOST_TYPE_KVM, api.HOST_TYPE_CONTAINER})
- hostq = hostq.IsNullOrEmpty("manager_id")
- if len(candidates) > 0 {
- hostq = hostq.In("id", candidates)
- }
- host := SHost{}
- err := hostq.First(&host)
- if err != nil {
- return nil, err
- }
- host.SetModelManager(HostManager, &host)
- return &host, nil
- }
- func (hh *SHost) GetMasterWire() *SWire {
- wires := WireManager.Query().SubQuery()
- netifs := NetInterfaceManager.Query().SubQuery()
- q := wires.Query()
- q = q.Join(netifs, sqlchemy.Equals(netifs.Field("wire_id"), wires.Field("id")))
- q = q.Filter(sqlchemy.Equals(netifs.Field("baremetal_id"), hh.Id))
- q = q.Filter(sqlchemy.Equals(netifs.Field("nic_type"), api.NIC_TYPE_ADMIN))
- wire := SWire{}
- wire.SetModelManager(WireManager, &wire)
- err := q.First(&wire)
- if err != nil {
- log.Errorf("GetMasterWire fail %s", err)
- return nil
- }
- return &wire
- }
- /*func (hh *SHost) getHostwires() ([]SHostwire, error) {
- hostwires := make([]SHostwire, 0)
- q := hh.GetWiresQuery()
- err := db.FetchModelObjects(HostwireManager, q, &hostwires)
- if err != nil {
- return nil, err
- }
- return hostwires, nil
- }
- func (hh *SHost) getHostwiresOfId(wireId string) []SHostwire {
- hostwires := make([]SHostwire, 0)
- q := hh.GetWiresQuery().Equals("wire_id", wireId)
- err := db.FetchModelObjects(HostwireManager, q, &hostwires)
- if err != nil {
- log.Errorf("getHostwiresOfId fail %s", err)
- return nil
- }
- return hostwires
- }
- func (hh *SHost) getHostwireOfIdAndMac(wireId string, mac string) *SHostwire {
- hostwire := SHostwire{}
- hostwire.SetModelManager(HostwireManager, &hostwire)
- q := hh.GetWiresQuery().Equals("wire_id", wireId)
- q = q.Equals("mac_addr", mac)
- err := q.First(&hostwire)
- if err != nil {
- log.Errorf("getHostwireOfIdAndMac fail %s", err)
- return nil
- }
- return &hostwire
- }*/
- func (hh *SHost) GetGuestsQuery() *sqlchemy.SQuery {
- return GuestManager.Query().Equals("host_id", hh.Id)
- }
- func (hh *SHost) GetGuests() ([]SGuest, error) {
- q := hh.GetGuestsQuery()
- guests := make([]SGuest, 0)
- err := db.FetchModelObjects(GuestManager, q, &guests)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return guests, nil
- }
- func (hh *SHost) GetKvmGuests() []SGuest {
- q := GuestManager.Query().Equals("host_id", hh.Id).Equals("hypervisor", api.HYPERVISOR_KVM)
- guests := make([]SGuest, 0)
- err := db.FetchModelObjects(GuestManager, q, &guests)
- if err != nil {
- log.Errorf("GetGuests %s", err)
- return nil
- }
- return guests
- }
- func (hh *SHost) GetGuestsMasterOnThisHost() []SGuest {
- q := hh.GetGuestsQuery().IsNotEmpty("backup_host_id")
- guests := make([]SGuest, 0)
- err := db.FetchModelObjects(GuestManager, q, &guests)
- if err != nil {
- log.Errorf("GetGuests %s", err)
- return nil
- }
- return guests
- }
- func (hh *SHost) GetGuestsBackupOnThisHost() []SGuest {
- q := GuestManager.Query().Equals("backup_host_id", hh.Id)
- guests := make([]SGuest, 0)
- err := db.FetchModelObjects(GuestManager, q, &guests)
- if err != nil {
- log.Errorf("GetGuests %s", err)
- return nil
- }
- return guests
- }
- func (hh *SHost) GetBackupGuestCount() (int, error) {
- q := GuestManager.Query().Equals("backup_host_id", hh.Id)
- return q.CountWithError()
- }
- func (hh *SHost) GetGuestCount() (int, error) {
- q := hh.GetGuestsQuery()
- return q.CountWithError()
- }
- func (hh *SHost) GetContainerCount(status []string) (int, error) {
- q := hh.GetGuestsQuery()
- q = q.Filter(sqlchemy.Equals(q.Field("hypervisor"), api.HYPERVISOR_POD))
- if len(status) > 0 {
- q = q.In("status", status)
- }
- return q.CountWithError()
- }
- func (hh *SHost) GetNonsystemGuestCount() (int, error) {
- q := hh.GetGuestsQuery()
- q = q.Filter(sqlchemy.OR(sqlchemy.IsNull(q.Field("is_system")), sqlchemy.IsFalse(q.Field("is_system"))))
- return q.CountWithError()
- }
- func (hh *SHost) GetRunningGuestCount() (int, error) {
- q := hh.GetGuestsQuery()
- q = q.In("status", api.VM_RUNNING_STATUS)
- return q.CountWithError()
- }
- func (host *SHost) hasUnknownGuests() bool {
- q := host.GetGuestsQuery()
- q = q.Equals("status", api.VM_UNKNOWN)
- cnt, _ := q.CountWithError()
- return cnt > 0
- }
- func (hh *SHost) GetNotReadyGuestsStat() (*SHostGuestResourceUsage, error) {
- guests := GuestManager.Query().SubQuery()
- q := guests.Query(sqlchemy.COUNT("guest_count"),
- sqlchemy.SUM("guest_vcpu_count", guests.Field("vcpu_count")),
- sqlchemy.SUM("guest_vmem_size", guests.Field("vmem_size")))
- cond := sqlchemy.OR(sqlchemy.Equals(q.Field("host_id"), hh.Id),
- sqlchemy.Equals(q.Field("backup_host_id"), hh.Id))
- q = q.Filter(cond)
- q = q.NotEquals("status", api.VM_READY)
- stat := SHostGuestResourceUsage{}
- err := q.First(&stat)
- if err != nil {
- return nil, err
- }
- return &stat, nil
- }
- func (hh *SHost) GetRunningGuestResourceUsage() *SHostGuestResourceUsage {
- return hh.getGuestsResource(api.VM_RUNNING)
- }
- func (hh *SHost) GetBaremetalnetworksQuery() *sqlchemy.SQuery {
- return HostnetworkManager.Query().Equals("baremetal_id", hh.Id)
- }
- func (hh *SHost) GetBaremetalnetworks() []SHostnetwork {
- q := hh.GetBaremetalnetworksQuery()
- hns := make([]SHostnetwork, 0)
- err := db.FetchModelObjects(HostnetworkManager, q, &hns)
- if err != nil {
- log.Errorf("GetBaremetalnetworks error: %s", err)
- }
- return hns
- }
- func (hh *SHost) GetAttach2Network(netId string) *SHostnetwork {
- q := hh.GetBaremetalnetworksQuery()
- netifs := NetInterfaceManager.Query().Equals("baremetal_id", hh.Id)
- netifs = netifs.Filter(sqlchemy.OR(
- sqlchemy.IsNullOrEmpty(netifs.Field("nic_type")),
- sqlchemy.NotEquals(netifs.Field("nic_type"), api.NIC_TYPE_IPMI),
- ))
- netifsSub := netifs.SubQuery()
- q = q.Join(netifsSub, sqlchemy.AND(
- sqlchemy.Equals(q.Field("mac_addr"), netifsSub.Field("mac")),
- sqlchemy.Equals(q.Field("vlan_id"), netifsSub.Field("vlan_id")),
- ))
- q = q.Equals("network_id", netId)
- hn := SHostnetwork{}
- hn.SetModelManager(HostnetworkManager, &hn)
- err := q.First(&hn)
- if err != nil {
- log.Errorf("GetAttach2Network fail %s", err)
- return nil
- }
- return &hn
- }
- func (h *SHost) getNetInterfacesInternal(wireId string, nicTypes []compute.TNicType) []SNetInterface {
- q := NetInterfaceManager.Query().Equals("baremetal_id", h.Id)
- if len(wireId) > 0 {
- q = q.Equals("wire_id", wireId)
- }
- if len(nicTypes) > 0 {
- //q.IsNullOrEmpty()
- if ok, _ := utils.InArray(compute.NIC_TYPE_NORMAL, nicTypes); ok {
- q = q.Filter(sqlchemy.OR(sqlchemy.In(q.Field("nic_type"), nicTypes), sqlchemy.IsNull(q.Field("nic_type"))))
- } else {
- q = q.In("nic_type", nicTypes)
- }
- }
- q = q.Asc("index")
- q = q.Asc("vlan_id")
- q = q.Asc("nic_type")
- netifs := make([]SNetInterface, 0)
- err := db.FetchModelObjects(NetInterfaceManager, q, &netifs)
- if err != nil {
- log.Errorf("GetNetInterfaces fail %s", err)
- return nil
- }
- return netifs
- }
- func (hh *SHost) GetAllNetInterfaces() []SNetInterface {
- return hh.getNetInterfacesInternal("", nil)
- }
- func (hh *SHost) GetHostNetInterfaces() []SNetInterface {
- return hh.getNetInterfacesInternal("", api.HOST_NIC_TYPES)
- }
- func (hh *SHost) GetAdminNetInterfaces() []SNetInterface {
- return hh.getNetInterfacesInternal("", []compute.TNicType{api.NIC_TYPE_ADMIN})
- }
- func (hh *SHost) GetNetInterface(mac string, vlanId int) *SNetInterface {
- netif, _ := NetInterfaceManager.FetchByMacVlan(mac, vlanId)
- if netif != nil && netif.BaremetalId == hh.Id {
- return netif
- }
- return nil
- }
- func (hh *SHost) DeleteBaremetalnetwork(ctx context.Context, userCred mcclient.TokenCredential, bn *SHostnetwork, reserve bool) {
- net := bn.GetNetwork()
- bn.Delete(ctx, userCred)
- db.OpsLog.LogDetachEvent(ctx, hh, net, userCred, nil)
- if reserve && net != nil {
- if len(bn.IpAddr) > 0 && regutils.MatchIP4Addr(bn.IpAddr) {
- ReservedipManager.ReserveIP(ctx, userCred, net, bn.IpAddr, "Delete baremetalnetwork to reserve", api.AddressTypeIPv4)
- }
- if len(bn.Ip6Addr) > 0 && regutils.MatchIP6Addr(bn.Ip6Addr) {
- ReservedipManager.ReserveIP(ctx, userCred, net, bn.Ip6Addr, "Delete baremetalnetwork to reserve", api.AddressTypeIPv6)
- }
- }
- }
- func (hh *SHost) GetHostDriver() (IHostDriver, error) {
- if len(hh.HostType) == 0 {
- hh.HostType = api.HOST_TYPE_DEFAULT
- }
- region, err := hh.GetRegion()
- if err != nil {
- return nil, errors.Wrapf(err, "GetRegion")
- }
- return GetHostDriver(hh.HostType, region.Provider)
- }
- func (manager *SHostManager) getHostsByZoneProvider(zone *SZone, region *SCloudregion, provider *SCloudprovider) ([]SHost, error) {
- hosts := make([]SHost, 0)
- q := manager.Query()
- if zone != nil {
- q = q.Equals("zone_id", zone.Id)
- }
- if region != nil {
- zoneQ := ZoneManager.Query().Equals("cloudregion_id", region.Id).SubQuery()
- q = q.Join(zoneQ, sqlchemy.Equals(q.Field("zone_id"), zoneQ.Field("id")))
- }
- if provider != nil {
- q = q.Equals("manager_id", provider.Id)
- }
- // exclude prepaid_recycle fake hosts
- q = q.NotEquals("resource_type", api.HostResourceTypePrepaidRecycle)
- err := db.FetchModelObjects(manager, q, &hosts)
- if err != nil {
- log.Errorf("%s", err)
- return nil, err
- }
- return hosts, nil
- }
- func (manager *SHostManager) SyncHosts(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, zone *SZone, region *SCloudregion, hosts []cloudprovider.ICloudHost, xor bool) ([]SHost, []cloudprovider.ICloudHost, compare.SyncResult) {
- key := provider.Id
- if zone != nil {
- key = fmt.Sprintf("%s-%s", zone.Id, provider.Id)
- }
- lockman.LockRawObject(ctx, manager.Keyword(), key)
- defer lockman.ReleaseRawObject(ctx, manager.Keyword(), key)
- syncResult := compare.SyncResult{}
- dbHosts, err := manager.getHostsByZoneProvider(zone, region, provider)
- if err != nil {
- syncResult.Error(err)
- return nil, nil, syncResult
- }
- localHosts := make([]SHost, 0)
- remoteHosts := make([]cloudprovider.ICloudHost, 0)
- removed := make([]SHost, 0)
- commondb := make([]SHost, 0)
- commonext := make([]cloudprovider.ICloudHost, 0)
- added := make([]cloudprovider.ICloudHost, 0)
- err = compare.CompareSets(dbHosts, hosts, &removed, &commondb, &commonext, &added)
- if err != nil {
- syncResult.Error(err)
- return nil, nil, syncResult
- }
- for i := 0; i < len(removed); i += 1 {
- if removed[i].IsPrepaidRecycleResource() {
- continue
- }
- err = removed[i].syncRemoveCloudHost(ctx, userCred)
- if err != nil {
- syncResult.DeleteError(err)
- } else {
- syncResult.Delete()
- }
- }
- for i := 0; i < len(commondb); i += 1 {
- if !xor {
- err = commondb[i].SyncWithCloudHost(ctx, userCred, commonext[i])
- if err != nil {
- syncResult.UpdateError(err)
- }
- }
- localHosts = append(localHosts, commondb[i])
- remoteHosts = append(remoteHosts, commonext[i])
- syncResult.Update()
- }
- for i := 0; i < len(added); i += 1 {
- new, err := manager.NewFromCloudHost(ctx, userCred, added[i], provider, zone)
- if err != nil {
- syncResult.AddError(err)
- } else {
- localHosts = append(localHosts, *new)
- remoteHosts = append(remoteHosts, added[i])
- syncResult.Add()
- }
- }
- return localHosts, remoteHosts, syncResult
- }
- func (hh *SHost) syncRemoveCloudHost(ctx context.Context, userCred mcclient.TokenCredential) error {
- lockman.LockObject(ctx, hh)
- defer lockman.ReleaseObject(ctx, hh)
- err := hh.validateDeleteCondition(ctx, true)
- if err != nil {
- err = hh.purge(ctx, userCred)
- if err != nil {
- return errors.Wrap(err, "purge")
- }
- } else {
- err = hh.RealDelete(ctx, userCred)
- }
- return err
- }
- func (hh *SHost) SyncWithCloudHost(ctx context.Context, userCred mcclient.TokenCredential, extHost cloudprovider.ICloudHost) error {
- provider := hh.GetCloudprovider()
- diff, err := db.UpdateWithLock(ctx, hh, func() error {
- // hh.Name = extHost.GetName()
- hh.Status = extHost.GetStatus()
- hh.HostStatus = extHost.GetHostStatus()
- hh.AccessIp = extHost.GetAccessIp()
- hh.AccessMac = extHost.GetAccessMac()
- hh.SN = extHost.GetSN()
- hh.SysInfo = extHost.GetSysInfo()
- hh.StorageType = extHost.GetStorageType()
- hh.HostType = extHost.GetHostType()
- if hh.HostType == api.HOST_TYPE_BAREMETAL {
- hh.IsBaremetal = true
- }
- hh.StorageInfo = extHost.GetStorageInfo()
- if storageDriver := extHost.GetStorageDriver(); len(storageDriver) > 0 {
- hh.StorageDriver = storageDriver
- }
- hh.OvnVersion = extHost.GetOvnVersion()
- if ipmiInfo := extHost.GetIpmiInfo(); !gotypes.IsNil(ipmiInfo) {
- info := jsonutils.Marshal(ipmiInfo).(*jsonutils.JSONDict)
- passwd, _ := info.GetString("password")
- if len(passwd) > 0 {
- passwd, _ = utils.EncryptAESBase64(hh.Id, passwd)
- info.Set("password", jsonutils.NewString(passwd))
- }
- hh.IpmiInfo = info
- }
- if provider != nil && !utils.IsInStringArray(provider.Provider, strings.Split(options.Options.SkipSyncHostConfigInfoProviders, ",")) {
- hh.CpuCount = extHost.GetCpuCount()
- hh.NodeCount = extHost.GetNodeCount()
- cpuDesc := extHost.GetCpuDesc()
- if len(cpuDesc) > 128 {
- cpuDesc = cpuDesc[:128]
- }
- hh.CpuDesc = cpuDesc
- hh.CpuMhz = extHost.GetCpuMhz()
- hh.MemSize = extHost.GetMemSizeMB()
- hh.StorageSize = extHost.GetStorageSizeMB()
- if cpuCmt := extHost.GetCpuCmtbound(); cpuCmt > 0 {
- hh.CpuCmtbound = cpuCmt
- }
- if memCmt := extHost.GetMemCmtbound(); memCmt > 0 {
- hh.MemCmtbound = memCmt
- }
- if arch := extHost.GetCpuArchitecture(); len(arch) > 0 {
- hh.CpuArchitecture = arch
- }
- if reservedMem := extHost.GetReservedMemoryMb(); reservedMem > 0 {
- hh.MemReserved = reservedMem
- }
- }
- hh.IsEmulated = extHost.IsEmulated()
- hh.SetEnabled(extHost.GetEnabled())
- hh.IsMaintenance = extHost.GetIsMaintenance()
- hh.Version = extHost.GetVersion()
- return nil
- })
- if err != nil {
- return errors.Wrapf(err, "syncWithCloudZone")
- }
- db.OpsLog.LogSyncUpdate(hh, diff, userCred)
- if provider != nil {
- SyncCloudDomain(userCred, hh, provider.GetOwnerId())
- hh.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
- }
- if account := hh.GetCloudaccount(); account != nil {
- syncMetadata(ctx, userCred, hh, extHost, account.ReadOnly)
- }
- if !options.Options.DisableSyncSchedtags {
- err = hh.syncSchedtags(ctx, userCred, extHost)
- if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound && errors.Cause(err) != errors.ErrNotImplemented {
- log.Errorf("syncSchedtags for %s fail: %v", hh.Name, err)
- }
- }
- if len(diff) > 0 {
- if err := HostManager.ClearSchedDescCache(hh.Id); err != nil {
- log.Errorf("ClearSchedDescCache for host %s error %v", hh.Name, err)
- }
- }
- return nil
- }
- func (hh *SHost) syncWithCloudPrepaidVM(extVM cloudprovider.ICloudVM, host *SHost) error {
- _, err := hh.SaveUpdates(func() error {
- hh.CpuCount = extVM.GetVcpuCount()
- hh.MemSize = extVM.GetVmemSizeMB()
- hh.BillingType = billing_api.ParseBillingType(extVM.GetBillingType())
- hh.ExpiredAt = extVM.GetExpiredAt()
- hh.ExternalId = host.ExternalId
- return nil
- })
- if err != nil {
- log.Errorf("syncWithCloudZone error %s", err)
- }
- if err := HostManager.ClearSchedDescCache(hh.Id); err != nil {
- log.Errorf("ClearSchedDescCache for host %s error %v", hh.Name, err)
- }
- return err
- }
- var (
- METADATA_EXT_SCHEDTAG_KEY = "ext:schedtag"
- )
- func (h *SHost) getAllSchedtagsWithExtSchedtagKey() (map[string]string, error) {
- sq := SchedtagManager.Query("id").SubQuery()
- q := db.Metadata.Query("obj_id", "value").Equals("obj_type", SchedtagManager.Keyword()).Equals("key", METADATA_EXT_SCHEDTAG_KEY).In("obj_id", sq)
- result := []struct {
- ObjId string
- Value string
- }{}
- err := q.All(&result)
- if err != nil {
- return nil, err
- }
- ret := make(map[string]string)
- for i := range result {
- ret[result[i].Value] = result[i].ObjId
- }
- return ret, nil
- }
- func (h *SHost) GetSchedtags() ([]SSchedtag, error) {
- sq := HostschedtagManager.Query("schedtag_id").Equals("host_id", h.Id).SubQuery()
- q := SchedtagManager.Query().In("id", sq)
- schedtags := make([]SSchedtag, 0)
- err := db.FetchModelObjects(SchedtagManager, q, &schedtags)
- if err != nil {
- return nil, errors.Wrap(err, "db.FetchModelObjects")
- }
- return schedtags, nil
- }
- func (h *SHost) syncSchedtags(ctx context.Context, userCred mcclient.TokenCredential, extHost cloudprovider.ICloudHost) error {
- schedtags, err := h.GetSchedtags()
- if err != nil {
- return errors.Wrap(err, "GetSchedtags")
- }
- extSchedTags, err := extHost.GetSchedtags()
- if err != nil {
- return errors.Wrap(err, "extHost.GetSchedtags")
- }
- extTagMap := map[string]*cloudprovider.Schedtag{}
- extTagIdSet := sets.NewString()
- for i := range extSchedTags {
- extSchedtag := &extSchedTags[i]
- extTagIdSet.Insert(extSchedtag.Id)
- extTagMap[extSchedtag.Id] = &extSchedTags[i]
- }
- removed := make([]*SSchedtag, 0)
- removedIds := make([]string, 0)
- for i := range schedtags {
- stag := &schedtags[i]
- extTagId := stag.GetMetadata(ctx, METADATA_EXT_SCHEDTAG_KEY, userCred)
- if len(extTagId) == 0 {
- continue
- }
- if !extTagIdSet.Has(extTagId) {
- removed = append(removed, stag)
- removedIds = append(removedIds, stag.GetId())
- } else {
- extTagIdSet.Delete(extTagId)
- }
- }
- added := extTagIdSet.UnsortedList()
- stagMap := make(map[string]string)
- if len(added) > 0 {
- stagMap, err = h.getAllSchedtagsWithExtSchedtagKey()
- if err != nil {
- return errors.Wrap(err, "getAllSchedtagsWithExtSchedtagKey")
- }
- }
- for _, extSchedId := range added {
- stagId, ok := stagMap[extSchedId]
- if !ok {
- st := &SSchedtag{
- ResourceType: HostManager.KeywordPlural(),
- }
- st.DomainId = h.DomainId
- st.Name = extTagMap[extSchedId].Name
- st.Description = "Sync from cloud"
- st.SetModelManager(SchedtagManager, st)
- err := SchedtagManager.TableSpec().Insert(ctx, st)
- if err != nil {
- return errors.Wrapf(err, "unable to create schedtag %s", st.Name)
- }
- stagId = st.GetId()
- meta := make(map[string]interface{})
- meta[METADATA_EXT_SCHEDTAG_KEY] = extSchedId
- for k, v := range extTagMap[extSchedId].Meta {
- meta[k] = v
- }
- st.SetAllMetadata(ctx, meta, userCred)
- }
- // attach
- hostschedtag := &SHostschedtag{
- HostId: h.GetId(),
- }
- hostschedtag.SetModelManager(HostschedtagManager, hostschedtag)
- hostschedtag.SchedtagId = stagId
- err = HostschedtagManager.TableSpec().Insert(ctx, hostschedtag)
- if err != nil {
- return errors.Wrapf(err, "unable to create hostschedtag for tag %s host %s", stagId, h.GetId())
- }
- }
- if len(removedIds) == 0 {
- return nil
- }
- q := HostschedtagManager.Query().Equals("host_id", h.GetId()).In("schedtag_id", removedIds)
- hostschedtags := make([]SHostschedtag, 0, len(removedIds))
- err = db.FetchModelObjects(HostschedtagManager, q, &hostschedtags)
- if err != nil {
- return errors.Wrap(err, "db.FetchModelObject")
- }
- for i := range hostschedtags {
- err = hostschedtags[i].Detach(ctx, userCred)
- if err != nil {
- return errors.Wrapf(err, "unable to detach host %q and schedtag %q", hostschedtags[i].HostId, hostschedtags[i].SchedtagId)
- }
- }
- // try to clean
- for _, tag := range removed {
- cnt, err := tag.GetObjectCount()
- if err != nil {
- log.Errorf("unable to GetObjectCount for schedtag %q: %v", tag.GetName(), err)
- continue
- }
- if cnt > 0 {
- continue
- }
- err = tag.Delete(ctx, userCred)
- if err != nil {
- log.Errorf("unable to delete schedtag %q: %v", tag.GetName(), err)
- continue
- }
- }
- return nil
- }
- func (manager *SHostManager) NewFromCloudHost(ctx context.Context, userCred mcclient.TokenCredential, extHost cloudprovider.ICloudHost, provider *SCloudprovider, izone *SZone) (*SHost, error) {
- host := SHost{}
- host.SetModelManager(manager, &host)
- if izone == nil {
- // onpremise host
- accessIp := extHost.GetAccessIp()
- if len(accessIp) == 0 {
- msg := fmt.Sprintf("fail to find wire for host %s: empty host access ip", extHost.GetName())
- return nil, fmt.Errorf("%s", msg)
- }
- wire, err := WireManager.GetOnPremiseWireOfIp(accessIp)
- if err != nil {
- return nil, errors.Wrapf(err, "GetOnPremiseWireOfIp for host %s with ip %s", extHost.GetName(), accessIp)
- }
- izone, err = wire.GetZone()
- if err != nil {
- return nil, errors.Wrapf(err, "get zone for wire %s", wire.Name)
- }
- }
- host.ExternalId = extHost.GetGlobalId()
- host.ZoneId = izone.Id
- host.HostType = extHost.GetHostType()
- if host.HostType == api.HOST_TYPE_BAREMETAL {
- host.IsBaremetal = true
- }
- host.StorageInfo = extHost.GetStorageInfo()
- host.OvnVersion = extHost.GetOvnVersion()
- if ipmiInfo := extHost.GetIpmiInfo(); !gotypes.IsNil(ipmiInfo) {
- info := jsonutils.Marshal(ipmiInfo).(*jsonutils.JSONDict)
- passwd, _ := info.GetString("password")
- if len(passwd) > 0 {
- passwd, _ = utils.EncryptAESBase64(host.Id, passwd)
- info.Set("password", jsonutils.NewString(passwd))
- }
- host.IpmiInfo = info
- }
- host.Status = extHost.GetStatus()
- host.HostStatus = extHost.GetHostStatus()
- host.SetEnabled(extHost.GetEnabled())
- host.AccessIp = extHost.GetAccessIp()
- host.AccessMac = extHost.GetAccessMac()
- host.SN = extHost.GetSN()
- host.SysInfo = extHost.GetSysInfo()
- host.CpuCount = extHost.GetCpuCount()
- host.NodeCount = extHost.GetNodeCount()
- cpuDesc := extHost.GetCpuDesc()
- if len(cpuDesc) > 128 {
- cpuDesc = cpuDesc[:128]
- }
- host.CpuDesc = cpuDesc
- host.CpuMhz = extHost.GetCpuMhz()
- host.MemSize = extHost.GetMemSizeMB()
- host.StorageSize = extHost.GetStorageSizeMB()
- host.StorageType = extHost.GetStorageType()
- host.StorageDriver = extHost.GetStorageDriver()
- host.CpuCmtbound = 8.0
- if cpuCmt := extHost.GetCpuCmtbound(); cpuCmt > 0 {
- host.CpuCmtbound = cpuCmt
- }
- host.MemCmtbound = 1.0
- if memCmt := extHost.GetMemCmtbound(); memCmt > 0 {
- host.MemCmtbound = memCmt
- }
- if arch := extHost.GetCpuArchitecture(); len(arch) > 0 {
- host.CpuArchitecture = arch
- }
- if reservedMem := extHost.GetReservedMemoryMb(); reservedMem > 0 {
- host.MemReserved = reservedMem
- }
- host.ManagerId = provider.Id
- host.IsEmulated = extHost.IsEmulated()
- host.IsMaintenance = extHost.GetIsMaintenance()
- host.Version = extHost.GetVersion()
- host.IsPublic = false
- host.PublicScope = string(rbacscope.ScopeNone)
- var err = func() error {
- lockman.LockRawObject(ctx, manager.Keyword(), "name")
- defer lockman.ReleaseRawObject(ctx, manager.Keyword(), "name")
- //newName, err := db.GenerateName(ctx, manager, userCred, extHost.GetName())
- //if err != nil {
- // return errors.Wrapf(err, "db.GenerateName")
- //}
- host.Name = extHost.GetName()
- return manager.TableSpec().Insert(ctx, &host)
- }()
- if err != nil {
- return nil, errors.Wrapf(err, "Insert")
- }
- db.OpsLog.LogEvent(&host, db.ACT_CREATE, host.GetShortDesc(ctx), userCred)
- SyncCloudDomain(userCred, &host, provider.GetOwnerId())
- err = host.syncSchedtags(ctx, userCred, extHost)
- if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound && errors.Cause(err) != errors.ErrNotImplemented {
- log.Errorf("syncSchedtags %s fail %v", host.Name, err)
- }
- if provider != nil {
- host.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
- }
- if err := manager.ClearSchedDescCache(host.Id); err != nil {
- log.Errorf("ClearSchedDescCache for host %s error %v", host.Name, err)
- }
- return &host, nil
- }
- func (hh *SHost) SyncHostStorages(ctx context.Context, userCred mcclient.TokenCredential, storages []cloudprovider.ICloudStorage, provider *SCloudprovider, xor bool) ([]SStorage, []cloudprovider.ICloudStorage, compare.SyncResult) {
- lockman.LockRawObject(ctx, "storages", hh.Id)
- defer lockman.ReleaseRawObject(ctx, "storages", hh.Id)
- localStorages := make([]SStorage, 0)
- remoteStorages := make([]cloudprovider.ICloudStorage, 0)
- syncResult := compare.SyncResult{}
- dbStorages := make([]SStorage, 0)
- hostStorages := hh.GetHoststorages()
- for i := 0; i < len(hostStorages); i += 1 {
- storage := hostStorages[i].GetStorage()
- if storage == nil {
- hostStorages[i].Delete(ctx, userCred)
- } else {
- dbStorages = append(dbStorages, *storage)
- }
- }
- // dbStorages := hh._getAttachedStorages(tristate.None, tristate.None)
- removed := make([]SStorage, 0)
- commondb := make([]SStorage, 0)
- commonext := make([]cloudprovider.ICloudStorage, 0)
- added := make([]cloudprovider.ICloudStorage, 0)
- err := compare.CompareSets(dbStorages, storages, &removed, &commondb, &commonext, &added)
- if err != nil {
- syncResult.Error(err)
- return nil, nil, syncResult
- }
- for i := 0; i < len(removed); i += 1 {
- log.Infof("host %s not connected with %s any more, to detach...", hh.Id, removed[i].Id)
- err := hh.syncRemoveCloudHostStorage(ctx, userCred, &removed[i])
- if errors.Cause(err) == ErrStorageInUse && removed[i].StorageType == api.STORAGE_LOCAL {
- removed[i].SetStatus(ctx, userCred, api.STORAGE_OFFLINE, "the only host used this local storage has detached")
- // prevent generating a delete error for syncResult
- continue
- }
- if err != nil {
- syncResult.DeleteError(err)
- } else {
- syncResult.Delete()
- }
- }
- for i := 0; i < len(commondb); i += 1 {
- if !xor {
- log.Infof("host %s is still connected with %s, to update ...", hh.Id, commondb[i].Id)
- err := hh.syncWithCloudHostStorage(ctx, userCred, &commondb[i], commonext[i], provider)
- if err != nil {
- syncResult.UpdateError(err)
- }
- }
- localStorages = append(localStorages, commondb[i])
- remoteStorages = append(remoteStorages, commonext[i])
- syncResult.Update()
- }
- for i := 0; i < len(added); i += 1 {
- log.Infof("host %s is found connected with %s, to add ...", hh.Id, added[i].GetId())
- local, err := hh.newCloudHostStorage(ctx, userCred, added[i], provider)
- if err != nil {
- syncResult.AddError(err)
- } else {
- localStorages = append(localStorages, *local)
- remoteStorages = append(remoteStorages, added[i])
- syncResult.Add()
- }
- }
- return localStorages, remoteStorages, syncResult
- }
- func (hh *SHost) syncRemoveCloudHostStorage(ctx context.Context, userCred mcclient.TokenCredential, localStorage *SStorage) error {
- hs := hh.GetHoststorageOfId(localStorage.Id)
- err := hs.ValidateDeleteCondition(ctx, nil)
- if err == nil {
- log.Errorf("sync remove hoststorage fail: %s", err)
- err = hs.Detach(ctx, userCred)
- } else {
- }
- return err
- }
- func (hh *SHost) syncWithCloudHostStorage(ctx context.Context, userCred mcclient.TokenCredential, localStorage *SStorage, extStorage cloudprovider.ICloudStorage, provider *SCloudprovider) error {
- // do nothing
- hs := hh.GetHoststorageOfId(localStorage.Id)
- err := hs.syncWithCloudHostStorage(userCred, extStorage)
- if err != nil {
- return err
- }
- s := hs.GetStorage()
- err = s.syncWithCloudStorage(ctx, userCred, extStorage, provider)
- return err
- }
- func (hh *SHost) isAttach2Storage(storage *SStorage) bool {
- hs := hh.GetHoststorageOfId(storage.Id)
- return hs != nil
- }
- func (hh *SHost) Attach2Storage(ctx context.Context, userCred mcclient.TokenCredential, storage *SStorage, mountPoint string) error {
- if hh.isAttach2Storage(storage) {
- return nil
- }
- hs := SHoststorage{}
- hs.SetModelManager(HoststorageManager, &hs)
- hs.StorageId = storage.Id
- hs.HostId = hh.Id
- hs.MountPoint = mountPoint
- err := HoststorageManager.TableSpec().Insert(ctx, &hs)
- if err != nil {
- return err
- }
- db.OpsLog.LogAttachEvent(ctx, hh, storage, userCred, nil)
- return nil
- }
- func (hh *SHost) newCloudHostStorage(ctx context.Context, userCred mcclient.TokenCredential, extStorage cloudprovider.ICloudStorage, provider *SCloudprovider) (*SStorage, error) {
- storageObj, err := db.FetchByExternalIdAndManagerId(StorageManager, extStorage.GetGlobalId(), func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- return q.Equals("manager_id", provider.Id)
- })
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- // no cloud storage found, this may happen for on-premise host
- // create the storage right now
- zone, _ := hh.GetZone()
- storageObj, err = StorageManager.newFromCloudStorage(ctx, userCred, extStorage, provider, zone)
- if err != nil {
- return nil, errors.Wrapf(err, "StorageManager.newFromCloudStorage")
- }
- } else {
- return nil, errors.Wrapf(err, "FetchByExternalIdAndManagerId(%s)", extStorage.GetGlobalId())
- }
- }
- storage := storageObj.(*SStorage)
- err = hh.Attach2Storage(ctx, userCred, storage, extStorage.GetMountPoint())
- return storage, err
- }
- func (hh *SHost) SyncHostWires(ctx context.Context, userCred mcclient.TokenCredential, wires []cloudprovider.ICloudWire) compare.SyncResult {
- lockman.LockRawObject(ctx, "wires", hh.Id)
- defer lockman.ReleaseRawObject(ctx, "wires", hh.Id)
- syncResult := compare.SyncResult{}
- dbWires := make([]SWire, 0)
- hostNetifs := hh.GetHostNetInterfaces()
- for i := 0; i < len(hostNetifs); i += 1 {
- wire := hostNetifs[i].GetWire()
- if wire != nil {
- // hostNetifs[i].Remove(ctx, userCred)
- } else {
- dbWires = append(dbWires, *wire)
- }
- }
- // dbWires := hh.getAttachedWires()
- removed := make([]SWire, 0)
- commondb := make([]SWire, 0)
- commonext := make([]cloudprovider.ICloudWire, 0)
- added := make([]cloudprovider.ICloudWire, 0)
- err := compare.CompareSets(dbWires, wires, &removed, &commondb, &commonext, &added)
- if err != nil {
- syncResult.Error(err)
- return syncResult
- }
- for i := 0; i < len(removed); i += 1 {
- log.Infof("host %s not connected with %s any more, to detach...", hh.Id, removed[i].Id)
- err := hh.syncRemoveCloudHostWire(ctx, userCred, &removed[i])
- if err != nil {
- syncResult.DeleteError(err)
- } else {
- syncResult.Delete()
- }
- }
- for i := 0; i < len(commondb); i += 1 {
- log.Infof("host %s is still connected with %s, to update...", hh.Id, commondb[i].Id)
- err := hh.syncWithCloudHostWire(commonext[i])
- if err != nil {
- syncResult.UpdateError(err)
- } else {
- syncResult.Update()
- }
- }
- for i := 0; i < len(added); i += 1 {
- log.Infof("host %s is found connected with %s, to add...", hh.Id, added[i].GetId())
- err := hh.newCloudHostWire(ctx, userCred, added[i])
- if err != nil {
- syncResult.AddError(err)
- } else {
- syncResult.Add()
- }
- }
- return syncResult
- }
- func (hh *SHost) syncRemoveCloudHostWire(ctx context.Context, userCred mcclient.TokenCredential, localwire *SWire) error {
- netifs := hh.getNetifsOnWire(localwire.Id)
- for i := range netifs {
- err := netifs[i].Delete(ctx, userCred)
- if err != nil {
- return errors.Wrap(err, "delete")
- }
- }
- return nil
- }
- func (hh *SHost) syncWithCloudHostWire(extWire cloudprovider.ICloudWire) error {
- // do nothing
- return nil
- }
- func (hh *SHost) Attach2Wire(ctx context.Context, userCred mcclient.TokenCredential, wire *SWire) error {
- netif := SNetInterface{}
- netif.SetModelManager(NetInterfaceManager, &netif)
- netif.Mac = stringutils2.HashIdsMac(hh.Id, wire.Id)
- netif.VlanId = 1
- netif.WireId = wire.Id
- netif.BaremetalId = hh.Id
- err := NetInterfaceManager.TableSpec().InsertOrUpdate(ctx, &netif)
- if err != nil {
- return errors.Wrap(err, "InsertOrUpdate")
- }
- return nil
- }
- func (hh *SHost) newCloudHostWire(ctx context.Context, userCred mcclient.TokenCredential, extWire cloudprovider.ICloudWire) error {
- wireObj, err := db.FetchByExternalIdAndManagerId(WireManager, extWire.GetGlobalId(), func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- sq := VpcManager.Query().SubQuery()
- return q.Join(sq, sqlchemy.Equals(sq.Field("id"), q.Field("vpc_id"))).Filter(sqlchemy.Equals(sq.Field("manager_id"), hh.ManagerId))
- })
- if err != nil {
- log.Errorf("%s", err)
- return nil
- }
- wire := wireObj.(*SWire)
- err = hh.Attach2Wire(ctx, userCred, wire)
- return err
- }
- type SGuestSyncResult struct {
- Local *SGuest
- Remote cloudprovider.ICloudVM
- IsNew bool
- }
- func IsNeedSkipSync(ext cloudprovider.ICloudResource) (bool, string) {
- if len(options.Options.SkipServerBySysTagKeys) == 0 &&
- len(options.Options.SkipServerByUserTagKeys) == 0 &&
- len(options.Options.SkipServerByUserTagValues) == 0 &&
- len(options.Options.RetentionServerByUserTagKeys) == 0 &&
- len(options.Options.RetentionServerByUserTagValues) == 0 &&
- len(options.Options.RetentionServerByUserTags) == 0 {
- return false, ""
- }
- tags, _ := ext.GetTags()
- if keys := strings.Split(options.Options.SkipServerBySysTagKeys, ","); len(keys) > 0 {
- for key := range ext.GetSysTags() {
- key = strings.Trim(key, "")
- if len(key) > 0 && utils.IsInStringArray(key, keys) {
- return true, key
- }
- }
- }
- if userKeys := strings.Split(options.Options.SkipServerByUserTagKeys, ","); len(userKeys) > 0 {
- for key := range tags {
- key = strings.Trim(key, "")
- if len(key) > 0 && utils.IsInStringArray(key, userKeys) {
- return true, key
- }
- }
- }
- if len(options.Options.SkipServerByUserTagValues) > 0 {
- for _, value := range tags {
- value = strings.Trim(value, "")
- if len(value) > 0 && utils.IsInStringArray(value, options.Options.SkipServerByUserTagValues) {
- return true, value
- }
- }
- }
- keys, values, pairs := []string{}, []string{}, []string{}
- for key, value := range tags {
- key = strings.Trim(key, "")
- keys = append(keys, key)
- values = append(values, value)
- pairs = append(pairs, fmt.Sprintf("%s:%s", key, value))
- }
- if len(options.Options.RetentionServerByUserTagKeys) > 0 {
- skip, tagKey := true, ""
- for _, key := range options.Options.RetentionServerByUserTagKeys {
- key = strings.Trim(key, "")
- if len(key) > 0 && utils.IsInStringArray(key, keys) {
- skip, tagKey = false, key
- break
- }
- }
- return skip, tagKey
- }
- if len(options.Options.RetentionServerByUserTagValues) > 0 {
- skip, tagValue := true, ""
- for _, value := range options.Options.RetentionServerByUserTagValues {
- value = strings.Trim(value, "")
- if len(value) > 0 && utils.IsInStringArray(value, values) {
- skip, tagValue = false, value
- break
- }
- }
- return skip, tagValue
- }
- if len(options.Options.RetentionServerByUserTags) > 0 {
- skip, tagPair := true, ""
- for _, pair := range options.Options.RetentionServerByUserTags {
- pair = strings.Trim(pair, "")
- if len(pair) > 0 && utils.IsInStringArray(pair, pairs) {
- skip, tagPair = false, pair
- break
- }
- }
- return skip, tagPair
- }
- return false, ""
- }
- func (self *SGuest) Purge(ctx context.Context, userCred mcclient.TokenCredential) error {
- return self.purge(ctx, userCred)
- }
- func (hh *SHost) GetIsolateDevices() ([]SIsolatedDevice, error) {
- q := IsolatedDeviceManager.Query().Equals("host_id", hh.Id)
- ret := []SIsolatedDevice{}
- err := db.FetchModelObjects(IsolatedDeviceManager, q, &ret)
- if err != nil {
- return nil, err
- }
- return ret, nil
- }
- func (hh *SHost) SyncHostIsolateDevices(ctx context.Context, userCred mcclient.TokenCredential, iprovider cloudprovider.ICloudProvider, devs []cloudprovider.IsolateDevice, syncOwnerId mcclient.IIdentityProvider, xor bool) compare.SyncResult {
- lockman.LockRawObject(ctx, IsolatedDeviceManager.Keyword(), hh.Id)
- defer lockman.ReleaseRawObject(ctx, IsolatedDeviceManager.Keyword(), hh.Id)
- result := compare.SyncResult{}
- dbDevs, err := hh.GetIsolateDevices()
- if err != nil {
- result.Error(errors.Wrapf(err, "GetIsolateDevices"))
- return result
- }
- removed := make([]SIsolatedDevice, 0)
- commondb := make([]SIsolatedDevice, 0)
- commonext := make([]cloudprovider.IsolateDevice, 0)
- added := make([]cloudprovider.IsolateDevice, 0)
- duplicated := make(map[string][]cloudprovider.IsolateDevice)
- err = compare.CompareSets2(dbDevs, devs, &removed, &commondb, &commonext, &added, &duplicated)
- if err != nil {
- result.Error(err)
- return result
- }
- for i := 0; i < len(removed); i += 1 {
- err := removed[i].Delete(ctx, userCred)
- if err != nil {
- result.DeleteError(err)
- continue
- }
- result.Delete()
- }
- if !xor {
- for i := 0; i < len(commondb); i += 1 {
- err := commondb[i].syncWithCloudIsolateDevice(ctx, userCred, commonext[i])
- if err != nil {
- result.UpdateError(err)
- continue
- }
- result.Update()
- }
- }
- for i := 0; i < len(added); i += 1 {
- err := hh.newIsolateDevice(ctx, userCred, added[i])
- if err != nil {
- result.AddError(err)
- continue
- }
- result.Add()
- }
- if len(duplicated) > 0 {
- errs := make([]error, 0)
- for k, vms := range duplicated {
- errs = append(errs, errors.Wrapf(errors.ErrDuplicateId, "Duplicate Id %s (%d)", k, len(vms)))
- }
- result.AddError(errors.NewAggregate(errs))
- }
- return result
- }
- func (hh *SHost) newIsolateDevice(ctx context.Context, userCred mcclient.TokenCredential, dev cloudprovider.IsolateDevice) error {
- ret := &SIsolatedDevice{}
- ret.SetModelManager(IsolatedDeviceManager, ret)
- ret.HostId = hh.Id
- ret.ExternalId = dev.GetGlobalId()
- ret.Name = dev.GetName()
- ret.Model = dev.GetModel()
- ret.Addr = dev.GetAddr()
- ret.DevType = dev.GetDevType()
- ret.NumaNode = dev.GetNumaNode()
- ret.VendorDeviceId = dev.GetVendorDeviceId()
- err := IsolatedDeviceManager.TableSpec().Insert(ctx, ret)
- if err != nil {
- return err
- }
- sharedProjectIds, err := dev.GetSharedProjectIds()
- if err != nil {
- if errors.Cause(err) == cloudprovider.ErrNotImplemented {
- return nil
- }
- return err
- }
- if len(sharedProjectIds) == 0 {
- return nil
- }
- if len(sharedProjectIds) > 0 {
- projectIds, err := db.FetchField(ExternalProjectManager, "tenant_id", func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- return q.Equals("manager_id", hh.ManagerId).In("external_id", sharedProjectIds)
- })
- if err != nil {
- return err
- }
- input := apis.PerformPublicProjectInput{SharedProjectIds: projectIds}
- input.Scope = "project"
- db.SharablePerformPublic(ret, ctx, userCred, input)
- }
- return nil
- }
- func (hh *SHost) SyncHostVMs(ctx context.Context, userCred mcclient.TokenCredential, iprovider cloudprovider.ICloudProvider, vms []cloudprovider.ICloudVM, syncOwnerId mcclient.IIdentityProvider, xor bool) ([]SGuestSyncResult, compare.SyncResult) {
- lockman.LockRawObject(ctx, GuestManager.Keyword(), hh.Id)
- defer lockman.ReleaseRawObject(ctx, GuestManager.Keyword(), hh.Id)
- syncVMPairs := make([]SGuestSyncResult, 0)
- syncResult := compare.SyncResult{}
- dbVMs, err := hh.GetGuests()
- if err != nil {
- syncResult.Error(errors.Wrapf(err, "GetGuests"))
- return nil, syncResult
- }
- for i := range dbVMs {
- if taskman.TaskManager.IsInTask(&dbVMs[i]) {
- syncResult.Error(fmt.Errorf("server %s(%s)in task", dbVMs[i].Name, dbVMs[i].Id))
- return nil, syncResult
- }
- }
- removed := make([]SGuest, 0)
- commondb := make([]SGuest, 0)
- commonext := make([]cloudprovider.ICloudVM, 0)
- added := make([]cloudprovider.ICloudVM, 0)
- duplicated := make(map[string][]cloudprovider.ICloudVM)
- err = compare.CompareSets2(dbVMs, vms, &removed, &commondb, &commonext, &added, &duplicated)
- if err != nil {
- syncResult.Error(err)
- return nil, syncResult
- }
- for i := 0; i < len(removed); i += 1 {
- err := removed[i].SyncRemoveCloudVM(ctx, userCred, true)
- if err != nil {
- syncResult.DeleteError(err)
- } else {
- syncResult.Delete()
- }
- }
- if !xor {
- for i := 0; i < len(commondb); i += 1 {
- skip, key := IsNeedSkipSync(commonext[i])
- if skip {
- log.Infof("delete server %s(%s) with tag key or value: %s", commonext[i].GetName(), commonext[i].GetGlobalId(), key)
- err := commondb[i].purge(ctx, userCred)
- if err != nil {
- syncResult.DeleteError(err)
- continue
- }
- syncResult.Delete()
- continue
- }
- err := commondb[i].syncWithCloudVM(ctx, userCred, iprovider, hh, commonext[i], syncOwnerId, true)
- if err != nil {
- syncResult.UpdateError(err)
- continue
- }
- syncVMPair := SGuestSyncResult{
- Local: &commondb[i],
- Remote: commonext[i],
- IsNew: false,
- }
- syncVMPairs = append(syncVMPairs, syncVMPair)
- syncResult.Update()
- }
- }
- for i := 0; i < len(added); i += 1 {
- skip, key := IsNeedSkipSync(added[i])
- if skip {
- log.Infof("skip server %s(%s) sync with tag key or value: %s", added[i].GetName(), added[i].GetGlobalId(), key)
- continue
- }
- vm, err := db.FetchByExternalIdAndManagerId(GuestManager, added[i].GetGlobalId(), func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- sq := HostManager.Query().SubQuery()
- return q.Join(sq, sqlchemy.Equals(sq.Field("id"), q.Field("host_id"))).Filter(sqlchemy.Equals(sq.Field("manager_id"), hh.ManagerId))
- })
- if err != nil && errors.Cause(err) != sql.ErrNoRows {
- log.Errorf("failed to found guest by externalId %s error: %v", added[i].GetGlobalId(), err)
- continue
- }
- if vm != nil {
- guest := vm.(*SGuest)
- ihost := added[i].GetIHost()
- if ihost == nil {
- log.Errorf("failed to found ihost from vm %s", added[i].GetGlobalId())
- continue
- }
- _host, err := db.FetchByExternalIdAndManagerId(HostManager, ihost.GetGlobalId(), func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- return q.Equals("manager_id", hh.ManagerId)
- })
- if err != nil {
- log.Errorf("failed to found host by externalId %s", ihost.GetGlobalId())
- continue
- }
- host := _host.(*SHost)
- err = guest.syncWithCloudVM(ctx, userCred, iprovider, host, added[i], syncOwnerId, true)
- if err != nil {
- syncResult.UpdateError(err)
- } else {
- syncResult.Update()
- }
- continue
- }
- if added[i].GetBillingType() == string(billing_api.BILLING_TYPE_PREPAID) {
- vhost := HostManager.GetHostByRealExternalId(added[i].GetGlobalId())
- if vhost != nil {
- // this recycle vm is not build yet, skip synchronize
- err = vhost.SyncWithRealPrepaidVM(ctx, userCred, added[i])
- if err != nil {
- syncResult.AddError(err)
- }
- continue
- }
- }
- new, err := GuestManager.newCloudVM(ctx, userCred, iprovider, hh, added[i], syncOwnerId)
- if err != nil {
- syncResult.AddError(err)
- } else {
- syncVMPair := SGuestSyncResult{
- Local: new,
- Remote: added[i],
- IsNew: true,
- }
- syncVMPairs = append(syncVMPairs, syncVMPair)
- syncResult.Add()
- }
- }
- if len(duplicated) > 0 {
- errs := make([]error, 0)
- for k, vms := range duplicated {
- errs = append(errs, errors.Wrapf(errors.ErrDuplicateId, "Duplicate Id %s (%d)", k, len(vms)))
- }
- syncResult.AddError(errors.NewAggregate(errs))
- }
- return syncVMPairs, syncResult
- }
- func (hh *SHost) getNetworkOfIPOnHost(ctx context.Context, ipAddr string) (*SNetwork, error) {
- netInterfaces := hh.GetHostNetInterfaces()
- for _, netInterface := range netInterfaces {
- network, err := netInterface.GetCandidateNetworkForIp(ctx, nil, nil, rbacscope.ScopeNone, ipAddr)
- if err == nil && network != nil {
- return network, nil
- }
- }
- return nil, fmt.Errorf("IP %s not reachable on this host", ipAddr)
- }
- func (hh *SHost) GetNetinterfacesWithIdAndCredential(netId string, userCred mcclient.TokenCredential, reserved bool) ([]SNetInterface, *SNetwork, error) {
- netObj, err := NetworkManager.FetchById(netId)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "fetch by id %q", netId)
- }
- net := netObj.(*SNetwork)
- used, err := net.getFreeAddressCount()
- if err != nil {
- return nil, nil, errors.Wrapf(err, "get network %q free address count", net.GetName())
- }
- if used == 0 && !reserved && !options.Options.BaremetalServerReuseHostIp {
- return nil, nil, errors.Errorf("network %q out of usage", net.GetName())
- }
- matchNetIfs := make([]SNetInterface, 0)
- netifs := hh.GetHostNetInterfaces()
- for i := 0; i < len(netifs); i++ {
- if !netifs[i].IsUsableServernic() {
- continue
- }
- if netifs[i].WireId == net.WireId {
- matchNetIfs = append(matchNetIfs, netifs[i])
- // return &netifs[i], net
- }
- }
- if len(matchNetIfs) > 0 {
- return matchNetIfs, net, nil
- }
- return nil, nil, errors.Errorf("not found matched netinterface by net %q wire %q", net.GetName(), net.WireId)
- }
- func (hh *SHost) GetNetworkWithId(netId string, reserved bool) (*SNetwork, error) {
- var q1, q2, q3, q4 *sqlchemy.SQuery
- {
- // classic network
- networks := NetworkManager.Query()
- netifs := NetInterfaceManager.Query().SubQuery()
- hosts := HostManager.Query().SubQuery()
- q1 = networks
- q1 = q1.Join(netifs, sqlchemy.Equals(netifs.Field("wire_id"), networks.Field("wire_id")))
- q1 = q1.Join(hosts, sqlchemy.Equals(hosts.Field("id"), netifs.Field("baremetal_id")))
- q1 = q1.Filter(sqlchemy.Equals(networks.Field("id"), netId))
- q1 = q1.Filter(sqlchemy.Equals(hosts.Field("id"), hh.Id))
- }
- {
- // vpc network
- networks := NetworkManager.Query()
- wires := WireManager.Query().SubQuery()
- vpcs := VpcManager.Query().SubQuery()
- regions := CloudregionManager.Query().SubQuery()
- q2 = networks
- q2 = q2.Join(wires, sqlchemy.Equals(wires.Field("id"), networks.Field("wire_id")))
- q2 = q2.Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id")))
- q2 = q2.Join(regions, sqlchemy.Equals(regions.Field("id"), vpcs.Field("cloudregion_id")))
- q2 = q2.Filter(sqlchemy.Equals(networks.Field("id"), netId))
- q2 = q2.Filter(
- sqlchemy.OR(
- sqlchemy.AND(
- sqlchemy.Equals(regions.Field("provider"), api.CLOUD_PROVIDER_ONECLOUD),
- sqlchemy.NOT(sqlchemy.Equals(vpcs.Field("id"), api.DEFAULT_VPC_ID)),
- ),
- sqlchemy.AND(
- sqlchemy.Equals(regions.Field("provider"), api.CLOUD_PROVIDER_CLOUDPODS),
- sqlchemy.NOT(sqlchemy.Equals(vpcs.Field("external_id"), api.DEFAULT_VPC_ID)),
- ),
- ),
- )
- }
- {
- // network additional wires
- networks := NetworkManager.Query()
- networkAdditionalWires := NetworkAdditionalWireManager.Query().SubQuery()
- netifs := NetInterfaceManager.Query().SubQuery()
- hosts := HostManager.Query().SubQuery()
- q3 = networks
- q3 = q3.Join(networkAdditionalWires, sqlchemy.Equals(networks.Field("id"), networkAdditionalWires.Field("network_id")))
- q3 = q3.Join(netifs, sqlchemy.Equals(netifs.Field("wire_id"), networkAdditionalWires.Field("wire_id")))
- q3 = q3.Join(hosts, sqlchemy.Equals(hosts.Field("id"), netifs.Field("baremetal_id")))
- q3 = q3.Filter(sqlchemy.Equals(networks.Field("id"), netId))
- q3 = q3.Filter(sqlchemy.Equals(hosts.Field("id"), hh.Id))
- }
- {
- // host local network
- networks := NetworkManager.Query()
- wires := WireManager.Query().SubQuery()
- vpcs := VpcManager.Query().SubQuery()
- regions := CloudregionManager.Query().SubQuery()
- q4 = networks
- q4 = q4.Join(wires, sqlchemy.Equals(wires.Field("id"), networks.Field("wire_id")))
- q4 = q4.Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id")))
- q4 = q4.Join(regions, sqlchemy.Equals(regions.Field("id"), vpcs.Field("cloudregion_id")))
- q4 = q4.Filter(sqlchemy.Equals(networks.Field("id"), netId))
- q4 = q4.Filter(
- sqlchemy.OR(
- sqlchemy.AND(
- sqlchemy.Equals(regions.Field("provider"), api.CLOUD_PROVIDER_ONECLOUD),
- sqlchemy.Equals(vpcs.Field("id"), api.DEFAULT_VPC_ID),
- sqlchemy.Equals(wires.Field("id"), computeapi.DEFAULT_HOST_LOCAL_WIRE_ID),
- ),
- sqlchemy.AND(
- sqlchemy.Equals(regions.Field("provider"), api.CLOUD_PROVIDER_CLOUDPODS),
- sqlchemy.Equals(vpcs.Field("external_id"), api.DEFAULT_VPC_ID),
- sqlchemy.Equals(wires.Field("external_id"), computeapi.DEFAULT_HOST_LOCAL_WIRE_ID),
- ),
- ),
- )
- }
- q := sqlchemy.Union(q1, q2, q3, q4).Query().Distinct()
- net := SNetwork{}
- net.SetModelManager(NetworkManager, &net)
- err := q.First(&net)
- if err != nil {
- return nil, err
- }
- if reserved {
- return &net, nil
- }
- freeCnt, err := net.getFreeAddressCount()
- if err != nil {
- return nil, err
- }
- if freeCnt > 0 {
- return &net, nil
- }
- return nil, fmt.Errorf("No IP address")
- }
- func (manager *SHostManager) FetchHostById(hostId string) *SHost {
- host := SHost{}
- host.SetModelManager(manager, &host)
- err := manager.Query().Equals("id", hostId).First(&host)
- if err != nil {
- log.Errorf("fetchHostById fail %s", err)
- return nil
- } else {
- return &host
- }
- }
- func (manager *SHostManager) FetchHostByHostname(hostname string) *SHost {
- host := SHost{}
- host.SetModelManager(manager, &host)
- err := manager.Query().Startswith("name", hostname).First(&host)
- if err != nil {
- log.Errorf("fetch host by hostname %s failed %s", hostname, err)
- return nil
- } else {
- return &host
- }
- }
- func (manager *SHostManager) totalCountQ(
- ctx context.Context,
- userCred mcclient.IIdentityProvider,
- scope rbacscope.TRbacScope,
- rangeObjs []db.IStandaloneModel,
- hostStatus, status string,
- hostTypes []string,
- resourceTypes []string,
- providers []string, brands []string, cloudEnv string,
- enabled, isBaremetal tristate.TriState,
- policyResult rbacutils.SPolicyResult,
- ) *sqlchemy.SQuery {
- hosts := manager.Query().SubQuery()
- q := hosts.Query(
- hosts.Field("mem_size"),
- hosts.Field("memory_used_mb"),
- hosts.Field("page_size_kb"),
- hosts.Field("mem_reserved"),
- hosts.Field("mem_cmtbound"),
- hosts.Field("cpu_count"),
- hosts.Field("cpu_usage_percent"),
- hosts.Field("cpu_reserved"),
- hosts.Field("cpu_cmtbound"),
- hosts.Field("storage_size"),
- )
- if scope != rbacscope.ScopeSystem && userCred != nil {
- q = q.Filter(sqlchemy.Equals(hosts.Field("domain_id"), userCred.GetProjectDomainId()))
- }
- if len(status) > 0 {
- q = q.Filter(sqlchemy.Equals(hosts.Field("status"), status))
- }
- if len(hostStatus) > 0 {
- q = q.Filter(sqlchemy.Equals(hosts.Field("host_status"), hostStatus))
- }
- if !enabled.IsNone() {
- cond := sqlchemy.IsFalse
- if enabled.Bool() {
- cond = sqlchemy.IsTrue
- }
- q = q.Filter(cond(hosts.Field("enabled")))
- }
- if !isBaremetal.IsNone() {
- if isBaremetal.Bool() {
- q = q.Filter(sqlchemy.AND(
- sqlchemy.IsTrue(hosts.Field("is_baremetal")),
- sqlchemy.Equals(hosts.Field("host_type"), api.HOST_TYPE_BAREMETAL),
- ))
- } else {
- q = q.Filter(sqlchemy.OR(
- sqlchemy.IsFalse(hosts.Field("is_baremetal")),
- sqlchemy.NotEquals(hosts.Field("host_type"), api.HOST_TYPE_BAREMETAL),
- ))
- }
- }
- q = db.ObjectIdQueryWithPolicyResult(ctx, q, HostManager, policyResult)
- isolatedDevices := IsolatedDeviceManager.Query().SubQuery()
- iq := isolatedDevices.Query(
- isolatedDevices.Field("host_id"),
- sqlchemy.SUM("isolated_reserved_memory", isolatedDevices.Field("reserved_memory")),
- sqlchemy.SUM("isolated_reserved_cpu", isolatedDevices.Field("reserved_cpu")),
- sqlchemy.SUM("isolated_reserved_storage", isolatedDevices.Field("reserved_storage")),
- ).IsNullOrEmpty("guest_id").GroupBy(isolatedDevices.Field("host_id")).SubQuery()
- q = q.LeftJoin(iq, sqlchemy.Equals(q.Field("id"), iq.Field("host_id")))
- q.AppendField(
- iq.Field("isolated_reserved_memory"),
- iq.Field("isolated_reserved_cpu"),
- iq.Field("isolated_reserved_storage"),
- )
- q = AttachUsageQuery(q, hosts, hostTypes, resourceTypes, providers, brands, cloudEnv, rangeObjs)
- // log.Debugf("hostCount: %s", q.String())
- return q
- }
- type HostStat struct {
- MemSize int
- MemoryUsedMb int64
- PageSizeKB int
- MemReserved int
- MemCmtbound float32
- CpuCount int
- CpuUsagePercent float64
- CpuReserved int
- CpuCmtbound float32
- StorageSize int
- IsolatedReservedMemory int64
- IsolatedReservedCpu int64
- IsolatedReservedStorage int64
- }
- type HostsCountStat struct {
- StorageSize int64
- Count int64
- Memory int64
- MemoryUsed int64
- MemoryTotal int64
- MemoryVirtual float64
- MemoryReserved int64
- CPU int64
- CPUTotal int64
- CPUUsed int64
- CPUVirtual float64
- IsolatedReservedMemory int64
- IsolatedReservedCpu int64
- IsolatedReservedStorage int64
- }
- func (manager *SHostManager) calculateCount(q *sqlchemy.SQuery) HostsCountStat {
- usableSize := func(act, reserved int) int {
- aSize := 0
- if reserved > 0 && reserved < act {
- aSize = act - reserved
- } else {
- aSize = act
- }
- return aSize
- }
- var (
- tStore int64 = 0
- tCnt int64 = 0
- tMem int64 = 0
- tVmem float64 = 0.0
- rMem int64 = 0
- tCPU int64 = 0
- tVCPU float64 = 0.0
- irMem int64 = 0
- irCpu int64 = 0
- irStore int64 = 0
- totalMem int64 = 0
- totalMemUsed int64 = 0
- totalCPU int64 = 0
- totalCPUUsed float64 = 0.0
- )
- stats := make([]HostStat, 0)
- err := q.All(&stats)
- if err != nil {
- log.Errorf("%v", err)
- }
- for _, stat := range stats {
- if stat.MemSize == 0 {
- continue
- }
- tCnt += 1
- if stat.StorageSize > 0 {
- tStore += int64(stat.StorageSize)
- }
- aMem := usableSize(stat.MemSize, stat.MemReserved)
- aCpu := usableSize(int(stat.CpuCount), int(stat.CpuReserved))
- tMem += int64(aMem)
- totalMem += int64(stat.MemSize)
- totalMemUsed += int64(stat.MemoryUsedMb)
- tCPU += int64(aCpu)
- totalCPU += int64(stat.CpuCount)
- totalCPUUsed += stat.CpuUsagePercent * float64(stat.CpuCount) / 100
- if isHugePage(stat.PageSizeKB) {
- stat.MemCmtbound = 1.0
- } else if stat.MemCmtbound <= 0.0 {
- stat.MemCmtbound = options.Options.DefaultMemoryOvercommitBound
- }
- if stat.CpuCmtbound <= 0.0 {
- stat.CpuCmtbound = options.Options.DefaultCPUOvercommitBound
- }
- rMem += int64(stat.MemReserved)
- tVmem += float64(float32(aMem) * stat.MemCmtbound)
- tVCPU += float64(float32(aCpu) * stat.CpuCmtbound)
- irMem += stat.IsolatedReservedMemory
- irCpu += stat.IsolatedReservedCpu
- irStore += stat.IsolatedReservedStorage
- }
- return HostsCountStat{
- StorageSize: tStore,
- Count: tCnt,
- Memory: tMem,
- MemoryUsed: totalMemUsed,
- MemoryTotal: totalMem,
- MemoryVirtual: tVmem,
- MemoryReserved: rMem,
- CPU: tCPU,
- CPUUsed: int64(totalCPUUsed),
- CPUTotal: totalCPU,
- CPUVirtual: tVCPU,
- IsolatedReservedCpu: irCpu,
- IsolatedReservedMemory: irMem,
- IsolatedReservedStorage: irStore,
- }
- }
- func (manager *SHostManager) TotalCount(
- ctx context.Context,
- userCred mcclient.IIdentityProvider,
- scope rbacscope.TRbacScope,
- rangeObjs []db.IStandaloneModel,
- hostStatus, status string,
- hostTypes []string,
- resourceTypes []string,
- providers []string, brands []string, cloudEnv string,
- enabled, isBaremetal tristate.TriState,
- policyResult rbacutils.SPolicyResult,
- ) HostsCountStat {
- return manager.calculateCount(
- manager.totalCountQ(
- ctx,
- userCred,
- scope,
- rangeObjs,
- hostStatus,
- status,
- hostTypes,
- resourceTypes,
- providers,
- brands,
- cloudEnv,
- enabled,
- isBaremetal,
- policyResult,
- ),
- )
- }
- func (hh *SHost) GetIHost(ctx context.Context) (cloudprovider.ICloudHost, error) {
- host, _, err := hh.GetIHostAndProvider(ctx)
- return host, err
- }
- func (hh *SHost) GetIHostAndProvider(ctx context.Context) (cloudprovider.ICloudHost, cloudprovider.ICloudProvider, error) {
- iregion, provider, err := hh.GetIRegionAndProvider(ctx)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "GetIRegionAndProvider")
- }
- ihost, err := iregion.GetIHostById(hh.ExternalId)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "iregion.GetIHostById(%s)", hh.ExternalId)
- }
- return ihost, provider, nil
- }
- func (hh *SHost) GetIRegionAndProvider(ctx context.Context) (cloudprovider.ICloudRegion, cloudprovider.ICloudProvider, error) {
- provider, err := hh.GetDriver(ctx)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "GetDriver")
- }
- var iregion cloudprovider.ICloudRegion
- if provider.GetFactory().IsOnPremise() {
- iregion, err = provider.GetOnPremiseIRegion()
- if err != nil {
- return nil, nil, errors.Wrapf(err, "provider.GetOnPremiseIRegio")
- }
- } else {
- region, err := hh.GetRegion()
- if err != nil {
- return nil, nil, errors.Wrapf(err, "GetRegion")
- }
- iregion, err = provider.GetIRegionById(region.ExternalId)
- if err != nil {
- return nil, nil, errors.Wrapf(err, "provider.GetIRegionById(%s)", region.ExternalId)
- }
- }
- return iregion, provider, nil
- }
- func (hh *SHost) GetIRegion(ctx context.Context) (cloudprovider.ICloudRegion, error) {
- region, _, err := hh.GetIRegionAndProvider(ctx)
- return region, err
- }
- func (hh *SHost) getDiskConfig() jsonutils.JSONObject {
- bs := hh.GetBaremetalstorage()
- if bs != nil {
- return bs.Config
- }
- return nil
- }
- func (hh *SHost) GetBaremetalServer() *SGuest {
- if !hh.IsBaremetal {
- return nil
- }
- guest := SGuest{}
- guest.SetModelManager(GuestManager, &guest)
- q := GuestManager.Query().Equals("host_id", hh.Id).Equals("hypervisor", api.HOST_TYPE_BAREMETAL)
- err := q.First(&guest)
- if err != nil {
- if err != sql.ErrNoRows {
- log.Errorf("query fail %s", err)
- }
- return nil
- }
- return &guest
- }
- type SHostGuestResourceUsage struct {
- GuestCount int
- GuestVcpuCount int
- GuestVmemSize int
- }
- func (hh *SHost) getGuestsResource(status string) *SHostGuestResourceUsage {
- guests := GuestManager.Query().SubQuery()
- q := guests.Query(sqlchemy.COUNT("guest_count"),
- sqlchemy.SUM("guest_vcpu_count", guests.Field("vcpu_count")),
- sqlchemy.SUM("guest_vmem_size", guests.Field("vmem_size")))
- cond := sqlchemy.OR(sqlchemy.Equals(q.Field("host_id"), hh.Id),
- sqlchemy.Equals(q.Field("backup_host_id"), hh.Id))
- q = q.Filter(cond)
- if len(status) > 0 {
- q = q.Equals("status", status)
- }
- stat := SHostGuestResourceUsage{}
- err := q.First(&stat)
- if err != nil {
- log.Errorf("%s", err)
- return nil
- }
- return &stat
- }
- func fetchHostGuestResource(hostIds []string, status string) (map[string]SHostGuestResourceUsage, error) {
- ret := map[string]SHostGuestResourceUsage{}
- // Query by host_id
- {
- guests := GuestManager.Query().In("host_id", hostIds)
- if len(status) > 0 {
- guests = guests.Equals("status", status)
- }
- sq := guests.SubQuery()
- q := sq.Query(
- sqlchemy.COUNT("id").Label("guest_count"),
- sq.Field("host_id"),
- sqlchemy.SUM("guest_vcpu_count", sq.Field("vcpu_count")),
- sqlchemy.SUM("guest_vmem_size", sq.Field("vmem_size")),
- ).GroupBy(sq.Field("host_id"))
- stat := []struct {
- HostId string
- SHostGuestResourceUsage
- }{}
- if err := q.All(&stat); err != nil {
- return nil, err
- }
- for i := range stat {
- ret[stat[i].HostId] = stat[i].SHostGuestResourceUsage
- }
- }
- // Query by backup_host_id, and attribute usage to backup host
- {
- guests := GuestManager.Query().In("backup_host_id", hostIds)
- if len(status) > 0 {
- guests = guests.Equals("status", status)
- }
- sq := guests.SubQuery()
- backupHostId := sq.Field("backup_host_id").Label("host_id")
- q := sq.Query(
- sqlchemy.COUNT("id").Label("guest_count"),
- backupHostId,
- sqlchemy.SUM("guest_vcpu_count", sq.Field("vcpu_count")),
- sqlchemy.SUM("guest_vmem_size", sq.Field("vmem_size")),
- ).GroupBy(sq.Field("backup_host_id"))
- stat := []struct {
- HostId string
- SHostGuestResourceUsage
- }{}
- if err := q.All(&stat); err != nil {
- return nil, err
- }
- for i := range stat {
- v := ret[stat[i].HostId]
- v.GuestCount += stat[i].GuestCount
- v.GuestVcpuCount += stat[i].GuestVcpuCount
- v.GuestVmemSize += stat[i].GuestVmemSize
- ret[stat[i].HostId] = v
- }
- }
- return ret, nil
- }
- func fetchHostNics(hostIds []string) (map[string][]*types.SNic, error) {
- nicQ := NetInterfaceManager.Query().In("baremetal_id", hostIds).SubQuery()
- wires := WireManager.Query().SubQuery()
- zones := ZoneManager.Query().SubQuery()
- hn := HostnetworkManager.Query().SubQuery()
- networks := NetworkManager.Query().SubQuery()
- q := nicQ.Query(
- nicQ.Field("mac"),
- nicQ.Field("vlan_id"),
- nicQ.Field("baremetal_id"),
- nicQ.Field("wire_id"),
- nicQ.Field("rate"),
- nicQ.Field("nic_type"),
- nicQ.Field("index"),
- nicQ.Field("link_up"),
- nicQ.Field("bridge"),
- nicQ.Field("mtu"),
- wires.Field("name").Label("wire"),
- wires.Field("bandwidth"),
- hn.Field("ip_addr"),
- hn.Field("ip6_addr"),
- networks.Field("guest_gateway").Label("gateway"),
- networks.Field("guest_gateway6").Label("gateway6"),
- networks.Field("guest_dns").Label("dns"),
- networks.Field("guest_domain").Label("domain"),
- networks.Field("guest_ntp").Label("ntp"),
- networks.Field("guest_ip_mask").Label("masklen"),
- networks.Field("guest_ip6_mask").Label("masklen6"),
- networks.Field("name").Label("net"),
- networks.Field("id").Label("net_id"),
- zones.Field("name").Label("zone"),
- )
- q = q.LeftJoin(wires, sqlchemy.Equals(wires.Field("id"), nicQ.Field("wire_id")))
- q = q.LeftJoin(hn, sqlchemy.AND(
- sqlchemy.Equals(nicQ.Field("baremetal_id"), hn.Field("baremetal_id")),
- sqlchemy.Equals(nicQ.Field("mac"), hn.Field("mac_addr")),
- sqlchemy.Equals(nicQ.Field("vlan_id"), hn.Field("vlan_id")),
- ))
- q = q.LeftJoin(networks, sqlchemy.Equals(hn.Field("network_id"), networks.Field("id")))
- q = q.LeftJoin(zones, sqlchemy.Equals(wires.Field("zone_id"), zones.Field("id")))
- nics := []struct {
- types.SNic
- BaremetalId string
- Zone string
- }{}
- err := q.All(&nics)
- if err != nil {
- return nil, err
- }
- ret := map[string][]*types.SNic{}
- for i := range nics {
- nic := nics[i]
- _, ok := ret[nic.BaremetalId]
- if !ok {
- ret[nic.BaremetalId] = []*types.SNic{}
- }
- if len(nic.Gateway) > 0 && !regutils.MatchIP4Addr(nic.Gateway) {
- nic.Gateway = ""
- }
- if len(nic.Dns) == 0 && len(nic.Zone) > 0 {
- srvs, _ := auth.GetDNSServers(options.Options.Region, nic.Zone)
- if len(srvs) > 0 {
- nic.Dns = strings.Join(srvs, ",")
- } else {
- nic.Dns = options.Options.DNSServer
- }
- }
- if len(nic.Domain) == 0 {
- nic.Domain = options.Options.DNSDomain
- }
- if len(nic.Ntp) == 0 && len(nic.Zone) > 0 {
- srvs, _ := auth.GetNTPServers(options.Options.Region, nic.Zone)
- if len(srvs) > 0 {
- nic.Ntp = strings.Join(srvs, ",")
- }
- }
- ret[nic.BaremetalId] = append(ret[nic.BaremetalId], &nic.SNic)
- }
- return ret, nil
- }
- func fetchHostStorages(hostIds []string) (map[string]*SStorageCapacity, error) {
- hoststorages := HoststorageManager.Query().In("host_id", hostIds).SubQuery()
- storageQ := StorageManager.Query().IsTrue("enabled").NotEquals("storage_type", api.STORAGE_BAREMETAL).In("storage_type", api.HOST_STORAGE_LOCAL_TYPES).SubQuery()
- diskReadySQ := DiskManager.Query().Equals("status", api.DISK_READY).SubQuery()
- diskReadyQ := diskReadySQ.Query(sqlchemy.SUM("sum", diskReadySQ.Field("disk_size")).Label("used")).GroupBy(diskReadySQ.Field("storage_id"))
- readySQ := diskReadyQ.SubQuery()
- diskWasteSQ := DiskManager.Query().NotEquals("status", api.DISK_READY).SubQuery()
- diskWasteQ := diskWasteSQ.Query(sqlchemy.SUM("sum", diskWasteSQ.Field("disk_size")).Label("wasted")).GroupBy(diskWasteSQ.Field("storage_id"))
- wasteSQ := diskWasteQ.SubQuery()
- q := storageQ.Query(
- storageQ.Field("id"),
- storageQ.Field("capacity"),
- storageQ.Field("reserved"),
- hoststorages.Field("host_id"),
- storageQ.Field("cmtbound"),
- storageQ.Field("actual_capacity_used"),
- readySQ.Field("used"),
- wasteSQ.Field("wasted"),
- )
- q = q.Join(hoststorages, sqlchemy.Equals(q.Field("id"), hoststorages.Field("storage_id")))
- q = q.LeftJoin(readySQ, sqlchemy.Equals(readySQ.Field("storage_id"), storageQ.Field("id")))
- q = q.LeftJoin(wasteSQ, sqlchemy.Equals(wasteSQ.Field("storage_id"), storageQ.Field("id")))
- values := []struct {
- HostId string
- Capacity int64
- Reserved int64
- Cmtbound float32
- ActualCapacityUsed int64
- Used int64
- Wasted int64
- }{}
- err := q.All(&values)
- if err != nil {
- return nil, err
- }
- ret := map[string]*SStorageCapacity{}
- for i := range values {
- v := values[i]
- _, ok := ret[v.HostId]
- if !ok {
- ret[v.HostId] = &SStorageCapacity{}
- }
- capa := SStorageCapacity{}
- capa.Capacity = v.Capacity - v.Reserved
- capa.Used = v.Used
- capa.Wasted = v.Wasted
- cmtbound := options.Options.DefaultStorageOvercommitBound
- if v.Cmtbound > 0 {
- cmtbound = v.Cmtbound
- }
- capa.VCapacity = int64(float32(capa.Capacity) * cmtbound)
- capa.ActualUsed = v.ActualCapacityUsed
- ret[v.HostId].Add(capa)
- }
- return ret, nil
- }
- func fetchHostSchedtags(hostIds []string) (map[string][]api.SchedtagShortDescDetails, error) {
- schedtags := SchedtagManager.Query().SubQuery()
- objschedtags := HostschedtagManager.Query().SubQuery()
- q := schedtags.Query(
- objschedtags.Field("host_id"),
- schedtags.Field("id"),
- schedtags.Field("name"),
- schedtags.Field("default_strategy").Label("default"),
- sqlchemy.NewStringField("schedtag").Label("res_name"),
- )
- q = q.Join(objschedtags, sqlchemy.AND(sqlchemy.Equals(objschedtags.Field("schedtag_id"), schedtags.Field("id")),
- sqlchemy.IsFalse(objschedtags.Field("deleted"))))
- q = q.Filter(sqlchemy.In(objschedtags.Field("host_id"), hostIds))
- tags := []struct {
- Id string
- HostId string
- Name string
- ResName string
- Default string
- }{}
- err := q.All(&tags)
- if err != nil {
- return nil, err
- }
- ret := map[string][]api.SchedtagShortDescDetails{}
- for i := range tags {
- _, ok := ret[tags[i].HostId]
- if !ok {
- ret[tags[i].HostId] = []api.SchedtagShortDescDetails{}
- }
- tag := api.SchedtagShortDescDetails{}
- jsonutils.Update(&tag, tags[i])
- ret[tags[i].HostId] = append(ret[tags[i].HostId], tag)
- }
- return ret, nil
- }
- type sGuestCnt struct {
- GuestCnt int
- BackupGuestCnt int
- RunningGuestCnt int
- ReadyGuestCnt int
- OtherGuestCnt int
- PendingDeletedGuestCnt int
- NonsystemGuestCnt int
- }
- func (manager *SHostManager) FetchGuestCnt(hostIds []string) map[string]*sGuestCnt {
- ret := map[string]*sGuestCnt{}
- if len(hostIds) == 0 {
- return ret
- }
- guests := []SGuest{}
- err := GuestManager.RawQuery().IsFalse("deleted").In("host_id", hostIds).NotEquals("hypervisor", api.HYPERVISOR_POD).All(&guests)
- if err != nil {
- log.Errorf("query host %s guests error: %v", hostIds, err)
- }
- for _, guest := range guests {
- _, ok := ret[guest.HostId]
- if !ok {
- ret[guest.HostId] = &sGuestCnt{}
- }
- if guest.PendingDeleted {
- ret[guest.HostId].PendingDeletedGuestCnt += 1
- continue
- }
- ret[guest.HostId].GuestCnt += 1
- switch guest.Status {
- case api.VM_RUNNING:
- ret[guest.HostId].RunningGuestCnt += 1
- case api.VM_READY:
- ret[guest.HostId].ReadyGuestCnt += 1
- default:
- ret[guest.HostId].OtherGuestCnt += 1
- }
- if !guest.IsSystem {
- ret[guest.HostId].NonsystemGuestCnt += 1
- }
- }
- GuestManager.RawQuery().IsFalse("deleted").In("backup_host_id", hostIds).NotEquals("hypervisor", api.HYPERVISOR_POD).All(&guests)
- for _, guest := range guests {
- _, ok := ret[guest.BackupHostId]
- if !ok {
- ret[guest.BackupHostId] = &sGuestCnt{}
- }
- ret[guest.BackupHostId].BackupGuestCnt += 1
- }
- return ret
- }
- func (hh *SHost) GetReservedResourceForIsolatedDevice() (int, *api.IsolatedDeviceReservedResourceInput) {
- if devs := IsolatedDeviceManager.FindByHost(hh.Id); len(devs) == 0 {
- return -1, nil
- } else {
- return len(devs), hh.GetDevsReservedResource(devs)
- }
- }
- func (hh *SHost) GetDevsReservedResource(devs []SIsolatedDevice) *api.IsolatedDeviceReservedResourceInput {
- reservedCpu, reservedMem, reservedStorage := 0, 0, 0
- reservedResourceForGpu := api.IsolatedDeviceReservedResourceInput{
- ReservedStorage: &reservedStorage,
- ReservedMemory: &reservedMem,
- ReservedCpu: &reservedCpu,
- }
- for _, dev := range devs {
- if !utils.IsInStringArray(dev.DevType, api.VALID_GPU_TYPES) {
- continue
- }
- reservedCpu += dev.ReservedCpu
- reservedMem += dev.ReservedMemory
- reservedStorage += dev.ReservedStorage
- }
- return &reservedResourceForGpu
- }
- func (hh *SHost) GetMetadataHiddenKeys() []string {
- return []string{}
- }
- func (manager *SHostManager) FetchCustomizeColumns(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- objs []interface{},
- fields stringutils2.SSortedStrings,
- isList bool,
- ) []api.HostDetails {
- rows := make([]api.HostDetails, len(objs))
- stdRows := manager.SEnabledStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- showReason := false
- if query.Contains("show_fail_reason") {
- showReason = true
- }
- var hideCpuTypoInfo = jsonutils.QueryBoolean(query, "hide_cpu_topo_info", false)
- hostIds := make([]string, len(objs))
- hosts := make([]*SHost, len(objs))
- for i := range rows {
- rows[i] = api.HostDetails{
- EnabledStatusInfrasResourceBaseDetails: stdRows[i],
- ManagedResourceInfo: managerRows[i],
- ZoneResourceInfo: zoneRows[i],
- }
- host := objs[i].(*SHost)
- hostIds[i] = host.Id
- hosts[i] = host
- }
- baremetalServers, err := fetchBaremetalServer(hostIds)
- if err != nil {
- log.Errorf("fetchBaremetalServer error: %v", err)
- return rows
- }
- serverIds := []string{}
- for _, server := range baremetalServers {
- serverIds = append(serverIds, server.Id)
- }
- serverIps := fetchGuestIPs(serverIds, tristate.False)
- status := ""
- if options.Options.IgnoreNonrunningGuests {
- status = api.VM_RUNNING
- }
- guestResources, err := fetchHostGuestResource(hostIds, status)
- if err != nil {
- log.Errorf("fetchHostGuestResource error: %v", err)
- return rows
- }
- metas := []db.SMetadata{}
- err = db.Metadata.Query().In("obj_id", hostIds).In("key", []string{api.HOSTMETA_AUTO_MIGRATE_ON_HOST_DOWN, api.HOSTMETA_AUTO_MIGRATE_ON_HOST_SHUTDOWN}).All(&metas)
- if err != nil {
- log.Errorf("query meta error: %v", err)
- return rows
- }
- downMap, shutdownMap := map[string]bool{}, map[string]bool{}
- for _, meta := range metas {
- switch meta.Key {
- case api.HOSTMETA_AUTO_MIGRATE_ON_HOST_DOWN:
- downMap[meta.ObjId] = (meta.Value == "enable")
- case api.HOSTMETA_AUTO_MIGRATE_ON_HOST_SHUTDOWN:
- shutdownMap[meta.ObjId] = (meta.Value == "enable")
- }
- }
- isolatedDevices := IsolatedDeviceManager.FindByHosts(hostIds)
- isolatedDeviceMap := map[string][]SIsolatedDevice{}
- for i := range isolatedDevices {
- _, ok := isolatedDeviceMap[isolatedDevices[i].HostId]
- if !ok {
- isolatedDeviceMap[isolatedDevices[i].HostId] = []SIsolatedDevice{}
- }
- isolatedDeviceMap[isolatedDevices[i].HostId] = append(isolatedDeviceMap[isolatedDevices[i].HostId], isolatedDevices[i])
- }
- schedtags, err := fetchHostSchedtags(hostIds)
- if err != nil {
- log.Errorf("fetchHostSchedtags error: %v", err)
- // return rows
- }
- storages, err := fetchHostStorages(hostIds)
- if err != nil {
- log.Errorf("host storages error: %v", err)
- // return rows
- }
- nics, err := fetchHostNics(hostIds)
- if err != nil {
- log.Errorf("fetchHostNics error: %v", err)
- // return rows
- }
- guestCnts := manager.FetchGuestCnt(hostIds)
- hostFiles, err := fetchHostHostFiles(hostIds)
- if err != nil {
- log.Errorf("fetchHostHostFiles error: %v", err)
- }
- for i := range rows {
- cnt, ok := guestCnts[hostIds[i]]
- if ok {
- rows[i].Guests = cnt.GuestCnt
- rows[i].RunningGuests = cnt.RunningGuestCnt
- rows[i].ReadyGuests = cnt.ReadyGuestCnt
- rows[i].OtherGuests = cnt.OtherGuestCnt
- rows[i].NonsystemGuests = cnt.NonsystemGuestCnt
- rows[i].PendingDeletedGuests = cnt.PendingDeletedGuestCnt
- }
- if server, ok := baremetalServers[hostIds[i]]; ok {
- rows[i].ServerId = server.Id
- rows[i].Server = server.Name
- rows[i].ServerPendingDeleted = server.PendingDeleted
- if hosts[i].HostType == api.HOST_TYPE_BAREMETAL && len(serverIps) > 0 {
- if ips, _ := serverIps[server.Id]; len(ips) > 0 {
- rows[i].ServerIps = strings.Join(ips, ",")
- }
- }
- }
- if hosts[i].EnableHealthCheck && hostHealthChecker != nil {
- rows[i].AllowHealthCheck = true
- }
- rows[i].AutoMigrateOnHostDown = downMap[hostIds[i]]
- rows[i].AutoMigrateOnHostShutdown = shutdownMap[hostIds[i]]
- if hosts[i].IsBaremetal {
- rows[i].CanPrepare = true
- if server := baremetalServers[hostIds[i]]; server != nil && server.Status != api.VM_ADMIN {
- rows[i].CanPrepare = false
- if showReason {
- rows[i].PrepareFailReason = fmt.Sprintf("Cannot prepare baremetal in server status %s", server.Status)
- }
- }
- err := hosts[i].canPrepare()
- if err != nil && rows[i].CanPrepare {
- rows[i].CanPrepare = false
- if showReason {
- rows[i].PrepareFailReason = err.Error()
- }
- }
- }
- if !isList {
- pinnedCpus, _ := hosts[i].GetPinnedCpusetCores(ctx, userCred, nil)
- if pinnedCpus != nil {
- rows[i].GuestPinnedCpus = pinnedCpus.ToSlice()
- }
- }
- if usage, ok := guestResources[hostIds[i]]; ok {
- rows[i].CpuCommit = usage.GuestVcpuCount
- rows[i].MemCommit = usage.GuestVmemSize
- totalCpu := hosts[i].GetCpuCount()
- cpuCommitRate := 0.0
- if totalCpu > 0 && usage.GuestVcpuCount > 0 {
- cpuCommitRate = float64(usage.GuestVcpuCount) * 1.0 / float64(totalCpu)
- }
- rows[i].CpuCommitRate = cpuCommitRate
- totalMem := hosts[i].GetMemSize()
- memCommitRate := 0.0
- if totalMem > 0 && usage.GuestVmemSize > 0 {
- memCommitRate = float64(usage.GuestVmemSize) * 1.0 / float64(totalMem)
- }
- rows[i].MemCommitRate = memCommitRate
- }
- if devs, ok := isolatedDeviceMap[hostIds[i]]; ok {
- rows[i].IsolatedDeviceCount = len(devs)
- for j := range devs {
- dev := devs[j]
- if rows[i].IsolatedDeviceTypeCount == nil {
- rows[i].IsolatedDeviceTypeCount = make(map[string]int, 0)
- }
- if cnt, ok := rows[i].IsolatedDeviceTypeCount[dev.DevType]; ok {
- rows[i].IsolatedDeviceTypeCount[dev.DevType] = cnt + 1
- } else {
- rows[i].IsolatedDeviceTypeCount[dev.DevType] = 1
- }
- }
- rows[i].ReservedResourceForGpu = hosts[i].GetDevsReservedResource(devs)
- }
- if capa, ok := storages[hostIds[i]]; ok {
- rows[i].Storage = capa.Capacity
- rows[i].StorageUsed = capa.Used
- rows[i].ActualStorageUsed = capa.ActualUsed
- rows[i].StorageWaste = capa.Wasted
- rows[i].StorageVirtual = capa.VCapacity
- rows[i].StorageFree = capa.GetFree()
- rows[i].StorageCommitRate = capa.GetCommitRate()
- }
- rows[i].IsPrepaidRecycle = hosts[i].IsPrepaidRecycle()
- rows[i].CpuCommitBound = hosts[i].GetCPUOvercommitBound()
- rows[i].MemCommitBound = hosts[i].GetMemoryOvercommitBound()
- rows[i].Spec = hosts[i].GetHardwareSpecification()
- rows[i].Schedtags, _ = schedtags[hostIds[i]]
- rows[i].NicInfo, _ = nics[hostIds[i]]
- rows[i].NicCount = len(rows[i].NicInfo)
- rows[i].HostFiles = hostFiles[hostIds[i]]
- if hideCpuTypoInfo {
- sysInfo, ok := hosts[i].SysInfo.(*jsonutils.JSONDict)
- if ok {
- sysInfo.Remove("cpu_info")
- sysInfo.Remove("topology")
- }
- delete(rows[i].Metadata, "cpu_info")
- delete(rows[i].Metadata, "topology")
- }
- }
- return rows
- }
- type SInfrasStatusInfo struct {
- apis.TotalCountBase
- StatusInfo []apis.StatusStatisticStatusInfo
- }
- type SHostTotalCount struct {
- SInfrasStatusInfo
- MemoryUsed int64
- MemoryTotal int64
- CPUUsed int64
- CPUTotal int64
- }
- func (manager *SHostManager) CustomizedTotalCount(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, totalQ *sqlchemy.SQuery) (int, jsonutils.JSONObject, error) {
- results := SHostTotalCount{}
- totalQ = totalQ.AppendField(sqlchemy.SUM("cpu_total", totalQ.Field("cpu_count")))
- totalQ = totalQ.AppendField(sqlchemy.SUM("memory_total", totalQ.Field("mem_size")))
- totalQ = totalQ.AppendField(sqlchemy.SUM("memory_used", totalQ.Field("memory_used_mb")))
- totalQ = totalQ.AppendField(sqlchemy.CASTInt(sqlchemy.SUM("cpu_used", sqlchemy.MUL("use_cpu", totalQ.Field("cpu_usage_percent"), totalQ.Field("cpu_count"), sqlchemy.NewConstField(0.01))), "cpu_used"))
- err := totalQ.First(&results)
- if err != nil && errors.Cause(err) != sql.ErrNoRows {
- return -1, nil, errors.Wrapf(err, "First")
- }
- _, statusInfo, err := manager.SEnabledStatusInfrasResourceBaseManager.CustomizedTotalCount(ctx, userCred, query, totalQ)
- if err != nil {
- return -1, nil, errors.Wrapf(err, "virt.CustomizedTotalCount")
- }
- statusInfo.Unmarshal(&results.SInfrasStatusInfo)
- log.Debugf("CustomizedTotalCount %s", jsonutils.Marshal(results))
- return results.Count, jsonutils.Marshal(results), nil
- }
- func fetchBaremetalServer(hostIds []string) (map[string]*SGuest, error) {
- guests := []SGuest{}
- err := GuestManager.Query().In("host_id", hostIds).Equals("hypervisor", api.HOST_TYPE_BAREMETAL).All(&guests)
- if err != nil {
- return nil, err
- }
- ret := map[string]*SGuest{}
- for i := range guests {
- ret[guests[i].HostId] = &guests[i]
- }
- return ret, nil
- }
- func (hh *SHost) GetDetailsVnc(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if utils.IsInStringArray(hh.Status, []string{api.BAREMETAL_READY, api.BAREMETAL_RUNNING}) {
- retval := jsonutils.NewDict()
- retval.Set("host_id", jsonutils.NewString(hh.Id))
- zone, _ := hh.GetZone()
- retval.Set("zone", jsonutils.NewString(zone.GetName()))
- return retval, nil
- }
- return jsonutils.NewDict(), nil
- }
- func (hh *SHost) GetDetailsIpmi(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- ret, ok := hh.IpmiInfo.(*jsonutils.JSONDict)
- if !ok {
- return nil, httperrors.NewNotFoundError("No ipmi information was found for host %s", hh.Name)
- }
- password, err := ret.GetString("password")
- if err != nil {
- return nil, httperrors.NewNotFoundError("IPMI has no password information")
- }
- descryptedPassword, err := utils.DescryptAESBase64(hh.Id, password)
- if err != nil {
- return nil, err
- }
- ret.Set("password", jsonutils.NewString(descryptedPassword))
- return ret, nil
- }
- func (manager *SHostManager) GetHostsByManagerAndRegion(managerId string, regionId string) []SHost {
- zones := ZoneManager.Query().Equals("cloudregion_id", regionId).SubQuery()
- hosts := HostManager.Query()
- q := hosts.Equals("manager_id", managerId)
- q = q.Join(zones, sqlchemy.Equals(zones.Field("id"), hosts.Field("zone_id")))
- ret := make([]SHost, 0)
- err := db.FetchModelObjects(HostManager, q, &ret)
- if err != nil {
- log.Errorf("GetHostsByManagerAndRegion fail %s", err)
- return nil
- }
- return ret
- }
- func (hh *SHost) RequestScanIsolatedDevices(ctx context.Context, userCred mcclient.TokenCredential) error {
- _, err := hh.Request(ctx, userCred, "POST", fmt.Sprintf("/hosts/%s/probe-isolated-devices", hh.Id), mcclient.GetTokenHeaders(userCred), nil)
- if err != nil {
- return errors.Wrapf(err, "request host %s probe isolaed devices", hh.Id)
- }
- return nil
- }
- func (hh *SHost) Request(ctx context.Context, userCred mcclient.TokenCredential, method httputils.THttpMethod, url string, headers http.Header, body jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- s := auth.GetSession(ctx, userCred, "")
- _, ret, err := s.JSONRequest(hh.ManagerUri, "", method, url, headers, body)
- return ret, err
- }
- func (hh *SHost) GetLocalStoragecache() *SStoragecache {
- localStorages := hh.GetAttachedLocalStorages()
- for i := 0; i < len(localStorages); i += 1 {
- sc := localStorages[i].GetStoragecache()
- if sc != nil {
- return sc
- }
- }
- return nil
- }
- func (hh *SHost) GetStoragecache() *SStoragecache {
- localStorages := hh.GetAttachedEnabledHostStorages(nil)
- for i := 0; i < len(localStorages); i += 1 {
- sc := localStorages[i].GetStoragecache()
- if sc != nil {
- return sc
- }
- }
- return nil
- }
- func (hh *SHost) PostCreate(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider,
- query jsonutils.JSONObject,
- data jsonutils.JSONObject,
- ) {
- hh.SEnabledStatusInfrasResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
- input := api.HostCreateInput{}
- err := data.Unmarshal(&input)
- if err != nil {
- log.Errorf("data.Unmarshal fail %s", err)
- return
- }
- kwargs := data.(*jsonutils.JSONDict)
- ipmiInfo, err := fetchIpmiInfo(input.HostIpmiAttributes, hh.Id)
- if err != nil {
- log.Errorf("fetchIpmiInfo fail %s", err)
- return
- }
- ipmiInfoJson := jsonutils.Marshal(ipmiInfo).(*jsonutils.JSONDict)
- if ipmiInfoJson.Length() > 0 {
- _, err := hh.SaveUpdates(func() error {
- hh.IpmiInfo = ipmiInfoJson
- return nil
- })
- if err != nil {
- log.Errorf("save updates: %v", err)
- } else if len(ipmiInfo.IpAddr) > 0 {
- hh.setIpmiIp(userCred, ipmiInfo.IpAddr)
- }
- }
- if len(input.AccessIp) > 0 {
- hh.setAccessIp(userCred, input.AccessIp)
- }
- if len(input.AccessMac) > 0 {
- hh.setAccessMac(userCred, input.AccessMac)
- }
- noProbe := false
- if input.NoProbe != nil {
- noProbe = *input.NoProbe
- }
- if len(hh.ZoneId) > 0 && hh.HostType == api.HOST_TYPE_BAREMETAL && !noProbe {
- // ipmiInfo, _ := hh.GetIpmiInfo()
- if len(ipmiInfo.IpAddr) > 0 {
- hh.StartBaremetalCreateTask(ctx, userCred, kwargs, "")
- }
- }
- if hh.OvnVersion != "" && hh.OvnMappedIpAddr == "" {
- HostManager.lockAllocOvnMappedIpAddr(ctx)
- defer HostManager.unlockAllocOvnMappedIpAddr(ctx)
- addr, err := HostManager.allocOvnMappedIpAddr(ctx)
- if err != nil {
- log.Errorf("host %s(%s): alloc vpc mapped addr: %v",
- hh.Name, hh.Id, err)
- }
- if _, err := db.Update(hh, func() error {
- hh.OvnMappedIpAddr = addr
- hh.OvnMappedIp6Addr = api.GenVpcMappedIP6(addr)
- return nil
- }); err != nil {
- log.Errorf("host %s(%s): db update vpc mapped addr: %v",
- hh.Name, hh.Id, err)
- }
- }
- keys := GetHostQuotaKeysFromCreateInput(ownerId, input)
- quota := SInfrasQuota{Host: 1}
- quota.SetKeys(keys)
- err = quotas.CancelPendingUsage(ctx, userCred, "a, "a, true)
- if err != nil {
- log.Errorf("CancelPendingUsage fail %s", err)
- }
- hh.SEnabledStatusInfrasResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
- notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
- Obj: hh,
- Action: notifyclient.ActionCreate,
- })
- }
- func (hh *SHost) StartBaremetalCreateTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error {
- if task, err := taskman.TaskManager.NewTask(ctx, "BaremetalCreateTask", hh, userCred, data, parentTaskId, "", nil); err != nil {
- log.Errorln(err)
- return err
- } else {
- task.ScheduleRun(nil)
- return nil
- }
- }
- func (manager *SHostManager) ValidateSizeParams(input api.HostSizeAttributes) (api.HostSizeAttributes, error) {
- memStr := input.MemSize
- if len(memStr) > 0 {
- if !regutils.MatchSize(memStr) {
- return input, errors.Wrap(httperrors.ErrInputParameter, "Memory size must be number[+unit], like 256M, 1G or 256")
- }
- memSize, err := fileutils.GetSizeMb(memStr, 'M', 1024)
- if err != nil {
- return input, errors.Wrap(err, "fileutils.GetSizeMb")
- }
- input.MemSize = strconv.FormatInt(int64(memSize), 10)
- // data.Set("mem_size", jsonutils.NewInt(int64(memSize)))
- }
- memReservedStr := input.MemReserved
- if len(memReservedStr) > 0 {
- if !regutils.MatchSize(memReservedStr) {
- return input, errors.Wrap(httperrors.ErrInputParameter, "Memory size must be number[+unit], like 256M, 1G or 256")
- }
- memSize, err := fileutils.GetSizeMb(memReservedStr, 'M', 1024)
- if err != nil {
- return input, errors.Wrap(err, "fileutils.GetSizeMb")
- }
- input.MemReserved = strconv.FormatInt(int64(memSize), 10)
- // data.Set("mem_reserved", jsonutils.NewInt(int64(memSize)))
- }
- cpuCacheStr := input.CpuCache
- if len(cpuCacheStr) > 0 {
- if !regutils.MatchSize(cpuCacheStr) {
- return input, errors.Wrapf(httperrors.ErrInputParameter, "Illegal cpu cache size %s", cpuCacheStr)
- }
- cpuCache, err := fileutils.GetSizeKb(cpuCacheStr, 'K', 1024)
- if err != nil {
- return input, errors.Wrap(err, "fileutils.GetSizeKb")
- }
- input.CpuCache = strconv.FormatInt(int64(cpuCache), 10)
- // data.Set("cpu_cache", jsonutils.NewInt(int64(cpuCache)))
- }
- return input, nil
- }
- func (manager *SHostManager) inputUniquenessCheck(input api.HostAccessAttributes, zoneId string, hostId string) (api.HostAccessAttributes, error) {
- for key, val := range map[string]string{
- "manager_uri": input.ManagerUri,
- "access_ip": input.AccessIp,
- } {
- if len(val) > 0 {
- q := manager.Query().Equals(key, val)
- if len(zoneId) > 0 {
- q = q.Equals("zone_id", zoneId)
- } else {
- q = q.IsNullOrEmpty("zone_id")
- }
- if len(hostId) > 0 {
- q = q.NotEquals("id", hostId)
- }
- cnt, err := q.CountWithError()
- if err != nil {
- return input, httperrors.NewInternalServerError("check %s duplication fail %s", key, err)
- }
- if cnt > 0 {
- return input, httperrors.NewConflictError("duplicate %s %s", key, val)
- }
- }
- }
- accessMac := input.AccessMac
- if len(accessMac) > 0 {
- accessMac2 := netutils.FormatMacAddr(accessMac)
- if len(accessMac2) == 0 {
- return input, httperrors.NewInputParameterError("invalid macAddr %s", accessMac)
- }
- if accessMac2 != api.ACCESS_MAC_ANY {
- q := manager.Query().Equals("access_mac", accessMac2)
- if len(hostId) > 0 {
- q = q.NotEquals("id", hostId)
- }
- cnt, err := q.CountWithError()
- if err != nil {
- return input, httperrors.NewInternalServerError("check access_mac duplication fail %s", err)
- }
- if cnt > 0 {
- return input, httperrors.NewConflictError("duplicate access_mac %s", accessMac)
- }
- input.AccessMac = accessMac2
- }
- }
- return input, nil
- }
- func (manager *SHostManager) ValidateCreateData(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider,
- query jsonutils.JSONObject,
- input api.HostCreateInput,
- ) (api.HostCreateInput, error) {
- var err error
- if len(input.ZoneId) > 0 {
- _, input.ZoneResourceInput, err = ValidateZoneResourceInput(ctx, userCred, input.ZoneResourceInput)
- if err != nil {
- return input, errors.Wrap(err, "ValidateZoneResourceInput")
- }
- }
- noProbe := false
- if input.NoProbe != nil {
- noProbe = *input.NoProbe
- }
- input.HostAccessAttributes, err = manager.inputUniquenessCheck(input.HostAccessAttributes, input.ZoneId, "")
- if err != nil {
- return input, errors.Wrap(err, "manager.inputUniquenessCheck")
- }
- input.HostSizeAttributes, err = manager.ValidateSizeParams(input.HostSizeAttributes)
- if err != nil {
- return input, errors.Wrap(err, "manager.ValidateSizeParams")
- }
- if len(input.MemReserved) == 0 {
- if input.HostType != api.HOST_TYPE_BAREMETAL {
- memSize, _ := strconv.ParseInt(input.MemSize, 10, 64)
- memReserved := memSize / 8
- if memReserved > 4096 {
- memReserved = 4096
- }
- input.MemReserved = strconv.FormatInt(memReserved, 10)
- // data.Set("mem_reserved", jsonutils.NewInt(memReserved))
- } else {
- input.MemReserved = "0"
- // data.Set("mem_reserved", jsonutils.NewInt(0))
- }
- }
- ipmiInfo, err := fetchIpmiInfo(input.HostIpmiAttributes, "")
- if err != nil {
- return input, errors.Wrap(err, "fetchIpmiInfo")
- }
- ipmiIpAddr := ipmiInfo.IpAddr
- if len(ipmiIpAddr) == 0 {
- noProbe = true
- }
- if len(ipmiIpAddr) > 0 && !noProbe {
- net, _ := NetworkManager.GetOnPremiseNetworkOfIP(ipmiIpAddr, "", tristate.None)
- if net == nil {
- return input, httperrors.NewInputParameterError("%s is out of network IP ranges", ipmiIpAddr)
- }
- // check ip has been reserved
- rip := ReservedipManager.GetReservedIP(net, ipmiIpAddr, api.AddressTypeIPv4)
- if rip == nil {
- // if not, reserve this IP temporarily
- err := net.reserveIpWithDuration(ctx, userCred, ipmiIpAddr, "reserve for baremetal ipmi IP", 30*time.Minute)
- if err != nil {
- return input, errors.Wrap(err, "net.reserveIpWithDuration")
- }
- }
- zoneObj, _ := net.GetZone()
- if zoneObj == nil {
- return input, httperrors.NewInputParameterError("IPMI network has no zone???")
- }
- originZoneId := input.ZoneId
- if len(originZoneId) > 0 && originZoneId != zoneObj.GetId() {
- return input, httperrors.NewInputParameterError("IPMI address located in different zone than specified")
- }
- input.ZoneId = zoneObj.GetId()
- // data.Set("zone_id", jsonutils.NewString(zoneObj.GetId()))
- }
- if !noProbe || input.NoBMC {
- var accessNet *SNetwork
- accessIpAddr := input.AccessIp // tString("access_ip")
- if len(accessIpAddr) > 0 {
- net, _ := NetworkManager.GetOnPremiseNetworkOfIP(accessIpAddr, "", tristate.None)
- if net == nil {
- return input, httperrors.NewInputParameterError("%s is out of network IP ranges", accessIpAddr)
- }
- accessNet = net
- } else {
- accessNetStr := input.AccessNet // data.GetString("access_net")
- if len(accessNetStr) > 0 {
- netObj, err := NetworkManager.FetchByIdOrName(ctx, userCred, accessNetStr)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return input, httperrors.NewResourceNotFoundError2("network", accessNetStr)
- } else {
- return input, httperrors.NewGeneralError(err)
- }
- }
- accessNet = netObj.(*SNetwork)
- } else {
- accessWireStr := input.AccessWire // data.GetString("access_wire")
- if len(accessWireStr) > 0 {
- wireObj, err := WireManager.FetchByIdOrName(ctx, userCred, accessWireStr)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return input, httperrors.NewResourceNotFoundError2("wire", accessWireStr)
- } else {
- return input, httperrors.NewGeneralError(err)
- }
- }
- wire := wireObj.(*SWire)
- lockman.LockObject(ctx, wire)
- defer lockman.ReleaseObject(ctx, wire)
- net, err := wire.GetCandidatePrivateNetwork(ctx, userCred, userCred, NetworkManager.AllowScope(userCred), false, []api.TNetworkType{api.NETWORK_TYPE_PXE, api.NETWORK_TYPE_BAREMETAL, api.NETWORK_TYPE_GUEST})
- if err != nil {
- return input, httperrors.NewGeneralError(err)
- }
- accessNet = net
- }
- }
- }
- if accessNet != nil {
- lockman.LockObject(ctx, accessNet)
- defer lockman.ReleaseObject(ctx, accessNet)
- accessIp, err := accessNet.GetFreeIP(ctx, userCred, nil, nil, accessIpAddr, api.IPAllocationNone, true, api.AddressTypeIPv4)
- if err != nil {
- return input, httperrors.NewGeneralError(err)
- }
- if len(accessIpAddr) > 0 && accessIpAddr != accessIp {
- return input, httperrors.NewConflictError("Access ip %s has been used", accessIpAddr)
- }
- zoneObj, _ := accessNet.GetZone()
- if zoneObj == nil {
- return input, httperrors.NewInputParameterError("Access network has no zone???")
- }
- originZoneId := input.ZoneId // data.GetString("zone_id")
- if len(originZoneId) > 0 && originZoneId != zoneObj.GetId() {
- return input, httperrors.NewInputParameterError("Access address located in different zone than specified")
- }
- // check ip has been reserved
- rip := ReservedipManager.GetReservedIP(accessNet, accessIp, api.AddressTypeIPv4)
- if rip == nil {
- // if not reserved, reserve this IP temporarily
- err = accessNet.reserveIpWithDuration(ctx, userCred, accessIp, "reserve for baremetal access IP", 30*time.Minute)
- if err != nil {
- return input, err
- }
- }
- input.AccessIp = accessIp
- input.ZoneId = zoneObj.GetId()
- // data.Set("access_ip", jsonutils.NewString(accessIp))
- // data.Set("zone_id", jsonutils.NewString(zoneObj.GetId()))
- }
- }
- // only baremetal can be created
- hostType := input.HostType // .GetString("host_type")
- if len(hostType) == 0 {
- hostType = api.HOST_TYPE_BAREMETAL
- input.HostType = hostType
- // data.Set("host_type", jsonutils.NewString(hostType))
- }
- if hostType == api.HOST_TYPE_BAREMETAL {
- isBaremetal := true
- input.IsBaremetal = &isBaremetal
- // data.Set("is_baremetal", jsonutils.JSONTrue)
- }
- if noProbe {
- // accessMac := input.AccessMac // data.GetString("access_mac")
- // uuid := input.Uuid // data.GetString("uuid")
- if len(input.AccessMac) == 0 && len(input.Uuid) == 0 {
- return input, httperrors.NewInputParameterError("missing access_mac and uuid in no_probe mode")
- }
- }
- input.EnabledStatusInfrasResourceBaseCreateInput, err = manager.SEnabledStatusInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledStatusInfrasResourceBaseCreateInput)
- if err != nil {
- return input, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ValidateCreateData")
- }
- name := input.Name
- if len(name) == 0 {
- name = input.GenerateName
- }
- input.HostnameInput, err = manager.SHostnameResourceBaseManager.ValidateHostname(name, "", input.HostnameInput)
- if err != nil {
- return input, err
- }
- keys := GetHostQuotaKeysFromCreateInput(ownerId, input)
- quota := SInfrasQuota{Host: 1}
- quota.SetKeys(keys)
- err = quotas.CheckSetPendingQuota(ctx, userCred, "a)
- if err != nil {
- return input, errors.Wrapf(err, "CheckSetPendingQuota")
- }
- return input, nil
- }
- func (hh *SHost) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.HostUpdateInput) (api.HostUpdateInput, error) {
- // validate Hostname
- if len(input.Hostname) > 0 {
- if !regutils.MatchDomainName(input.Hostname) {
- return input, httperrors.NewInputParameterError("hostname should be a legal domain name")
- }
- }
- var err error
- input.HostAccessAttributes, err = HostManager.inputUniquenessCheck(input.HostAccessAttributes, hh.ZoneId, hh.Id)
- if err != nil {
- return input, errors.Wrap(err, "inputUniquenessCheck")
- }
- if hh.IsHugePage() && input.MemCmtbound != nil && *input.MemCmtbound != hh.MemCmtbound {
- return input, errors.Errorf("host mem is hugepage, cannot update mem_cmtbound")
- }
- if input.CpuReserved != nil {
- info := hh.GetMetadata(ctx, api.HOSTMETA_RESERVED_CPUS_INFO, nil)
- if len(info) > 0 {
- return input, errors.Wrap(httperrors.ErrInputParameter, "host cpu has been reserved, cannot update cpu_reserved")
- }
- }
- input.HostSizeAttributes, err = HostManager.ValidateSizeParams(input.HostSizeAttributes)
- if err != nil {
- return input, errors.Wrap(err, "ValidateSizeParams")
- }
- ipmiInfo, err := fetchIpmiInfo(input.HostIpmiAttributes, hh.Id)
- if err != nil {
- return input, errors.Wrap(err, "fetchIpmiInfo")
- }
- ipmiInfoJson := jsonutils.Marshal(ipmiInfo).(*jsonutils.JSONDict)
- if ipmiInfoJson.Length() > 0 {
- ipmiIpAddr := ipmiInfo.IpAddr
- if len(ipmiIpAddr) > 0 {
- net, _ := NetworkManager.GetOnPremiseNetworkOfIP(ipmiIpAddr, "", tristate.None)
- if net == nil {
- return input, httperrors.NewInputParameterError("%s is out of network IP ranges", ipmiIpAddr)
- }
- zoneObj, _ := net.GetZone()
- if zoneObj == nil {
- return input, httperrors.NewInputParameterError("IPMI network has not zone???")
- }
- if zoneObj.GetId() != hh.ZoneId {
- return input, httperrors.NewInputParameterError("New IPMI address located in another zone!")
- }
- }
- val := jsonutils.NewDict()
- val.Update(hh.IpmiInfo)
- val.Update(ipmiInfoJson)
- input.IpmiInfo = val
- }
- input.EnabledStatusInfrasResourceBaseUpdateInput, err = hh.SEnabledStatusInfrasResourceBase.ValidateUpdateData(ctx, userCred, query, input.EnabledStatusInfrasResourceBaseUpdateInput)
- if err != nil {
- return input, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.ValidateUpdateData")
- }
- if len(input.Name) > 0 {
- hh.UpdateDnsRecords(false)
- }
- if input.EnableNumaAllocate != nil {
- if hh.HostType != api.HOST_TYPE_CONTAINER {
- if cnt, err := hh.GetRunningGuestCount(); err != nil {
- return input, errors.Wrap(err, "GetRunningGuestCount")
- } else if cnt > 0 {
- return input, errors.Errorf("Host has running guest, can't enable/disable numa allocate")
- }
- }
- }
- return input, nil
- }
- func (hh *SHost) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
- hh.SEnabledStatusInfrasResourceBase.PostUpdate(ctx, userCred, query, data)
- if data.Contains("cpu_cmtbound") || data.Contains("mem_cmtbound") || data.Contains("enable_numa_allocate") {
- hh.ClearSchedDescCache()
- }
- if hh.OvnVersion != "" && hh.OvnMappedIpAddr == "" {
- HostManager.lockAllocOvnMappedIpAddr(ctx)
- defer HostManager.unlockAllocOvnMappedIpAddr(ctx)
- addr, err := HostManager.allocOvnMappedIpAddr(ctx)
- if err != nil {
- log.Errorf("host %s(%s): alloc vpc mapped addr: %v",
- hh.Name, hh.Id, err)
- return
- }
- if _, err := db.Update(hh, func() error {
- hh.OvnMappedIpAddr = addr
- hh.OvnMappedIp6Addr = api.GenVpcMappedIP6(addr)
- return nil
- }); err != nil {
- log.Errorf("host %s(%s): db update vpc mapped addr: %v",
- hh.Name, hh.Id, err)
- return
- }
- }
- // update baremetal host related server
- if guest := hh.GetBaremetalServer(); guest != nil && hh.HostType == api.HOST_TYPE_BAREMETAL {
- if _, err := db.Update(guest, func() error {
- guest.VmemSize = hh.MemSize
- guest.VcpuCount = hh.CpuCount
- return nil
- }); err != nil {
- log.Errorf("baremetal host %s update related server %s spec error: %v", hh.GetName(), guest.GetName(), err)
- }
- }
- notSyncConf, _ := data.Bool("not_sync_config")
- if !notSyncConf {
- if err := hh.startSyncConfig(ctx, userCred, "", true); err != nil {
- log.Errorf("start sync host %q config after updated", hh.GetName())
- }
- }
- }
- func (hh *SHost) PostDelete(ctx context.Context, userCred mcclient.TokenCredential) {
- hh.SEnabledStatusInfrasResourceBase.PostDelete(ctx, userCred)
- notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
- Obj: hh,
- Action: notifyclient.ActionDelete,
- })
- }
- func (hh *SHost) UpdateDnsRecords(isAdd bool) {
- for _, netif := range hh.GetHostNetInterfaces() {
- hh.UpdateDnsRecord(&netif, isAdd)
- }
- }
- func (hh *SHost) UpdateDnsRecord(netif *SNetInterface, isAdd bool) {
- name := hh.GetNetifName(netif)
- if len(name) == 0 {
- return
- }
- bn := netif.GetHostNetwork()
- if bn == nil {
- log.Errorf("Interface %s not enable", netif.GetId())
- return
- }
- net := bn.GetNetwork()
- if net == nil {
- log.Errorf("BaremetalNetwoke %s not found network", bn.GetId())
- }
- net._updateDnsRecord(name, bn.IpAddr, isAdd)
- }
- func (hh *SHost) GetNetifName(netif *SNetInterface) string {
- if netif.NicType == api.NIC_TYPE_IPMI {
- return hh.GetName()
- } else if netif.NicType == api.NIC_TYPE_ADMIN {
- return hh.GetName() + "-admin"
- }
- return ""
- }
- func fetchIpmiInfo(data api.HostIpmiAttributes, hostId string) (types.SIPMIInfo, error) {
- info := types.SIPMIInfo{}
- info.Username = data.IpmiUsername
- if len(data.IpmiPassword) > 0 {
- if len(hostId) > 0 {
- value, err := utils.EncryptAESBase64(hostId, data.IpmiPassword)
- if err != nil {
- log.Errorf("encrypt password failed %s", err)
- return info, errors.Wrap(err, "utils.EncryptAESBase64")
- }
- info.Password = value
- } else {
- info.Password = data.IpmiPassword
- }
- }
- if len(data.IpmiIpAddr) > 0 && !regutils.MatchIP4Addr(data.IpmiIpAddr) && !regutils.MatchIP6Addr(data.IpmiIpAddr) {
- msg := fmt.Sprintf("ipmi_ip_addr: %v not valid address", data.IpmiIpAddr)
- log.Errorf("%s", msg)
- return info, errors.Wrap(httperrors.ErrInvalidFormat, msg)
- }
- info.IpAddr = data.IpmiIpAddr
- if data.IpmiPresent != nil {
- info.Present = *data.IpmiPresent
- }
- if data.IpmiLanChannel != nil {
- info.LanChannel = *data.IpmiLanChannel
- }
- if data.IpmiVerified != nil {
- info.Verified = *data.IpmiVerified
- }
- if data.IpmiRedfishApi != nil {
- info.RedfishApi = *data.IpmiRedfishApi
- }
- if data.IpmiCdromBoot != nil {
- info.CdromBoot = *data.IpmiCdromBoot
- }
- if data.IpmiPxeBoot != nil {
- info.PxeBoot = *data.IpmiPxeBoot
- }
- return info, nil
- }
- func (hh *SHost) PerformStart(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input api.HostPerformStartInput,
- ) (jsonutils.JSONObject, error) {
- if !hh.IsBaremetal {
- return nil, httperrors.NewBadRequestError("Cannot start a non-baremetal host")
- }
- if !utils.IsInStringArray(hh.Status, []string{api.BAREMETAL_READY}) {
- return nil, httperrors.NewInvalidStatusError("Cannot start baremetal with active guest")
- }
- guest := hh.GetBaremetalServer()
- if guest != nil {
- if hh.HostType == api.HOST_TYPE_BAREMETAL && utils.ToBool(guest.GetMetadata(ctx, "is_fake_baremetal_server", userCred)) {
- return nil, hh.InitializedGuestStart(ctx, userCred, guest)
- }
- // if !utils.IsInStringArray(guest.Status, []string{VM_ADMIN}) {
- // return nil, httperrors.NewBadRequestError("Cannot start baremetal with active guest")
- // }
- hh.SetStatus(ctx, userCred, api.BAREMETAL_START_MAINTAIN, "")
- return guest.PerformStart(ctx, userCred, query, api.GuestPerformStartInput{})
- }
- params := jsonutils.NewDict()
- params.Set("force_reboot", jsonutils.NewBool(false))
- params.Set("action", jsonutils.NewString("start"))
- return hh.PerformMaintenance(ctx, userCred, nil, params)
- }
- func (hh *SHost) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject,
- data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if hh.GetEnabled() {
- return nil, httperrors.NewInvalidStatusError("Host is not disabled")
- }
- return nil, hh.purge(ctx, userCred)
- }
- func (hh *SHost) PerformStop(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject,
- data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if !hh.IsBaremetal {
- return nil, httperrors.NewBadRequestError("Cannot stop a non-baremetal host")
- }
- if !utils.IsInStringArray(hh.Status, []string{api.BAREMETAL_RUNNING}) {
- return nil, httperrors.NewInvalidStatusError("Cannot stop baremetal with non-active guest")
- }
- guest := hh.GetBaremetalServer()
- if guest != nil {
- if hh.HostType != api.HOST_TYPE_BAREMETAL {
- if !utils.IsInStringArray(guest.Status, []string{api.VM_ADMIN}) {
- return nil, httperrors.NewBadRequestError("Cannot stop baremetal with active guest")
- }
- } else {
- if utils.ToBool(guest.GetMetadata(ctx, "is_fake_baremetal_server", userCred)) {
- return nil, hh.InitializedGuestStop(ctx, userCred, guest)
- }
- hh.SetStatus(ctx, userCred, api.BAREMETAL_START_MAINTAIN, "")
- input := api.ServerStopInput{}
- data.Unmarshal(&input)
- return guest.PerformStop(ctx, userCred, query, input)
- }
- }
- return nil, hh.StartBaremetalUnmaintenanceTask(ctx, userCred, false, "stop")
- }
- func (hh *SHost) InitializedGuestStart(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest) error {
- task, err := taskman.TaskManager.NewTask(ctx, "BaremetalServerStartTask", guest, userCred, nil, "", "", nil)
- if err != nil {
- return err
- }
- return task.ScheduleRun(nil)
- }
- func (hh *SHost) InitializedGuestStop(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest) error {
- task, err := taskman.TaskManager.NewTask(ctx, "BaremetalServerStopTask", guest, userCred, nil, "", "", nil)
- if err != nil {
- return err
- }
- task.ScheduleRun(nil)
- return nil
- }
- func (hh *SHost) PerformMaintenance(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if !utils.IsInStringArray(hh.Status, []string{api.BAREMETAL_READY, api.BAREMETAL_RUNNING}) {
- return nil, httperrors.NewInvalidStatusError("Cannot do maintenance in status %s", hh.Status)
- }
- guest := hh.GetBaremetalServer()
- if guest != nil && !utils.IsInStringArray(guest.Status, []string{api.VM_READY, api.VM_RUNNING, api.VM_ADMIN}) {
- return nil, httperrors.NewInvalidStatusError("Cannot do maintenance while guest status %s", guest.Status)
- }
- params := jsonutils.NewDict()
- if guest != nil {
- if guest.Status == api.VM_RUNNING {
- params.Set("guest_running", jsonutils.NewBool(true))
- }
- guest.SetStatus(ctx, userCred, api.VM_ADMIN, "")
- }
- if hh.Status == api.BAREMETAL_RUNNING && jsonutils.QueryBoolean(data, "force_reboot", false) {
- params.Set("force_reboot", jsonutils.NewBool(true))
- }
- action := "maintenance"
- if data.Contains("action") {
- action, _ = data.GetString("action")
- }
- params.Set("action", jsonutils.NewString(action))
- hh.SetStatus(ctx, userCred, api.BAREMETAL_START_MAINTAIN, "")
- task, err := taskman.TaskManager.NewTask(ctx, "BaremetalMaintenanceTask", hh, userCred, params, "", "", nil)
- if err != nil {
- return nil, err
- }
- return nil, task.ScheduleRun(nil)
- }
- func (hh *SHost) PerformUnmaintenance(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if !utils.IsInStringArray(hh.Status, []string{api.BAREMETAL_RUNNING, api.BAREMETAL_READY}) {
- return nil, httperrors.NewInvalidStatusError("Cannot do unmaintenance in status %s", hh.Status)
- }
- guest := hh.GetBaremetalServer()
- if guest != nil && guest.Status != api.VM_ADMIN {
- return nil, httperrors.NewInvalidStatusError("Wrong guest status %s", guest.Status)
- }
- action, _ := data.GetString("action")
- if len(action) == 0 {
- action = "unmaintenance"
- }
- guestRunning := hh.GetMetadata(ctx, "__maint_guest_running", userCred)
- var startGuest = false
- if utils.ToBool(guestRunning) {
- startGuest = true
- }
- return nil, hh.StartBaremetalUnmaintenanceTask(ctx, userCred, startGuest, action)
- }
- func (hh *SHost) StartBaremetalUnmaintenanceTask(ctx context.Context, userCred mcclient.TokenCredential, startGuest bool, action string) error {
- hh.SetStatus(ctx, userCred, api.BAREMETAL_START_MAINTAIN, "")
- params := jsonutils.NewDict()
- params.Set("guest_running", jsonutils.NewBool(startGuest))
- if len(action) == 0 {
- action = "unmaintenance"
- }
- params.Set("action", jsonutils.NewString(action))
- task, err := taskman.TaskManager.NewTask(ctx, "BaremetalUnmaintenanceTask", hh, userCred, params, "", "", nil)
- if err != nil {
- return err
- }
- task.ScheduleRun(nil)
- return nil
- }
- func (hh *SHost) StartSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- guest := hh.GetBaremetalServer()
- if guest != nil {
- return guest.StartSyncstatus(ctx, userCred, parentTaskId)
- }
- task, err := taskman.TaskManager.NewTask(ctx, "BaremetalSyncStatusTask", hh, userCred, nil, parentTaskId, "", nil)
- if err != nil {
- return errors.Wrapf(err, "NewTask")
- }
- return task.ScheduleRun(nil)
- }
- func (hh *SHost) PerformOffline(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input *api.HostOfflineInput) (jsonutils.JSONObject, error) {
- if hh.HostStatus != api.HOST_OFFLINE {
- _, err := hh.SaveUpdates(func() error {
- hh.HostStatus = api.HOST_OFFLINE
- if input.UpdateHealthStatus != nil && *input.UpdateHealthStatus {
- hh.EnableHealthCheck = false
- }
- // Note: update host status to unknown on host offline
- // we did not have host status after host offline
- hh.Status = api.BAREMETAL_UNKNOWN
- return nil
- })
- if err != nil {
- return nil, err
- }
- db.OpsLog.LogEvent(hh, db.ACT_OFFLINE, input.Reason, userCred)
- logclient.AddActionLogWithContext(ctx, hh, logclient.ACT_OFFLINE, input, userCred, true)
- ndata := jsonutils.Marshal(hh).(*jsonutils.JSONDict)
- if len(input.Reason) > 0 {
- ndata.Add(jsonutils.NewString(input.Reason), "reason")
- }
- notifyclient.SystemExceptionNotify(ctx, napi.ActionOffline, HostManager.Keyword(), ndata)
- hh.SyncAttachedStorageStatus(ctx)
- }
- return nil, nil
- }
- func (hh *SHost) PerformOnline(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if hh.HostStatus != api.HOST_ONLINE {
- _, err := hh.SaveUpdates(func() error {
- hh.LastPingAt = time.Now()
- hh.HostStatus = api.HOST_ONLINE
- hh.EnableHealthCheck = true
- if !hh.IsMaintaining() {
- hh.Status = api.BAREMETAL_RUNNING
- }
- return nil
- })
- if err != nil {
- return nil, err
- }
- if hostHealthChecker != nil {
- hostHealthChecker.WatchHost(context.Background(), hh.GetHostnameByName())
- }
- db.OpsLog.LogEvent(hh, db.ACT_ONLINE, "", userCred)
- logclient.AddActionLogWithContext(ctx, hh, logclient.ACT_ONLINE, data, userCred, true)
- hh.SyncAttachedStorageStatus(ctx)
- hh.StartUploadAllGuestsStatusTask(ctx, userCred)
- }
- return nil, nil
- }
- func (hh *SHost) PerformRestartHostAgent(
- ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject,
- ) (jsonutils.JSONObject, error) {
- _, err := hh.Request(ctx, userCred, "POST", fmt.Sprintf("/hosts/%s/restart-host-agent", hh.Id),
- mcclient.GetTokenHeaders(userCred), data)
- if err != nil {
- return nil, err
- }
- return nil, nil
- }
- func (hh *SHost) PerformAutoMigrateOnHostDown(
- ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.HostAutoMigrateInput,
- ) (jsonutils.JSONObject, error) {
- if input.AutoMigrateOnHostShutdown == "enable" &&
- input.AutoMigrateOnHostDown != "enable" {
- return nil, httperrors.NewBadRequestError("must enable auto_migrate_on_host_down at same time")
- }
- var meta = make(map[string]interface{})
- if input.AutoMigrateOnHostShutdown == "enable" {
- meta[api.HOSTMETA_AUTO_MIGRATE_ON_HOST_SHUTDOWN] = "enable"
- } else if input.AutoMigrateOnHostShutdown == "disable" {
- meta[api.HOSTMETA_AUTO_MIGRATE_ON_HOST_SHUTDOWN] = "disable"
- }
- data := jsonutils.NewDict()
- if input.AutoMigrateOnHostDown == "enable" {
- data.Set("shutdown_servers", jsonutils.JSONTrue)
- meta[api.HOSTMETA_AUTO_MIGRATE_ON_HOST_DOWN] = "enable"
- } else if input.AutoMigrateOnHostDown == "disable" {
- meta[api.HOSTMETA_AUTO_MIGRATE_ON_HOST_DOWN] = "disable"
- data.Set("shutdown_servers", jsonutils.JSONFalse)
- }
- _, err := hh.Request(ctx, userCred, "POST", fmt.Sprintf("/hosts/%s/shutdown-servers-on-host-down", hh.Id),
- mcclient.GetTokenHeaders(userCred), data)
- if err != nil {
- return nil, err
- }
- logclient.AddActionLogWithContext(ctx, hh, logclient.ACT_AUTO_MIGRATE_ON_HOST_DOWN, nil, userCred, true)
- return nil, hh.SetAllMetadata(ctx, meta, userCred)
- }
- func (hh *SHost) StartUploadAllGuestsStatusTask(ctx context.Context, userCred mcclient.TokenCredential) error {
- if task, err := taskman.TaskManager.NewTask(ctx, "BaremetalUploadAllGuestsStatusTask", hh, userCred, nil, "", "", nil); err != nil {
- log.Errorln(err)
- return err
- } else {
- task.ScheduleRun(nil)
- return nil
- }
- }
- func (hh *SHost) GetStoragesByMasterHost() ([]string, error) {
- sq := StorageManager.Query()
- sq = sq.In("storage_type", api.SHARED_STORAGE)
- sq = sq.Filter(sqlchemy.OR(sqlchemy.Equals(sq.Field("master_host"), hh.Id), sqlchemy.IsNullOrEmpty(sq.Field("master_host"))))
- subq := sq.SubQuery()
- hsq := HoststorageManager.Query().Equals("host_id", hh.Id)
- hsq = hsq.Join(subq, sqlchemy.Equals(subq.Field("id"), hsq.Field("storage_id")))
- hostStorages := make([]SHoststorage, 0)
- if err := hsq.All(&hostStorages); err != nil && err != sql.ErrNoRows {
- return nil, errors.Wrap(err, "get hostStorages")
- } else if err == sql.ErrNoRows {
- return nil, nil
- }
- storages := make([]string, len(hostStorages))
- for i := range storages {
- storages[i] = hostStorages[i].StorageId
- }
- return storages, nil
- }
- func (hh *SHost) PerformReportDmesg(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SHostReportDmesgInput) (jsonutils.JSONObject, error) {
- for i := range input.Entries {
- logLevel := db.LogLevelToString(input.Entries[i].Level)
- HostDmesgLogManager.LogDmesg(ctx, hh, logLevel, input.Entries[i].Time, input.Entries[i].Message, userCred)
- }
- return nil, nil
- }
- func (hh *SHost) PerformPing(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.SHostPingInput) (jsonutils.JSONObject, error) {
- if hh.HostType == api.HOST_TYPE_BAREMETAL {
- return nil, httperrors.NewNotSupportedError("ping host type %s not support", hh.HostType)
- }
- if input.WithData {
- // piggyback storage stats info
- log.Debugf("host ping %#v", input)
- for _, si := range input.StorageStats {
- storageObj, err := StorageManager.FetchById(si.StorageId)
- if err != nil {
- log.Errorf("fetch storage %s error %s", si.StorageId, err)
- } else {
- storage := storageObj.(*SStorage)
- _, err := db.Update(storage, func() error {
- storage.Capacity = si.CapacityMb
- storage.ActualCapacityUsed = si.ActualCapacityUsedMb
- return nil
- })
- if err != nil {
- log.Errorf("update storage info error %s", err)
- }
- }
- }
- if len(hh.ManagerId) == 0 {
- guests, _ := hh.GetGuests()
- for _, guest := range guests {
- if utils.IsInStringArray(guest.Id, input.QgaRunningGuestIds) {
- if guest.QgaStatus != api.QGA_STATUS_AVAILABLE {
- guest.UpdateQgaStatus(api.QGA_STATUS_AVAILABLE)
- }
- } else {
- if guest.QgaStatus != api.QGA_STATUS_UNKNOWN {
- guest.UpdateQgaStatus(api.QGA_STATUS_UNKNOWN)
- }
- }
- }
- }
- }
- hh.SaveUpdates(func() error {
- if hh.HostStatus == api.HOST_ONLINE {
- hh.LastPingAt = time.Now()
- }
- if input.WithData {
- if input.RootPartitionUsedCapacityMb > 0 {
- hh.RootPartitionUsedCapacityMb = input.RootPartitionUsedCapacityMb
- }
- if input.MemoryUsedMb > 0 {
- hh.MemoryUsedMb = input.MemoryUsedMb
- }
- if input.CpuUsagePercent > 0 {
- hh.CpuUsagePercent = input.CpuUsagePercent
- }
- }
- return nil
- })
- if hh.HostStatus != api.HOST_ONLINE {
- hh.PerformOnline(ctx, userCred, query, nil)
- } else {
- if hh.hasUnknownGuests() && len(hh.ManagerId) == 0 {
- hh.StartUploadAllGuestsStatusTask(ctx, userCred)
- }
- }
- if len(hh.ManagerId) > 0 {
- return nil, nil
- }
- result := jsonutils.NewDict()
- result.Set("name", jsonutils.NewString(hh.GetName()))
- dependSvcs := []string{"ntpd", "kafka", apis.SERVICE_TYPE_INFLUXDB, apis.SERVICE_TYPE_VICTORIA_METRICS, "elasticsearch", "opentsdb"}
- catalog := auth.GetCatalogData(dependSvcs, options.Options.Region)
- if catalog == nil {
- return nil, errors.Wrap(errors.ErrServer, "Get catalog error")
- }
- result.Set("catalog", catalog)
- if storages, err := hh.GetStoragesByMasterHost(); err != nil {
- return nil, errors.Wrap(err, "get storages by master host")
- } else {
- result.Set("master_host_storages", jsonutils.NewStringArray(storages))
- }
- hostFiles, err := hh.getHostFiles()
- if err != nil {
- return nil, errors.Wrap(err, "get host files")
- }
- result.Set("host_files", jsonutils.Marshal(hostFiles))
- appParams := appsrv.AppContextGetParams(ctx)
- if appParams != nil {
- // skip log&trace, when everything is normal
- appParams.SkipTrace = true
- appParams.SkipLog = true
- }
- return result, nil
- }
- func (host *SHost) getHostNodeReservePercent(reservedCpusStr string) (map[string]float32, error) {
- reservedCpuset, err := cpuset.Parse(reservedCpusStr)
- if err != nil {
- return nil, errors.Wrap(err, "cpuset parse reserved cpus")
- }
- topoObj, err := host.SysInfo.Get("topology")
- if err != nil {
- return nil, errors.Wrap(err, "get topology from host sys_info")
- }
- info := new(hostapi.HostTopology)
- if err := topoObj.Unmarshal(info); err != nil {
- return nil, errors.Wrap(err, "Unmarshal host topology struct")
- }
- nodecpus := map[int]int{}
- nodeReservedCpus := map[int]int{}
- for i := range info.Nodes {
- cSet := cpuset.NewBuilder()
- for j := 0; j < len(info.Nodes[i].Cores); j++ {
- for k := 0; k < len(info.Nodes[i].Cores[j].LogicalProcessors); k++ {
- if reservedCpuset.Contains(info.Nodes[i].Cores[j].LogicalProcessors[k]) {
- if cnt, ok := nodeReservedCpus[info.Nodes[i].ID]; !ok {
- nodeReservedCpus[info.Nodes[i].ID] = 1
- } else {
- nodeReservedCpus[info.Nodes[i].ID] = 1 + cnt
- }
- }
- cSet.Add(info.Nodes[i].Cores[j].LogicalProcessors[k])
- }
- }
- nodecpus[info.Nodes[i].ID] = cSet.Result().Size()
- }
- reserveRate := map[string]float32{}
- for nodeId, cnt := range nodecpus {
- reserveCnt, ok := nodeReservedCpus[nodeId]
- if !ok {
- reserveCnt = 0
- }
- reserveRate[strconv.Itoa(nodeId)] = float32(reserveCnt) / float32(cnt)
- }
- return reserveRate, nil
- }
- func (host *SHost) getHostLogicalCores() ([]int, error) {
- cpuObj, err := host.SysInfo.Get("cpu_info")
- if err != nil {
- return nil, errors.Wrap(err, "get cpu info from host sys_info")
- }
- cpuInfo := new(hostapi.HostCPUInfo)
- if err := cpuObj.Unmarshal(cpuInfo); err != nil {
- return nil, errors.Wrap(err, "Unmarshal host cpu info struct")
- }
- // get host logical cores
- allCores := []int{}
- if len(cpuInfo.Processors) != 0 {
- for _, p := range cpuInfo.Processors {
- for _, core := range p.Cores {
- allCores = append(allCores, core.LogicalProcessors...)
- }
- }
- sort.Ints(allCores)
- } else {
- topoObj, err := host.SysInfo.Get("topology")
- if err != nil {
- return nil, errors.Wrap(err, "get topology from host sys_info")
- }
- hostTopo := new(hostapi.HostTopology)
- if err := topoObj.Unmarshal(hostTopo); err != nil {
- return nil, errors.Wrap(err, "Unmarshal host topology struct")
- }
- for _, node := range hostTopo.Nodes {
- for _, cores := range node.Cores {
- allCores = append(allCores, cores.LogicalProcessors...)
- }
- }
- }
- return allCores, nil
- }
- func (hh *SHost) PerformUnreserveCpus(
- ctx context.Context, userCred mcclient.TokenCredential,
- query jsonutils.JSONObject, data jsonutils.JSONObject,
- ) (jsonutils.JSONObject, error) {
- return nil, hh.RemoveMetadata(ctx, api.HOSTMETA_RESERVED_CPUS_INFO, userCred)
- }
- func (hh *SHost) PerformReserveCpus(
- ctx context.Context, userCred mcclient.TokenCredential,
- query jsonutils.JSONObject, input api.HostReserveCpusInput,
- ) (jsonutils.JSONObject, error) {
- if !utils.IsInStringArray(hh.HostType, []string{api.HOST_TYPE_HYPERVISOR, api.HOST_TYPE_CONTAINER}) {
- return nil, httperrors.NewNotSupportedError("host type %s not support reserve cpus", hh.HostType)
- }
- if input.Cpus == "" {
- return nil, httperrors.NewInputParameterError("missing cpus")
- }
- cs, err := cpuset.Parse(input.Cpus)
- if err != nil {
- return nil, httperrors.NewInputParameterError("cpus %s not valid", input.Cpus)
- }
- allCores, err := hh.getHostLogicalCores()
- if err != nil {
- return nil, err
- }
- hSets := sets.NewInt(allCores...)
- cSlice := cs.ToSlice()
- if !hSets.HasAll(cSlice...) {
- return nil, httperrors.NewInputParameterError("Host cores not contains input %v", input.Cpus)
- }
- if hSets.Len() == len(cSlice) {
- return nil, httperrors.NewInputParameterError("Can't reserve host all cpus")
- }
- pinnedCores, err := hh.GetPinnedCpusetCores(ctx, userCred, nil)
- if err != nil {
- return nil, err
- }
- if pinnedCores != nil {
- if cs.Union(*pinnedCores).Size() != (cs.Size() + pinnedCores.Size()) {
- return nil, httperrors.NewBadRequestError("request cpus confilct with guest pinned cpus")
- }
- }
- if input.Mems != "" {
- mems, err := cpuset.Parse(input.Mems)
- if err != nil {
- return nil, httperrors.NewInputParameterError("mems %s not valid", input.Mems)
- }
- // to slice will sort slice default
- memSlice := mems.ToSlice()
- if 0 > memSlice[len(memSlice)-1] || memSlice[len(memSlice)-1] >= int(hh.NodeCount) {
- return nil, httperrors.NewInputParameterError("mems %s out of range", input.Mems)
- }
- }
- if len(input.Cpus) > 0 {
- reservePercent, err := hh.getHostNodeReservePercent(input.Cpus)
- if err != nil {
- return nil, errors.Errorf("failed getHostNodeReservePercent: %s", err)
- }
- err = hh.SetMetadata(ctx, api.HOSTMETA_RESERVED_CPUS_RATE, reservePercent, userCred)
- if err != nil {
- return nil, err
- }
- } else {
- err = hh.RemoveMetadata(ctx, api.HOSTMETA_RESERVED_CPUS_RATE, userCred)
- if err != nil {
- return nil, err
- }
- }
- err = hh.SetMetadata(ctx, api.HOSTMETA_RESERVED_CPUS_INFO, input, userCred)
- if err != nil {
- return nil, err
- }
- if err = hh.updateHostReservedCpus(ctx, userCred); err != nil {
- return nil, errors.Wrap(err, "update host reserved cpus")
- }
- return nil, err
- }
- func (hh *SHost) HasBMC() bool {
- ipmiInfo, _ := hh.GetIpmiInfo()
- if ipmiInfo.Username != "" && ipmiInfo.Password != "" {
- return true
- }
- return false
- }
- func (hh *SHost) IsUEFIBoot() bool {
- info, _ := hh.GetUEFIInfo()
- if info == nil {
- return false
- }
- if len(info.PxeBootNum) == 0 {
- return false
- }
- return true
- }
- func (hh *SHost) isRedfishCapable() bool {
- ipmiInfo, _ := hh.GetIpmiInfo()
- if ipmiInfo.Verified && ipmiInfo.RedfishApi {
- return true
- }
- return false
- }
- func (hh *SHost) canPrepare() error {
- if !hh.isRedfishCapable() && len(hh.AccessMac) == 0 && len(hh.Uuid) == 0 {
- return httperrors.NewInvalidStatusError("need valid access_mac and uuid to do prepare")
- }
- if !utils.IsInStringArray(hh.Status, []string{api.BAREMETAL_READY, api.BAREMETAL_RUNNING, api.BAREMETAL_PREPARE_FAIL}) {
- return httperrors.NewInvalidStatusError("Cannot prepare baremetal in status %s", hh.Status)
- }
- return nil
- }
- func (hh *SHost) PerformPrepare(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if !hh.IsBaremetal {
- return nil, httperrors.NewInvalidStatusError("not a baremetal")
- }
- server := hh.GetBaremetalServer()
- if server != nil && server.Status != api.VM_ADMIN {
- return nil, httperrors.NewInvalidStatusError("Cannot prepare baremetal in server status %s", server.Status)
- }
- err := hh.canPrepare()
- if err != nil {
- return nil, err
- }
- var onfinish string
- if server != nil && hh.Status == api.BAREMETAL_READY {
- onfinish = "shutdown"
- }
- return nil, hh.StartPrepareTask(ctx, userCred, onfinish, "")
- }
- func (hh *SHost) StartPrepareTask(ctx context.Context, userCred mcclient.TokenCredential, onfinish, parentTaskId string) error {
- data := jsonutils.NewDict()
- if len(onfinish) > 0 {
- data.Set("on_finish", jsonutils.NewString(onfinish))
- }
- hh.SetStatus(ctx, userCred, api.BAREMETAL_PREPARE, "start prepare task")
- if task, err := taskman.TaskManager.NewTask(ctx, "BaremetalPrepareTask", hh, userCred, data, parentTaskId, "", nil); err != nil {
- log.Errorln(err)
- return err
- } else {
- task.ScheduleRun(nil)
- return nil
- }
- }
- func (hh *SHost) PerformIpmiProbe(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if utils.IsInStringArray(hh.Status, []string{api.BAREMETAL_INIT, api.BAREMETAL_READY, api.BAREMETAL_RUNNING, api.BAREMETAL_PROBE_FAIL, api.BAREMETAL_UNKNOWN}) {
- return nil, hh.StartIpmiProbeTask(ctx, userCred, "")
- }
- return nil, httperrors.NewInvalidStatusError("Cannot do Ipmi-probe in status %s", hh.Status)
- }
- func (hh *SHost) StartIpmiProbeTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- data := jsonutils.NewDict()
- hh.SetStatus(ctx, userCred, api.BAREMETAL_START_PROBE, "start ipmi-probe task")
- if task, err := taskman.TaskManager.NewTask(ctx, "BaremetalIpmiProbeTask", hh, userCred, data, parentTaskId, "", nil); err != nil {
- log.Errorln(err)
- return err
- } else {
- task.ScheduleRun(nil)
- return nil
- }
- }
- func (hm *SHostManager) PerformValidateIpmi(ctx context.Context, userCred mcclient.TokenCredential, _ jsonutils.JSONObject, input *baremetalapi.ValidateIPMIRequest) (*baremetalapi.ValidateIPMIResponse, error) {
- resp, err := hm.BaremetalSyncRequest(ctx, "POST", "/baremetals/validate-ipmi", mcclient.GetTokenHeaders(userCred), jsonutils.Marshal(input).(*jsonutils.JSONDict), "")
- if err != nil {
- return nil, err
- }
- out := new(baremetalapi.ValidateIPMIResponse)
- resp.Unmarshal(out)
- return out, nil
- }
- func (hh *SHost) PerformInitialize(
- ctx context.Context, userCred mcclient.TokenCredential,
- query jsonutils.JSONObject, data jsonutils.JSONObject,
- ) (jsonutils.JSONObject, error) {
- if !utils.IsInStringArray(
- hh.Status, []string{api.BAREMETAL_INIT, api.BAREMETAL_PREPARE_FAIL}) {
- return nil, httperrors.NewBadRequestError(
- "Cannot do initialization in status %s", hh.Status)
- }
- name, err := data.GetString("name")
- if err != nil || hh.GetBaremetalServer() != nil {
- return nil, nil
- }
- err = db.NewNameValidator(ctx, GuestManager, userCred, name, nil)
- if err != nil {
- return nil, err
- }
- if hh.IpmiInfo == nil || !hh.IpmiInfo.Contains("ip_addr") ||
- !hh.IpmiInfo.Contains("password") {
- return nil, httperrors.NewBadRequestError("IPMI infomation not configured")
- }
- guest := &SGuest{}
- guest.Name = name
- guest.VmemSize = hh.MemSize
- guest.VcpuCount = hh.CpuCount
- guest.DisableDelete = tristate.True
- guest.Hypervisor = api.HYPERVISOR_BAREMETAL
- guest.HostId = hh.Id
- guest.ProjectId = userCred.GetProjectId()
- guest.DomainId = userCred.GetProjectDomainId()
- guest.Status = api.VM_RUNNING
- guest.PowerStates = api.VM_POWER_STATES_ON
- guest.OsType = "Linux"
- guest.SetModelManager(GuestManager, guest)
- err = GuestManager.TableSpec().Insert(ctx, guest)
- if err != nil {
- return nil, httperrors.NewInternalServerError("Guest Insert error: %s", err)
- }
- guest.SetAllMetadata(ctx, map[string]interface{}{
- "is_fake_baremetal_server": true, "host_ip": hh.AccessIp}, userCred)
- caps := hh.GetAttachedLocalStorageCapacity()
- diskConfig := &api.DiskConfig{SizeMb: int(caps.GetFree())}
- err = guest.CreateDisksOnHost(ctx, userCred, hh, []*api.DiskConfig{diskConfig}, nil, true, true, nil, nil, true)
- if err != nil {
- log.Errorf("Host perform initialize failed on create disk %s", err)
- }
- net, err := hh.getNetworkOfIPOnHost(ctx, hh.AccessIp)
- if err != nil {
- log.Errorf("host perfrom initialize failed fetch net of access ip %s", err)
- } else {
- if options.Options.BaremetalServerReuseHostIp {
- _, err = guest.attach2NetworkDesc(ctx, userCred, hh, &api.NetworkConfig{Network: net.Id}, nil, nil)
- if err != nil {
- log.Errorf("host perform initialize failed on attach network %s", err)
- }
- }
- }
- return nil, nil
- }
- func validateHostNetif(input api.HostNetifInput) (api.HostNetifInput, error) {
- mac := input.Mac
- if len(input.Mac) > 0 {
- mac = netutils.FormatMacAddr(input.Mac)
- }
- if len(mac) == 0 {
- return input, errors.Wrapf(httperrors.ErrInputParameter, "Invaild mac address %s", input.Mac)
- }
- input.Mac = mac
- vlan := input.VlanId
- if vlan == 0 {
- vlan = 1
- }
- if vlan < 0 || vlan > 4095 {
- return input, errors.Wrapf(httperrors.ErrInputParameter, "Invalid vlan_id %d", input.VlanId)
- }
- input.VlanId = vlan
- return input, nil
- }
- func (h *SHost) PerformAddNetif(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input api.HostAddNetifInput,
- ) (jsonutils.JSONObject, error) {
- log.Debugf("add_netif %s", jsonutils.Marshal(input))
- var err error
- input.HostNetifInput, err = validateHostNetif(input.HostNetifInput)
- if err != nil {
- return nil, errors.Wrap(err, "validateHostNetif")
- }
- mac := input.Mac
- vlan := input.VlanId
- wireId := input.WireId
- if len(input.WireId) > 0 {
- wireObj, err := WireManager.FetchByIdOrName(ctx, userCred, input.WireId)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotFoundError2(WireManager.Keyword(), input.WireId)
- } else {
- return nil, errors.Wrap(err, "FetchByIdOrName")
- }
- }
- wireId = wireObj.GetId()
- }
- ipAddr := input.IpAddr
- if len(ipAddr) > 0 && !regutils.MatchIP4Addr(ipAddr) {
- return nil, errors.Wrapf(httperrors.ErrInputParameter, "invalid ip_addr %s", ipAddr)
- }
- ip6Addr := input.Ip6Addr
- if len(ip6Addr) > 0 && !regutils.MatchIP6Addr(ip6Addr) {
- return nil, errors.Wrapf(httperrors.ErrInputParameter, "invalid ip6_addr %s", ip6Addr)
- }
- rate := input.Rate
- nicType := input.NicType
- index := input.Index
- linkUp := input.LinkUp
- mtu := input.Mtu
- reset := (input.Reset != nil && *input.Reset)
- netIf := input.Interface
- bridge := input.Bridge
- reserve := (input.Reserve != nil && *input.Reserve)
- requireDesignatedIp := (input.RequireDesignatedIp != nil && *input.RequireDesignatedIp)
- requireIpv6 := (input.RequireIpv6 != nil && *input.RequireIpv6)
- strictIpv6 := (input.StrictIpv6 != nil && *input.StrictIpv6)
- isLinkUp := tristate.None
- if linkUp != "" {
- if utils.ToBool(linkUp) {
- isLinkUp = tristate.True
- } else {
- isLinkUp = tristate.False
- }
- }
- err = h.addNetif(ctx, userCred, mac, vlan, wireId, ipAddr, ip6Addr, int(rate), nicType, index, isLinkUp,
- int16(mtu), reset, netIf, bridge, reserve, requireDesignatedIp, requireIpv6, strictIpv6)
- return nil, errors.Wrap(err, "addNetif")
- }
- func (h *SHost) addNetif(ctx context.Context, userCred mcclient.TokenCredential,
- mac string, vlanId int, wireId string, ipAddr string, ip6Addr string,
- rate int, nicType compute.TNicType, index int, linkUp tristate.TriState, mtu int16,
- reset bool, strInterface *string, strBridge *string,
- reserve bool, requireDesignatedIp bool, requireIpv6 bool, strictIpv6 bool,
- ) error {
- var sw *SWire
- if len(wireId) > 0 {
- iWire, err := WireManager.FetchById(wireId)
- if err != nil {
- if err == sql.ErrNoRows {
- return httperrors.NewResourceNotFoundError2(WireManager.Keyword(), wireId)
- } else {
- return httperrors.NewInternalServerError("find Wire %s error: %s", wireId, err)
- }
- }
- sw = iWire.(*SWire)
- if len(ipAddr) > 0 || len(ip6Addr) > 0 {
- var v4addr *netutils.IPV4Addr
- var v6addr *netutils.IPV6Addr
- if len(ipAddr) > 0 {
- iIpAddr, err := netutils.NewIPV4Addr(ipAddr)
- if err != nil {
- return httperrors.NewInputParameterError("invalid ipaddr %s", ipAddr)
- }
- v4addr = &iIpAddr
- }
- if len(ip6Addr) > 0 {
- iIp6Addr, err := netutils.NewIPV6Addr(ip6Addr)
- if err != nil {
- return httperrors.NewInputParameterError("invalid ip6addr %s", ip6Addr)
- }
- v6addr = &iIp6Addr
- }
- var v4net, v6net *SNetwork
- swNets, err := sw.getNetworks(ctx, userCred, userCred, NetworkManager.AllowScope(userCred))
- if err != nil {
- return httperrors.NewInputParameterError("no networks on wire %s", wireId)
- }
- for i := range swNets {
- if v4net == nil && v4addr != nil && swNets[i].IsAddressInRange(*v4addr) {
- v4net = &swNets[i]
- }
- if v6net == nil && v6addr != nil && swNets[i].IsAddress6InRange(*v6addr) {
- v6net = &swNets[i]
- }
- if v4net != nil && v6net != nil {
- break
- }
- }
- if v4net == nil && v6net == nil {
- var addrs []string
- if len(ipAddr) > 0 {
- addrs = append(addrs, ipAddr)
- }
- if len(ip6Addr) > 0 {
- addrs = append(addrs, ip6Addr)
- }
- return httperrors.NewBadRequestError("IP %s not attach to wire %s", strings.Join(addrs, ","), wireId)
- }
- if v4net != nil && v6net != nil && v4net.Id != v6net.Id {
- return httperrors.NewConflictError("IPv4 %s and IPv6 %s must be on the same network", ipAddr, ip6Addr)
- }
- }
- } else {
- var v4wire, v6wire *SWire
- if len(ipAddr) > 0 {
- ipWire, err := WireManager.GetOnPremiseWireOfIp(ipAddr)
- if err != nil {
- return httperrors.NewBadRequestError("IP %s not attach to any wire", ipAddr)
- }
- v4wire = ipWire
- }
- if len(ip6Addr) > 0 {
- ipWire, err := WireManager.GetOnPremiseWireOfIp6(ip6Addr)
- if err != nil {
- return httperrors.NewBadRequestError("IPv6 %s not attach to any wire", ip6Addr)
- }
- v6wire = ipWire
- }
- if v4wire != nil && v6wire != nil && v4wire.Id != v6wire.Id {
- return httperrors.NewConflictError("IPv4 %s and IPv6 %s must be on the same wire", ipAddr, ip6Addr)
- }
- if v4wire != nil {
- sw = v4wire
- } else if v6wire != nil {
- sw = v6wire
- }
- }
- netif, err := NetInterfaceManager.FetchByMacVlan(mac, vlanId)
- if err != nil {
- if errors.Cause(err) != sql.ErrNoRows {
- return httperrors.NewInternalServerError("fail to fetch netif by mac %s: %s", mac, err)
- }
- // else not found
- netif = &SNetInterface{}
- netif.SetModelManager(NetInterfaceManager, netif)
- netif.Mac = mac
- netif.VlanId = vlanId
- }
- var changed bool
- if netif.BaremetalId != h.Id {
- if len(netif.BaremetalId) > 0 {
- changed = true
- // previously conencted to another host
- }
- netif.BaremetalId = h.Id
- }
- if sw != nil && netif.WireId != sw.Id {
- if len(netif.WireId) > 0 {
- changed = true
- }
- netif.WireId = sw.Id
- } else if netif.WireId != "" && sw == nil {
- changed = true
- netif.WireId = ""
- }
- if rate > 0 && rate != netif.Rate {
- netif.Rate = rate
- }
- if nicType != "" && nicType != netif.NicType {
- netif.NicType = nicType
- }
- if index >= 0 {
- netif.Index = index
- }
- if !linkUp.IsNone() && linkUp.Bool() != netif.LinkUp {
- netif.LinkUp = linkUp.Bool()
- }
- if mtu > 0 && mtu != netif.Mtu {
- netif.Mtu = mtu
- }
- if strInterface != nil {
- netif.Interface = *strInterface
- }
- if strBridge != nil {
- netif.Bridge = *strBridge
- }
- // ensure index is unique on host
- {
- ifs := h.GetHostNetInterfaces()
- dupIdx := false
- var maxIdx int
- for i := range ifs {
- if ifs[i].Mac == netif.Mac && ifs[i].VlanId == netif.VlanId {
- // find self, skip
- continue
- }
- if netif.Index == ifs[i].Index {
- // duplicate nic index
- dupIdx = true
- }
- if maxIdx < ifs[i].Index {
- maxIdx = ifs[i].Index
- }
- }
- if dupIdx {
- netif.Index = maxIdx + 1
- }
- }
- err = NetInterfaceManager.TableSpec().InsertOrUpdate(ctx, netif)
- if err != nil {
- return errors.Wrap(err, "InsertOrUpdate")
- }
- if changed || reset {
- h.DisableNetif(ctx, userCred, netif, false)
- }
- if netif.NicType == api.NIC_TYPE_ADMIN {
- oldadmins := h.GetAdminNetInterfaces()
- for i := range oldadmins {
- oldNetif := oldadmins[i]
- if oldNetif.Mac != netif.Mac || oldNetif.VlanId != netif.VlanId {
- // make normal netif
- err := oldNetif.setNicType(api.NIC_TYPE_NORMAL)
- if err != nil {
- return errors.Wrapf(err, "setNicType %s", oldNetif.String())
- }
- }
- }
- err := h.setAccessMac(userCred, netif.Mac)
- if err != nil {
- return errors.Wrap(err, "setAccessMac")
- }
- // inherit wire's class metadata
- sw = netif.GetWire()
- if sw != nil {
- err := db.InheritFromTo(ctx, userCred, sw, h)
- if err != nil {
- return errors.Wrapf(err, "unable to inherit class metadata from sw %s", sw.GetName())
- }
- }
- }
- if len(ipAddr) > 0 || len(ip6Addr) > 0 {
- err = h.EnableNetif(ctx, userCred, netif, "", ipAddr, ip6Addr, "", "", reserve, requireDesignatedIp, requireIpv6, strictIpv6)
- if err != nil {
- return httperrors.NewBadRequestError("%v", err)
- }
- }
- h.ClearSchedDescCache()
- return nil
- }
- func (h *SHost) PerformEnableNetif(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input api.HostEnableNetifInput,
- ) (jsonutils.JSONObject, error) {
- log.Debugf("enable_netif %s", jsonutils.Marshal(input))
- var err error
- input.HostNetifInput, err = validateHostNetif(input.HostNetifInput)
- if err != nil {
- return nil, errors.Wrap(err, "validateHostNetif")
- }
- netif := h.GetNetInterface(input.Mac, input.VlanId)
- if netif == nil {
- return nil, httperrors.NewBadRequestError("Interface %s(vlan:%d) not exist", input.Mac, input.VlanId)
- }
- // if netif.NicType ! !utils.IsInArray(netif.NicType, api.NIC_TYPES) {
- // return nil, httperrors.NewBadRequestError("Only ADMIN and IPMI nic can be enable")
- // }
- reserve := (input.Reserve != nil && *input.Reserve)
- requireDesignatedIp := (input.RequireDesignatedIp != nil && *input.RequireDesignatedIp)
- requireIpv6 := (input.RequireIpv6 != nil && *input.RequireIpv6)
- strictIpv6 := (input.StrictIpv6 != nil && *input.StrictIpv6)
- err = h.EnableNetif(ctx, userCred, netif, input.NetworkId, input.IpAddr, input.Ip6Addr, input.AllocDir, input.NetType, reserve, requireDesignatedIp, requireIpv6, strictIpv6)
- if err != nil {
- return nil, httperrors.NewBadRequestError("%v", err)
- }
- return nil, nil
- }
- func (h *SHost) EnableNetif(ctx context.Context, userCred mcclient.TokenCredential, netif *SNetInterface,
- network, ipAddr, ip6Addr, allocDir string, netType api.TNetworkType, reserve, requireDesignatedIp bool,
- requireIpv6 bool, strictIpv6 bool) error {
- // bn := netif.GetHostNetwork()
- // if bn != nil {
- // log.Debugf("Netif has been attach2network? %s", jsonutils.Marshal(bn))
- // return nil
- // }
- var v4net, v6net *SNetwork
- var err error
- if len(ipAddr) > 0 && !strictIpv6 {
- net, err := netif.GetCandidateNetworkForIp(ctx, userCred, userCred, NetworkManager.AllowScope(userCred), ipAddr)
- if net != nil {
- log.Infof("find network %s for ip4 %s", net.GetName(), ipAddr)
- v4net = net
- } else if requireDesignatedIp {
- log.Errorf("Cannot allocate IP %s, not reachable: %s", ipAddr, err)
- return fmt.Errorf("Cannot allocate IP %s, not reachable: %s", ipAddr, err)
- } else {
- log.Infof("not found network with scope: %s, ip_addr: %s, err: %s", NetworkManager.AllowScope(userCred), ipAddr, err)
- // the ipaddr is not usable, should be reset to empty
- ipAddr = ""
- }
- }
- if len(ip6Addr) > 0 {
- if v4net != nil {
- ip6, err := netutils.NewIPV6Addr(ip6Addr)
- if err != nil {
- return errors.Wrapf(err, "netutils.NewIPV6Addr: %s", ip6Addr)
- }
- if v4net.IsAddress6InRange(ip6) {
- v6net = v4net
- }
- } else {
- net, err := netif.GetCandidateNetworkForIp6(ctx, userCred, userCred, NetworkManager.AllowScope(userCred), ip6Addr)
- if net != nil {
- log.Infof("find network %s for ip %s", net.GetName(), ip6Addr)
- v6net = net
- } else if requireIpv6 {
- log.Errorf("Cannot allocate IPv6 %s, not reachable: %s", ip6Addr, err)
- return fmt.Errorf("Cannot allocate IPv6 %s, not reachable: %s", ip6Addr, err)
- } else {
- log.Infof("not found network with scope: %s, ip6_addr: %s, err: %s", NetworkManager.AllowScope(userCred), ip6Addr, err)
- // the ipaddr is not usable, should be reset to empty
- ip6Addr = ""
- }
- }
- }
- var net *SNetwork
- if v4net != nil && v6net != nil {
- if v4net.Id != v6net.Id {
- return errors.Wrap(httperrors.ErrConflict, "v4net and v6net must be on the same network")
- }
- net = v4net
- } else if v6net != nil {
- net = v6net
- } else if v4net != nil {
- net = v4net
- }
- wire := netif.GetWire()
- if wire == nil {
- return fmt.Errorf("No wire attached")
- }
- if h.ZoneId == "" {
- if _, err := h.SaveUpdates(func() error {
- h.ZoneId = wire.ZoneId
- return nil
- }); err != nil {
- return errors.Wrapf(err, "set host zone_id %s by wire", wire.ZoneId)
- }
- }
- if net == nil {
- if len(network) > 0 {
- iNet, err := NetworkManager.FetchByIdOrName(ctx, userCred, network)
- if err != nil {
- return fmt.Errorf("Network %s not found: %s", network, err)
- }
- net = iNet.(*SNetwork)
- if len(net.WireId) == 0 || net.WireId != wire.Id {
- return fmt.Errorf("Network %s not reacheable on mac %s", network, netif.Mac)
- }
- } else {
- var netTypes []api.TNetworkType
- if len(netType) > 0 && netType != api.NETWORK_TYPE_BAREMETAL {
- netTypes = []api.TNetworkType{netType, api.NETWORK_TYPE_BAREMETAL}
- } else {
- netTypes = []api.TNetworkType{api.NETWORK_TYPE_BAREMETAL}
- }
- net, err = wire.GetCandidatePrivateNetwork(ctx, userCred, userCred, NetworkManager.AllowScope(userCred), false, netTypes)
- if err != nil {
- return fmt.Errorf("fail to find private network %s", err)
- }
- if net == nil {
- net, err = wire.GetCandidateAutoAllocNetwork(ctx, userCred, userCred, NetworkManager.AllowScope(userCred), false, netTypes)
- if err != nil {
- return fmt.Errorf("fail to find public network %s", err)
- }
- if net == nil {
- return fmt.Errorf("No auto_alloc network found of wire: %s(%s), netTypes: %v", wire.GetName(), wire.GetId(), netTypes)
- }
- }
- }
- } else if net.WireId != wire.Id {
- return fmt.Errorf("conflict??? candiate net is not on wire")
- }
- attachOpt := &hostAttachNetworkOption{
- netif: netif,
- net: net,
- ipAddr: ipAddr,
- allocDir: allocDir,
- reserved: reserve,
- requireDesignatedIp: requireDesignatedIp,
- ip6Addr: ip6Addr,
- requireIpv6: requireIpv6,
- strictIpv6: strictIpv6,
- }
- bn, err := h.attach2Network(ctx, userCred, attachOpt)
- if err != nil {
- return errors.Wrap(err, "hh.Attach2Network")
- }
- bnIP := bn.IpAddr
- if len(bnIP) == 0 {
- bnIP = bn.Ip6Addr
- }
- switch netif.NicType {
- case api.NIC_TYPE_IPMI:
- err = h.setIpmiIp(userCred, bnIP)
- if err != nil {
- return errors.Wrap(err, "setIpmiIp")
- }
- case api.NIC_TYPE_ADMIN:
- err = h.setAccessIp(userCred, bnIP)
- if err != nil {
- return errors.Wrap(err, "setAccessIp")
- }
- }
- return nil
- }
- func (hh *SHost) PerformDisableNetif(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input api.HostDisableNetifInput,
- ) (jsonutils.JSONObject, error) {
- var err error
- input.HostNetifInput, err = validateHostNetif(input.HostNetifInput)
- if err != nil {
- return nil, errors.Wrap(err, "validateHostNetif")
- }
- netif := hh.GetNetInterface(input.Mac, input.VlanId)
- if netif == nil {
- return nil, httperrors.NewBadRequestError("Interface %s(vlan:%d) not exists", input.Mac, input.VlanId)
- }
- reserve := (input.Reserve != nil && *input.Reserve)
- err = hh.DisableNetif(ctx, userCred, netif, reserve)
- if err != nil {
- return nil, httperrors.NewBadRequestError("%v", err)
- }
- return nil, nil
- }
- /*
- * Disable a net interface, remove IP address if assigned
- */
- func (hh *SHost) DisableNetif(ctx context.Context, userCred mcclient.TokenCredential, netif *SNetInterface, reserve bool) error {
- bn := netif.GetHostNetwork()
- var ipAddr, ip6Addr string
- if bn != nil {
- ipAddr = bn.IpAddr
- ip6Addr = bn.Ip6Addr
- hh.UpdateDnsRecord(netif, false)
- hh.DeleteBaremetalnetwork(ctx, userCred, bn, reserve)
- }
- var err error
- switch netif.NicType {
- case api.NIC_TYPE_IPMI:
- if ipAddr == hh.IpmiIp || ip6Addr == hh.IpmiIp {
- err = hh.setIpmiIp(userCred, "")
- }
- case api.NIC_TYPE_ADMIN:
- if ipAddr == hh.AccessIp || ip6Addr == hh.AccessIp {
- err = hh.setAccessIp(userCred, "")
- }
- }
- return err
- }
- type hostAttachNetworkOption struct {
- netif *SNetInterface
- net *SNetwork
- ipAddr string
- allocDir string
- reserved bool
- requireDesignatedIp bool
- ip6Addr string
- requireIpv6 bool
- strictIpv6 bool
- }
- func (hh *SHost) IsIpAddrWithinConvertedGuest(ctx context.Context, userCred mcclient.TokenCredential, ipAddr, ip6Addr string, netif *SNetInterface) error {
- if !hh.IsBaremetal {
- return httperrors.NewNotAcceptableError("Not a baremetal")
- }
- // ?
- // if hh.HostType == api.HOST_TYPE_KVM {
- // return httperrors.NewNotAcceptableError("Not being convert to hypervisor")
- // }
- bmServer := hh.GetBaremetalServer()
- if bmServer == nil {
- return httperrors.NewNotAcceptableError("Not found baremetal server record")
- }
- guestNics, err := bmServer.GetNetworks("")
- if err != nil {
- return errors.Wrap(err, "Get guest networks")
- }
- var findNic *SGuestnetwork
- for idx := range guestNics {
- nic := guestNics[idx]
- if nic.MacAddr == netif.Mac {
- findNic = &nic
- break
- }
- }
- if findNic == nil {
- return httperrors.NewNotFoundError("Not found guest nic by mac %s", netif.Mac)
- }
- if len(ipAddr) > 0 && findNic.IpAddr != ipAddr {
- return httperrors.NewNotAcceptableError("Guest nic ip addr %s not equal %s", findNic.IpAddr, ipAddr)
- }
- if len(ip6Addr) > 0 && findNic.Ip6Addr != ip6Addr {
- return httperrors.NewNotAcceptableError("Guest nic ip addr6 %s not equal %s", findNic.Ip6Addr, ip6Addr)
- }
- return nil
- }
- func (hh *SHost) attach2Network(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- opt *hostAttachNetworkOption,
- ) (*SHostnetwork, error) {
- log.Infof("host attach2Network: %s", jsonutils.Marshal(opt))
- netif := opt.netif
- net := opt.net
- ipAddr := opt.ipAddr
- ip6Addr := opt.ip6Addr
- allocDir := opt.allocDir
- reserved := opt.reserved
- requireDesignatedIp := opt.requireDesignatedIp
- bn := opt.netif.GetHostNetwork()
- lockman.LockObject(ctx, net)
- defer lockman.ReleaseObject(ctx, net)
- var freeIp4, freeIp6 string
- if (!opt.strictIpv6 || len(ipAddr) > 0) && (bn == nil || bn.IpAddr != ipAddr) && net.HasIPv4Addr() {
- // allocate ipv4 address
- usedAddrs := net.GetUsedAddresses(ctx)
- if ipAddr != "" {
- // converted baremetal can resuse related guest network ip
- if err := hh.IsIpAddrWithinConvertedGuest(ctx, userCred, ipAddr, "", netif); err == nil {
- // force remove used server addr for reuse
- delete(usedAddrs, ipAddr)
- } else {
- log.Warningf("check IsIpAddrWithinConvertedGuest: %v", err)
- }
- }
- freeIp, err := net.GetFreeIP(ctx, userCred, usedAddrs, nil, ipAddr, api.IPAllocationDirection(allocDir), reserved, api.AddressTypeIPv4)
- if err != nil {
- return nil, errors.Wrap(err, "net.GetFreeIPv4")
- }
- if len(ipAddr) > 0 && ipAddr != freeIp && requireDesignatedIp {
- return nil, fmt.Errorf("IPv4 address %s is occupied, get %s instead", ipAddr, freeIp)
- }
- freeIp4 = freeIp
- }
- if (opt.requireIpv6 || len(ip6Addr) > 0) && (bn == nil || bn.Ip6Addr != ip6Addr) && net.HasIPv6Addr() {
- usedAddrs6 := net.GetUsedAddresses6(ctx)
- if ip6Addr != "" {
- // converted baremetal can resuse related guest network ip
- if err := hh.IsIpAddrWithinConvertedGuest(ctx, userCred, "", ip6Addr, netif); err == nil {
- // force remove used server addr for reuse
- delete(usedAddrs6, ip6Addr)
- } else {
- log.Warningf("check IsIpAddrWithinConvertedGuest: %v", err)
- }
- }
- freeIp, err := net.GetFreeIP(ctx, userCred, usedAddrs6, nil, ip6Addr, api.IPAllocationDirection(allocDir), reserved, api.AddressTypeIPv6)
- if err != nil {
- return nil, errors.Wrap(err, "net.GetFreeIPv6")
- }
- if len(ip6Addr) > 0 && ip6Addr != freeIp && requireDesignatedIp {
- return nil, fmt.Errorf("IPv6 address %s is occupied, get %s instead", ip6Addr, freeIp)
- }
- freeIp6 = freeIp
- }
- if bn == nil {
- bn = &SHostnetwork{}
- bn.SetModelManager(HostnetworkManager, bn)
- bn.BaremetalId = hh.Id
- bn.NetworkId = net.Id
- bn.MacAddr = netif.Mac
- bn.VlanId = netif.VlanId
- bn.IpAddr = freeIp4
- bn.Ip6Addr = freeIp6
- err := HostnetworkManager.TableSpec().Insert(ctx, bn)
- if err != nil {
- return nil, errors.Wrap(err, "HostnetworkManager.TableSpec().Insert")
- }
- } else if (freeIp4 != "" && freeIp4 != bn.IpAddr) || (freeIp6 != "" && freeIp6 != bn.Ip6Addr) {
- _, err := db.Update(bn, func() error {
- if freeIp4 != "" {
- bn.IpAddr = freeIp4
- }
- if freeIp6 != "" {
- bn.Ip6Addr = freeIp6
- }
- return nil
- })
- if err != nil {
- return nil, errors.Wrap(err, "HostnetworkManager.TableSpec().Insert")
- }
- } else {
- return bn, nil
- }
- var addrs []string
- if len(freeIp4) > 0 {
- addrs = append(addrs, freeIp4)
- }
- if len(freeIp6) > 0 {
- addrs = append(addrs, freeIp6)
- }
- db.OpsLog.LogAttachEvent(ctx, hh, net, userCred, jsonutils.NewString(strings.Join(addrs, ",")))
- hh.UpdateDnsRecord(netif, true)
- // net.UpdateBaremetalNetmap(bn, hh.GetNetifName(netif))
- return bn, nil
- }
- func (hh *SHost) PerformRemoveNetif(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input api.HostRemoveNetifInput,
- ) (jsonutils.JSONObject, error) {
- var err error
- input.HostNetifInput, err = validateHostNetif(input.HostNetifInput)
- if err != nil {
- return nil, errors.Wrap(err, "validateHostNetif")
- }
- netif := hh.GetNetInterface(input.Mac, input.VlanId)
- if netif == nil {
- return nil, httperrors.NewBadRequestError("Interface %s(vlan:%d) not exists", input.Mac, input.VlanId)
- }
- reserve := (input.Reserve != nil && *input.Reserve)
- return nil, hh.RemoveNetif(ctx, userCred, netif, reserve)
- }
- func (h *SHost) RemoveNetif(ctx context.Context, userCred mcclient.TokenCredential, netif *SNetInterface, reserve bool) error {
- h.DisableNetif(ctx, userCred, netif, reserve)
- // is this a converted host?
- if h.HostType == api.HOST_TYPE_HYPERVISOR && h.IsBaremetal {
- guests, err := h.GetGuests()
- if err != nil {
- return errors.Wrap(err, "GetGuests")
- }
- for i := range guests {
- guest := &guests[i]
- if guest.Hypervisor == api.HYPERVISOR_BAREMETAL {
- gn, err := guest.GetGuestnetworkByMac(netif.Mac)
- if err != nil && errors.Cause(err) != sql.ErrNoRows {
- return errors.Wrap(err, "GetGuestnetworkByMac")
- } else if gn != nil {
- err = gn.Detach(ctx, userCred)
- if err != nil {
- return errors.Wrap(err, "detach guest nic")
- }
- }
- }
- }
- }
- if netif.NicType == api.NIC_TYPE_ADMIN && h.AccessMac == netif.Mac {
- err := h.setAccessMac(userCred, "")
- if err != nil {
- return errors.Wrap(err, "setAccessMac")
- }
- }
- err := netif.Delete(ctx, userCred)
- if err != nil {
- return errors.Wrap(err, "netif.Remove")
- }
- h.ClearSchedDescCache()
- return nil
- }
- func (hh *SHost) getNetifsOnWire(wireId string) []SNetInterface {
- return hh.getNetInterfacesInternal(wireId, api.HOST_NIC_TYPES)
- }
- func (hh *SHost) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if hh.HostType != api.HOST_TYPE_BAREMETAL {
- return nil, httperrors.NewBadRequestError("Cannot sync status a non-baremetal host")
- }
- hh.SetStatus(ctx, userCred, api.BAREMETAL_SYNCING_STATUS, "")
- return nil, hh.StartSyncstatus(ctx, userCred, "")
- }
- func (hh *SHost) PerformReset(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if !hh.IsBaremetal {
- return nil, httperrors.NewBadRequestError("Cannot start a non-baremetal host")
- }
- if hh.Status != api.BAREMETAL_RUNNING {
- return nil, httperrors.NewBadRequestError("Cannot reset baremetal in status %s", hh.Status)
- }
- guest := hh.GetBaremetalServer()
- if guest != nil {
- if hh.HostType == api.HOST_TYPE_BAREMETAL {
- if guest.Status != api.VM_ADMIN {
- return nil, httperrors.NewBadRequestError("Cannot reset baremetal with active guest")
- }
- } else {
- return guest.PerformReset(ctx, userCred, query, data)
- }
- }
- kwargs := jsonutils.NewDict()
- kwargs.Set("force_reboot", jsonutils.JSONTrue)
- kwargs.Set("action", jsonutils.NewString("reset"))
- return hh.PerformMaintenance(ctx, userCred, query, kwargs)
- }
- func (hh *SHost) PerformRemoveAllNetifs(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- netifs := hh.GetAllNetInterfaces()
- for i := 0; i < len(netifs); i++ {
- if netifs[i].NicType == api.NIC_TYPE_NORMAL {
- hh.RemoveNetif(ctx, userCred, &netifs[i], false)
- }
- }
- return nil, nil
- }
- func (hh *SHost) PerformEnable(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input apis.PerformEnableInput,
- ) (jsonutils.JSONObject, error) {
- if !hh.GetEnabled() {
- _, err := hh.SEnabledStatusInfrasResourceBase.PerformEnable(ctx, userCred, query, input)
- if err != nil {
- return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.PerformEnable")
- }
- hh.SyncAttachedStorageStatus(ctx)
- hh.updateNotify(ctx, userCred)
- }
- return nil, nil
- }
- func (hh *SHost) PerformDisable(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformDisableInput) (jsonutils.JSONObject, error) {
- if hh.GetEnabled() {
- _, err := hh.SEnabledStatusInfrasResourceBase.PerformDisable(ctx, userCred, query, input)
- if err != nil {
- return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.PerformDisable")
- }
- hh.SyncAttachedStorageStatus(ctx)
- hh.updateNotify(ctx, userCred)
- }
- return nil, nil
- }
- func (hh *SHost) PerformCacheImage(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CacheImageInput) (jsonutils.JSONObject, error) {
- if hh.HostType == api.HOST_TYPE_BAREMETAL || hh.HostStatus != api.HOST_ONLINE {
- return nil, httperrors.NewInvalidStatusError("Cannot perform cache image in status %s", hh.Status)
- }
- if len(input.ImageId) == 0 {
- return nil, httperrors.NewMissingParameterError("image_id")
- }
- img, err := CachedimageManager.getImageInfo(ctx, userCred, input.ImageId, false)
- if err != nil {
- return nil, httperrors.NewNotFoundError("image %s not found", input.ImageId)
- }
- input.ImageId = img.Id
- if len(img.Checksum) != 0 && regutils.MatchUUID(img.Checksum) {
- return nil, httperrors.NewInvalidStatusError("Cannot cache image with no checksum")
- }
- return nil, hh.StartImageCacheTask(ctx, userCred, input)
- }
- func (hh *SHost) StartImageCacheTask(ctx context.Context, userCred mcclient.TokenCredential, input api.CacheImageInput) error {
- var sc *SStoragecache
- switch hh.HostType {
- case api.HOST_TYPE_BAREMETAL:
- case api.HOST_TYPE_HYPERVISOR, api.HOST_TYPE_ESXI:
- sc = hh.GetLocalStoragecache()
- default:
- sc = hh.GetStoragecache()
- }
- if sc == nil {
- return errors.Wrap(errors.ErrNotSupported, "No associate storage cache found")
- }
- return sc.StartImageCacheTask(ctx, userCred, input)
- }
- func (hh *SHost) isAlterNameUnique(name string) (bool, error) {
- q := HostManager.Query().Equals("name", name).NotEquals("id", hh.Id).Equals("zone_id", hh.ZoneId)
- cnt, err := q.CountWithError()
- if err != nil {
- return false, err
- }
- return cnt == 0, nil
- }
- func (hh *SHost) PerformConvertHypervisor(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- hostType, err := data.GetString("host_type")
- if err != nil {
- return nil, httperrors.NewNotAcceptableError("host_type must be specified")
- }
- if hh.HostType != api.HOST_TYPE_BAREMETAL {
- return nil, httperrors.NewNotAcceptableError("Must be a baremetal host")
- }
- if hh.GetBaremetalServer() != nil {
- return nil, httperrors.NewNotAcceptableError("Baremetal host is aleady occupied")
- }
- if !utils.IsInStringArray(hh.Status, []string{api.BAREMETAL_READY, api.BAREMETAL_RUNNING}) {
- return nil, httperrors.NewNotAcceptableError("Connot convert hypervisor in status %s", hh.Status)
- }
- // check ownership
- var ownerId mcclient.IIdentityProvider
- hostOwnerId := hh.GetOwnerId()
- if userCred.GetProjectDomainId() != hostOwnerId.GetProjectDomainId() {
- if !db.IsAdminAllowPerform(ctx, userCred, hh, "convert-hypervisor") {
- return nil, httperrors.NewNotSufficientPrivilegeError("require system previleges to convert host in other domain")
- }
- firstProject, err := db.TenantCacheManager.FindFirstProjectOfDomain(ctx, hostOwnerId.GetProjectDomainId())
- if err != nil {
- return nil, errors.Wrap(err, "FindFirstProjectOfDomain")
- }
- ownerId = firstProject
- } else {
- ownerId = userCred
- }
- driver, err := GetHostDriver(hostType, api.CLOUD_PROVIDER_ONECLOUD)
- if err != nil {
- return nil, errors.Wrapf(err, "GetHostDriver")
- }
- if data.Contains("name") {
- name, _ := data.GetString("name")
- err := hh.GetModelManager().ValidateName(name)
- if err != nil {
- return nil, err
- }
- uniq, err := hh.isAlterNameUnique(name)
- if err != nil {
- return nil, httperrors.NewInternalServerError("isAlterNameUnique fail %s", err)
- }
- if !uniq {
- return nil, httperrors.NewDuplicateNameError(name, hh.Id)
- }
- }
- image, _ := data.GetString("image")
- raid, _ := data.GetString("raid")
- input, err := driver.PrepareConvert(hh, image, raid, data)
- if err != nil {
- return nil, httperrors.NewNotAcceptableError("Convert error: %s", err.Error())
- }
- // admin delegate user to create system resource
- input.ProjectDomainId = ownerId.GetProjectDomainId()
- input.ProjectId = ownerId.GetProjectId()
- params := input.JSON(input)
- adminCred := auth.AdminCredential()
- guest, err := db.DoCreate(GuestManager, ctx, adminCred, nil, params, ownerId)
- if err != nil {
- return nil, err
- }
- func() {
- lockman.LockObject(ctx, guest)
- defer lockman.ReleaseObject(ctx, guest)
- guest.PostCreate(ctx, adminCred, ownerId, nil, params)
- }()
- log.Infof("Host convert to %s", guest.GetName())
- db.OpsLog.LogEvent(hh, db.ACT_CONVERT_START, "", userCred)
- db.OpsLog.LogEvent(guest, db.ACT_CREATE, "Convert hypervisor", userCred)
- opts := jsonutils.NewDict()
- opts.Set("server_params", params)
- opts.Set("server_id", jsonutils.NewString(guest.GetId()))
- opts.Set("convert_host_type", jsonutils.NewString(hostType))
- task, err := taskman.TaskManager.NewTask(ctx, "BaremetalConvertHypervisorTask", hh, adminCred, opts, "", "", nil)
- if err != nil {
- return nil, err
- }
- task.ScheduleRun(nil)
- hh.SetStatus(ctx, userCred, api.BAREMETAL_START_CONVERT, "")
- return nil, nil
- }
- func (hh *SHost) PerformUndoConvert(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if !hh.IsBaremetal {
- return nil, httperrors.NewNotAcceptableError("Not a baremetal")
- }
- if hh.HostType == api.HOST_TYPE_BAREMETAL {
- return nil, httperrors.NewNotAcceptableError("Not being convert to hypervisor")
- }
- if hh.GetEnabled() {
- return nil, httperrors.NewNotAcceptableError("Host should be disabled")
- }
- if !utils.IsInStringArray(hh.Status, []string{api.BAREMETAL_READY, api.BAREMETAL_RUNNING}) {
- return nil, httperrors.NewNotAcceptableError("Cannot unconvert in status %s", hh.Status)
- }
- driver, err := hh.GetHostDriver()
- if err != nil {
- return nil, errors.Wrapf(err, "GetHostDriver")
- }
- err = driver.PrepareUnconvert(hh)
- if err != nil {
- return nil, httperrors.NewNotAcceptableError("%v", err)
- }
- guests, err := hh.GetGuests()
- if err != nil {
- return nil, httperrors.NewGeneralError(errors.Wrapf(err, "GetGuests"))
- }
- if len(guests) > 1 {
- return nil, httperrors.NewNotAcceptableError("Not an empty host")
- } else if len(guests) == 1 {
- guest := guests[0]
- if guest.Hypervisor != api.HYPERVISOR_BAREMETAL {
- return nil, httperrors.NewNotAcceptableError("Not an converted hypervisor")
- }
- err := guest.SetDisableDelete(userCred, false)
- if err != nil {
- return nil, err
- }
- db.OpsLog.LogEvent(&guest, db.ACT_DELETE, "Unconvert baremetal", userCred)
- }
- db.OpsLog.LogEvent(hh, db.ACT_UNCONVERT_START, "", userCred)
- logclient.AddActionLogWithContext(ctx, hh, logclient.ACT_UNCONVERT_START, nil, userCred, true)
- task, err := taskman.TaskManager.NewTask(ctx, "BaremetalUnconvertHypervisorTask", hh, userCred, nil, "", "", nil)
- if err != nil {
- return nil, err
- }
- task.ScheduleRun(nil)
- return nil, nil
- }
- func (hh *SHost) UpdateDiskConfig(userCred mcclient.TokenCredential, layouts []baremetal.Layout) error {
- bs := hh.GetBaremetalstorage()
- if bs != nil {
- diff, err := db.Update(bs, func() error {
- if len(layouts) != 0 {
- bs.Config = jsonutils.Marshal(layouts).(*jsonutils.JSONArray)
- var size int64
- for i := 0; i < len(layouts); i++ {
- size += layouts[i].Size
- }
- bs.RealCapacity = size
- } else {
- bs.Config = jsonutils.NewArray()
- bs.RealCapacity = bs.GetStorage().Capacity
- }
- return nil
- })
- if err != nil {
- log.Errorln(err)
- return err
- }
- db.OpsLog.LogEvent(bs, db.ACT_UPDATE, diff, userCred)
- }
- return nil
- }
- // TODO: support multithreaded operation
- /*func (host *SHost) SyncEsxiHostWires(ctx context.Context, userCred mcclient.TokenCredential, remoteHost cloudprovider.ICloudHost) compare.SyncResult {
- lockman.LockObject(ctx, host)
- defer lockman.ReleaseObject(ctx, host)
- result := compare.SyncResult{}
- ca := host.GetCloudaccount()
- host2wires, err := ca.GetHost2Wire(ctx, userCred)
- if err != nil {
- result.Error(errors.Wrap(err, "unable to GetHost2Wire"))
- return result
- }
- log.Infof("host2wires: %s", jsonutils.Marshal(host2wires))
- ihost := remoteHost.(*esxi.SHost)
- remoteHostId := ihost.GetId()
- vsWires := host2wires[remoteHostId]
- log.Infof("vsWires: %s", jsonutils.Marshal(vsWires))
- netIfs := host.GetHostNetInterfaces()
- for i := range vsWires {
- vsWire := vsWires[i]
- if vsWire.SyncTimes > 0 {
- continue
- }
- netif := host.findNetIfs(netIfs, vsWire.Mac, 1)
- if netif == nil {
- // do nothing
- continue
- }
- if netif.Bridge != vsWire.VsId {
- db.Update(netif, func() error {
- netif.Bridge = vsWire.VsId
- return nil
- })
- }
- if len(netif.WireId) == 0 {
- db.Update(netif, func() error {
- netif.WireId = vsWire.WireId
- return nil
- })
- }
- vsWires[i].SyncTimes += 1
- }
- log.Infof("after sync: %s", jsonutils.Marshal(host2wires))
- ca.SetHost2Wire(ctx, userCred, host2wires)
- return result
- }*/
- /*func (host *SHost) findHostwire(hostwires []SHostwire, wireId string, mac string) *SHostwire {
- for i := range hostwires {
- if hostwires[i].WireId == wireId && hostwires[i].MacAddr == mac {
- return &hostwires[i]
- }
- }
- return nil
- }*/
- func (host *SHost) findNetIfs(netIfs []SNetInterface, mac string, vlanId int) *SNetInterface {
- for i := range netIfs {
- if netIfs[i].Mac == mac && netIfs[i].VlanId == vlanId {
- return &netIfs[i]
- }
- }
- return nil
- }
- func (host *SHost) SyncHostExternalNics(ctx context.Context, userCred mcclient.TokenCredential, ihost cloudprovider.ICloudHost, provider *SCloudprovider) compare.SyncResult {
- result := compare.SyncResult{}
- netIfs := host.GetHostNetInterfaces()
- extNics, err := ihost.GetIHostNics()
- if err != nil {
- log.Errorf("GetIHostNics fail %s", err)
- result.Error(err)
- return result
- }
- log.Debugf("SyncHostExternalNics for host %s netIfs %d ihost %s extNics %d", host.Name, len(netIfs), ihost.GetName(), len(extNics))
- disables := make([]*SNetInterface, 0)
- enables := make([]cloudprovider.ICloudHostNetInterface, 0)
- type sRemoveNetInterface struct {
- netif *SNetInterface
- reserveIp bool
- }
- type sAddNetInterface struct {
- netif cloudprovider.ICloudHostNetInterface
- reserveIp bool
- }
- removes := make([]sRemoveNetInterface, 0)
- adds := make([]sAddNetInterface, 0)
- for i := 0; i < len(netIfs); i++ {
- find := false
- for j := 0; j < len(extNics); j++ {
- if netIfs[i].Mac == extNics[j].GetMac() && netIfs[i].VlanId == extNics[j].GetVlanId() {
- // find! need to update
- find = true
- obn := netIfs[i].GetHostNetwork()
- var oip string
- if obn != nil {
- oip = obn.IpAddr
- }
- nip := extNics[j].GetIpAddr()
- if oip != nip {
- if obn != nil {
- disables = append(disables, &netIfs[i])
- }
- if len(nip) > 0 {
- enables = append(enables, extNics[j])
- }
- } else {
- wireId := ""
- extWire := extNics[j].GetIWire()
- if extWire != nil {
- wire, err := WireManager.FetchWireByExternalId(provider.Id, extWire.GetGlobalId())
- if err != nil {
- result.AddError(err)
- } else {
- wireId = wire.Id
- }
- }
- // in sync, sync interface and bridge
- if netIfs[i].Bridge != extNics[j].GetBridge() || netIfs[i].Interface != extNics[j].GetDevice() || netIfs[i].WireId != wireId {
- _, err := db.Update(&netIfs[i], func() error {
- netIfs[i].Interface = extNics[j].GetDevice()
- netIfs[i].Bridge = extNics[j].GetBridge()
- netIfs[i].WireId = wireId
- return nil
- })
- if err != nil {
- result.Error(errors.Wrap(err, "update interface and bridge fail"))
- return result
- }
- }
- }
- break
- }
- }
- if !find {
- // need to remove
- removes = append(removes, sRemoveNetInterface{netif: &netIfs[i], reserveIp: false})
- }
- }
- for j := 0; j < len(extNics); j++ {
- find := false
- for i := 0; i < len(netIfs); i++ {
- if netIfs[i].Mac == extNics[j].GetMac() && netIfs[i].VlanId == extNics[j].GetVlanId() {
- find = true
- break
- }
- }
- if !find {
- // need to add
- adds = append(adds, sAddNetInterface{netif: extNics[j], reserveIp: false})
- }
- }
- // find out which ip need to be reserved
- for i := 0; i < len(removes); i++ {
- var oip string
- obn := removes[i].netif.GetHostNetwork()
- if obn != nil {
- oip = obn.IpAddr
- }
- if len(oip) == 0 {
- // skip
- continue
- }
- for j := 0; j < len(adds); j++ {
- if oip == adds[j].netif.GetIpAddr() {
- // find out ! IP reserved but interface changed!
- removes[i].reserveIp = true
- adds[j].reserveIp = true
- break
- }
- }
- }
- log.Debugf("SyncHostExternalNics %s remove %d disable %d enable %d add %d", host.Name, len(removes), len(disables), len(enables), len(adds))
- for i := len(removes) - 1; i >= 0; i -= 1 {
- log.Debugf("remove netif %s", removes[i].netif.Mac)
- err := host.RemoveNetif(ctx, userCred, removes[i].netif, removes[i].reserveIp)
- if err != nil {
- result.DeleteError(err)
- } else {
- result.Delete()
- }
- }
- for i := len(disables) - 1; i >= 0; i -= 1 {
- log.Debugf("disable netif %s", disables[i].Mac)
- err := host.DisableNetif(ctx, userCred, disables[i], false)
- if err != nil {
- result.DeleteError(err)
- } else {
- result.Delete()
- }
- }
- for i := 0; i < len(enables); i += 1 {
- netif := host.GetNetInterface(enables[i].GetMac(), enables[i].GetVlanId())
- // always true reserved address pool
- log.Debugf("enable netif %s", enables[i].GetMac())
- err = host.EnableNetif(ctx, userCred, netif, "", enables[i].GetIpAddr(), "", "", "", true, true, false, false)
- if err != nil {
- result.AddError(err)
- } else {
- result.Add()
- }
- }
- for i := 0; i < len(adds); i += 1 {
- log.Debugf("add netif %s", adds[i].netif.GetMac())
- // always try reserved pool
- extNic := adds[i].netif
- var strNetIf, strBridge *string
- netif := extNic.GetDevice()
- bridge := extNic.GetBridge()
- if len(netif) > 0 {
- strNetIf = &netif
- }
- if len(bridge) > 0 {
- strBridge = &bridge
- }
- wireId := ""
- extWire := extNic.GetIWire()
- if extWire != nil {
- wire, err := WireManager.FetchWireByExternalId(provider.Id, extWire.GetGlobalId())
- if err != nil {
- result.AddError(err)
- } else {
- wireId = wire.Id
- }
- }
- err = host.addNetif(ctx, userCred, extNic.GetMac(), extNic.GetVlanId(), wireId, extNic.GetIpAddr(), "", 0,
- compute.TNicType(extNic.GetNicType()), int(extNic.GetIndex()),
- extNic.IsLinkUp(), int16(extNic.GetMtu()), false, strNetIf, strBridge, true, true, false, false)
- if err != nil {
- result.AddError(err)
- } else {
- result.Add()
- }
- }
- return result
- }
- // func (manager *SHostManager) GetEsxiAgentHostId(key string) (string, error) {
- // q := HostManager.Query("id")
- // q = q.Equals("host_status", HOST_ONLINE)
- // q = q.Equals("host_type", HOST_TYPE_HYPERVISOR)
- // q = q.IsTrue("enabled")
- //
- // rows, err := q.Rows()
- // if err != nil {
- // return "", err
- // }
- // defer rows.Close()
- //
- // var hostId string
- // hostIds := make([]string, 0)
- // for rows.Next() {
- // err = rows.Scan(&hostId)
- // if err != nil {
- // return "", err
- // }
- // hostIds = append(hostIds, hostId)
- // }
- //
- // ring := hashring.New(hostIds)
- // ret, _ := ring.GetNode(key)
- // return ret, nil
- // }
- //
- // func (manager *SHostManager) GetEsxiAgentHost(key string) (*SHost, error) {
- // hostId, err := manager.GetEsxiAgentHostId(key)
- // if err != nil {
- // return nil, err
- // }
- // return manager.FetchHostById(hostId), nil
- // }
- //
- // func (host *SHost) GetEsxiAgentHost() (*SHost, error) {
- // return HostManager.GetEsxiAgentHost(host.Id)
- // }
- func (hh *SHost) IsBaremetalAgentReady() bool {
- return hh.isAgentReady(api.AgentTypeBaremetal)
- }
- func (hh *SHost) BaremetalSyncRequest(ctx context.Context, method httputils.THttpMethod, url string, headers http.Header, body *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
- return HostManager.BaremetalSyncRequest(ctx, method, url, headers, body, hh.ZoneId)
- }
- func (hm *SHostManager) BaremetalSyncRequest(ctx context.Context, method httputils.THttpMethod, url string, headers http.Header, body *jsonutils.JSONDict, zoneId string) (jsonutils.JSONObject, error) {
- return hm.doAgentRequest(api.AgentTypeBaremetal, ctx, method, url, headers, body, zoneId)
- }
- func (hh *SHost) IsEsxiAgentReady() bool {
- return hh.isAgentReady(api.AgentTypeEsxi)
- }
- func (hh *SHost) EsxiRequest(ctx context.Context, method httputils.THttpMethod, url string, headers http.Header, body *jsonutils.JSONDict) (jsonutils.JSONObject, error) {
- return HostManager.doAgentRequest(api.AgentTypeEsxi, ctx, method, url, headers, body, hh.ZoneId)
- }
- func (hh *SHost) GetAgent(at api.TAgentType) *SBaremetalagent {
- return HostManager.GetAgent(at, hh.ZoneId)
- }
- func (hm *SHostManager) GetAgent(at api.TAgentType, zoneId string) *SBaremetalagent {
- agent := BaremetalagentManager.GetAgent(at, zoneId)
- if agent == nil {
- agent = BaremetalagentManager.GetAgent(at, "")
- }
- return agent
- }
- func (hh *SHost) isAgentReady(agentType api.TAgentType) bool {
- agent := hh.GetAgent(agentType)
- if agent == nil {
- log.Errorf("%s ready: false", agentType)
- return false
- }
- return true
- }
- func (hm *SHostManager) doAgentRequest(agentType api.TAgentType, ctx context.Context, method httputils.THttpMethod, url string, headers http.Header, body *jsonutils.JSONDict, zoneId string) (jsonutils.JSONObject, error) {
- agent := hm.GetAgent(agentType, zoneId)
- if agent == nil {
- return nil, fmt.Errorf("no valid %s", agentType)
- }
- serviceUrl := agent.ManagerUri
- if url[0] != '/' && serviceUrl[len(serviceUrl)-1] != '/' {
- serviceUrl += "/"
- }
- url = serviceUrl + url
- _, data, err := httputils.JSONRequest(httputils.GetDefaultClient(), ctx, method, url, headers, body, false)
- return data, err
- }
- func (manager *SHostManager) GetHostByIp(managerId, hostType, hostIp string) (*SHost, error) {
- q := manager.Query()
- q = q.Equals("access_ip", hostIp).Equals("host_type", hostType)
- if len(managerId) > 0 {
- q = q.Equals("manager_id", managerId)
- }
- ret := []SHost{}
- err := db.FetchModelObjects(manager, q, &ret)
- if err != nil {
- return nil, err
- }
- if len(ret) == 0 {
- return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s %s", hostType, hostIp)
- }
- if len(ret) > 1 {
- return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "%s %s", hostType, hostIp)
- }
- return &ret[0], nil
- }
- func (hh *SHost) getCloudProviderInfo() SCloudProviderInfo {
- var region *SCloudregion
- zone, _ := hh.GetZone()
- if zone != nil {
- region, _ = zone.GetRegion()
- }
- provider := hh.GetCloudprovider()
- return MakeCloudProviderInfo(region, zone, provider)
- }
- func (hh *SHost) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
- desc := hh.SEnabledStatusInfrasResourceBase.GetShortDesc(ctx)
- info := hh.getCloudProviderInfo()
- desc.Update(jsonutils.Marshal(&info))
- return desc
- }
- func (hh *SHost) MarkGuestUnknown(ctx context.Context, userCred mcclient.TokenCredential) {
- guests, _ := hh.GetGuests()
- for _, guest := range guests {
- guest.SetStatus(ctx, userCred, api.VM_UNKNOWN, "host offline")
- guest.UpdateQgaStatus(api.QGA_STATUS_UNKNOWN)
- }
- guests2 := hh.GetGuestsBackupOnThisHost()
- for _, guest := range guests2 {
- guest.SetBackupGuestStatus(userCred, api.VM_UNKNOWN, "host offline")
- }
- }
- func (manager *SHostManager) PingDetectionTask(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
- deadline := time.Now().Add(-1 * time.Duration(options.Options.HostOfflineMaxSeconds) * time.Second)
- q := manager.Query().Equals("host_status", api.HOST_ONLINE).
- In("host_type", []string{api.HOST_TYPE_HYPERVISOR, api.HOST_TYPE_CONTAINER}).IsNullOrEmpty("manager_id")
- q = q.Filter(sqlchemy.OR(sqlchemy.IsNull(q.Field("last_ping_at")),
- sqlchemy.LT(q.Field("last_ping_at"), deadline)))
- hosts := []SHost{}
- err := db.FetchModelObjects(manager, q, &hosts)
- if err != nil {
- return
- }
- updateHealthStatus := false
- for i := range hosts {
- func() {
- lockman.LockObject(ctx, &hosts[i])
- defer lockman.ReleaseObject(ctx, &hosts[i])
- hosts[i].PerformOffline(ctx, userCred, nil, &api.HostOfflineInput{UpdateHealthStatus: &updateHealthStatus, Reason: fmt.Sprintf("last ping detection at %s", deadline)})
- hosts[i].MarkGuestUnknown(ctx, userCred)
- }()
- }
- }
- func (hh *SHost) IsPrepaidRecycleResource() bool {
- return hh.ResourceType == api.HostResourceTypePrepaidRecycle
- }
- func (host *SHost) PerformSetSchedtag(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- return PerformSetResourceSchedtag(host, ctx, userCred, query, data)
- }
- func (host *SHost) GetDynamicConditionInput() *jsonutils.JSONDict {
- return jsonutils.Marshal(host).(*jsonutils.JSONDict)
- }
- func (host *SHost) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) {
- ret, err := host.SEnabledStatusInfrasResourceBase.PerformStatus(ctx, userCred, query, input)
- if err != nil {
- return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.PerformStatus")
- }
- host.ClearSchedDescCache()
- return ret, nil
- }
- func (host *SHost) GetSchedtagJointManager() ISchedtagJointManager {
- return HostschedtagManager
- }
- func (host *SHost) PerformHostExitMaintenance(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if !utils.IsInStringArray(host.Status, []string{api.BAREMETAL_MAINTAIN_FAIL, api.BAREMETAL_MAINTAINING}) {
- return nil, httperrors.NewInvalidStatusError("host status %s can't exit maintenance", host.Status)
- }
- err := host.SetStatus(ctx, userCred, api.HOST_STATUS_RUNNING, "exit maintenance")
- if err != nil {
- return nil, err
- }
- logclient.AddSimpleActionLog(host, logclient.ACT_HOST_UNMAINTENANCE, "host unmaintenance", userCred, true)
- return nil, nil
- }
- func (host *SHost) PerformHostMaintenance(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if host.HostType != api.HOST_TYPE_HYPERVISOR {
- return nil, httperrors.NewBadRequestError("host type %s can't do host maintenance", host.HostType)
- }
- if host.HostStatus == api.BAREMETAL_START_MAINTAIN {
- return nil, httperrors.NewBadRequestError("unsupport on host status %s", host.HostStatus)
- }
- var preferHostId string
- preferHost, _ := data.GetString("prefer_host")
- if len(preferHost) > 0 {
- iHost, _ := HostManager.FetchByIdOrName(ctx, userCred, preferHost)
- if iHost == nil {
- return nil, httperrors.NewBadRequestError("Host %s not found", preferHost)
- }
- host := iHost.(*SHost)
- preferHostId = host.Id
- err := host.IsAssignable(ctx, userCred)
- if err != nil {
- return nil, errors.Wrap(err, "IsAssignable")
- }
- }
- guests := host.GetKvmGuests()
- for i := 0; i < len(guests); i++ {
- lockman.LockObject(ctx, &guests[i])
- defer lockman.ReleaseObject(ctx, &guests[i])
- guest, err := guests[i].validateForBatchMigrate(ctx, false)
- if err != nil {
- return nil, err
- }
- guests[i] = *guest
- if host.HostStatus == api.HOST_OFFLINE && guests[i].Status != api.VM_UNKNOWN {
- return nil, httperrors.NewBadRequestError("Host %s can't migrate guests %s in status %s",
- host.HostStatus, guests[i].Name, guests[i].Status)
- }
- }
- var hostGuests = []*api.GuestBatchMigrateParams{}
- for i := 0; i < len(guests); i++ {
- bmp := &api.GuestBatchMigrateParams{
- Id: guests[i].Id,
- LiveMigrate: guests[i].Status == api.VM_RUNNING,
- RescueMode: guests[i].Status == api.VM_UNKNOWN,
- OldStatus: guests[i].Status,
- }
- guests[i].SetStatus(ctx, userCred, api.VM_START_MIGRATE, "host maintainence")
- hostGuests = append(hostGuests, bmp)
- }
- kwargs := jsonutils.NewDict()
- kwargs.Set("guests", jsonutils.Marshal(hostGuests))
- kwargs.Set("prefer_host_id", jsonutils.NewString(preferHostId))
- return nil, host.StartMaintainTask(ctx, userCred, kwargs)
- }
- func (host *SHost) autoMigrateOnHostShutdown(ctx context.Context) bool {
- return host.GetMetadata(ctx, api.HOSTMETA_AUTO_MIGRATE_ON_HOST_SHUTDOWN, nil) == "enable"
- }
- func (host *SHost) RemoteHealthStatus(ctx context.Context) string {
- var status = api.HOST_HEALTH_STATUS_UNKNOWN
- userCred := auth.AdminCredential()
- res, err := host.Request(
- ctx, userCred, "GET", "/hosts/health-status",
- mcclient.GetTokenHeaders(userCred), nil,
- )
- if err != nil {
- log.Errorf("failed get remote health status %s", err)
- } else {
- status, _ = res.GetString("status")
- }
- log.Infof("remote health status %s", status)
- return status
- }
- func (host *SHost) GetHostnameByName() string {
- hostname := host.Name
- accessIp := strings.Replace(host.AccessIp, ".", "-", -1)
- if strings.HasSuffix(host.Name, "-"+accessIp) {
- hostname = hostname[0 : len(hostname)-len(accessIp)-1]
- }
- return hostname
- }
- func (host *SHost) OnHostDown(ctx context.Context, userCred mcclient.TokenCredential) {
- log.Errorf("watched host down %s, status %s", host.Name, host.HostStatus)
- hostHealthChecker.UnwatchHost(ctx, host.GetHostnameByName())
- if host.HostStatus == api.HOST_OFFLINE && !host.EnableHealthCheck &&
- !host.autoMigrateOnHostShutdown(ctx) {
- // hostagent requested offline, and not enable auto migrate on host shutdown
- log.Infof("host not need auto migrate on host shutdown")
- return
- }
- hostname := host.Name
- if host.HostStatus == api.HOST_OFFLINE {
- // host has been marked offline, check host status in k8s
- coreCli, err := tokens.GetCoreClient()
- if err != nil {
- log.Errorf("failed get k8s client %s", err)
- return
- }
- hostname = host.GetHostnameByName()
- node, err := coreCli.Nodes().Get(context.TODO(), hostname, metav1.GetOptions{})
- if err != nil {
- log.Errorf("failed get node %s info %s", hostname, err)
- return
- }
- // check node status is ready
- if length := len(node.Status.Conditions); length > 0 {
- if node.Status.Conditions[length-1].Type == v1.NodeReady &&
- node.Status.Conditions[length-1].Status == v1.ConditionTrue {
- log.Infof("node %s status ready, no need entry rescue", hostname)
- return
- }
- }
- }
- log.Errorf("host %s down, try rescue guests", hostname)
- if _, err := host.SaveCleanUpdates(func() error {
- host.EnableHealthCheck = false
- host.HostStatus = api.HOST_OFFLINE
- return nil
- }); err != nil {
- log.Errorf("update host %s failed %s", host.Id, err)
- }
- data := jsonutils.NewDict()
- data.Set("reason", jsonutils.NewString("host down"))
- db.OpsLog.LogEvent(host, db.ACT_HOST_DOWN, data, userCred)
- logclient.AddActionLogWithContext(ctx, host, logclient.ACT_OFFLINE, data, userCred, false)
- notifyclient.SystemExceptionNotify(ctx, napi.ActionHostDown, HostManager.Keyword(), data)
- host.SyncCleanSchedDescCache()
- host.switchWithBackup(ctx, userCred)
- host.migrateOnHostDown(ctx, userCred)
- }
- func (host *SHost) switchWithBackup(ctx context.Context, userCred mcclient.TokenCredential) {
- guests := host.GetGuestsMasterOnThisHost()
- for i := 0; i < len(guests); i++ {
- data := jsonutils.NewDict()
- _, err := guests[i].PerformSwitchToBackup(ctx, userCred, nil, data)
- if err != nil {
- db.OpsLog.LogEvent(
- &guests[i], db.ACT_SWITCH_FAILED, fmt.Sprintf("PerformSwitchToBackup on host down: %s", err), userCred,
- )
- logclient.AddSimpleActionLog(
- &guests[i], logclient.ACT_SWITCH_TO_BACKUP,
- fmt.Sprintf("PerformSwitchToBackup on host down: %s", err), userCred, false,
- )
- }
- }
- }
- func (host *SHost) migrateOnHostDown(ctx context.Context, userCred mcclient.TokenCredential) {
- if host.GetMetadata(ctx, api.HOSTMETA_AUTO_MIGRATE_ON_HOST_DOWN, nil) == "enable" {
- if err := host.MigrateSharedStorageServers(ctx, userCred); err != nil {
- db.OpsLog.LogEvent(host, db.ACT_HOST_DOWN, fmt.Sprintf("migrate servers failed %s", err), userCred)
- }
- }
- }
- func (host *SHost) MigrateSharedStorageServers(ctx context.Context, userCred mcclient.TokenCredential) error {
- guests, err := host.GetGuests()
- if err != nil {
- return errors.Wrapf(err, "host %s(%s) get guests", host.Name, host.Id)
- }
- migGuests := []*SGuest{}
- hostGuests := []*api.GuestBatchMigrateParams{}
- for i := 0; i < len(guests); i++ {
- if guests[i].isNotRunningStatus(guests[i].Status) {
- // skip not running guests
- continue
- }
- lockman.LockObject(ctx, &guests[i])
- defer lockman.ReleaseObject(ctx, &guests[i])
- _, err := guests[i].validateForBatchMigrate(ctx, true)
- if err != nil {
- continue
- } else {
- bmp := &api.GuestBatchMigrateParams{
- Id: guests[i].Id,
- LiveMigrate: false,
- RescueMode: true,
- OldStatus: guests[i].Status,
- }
- guests[i].SetStatus(ctx, userCred, api.VM_START_MIGRATE, "host down")
- hostGuests = append(hostGuests, bmp)
- migGuests = append(migGuests, &guests[i])
- }
- }
- kwargs := jsonutils.NewDict()
- kwargs.Set("guests", jsonutils.Marshal(hostGuests))
- db.OpsLog.LogEvent(host, db.ACT_HOST_DOWN_AUTO_MIGRATE, kwargs, userCred)
- logclient.AddActionLogWithContext(ctx, host, logclient.ACT_HOST_DOWN_AUTO_MIGRATE, kwargs, userCred, true)
- notifyclient.SystemExceptionNotify(ctx, napi.ActionHostDownAutoMigrate, HostManager.Keyword(), kwargs)
- return GuestManager.StartHostGuestsMigrateTask(ctx, userCred, migGuests, kwargs, "")
- }
- func (host *SHost) SetStatus(ctx context.Context, userCred mcclient.TokenCredential, status string, reason string) error {
- err := host.SEnabledStatusInfrasResourceBase.SetStatus(ctx, userCred, status, reason)
- if err != nil {
- return err
- }
- host.ClearSchedDescCache()
- return nil
- }
- func (host *SHost) StartMaintainTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict) error {
- host.SetStatus(ctx, userCred, api.BAREMETAL_START_MAINTAIN, "start maintenance")
- if task, err := taskman.TaskManager.NewTask(ctx, "HostMaintainTask", host, userCred, data, "", "", nil); err != nil {
- log.Errorln(err)
- return err
- } else {
- task.ScheduleRun(nil)
- }
- return nil
- }
- func (host *SHost) IsMaintaining() bool {
- return utils.IsInStringArray(host.Status, []string{api.BAREMETAL_START_MAINTAIN, api.BAREMETAL_MAINTAINING, api.BAREMETAL_MAINTAIN_FAIL})
- }
- // InstanceGroups returns the enabled group of guest in host and their frequency of occurrence
- func (host *SHost) InstanceGroups() ([]SGroup, map[string]int, error) {
- q := GuestManager.Query("id")
- guestQ := q.Filter(sqlchemy.OR(sqlchemy.Equals(q.Field("host_id"), host.Id),
- sqlchemy.Equals(q.Field("backup_host_id"), host.Id))).SubQuery()
- groupQ := GroupguestManager.Query().SubQuery()
- q = groupQ.Query().Join(guestQ, sqlchemy.Equals(guestQ.Field("id"), groupQ.Field("guest_id")))
- groupguests := make([]SGroupguest, 0, 1)
- err := db.FetchModelObjects(GroupguestManager, q, &groupguests)
- if err != nil {
- return nil, nil, err
- }
- groupIds, groupSet := make([]string, 0, len(groupguests)), make(map[string]int)
- for i := range groupguests {
- id := groupguests[i].GroupId
- if _, ok := groupSet[id]; !ok {
- groupIds = append(groupIds, id)
- groupSet[id] = 1
- continue
- }
- groupSet[id] += 1
- }
- if len(groupIds) == 0 {
- return []SGroup{}, make(map[string]int), nil
- }
- groups := make([]SGroup, 0, len(groupIds))
- q = GroupManager.Query().In("id", groupIds).IsTrue("enabled")
- err = db.FetchModelObjects(GroupManager, q, &groups)
- if err != nil {
- return nil, nil, err
- }
- retSet := make(map[string]int)
- for i := range groups {
- retSet[groups[i].GetId()] = groupSet[groups[i].GetId()]
- }
- return groups, retSet, nil
- }
- func (host *SHost) setIpmiIp(userCred mcclient.TokenCredential, ipAddr string) error {
- if host.IpmiIp == ipAddr {
- return nil
- }
- diff, err := db.Update(host, func() error {
- host.IpmiIp = ipAddr
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "db.Update")
- }
- db.OpsLog.LogEvent(host, db.ACT_UPDATE, diff, userCred)
- return nil
- }
- func (host *SHost) setAccessIp(userCred mcclient.TokenCredential, ipAddr string) error {
- if host.AccessIp == ipAddr {
- return nil
- }
- diff, err := db.Update(host, func() error {
- host.AccessIp = ipAddr
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "db.Update")
- }
- db.OpsLog.LogEvent(host, db.ACT_UPDATE, diff, userCred)
- return nil
- }
- func (host *SHost) setAccessMac(userCred mcclient.TokenCredential, mac string) error {
- mac = netutils.FormatMacAddr(mac)
- if host.AccessMac == mac {
- return nil
- }
- diff, err := db.Update(host, func() error {
- host.AccessMac = mac
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "db.Update")
- }
- db.OpsLog.LogEvent(host, db.ACT_UPDATE, diff, userCred)
- return nil
- }
- func (host *SHost) GetIpmiInfo() (types.SIPMIInfo, error) {
- info := types.SIPMIInfo{}
- if host.IpmiInfo != nil {
- err := host.IpmiInfo.Unmarshal(&info)
- if err != nil {
- return info, errors.Wrap(err, "host.IpmiInfo.Unmarshal")
- }
- }
- return info, nil
- }
- func (host *SHost) GetNics() []*types.SNic {
- netifs := host.GetAllNetInterfaces()
- nicInfos := []*types.SNic{}
- if netifs != nil && len(netifs) > 0 {
- for i := 0; i < len(netifs); i += 1 {
- nicInfos = append(nicInfos, netifs[i].getBaremetalJsonDesc())
- }
- }
- return nicInfos
- }
- func (host *SHost) GetUEFIInfo() (*types.EFIBootMgrInfo, error) {
- if host.UefiInfo == nil {
- return nil, nil
- }
- info := new(types.EFIBootMgrInfo)
- if err := host.UefiInfo.Unmarshal(info); err != nil {
- return nil, errors.Wrap(err, "host.UefiInfo.Unmarshal")
- }
- return info, nil
- }
- func (hh *SHost) GetDetailsJnlp(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- url := fmt.Sprintf("/baremetals/%s/jnlp", hh.Id)
- header := mcclient.GetTokenHeaders(userCred)
- resp, err := hh.BaremetalSyncRequest(ctx, "POST", url, header, nil)
- if err != nil {
- return nil, errors.Wrap(err, "BaremetalSyncRequest")
- }
- return resp, nil
- }
- func (hh *SHost) PerformInsertIso(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if utils.IsInStringArray(hh.Status, []string{api.BAREMETAL_READY, api.BAREMETAL_RUNNING}) {
- imageStr, err := data.GetString("image")
- image, err := CachedimageManager.getImageInfo(ctx, userCred, imageStr, false)
- if err != nil {
- if err == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotFoundError2("image", imageStr)
- } else {
- return nil, httperrors.NewGeneralError(err)
- }
- }
- if image.Status != cloudprovider.IMAGE_STATUS_ACTIVE {
- return nil, httperrors.NewInvalidStatusError("Image status is not active")
- }
- boot := jsonutils.QueryBoolean(data, "boot", false)
- return nil, hh.StartInsertIsoTask(ctx, userCred, image.Id, boot, "")
- }
- return nil, httperrors.NewInvalidStatusError("Cannot do insert-iso in status %s", hh.Status)
- }
- func (hh *SHost) StartInsertIsoTask(ctx context.Context, userCred mcclient.TokenCredential, imageId string, boot bool, parentTaskId string) error {
- data := jsonutils.NewDict()
- data.Add(jsonutils.NewString(imageId), "image_id")
- if boot {
- data.Add(jsonutils.JSONTrue, "boot")
- }
- data.Add(jsonutils.NewString(api.BAREMETAL_CDROM_ACTION_INSERT), "action")
- hh.SetStatus(ctx, userCred, api.BAREMETAL_START_INSERT_ISO, "start insert iso task")
- if task, err := taskman.TaskManager.NewTask(ctx, "BaremetalCdromTask", hh, userCred, data, parentTaskId, "", nil); err != nil {
- log.Errorln(err)
- return err
- } else {
- task.ScheduleRun(nil)
- return nil
- }
- }
- func (hh *SHost) PerformEjectIso(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if utils.IsInStringArray(hh.Status, []string{api.BAREMETAL_READY, api.BAREMETAL_RUNNING}) {
- return nil, hh.StartEjectIsoTask(ctx, userCred, "")
- }
- return nil, httperrors.NewInvalidStatusError("Cannot do eject-iso in status %s", hh.Status)
- }
- func (hh *SHost) StartEjectIsoTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- data := jsonutils.NewDict()
- data.Add(jsonutils.NewString(api.BAREMETAL_CDROM_ACTION_EJECT), "action")
- hh.SetStatus(ctx, userCred, api.BAREMETAL_START_EJECT_ISO, "start eject iso task")
- if task, err := taskman.TaskManager.NewTask(ctx, "BaremetalCdromTask", hh, userCred, data, parentTaskId, "", nil); err != nil {
- log.Errorln(err)
- return err
- } else {
- task.ScheduleRun(nil)
- return nil
- }
- }
- func (hh *SHost) PerformSyncConfig(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- if hh.HostType != api.HOST_TYPE_BAREMETAL {
- return nil, httperrors.NewBadRequestError("Cannot sync config a non-baremetal host")
- }
- hh.SetStatus(ctx, userCred, api.BAREMETAL_SYNCING_STATUS, "")
- return nil, hh.StartSyncConfig(ctx, userCred, "")
- }
- func (hh *SHost) StartSyncConfig(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- return hh.startSyncConfig(ctx, userCred, parentTaskId, false)
- }
- func (hh *SHost) startSyncConfig(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, noStatus bool) error {
- data := jsonutils.NewDict()
- data.Add(jsonutils.NewBool(noStatus), "not_sync_status")
- task, err := taskman.TaskManager.NewTask(ctx, "BaremetalSyncConfigTask", hh, userCred, data, parentTaskId, "", nil)
- if err != nil {
- return err
- }
- return task.ScheduleRun(nil)
- }
- func (model *SHost) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
- // make host default public
- return model.SEnabledStatusInfrasResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
- }
- func (host *SHost) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeDomainOwnerInput) (jsonutils.JSONObject, error) {
- ret, err := host.SEnabledStatusInfrasResourceBase.PerformChangeOwner(ctx, userCred, query, input)
- if err != nil {
- return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.PerformChangeOwner")
- }
- localStorages := host._getAttachedStorages(tristate.None, tristate.None, api.HOST_STORAGE_LOCAL_TYPES)
- for i := range localStorages {
- _, err := localStorages[i].performChangeOwnerInternal(ctx, userCred, query, input)
- if err != nil {
- return nil, errors.Wrap(err, "local storage change owner")
- }
- }
- err = host.StartSyncTask(ctx, userCred, "")
- if err != nil {
- return nil, errors.Wrap(err, "PerformChangeOwner StartSyncTask err")
- }
- return ret, nil
- }
- func (hh *SHost) StartSyncTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
- if task, err := taskman.TaskManager.NewTask(ctx, "HostSyncTask", hh, userCred, jsonutils.NewDict(), parentTaskId, "",
- nil); err != nil {
- log.Errorln(err)
- return err
- } else {
- task.ScheduleRun(nil)
- }
- return nil
- }
- func (host *SHost) GetChangeOwnerRequiredDomainIds() []string {
- requires := stringutils2.SSortedStrings{}
- guests, _ := host.GetGuests()
- for i := range guests {
- requires = stringutils2.Append(requires, guests[i].DomainId)
- }
- return requires
- }
- func GetHostQuotaKeysFromCreateInput(owner mcclient.IIdentityProvider, input api.HostCreateInput) quotas.SDomainRegionalCloudResourceKeys {
- ownerId := &db.SOwnerId{DomainId: owner.GetProjectDomainId()}
- var zone *SZone
- if len(input.ZoneId) > 0 {
- zone = ZoneManager.FetchZoneById(input.ZoneId)
- }
- zoneKeys := fetchZonalQuotaKeys(rbacscope.ScopeDomain, ownerId, zone, nil)
- keys := quotas.SDomainRegionalCloudResourceKeys{}
- keys.SBaseDomainQuotaKeys = zoneKeys.SBaseDomainQuotaKeys
- keys.SRegionalBaseKeys = zoneKeys.SRegionalBaseKeys
- return keys
- }
- func (model *SHost) GetQuotaKeys() quotas.SDomainRegionalCloudResourceKeys {
- zone, _ := model.GetZone()
- manager := model.GetCloudprovider()
- ownerId := model.GetOwnerId()
- zoneKeys := fetchZonalQuotaKeys(rbacscope.ScopeDomain, ownerId, zone, manager)
- keys := quotas.SDomainRegionalCloudResourceKeys{}
- keys.SBaseDomainQuotaKeys = zoneKeys.SBaseDomainQuotaKeys
- keys.SRegionalBaseKeys = zoneKeys.SRegionalBaseKeys
- keys.SCloudResourceBaseKeys = zoneKeys.SCloudResourceBaseKeys
- return keys
- }
- func (host *SHost) GetUsages() []db.IUsage {
- if host.Deleted {
- return nil
- }
- usage := SInfrasQuota{Host: 1}
- keys := host.GetQuotaKeys()
- usage.SetKeys(keys)
- return []db.IUsage{
- &usage,
- }
- }
- func (host *SHost) PerformPublic(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicDomainInput) (jsonutils.JSONObject, error) {
- // perform public for all connected local storage
- storages := host._getAttachedStorages(tristate.None, tristate.None, api.HOST_STORAGE_LOCAL_TYPES)
- for i := range storages {
- _, err := storages[i].performPublicInternal(ctx, userCred, query, input)
- if err != nil {
- return nil, errors.Wrap(err, "storage.PerformPublic")
- }
- }
- return host.SEnabledStatusInfrasResourceBase.PerformPublic(ctx, userCred, query, input)
- }
- func (host *SHost) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) (jsonutils.JSONObject, error) {
- // perform private for all connected local storage
- storages := host._getAttachedStorages(tristate.None, tristate.None, api.HOST_STORAGE_LOCAL_TYPES)
- for i := range storages {
- _, err := storages[i].performPrivateInternal(ctx, userCred, query, input)
- if err != nil {
- return nil, errors.Wrap(err, "storage.PerformPrivate")
- }
- }
- return host.SEnabledStatusInfrasResourceBase.PerformPrivate(ctx, userCred, query, input)
- }
- func (host *SHost) PerformSetReservedResourceForIsolatedDevice(
- ctx context.Context, userCred mcclient.TokenCredential,
- query jsonutils.JSONObject, input api.IsolatedDeviceReservedResourceInput,
- ) (jsonutils.JSONObject, error) {
- if input.ReservedCpu != nil && *input.ReservedCpu < 0 {
- return nil, httperrors.NewInputParameterError("reserved cpu must >= 0")
- }
- if input.ReservedMemory != nil && *input.ReservedMemory < 0 {
- return nil, httperrors.NewInputParameterError("reserved memory must >= 0")
- }
- if input.ReservedStorage != nil && *input.ReservedStorage < 0 {
- return nil, httperrors.NewInputParameterError("reserved storage must >= 0")
- }
- devs := IsolatedDeviceManager.FindByHost(host.Id)
- if len(devs) == 0 {
- return nil, nil
- }
- if input.ReservedCpu != nil && host.GetCpuCount() < *input.ReservedCpu*len(devs) {
- return nil, httperrors.NewBadRequestError(
- "host %s can't reserve %d cpu for each isolated device, not enough", host.Name, *input.ReservedCpu)
- }
- if input.ReservedMemory != nil && host.GetMemSize() < *input.ReservedMemory*len(devs) {
- return nil, httperrors.NewBadRequestError(
- "host %s can't reserve %dM memory for each isolated device, not enough", host.Name, *input.ReservedMemory)
- }
- caps := host.GetAttachedLocalStorageCapacity()
- if input.ReservedStorage != nil && caps.Capacity < int64(*input.ReservedStorage*len(devs)) {
- return nil, httperrors.NewBadRequestError(
- "host %s can't reserve %dM storage for each isolated device, not enough", host.Name, input.ReservedStorage)
- }
- defer func() {
- go host.ClearSchedDescCache()
- }()
- for i := 0; i < len(devs); i++ {
- _, err := db.Update(&devs[i], func() error {
- if input.ReservedCpu != nil {
- devs[i].ReservedCpu = *input.ReservedCpu
- }
- if input.ReservedMemory != nil {
- devs[i].ReservedMemory = *input.ReservedMemory
- }
- if input.ReservedStorage != nil {
- devs[i].ReservedStorage = *input.ReservedStorage
- }
- return nil
- })
- if err != nil {
- return nil, errors.Wrap(err, "update isolated device")
- }
- }
- logclient.AddSimpleActionLog(host, logclient.ACT_SET_RESERVE_RESOURCE_FOR_ISOLATED_DEVICES, nil, userCred, true)
- return nil, nil
- }
- func (manager *SHostManager) ListItemExportKeys(ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- keys stringutils2.SSortedStrings,
- ) (*sqlchemy.SQuery, error) {
- q, err := manager.SEnabledStatusInfrasResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBaseManager.ListItemExportKeys")
- }
- if keys.ContainsAny(manager.SManagedResourceBaseManager.GetExportKeys()...) {
- q, err = manager.SManagedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemExportKeys")
- }
- }
- if keys.ContainsAny(manager.SZoneResourceBaseManager.GetExportKeys()...) {
- q, err = manager.SZoneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemExportKeys")
- }
- }
- return q, nil
- }
- func (manager *SHostManager) FetchHostByExtId(extid string) *SHost {
- host := SHost{}
- host.SetModelManager(manager, &host)
- err := manager.Query().Equals("external_id", extid).First(&host)
- if err != nil {
- log.Errorf("fetchHostByExtId fail %s", err)
- return nil
- } else {
- return &host
- }
- }
- func (host *SHost) IsAssignable(ctx context.Context, userCred mcclient.TokenCredential) error {
- if db.IsAdminAllowPerform(ctx, userCred, host, "assign-host") {
- return nil
- } else if db.IsDomainAllowPerform(ctx, userCred, host, "assign-host") &&
- (userCred.GetProjectDomainId() == host.DomainId ||
- host.PublicScope == string(rbacscope.ScopeSystem) ||
- (host.PublicScope == string(rbacscope.ScopeDomain) && utils.IsInStringArray(userCred.GetProjectDomainId(), host.GetSharedDomains()))) {
- return nil
- } else {
- return httperrors.NewNotSufficientPrivilegeError("Only system admin can assign host")
- }
- }
- func (manager *SHostManager) initHostname() error {
- hosts := []SHost{}
- q := manager.Query().IsNullOrEmpty("hostname")
- err := db.FetchModelObjects(manager, q, &hosts)
- if err != nil {
- return errors.Wrapf(err, "db.FetchModelObjects")
- }
- for i := range hosts {
- db.Update(&hosts[i], func() error {
- hostname, _ := manager.SHostnameResourceBaseManager.ValidateHostname(
- hosts[i].Hostname,
- "",
- api.HostnameInput{
- Hostname: hosts[i].Name,
- },
- )
- hosts[i].Hostname = hostname.Hostname
- return nil
- })
- }
- return nil
- }
- func (manager *SHostManager) initOvnMappedIp6Addr() error {
- hosts := []SHost{}
- q := manager.Query().IsNotEmpty("ovn_version")
- q = q.Filter(
- sqlchemy.OR(
- sqlchemy.IsNullOrEmpty(q.Field("ovn_mapped_ip6_addr")),
- sqlchemy.IsNullOrEmpty(q.Field("ovn_mapped_ip_addr")),
- ),
- )
- err := db.FetchModelObjects(manager, q, &hosts)
- if err != nil {
- return errors.Wrapf(err, "db.FetchModelObjects")
- }
- for i := range hosts {
- hh := &hosts[i]
- var v4addr string
- if hh.OvnMappedIp6Addr == "" {
- addr, err := HostManager.allocOvnMappedIpAddr(context.Background())
- if err != nil {
- return errors.Wrapf(err, "host %s(%s): alloc vpc mapped addr", hh.Name, hh.Id)
- }
- v4addr = addr
- } else {
- v4addr = hh.OvnMappedIpAddr
- }
- if _, err := db.Update(hh, func() error {
- hh.OvnMappedIpAddr = v4addr
- hh.OvnMappedIp6Addr = api.GenVpcMappedIP6(v4addr)
- return nil
- }); err != nil {
- return errors.Wrapf(err, "host %s(%s): db update vpc mapped addr", hh.Name, hh.Id)
- }
- }
- return nil
- }
- func (manager *SHostManager) InitializeData() error {
- var err error
- err = manager.initHostname()
- if err != nil {
- return errors.Wrapf(err, "initHostname")
- }
- err = manager.initOvnMappedIp6Addr()
- if err != nil {
- return errors.Wrapf(err, "initOvnMappedIp6Addr")
- }
- return nil
- }
- func (hh *SHost) PerformProbeIsolatedDevices(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- driver, err := hh.GetHostDriver()
- if err != nil {
- return nil, errors.Wrapf(err, "GetHostDriver")
- }
- return driver.RequestProbeIsolatedDevices(ctx, userCred, hh, data)
- }
- func (hh *SHost) PerformSyncIsolatedDevices(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- devs, err := IsolatedDeviceManager.GetAllDevsOnHost(hh.Id)
- if err != nil {
- return nil, err
- }
- reqDevs, err := data.GetArray("isolated_devices")
- if err != nil {
- return nil, httperrors.NewMissingParameterError("isolated_devices")
- }
- retDevs := jsonutils.NewArray()
- foundDevIndex := map[int]struct{}{}
- eg := errgroup.Group{}
- wg := sync.Mutex{}
- for i := range devs {
- foundDev := false
- dev := &devs[i]
- for j := range reqDevs {
- venderDeviceId, _ := reqDevs[j].GetString("vendor_device_id")
- devAddr, _ := reqDevs[j].GetString("addr")
- mdevId, _ := reqDevs[j].GetString("mdev_id")
- if dev.VendorDeviceId == venderDeviceId && dev.Addr == devAddr && dev.MdevId == mdevId {
- eg.Go(func() error {
- // update isolated device
- log.Infof("dev %s %s do update", dev.DevType, dev.Addr)
- devRet, err := db.DoUpdate(IsolatedDeviceManager, dev, ctx, userCred, jsonutils.NewDict(), reqDevs[j])
- if err != nil {
- return err
- }
- wg.Lock()
- retDevs.Add(devRet)
- wg.Unlock()
- return nil
- })
- foundDevIndex[j] = struct{}{}
- foundDev = true
- break
- }
- }
- if !foundDev {
- eg.Go(func() error {
- // detach isolated device
- params := jsonutils.NewDict()
- params.Set("purge", jsonutils.JSONTrue)
- _, err := dev.PerformPurge(ctx, userCred, nil, params)
- if err != nil {
- return err
- }
- return err
- })
- }
- }
- if err = eg.Wait(); err != nil {
- return nil, err
- }
- for i := range reqDevs {
- if _, ok := foundDevIndex[i]; ok {
- continue
- }
- // create isolated device
- dev, err := db.DoCreate(IsolatedDeviceManager, ctx, userCred, nil, reqDevs[i], userCred)
- if err != nil {
- return nil, err
- }
- devRet, err := db.GetItemDetails(IsolatedDeviceManager, dev, ctx, userCred)
- if err != nil {
- return nil, err
- }
- retDevs.Add(devRet)
- }
- res := jsonutils.NewDict()
- res.Set("isolated_devices", retDevs)
- return res, nil
- }
- func (hh *SHost) GetPinnedCpusetCores(ctx context.Context, userCred mcclient.TokenCredential, excludeGuestIds []string) (*cpuset.CPUSet, error) {
- gsts, err := hh.GetGuests()
- if err != nil {
- return nil, errors.Wrap(err, "Get all guests")
- }
- ret := cpuset.NewBuilder()
- for _, gst := range gsts {
- if utils.IsInStringArray(gst.Id, excludeGuestIds) {
- continue
- }
- pinned, err := gst.getPinnedCpusetCores(ctx, userCred)
- if err != nil {
- return nil, errors.Wrapf(err, "get guest %s pinned cpuset cores", gst.GetName())
- }
- ret.Add(pinned...)
- }
- resCpuset := ret.Result()
- if resCpuset.Size() == 0 {
- return nil, nil
- }
- return &resCpuset, nil
- }
- func (hh *SHost) GetReservedCpus() (*cpuset.CPUSet, error) {
- reservedCpusStr := hh.GetMetadata(context.Background(), api.HOSTMETA_RESERVED_CPUS_INFO, nil)
- if reservedCpusStr != "" {
- reservedCpusJson, err := jsonutils.ParseString(reservedCpusStr)
- if err != nil {
- return nil, errors.Wrap(err, "parse reserved cpus info failed")
- }
- reservedCpusInfo := api.HostReserveCpusInput{}
- err = reservedCpusJson.Unmarshal(&reservedCpusInfo)
- if err != nil {
- return nil, errors.Wrap(err, "unmarshal host reserved cpus info failed")
- }
- if reservedCpusInfo.Cpus == "" {
- return nil, nil
- }
- cs, err := cpuset.Parse(reservedCpusInfo.Cpus)
- if err != nil {
- return nil, errors.Wrap(err, "parse reserved cpuset")
- }
- return &cs, nil
- }
- return nil, nil
- }
- func (hh *SHost) updateHostReservedCpus(ctx context.Context, userCred mcclient.TokenCredential) error {
- reservedCpus, err := hh.GetReservedCpus()
- if err != nil {
- return err
- }
- pinnedCpus, err := hh.GetPinnedCpusetCores(ctx, userCred, nil)
- if err != nil {
- return err
- }
- var reservedCpuCnt = 0
- if reservedCpus != nil {
- reservedCpuCnt += reservedCpus.Size()
- }
- if pinnedCpus != nil {
- reservedCpuCnt += pinnedCpus.Size()
- }
- if hh.CpuReserved != reservedCpuCnt {
- _, err = db.Update(hh, func() error {
- hh.CpuReserved = reservedCpuCnt
- return nil
- })
- if err != nil {
- return err
- }
- }
- hh.ClearSchedDescCache()
- return nil
- }
- func (h *SHost) PerformSyncGuestNicTraffics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.GuestNicTrafficSyncInput) (jsonutils.JSONObject, error) {
- for guestId := range input.Traffic {
- nicTrafficMap := input.Traffic[guestId]
- guest := GuestManager.FetchGuestById(guestId)
- gns, err := guest.GetNetworks("")
- if err != nil {
- log.Errorf("failed fetch guest %s networks %s", guestId, err)
- continue
- }
- for i := range gns {
- nicTraffic, ok := nicTrafficMap[gns[i].MacAddr]
- if !ok {
- continue
- }
- if err := gns[i].UpdateNicTrafficUsed(ctx, guest, nicTraffic, input.SyncAt, input.IsReset); err != nil {
- log.Errorf("failed update guestnetwork %d traffic used %s", gns[i].RowId, err)
- continue
- }
- }
- }
- return nil, nil
- }
- func (h *SHost) GetDetailsAppOptions(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- return h.Request(ctx, userCred, httputils.GET, "/app-options", nil, nil)
- }
- func (h *SHost) GetDetailsWorkerStats(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- return h.Request(ctx, userCred, httputils.GET, "/worker_stats", nil, nil)
- }
- func (hh *SHost) GetDetailsIsolatedDeviceNumaStats(ctx context.Context, userCred mcclient.TokenCredential, input *api.HostIsolatedDeviceNumaStatsInput) (jsonutils.JSONObject, error) {
- if !utils.IsInStringArray(input.DevType, api.VALID_PASSTHROUGH_TYPES) {
- return nil, httperrors.NewInputParameterError("dev_type %s is invalid", input.DevType)
- }
- stats, err := IsolatedDeviceManager.GetHostAllocatedIsolatedDeviceNumaStats(input.DevType, hh.Id)
- if err != nil {
- return nil, err
- }
- return jsonutils.Marshal(stats), nil
- }
- func (hh *SHost) IsAttach2Wire(wireId string) bool {
- netifs := hh.getNetifsOnWire(wireId)
- return len(netifs) > 0
- }
- func (h *SHost) updateNotify(ctx context.Context, userCred mcclient.TokenCredential) {
- notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
- Action: notifyclient.ActionUpdate,
- Obj: h,
- })
- }
|