| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631 |
- // 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 (
- "bytes"
- "context"
- "database/sql"
- "fmt"
- "net/http"
- "net/url"
- "regexp"
- "strconv"
- "strings"
- "time"
- "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/billing"
- "yunion.io/x/pkg/util/compare"
- "yunion.io/x/pkg/util/netutils"
- "yunion.io/x/pkg/util/osprofile"
- "yunion.io/x/pkg/util/pinyinutils"
- "yunion.io/x/pkg/util/rbacscope"
- "yunion.io/x/pkg/util/regutils"
- "yunion.io/x/pkg/util/timeutils"
- "yunion.io/x/pkg/utils"
- "yunion.io/x/sqlchemy"
- "yunion.io/x/onecloud/pkg/apis"
- billing_api "yunion.io/x/onecloud/pkg/apis/billing"
- api "yunion.io/x/onecloud/pkg/apis/compute"
- imageapi "yunion.io/x/onecloud/pkg/apis/image"
- schedapi "yunion.io/x/onecloud/pkg/apis/scheduler"
- "yunion.io/x/onecloud/pkg/cloudcommon/cmdline"
- "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/policy"
- "yunion.io/x/onecloud/pkg/cloudcommon/userdata"
- "yunion.io/x/onecloud/pkg/compute/options"
- "yunion.io/x/onecloud/pkg/compute/sshkeys"
- devtool_utils "yunion.io/x/onecloud/pkg/devtool/utils"
- "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/image"
- "yunion.io/x/onecloud/pkg/util/bitmap"
- "yunion.io/x/onecloud/pkg/util/logclient"
- "yunion.io/x/onecloud/pkg/util/netutils2"
- "yunion.io/x/onecloud/pkg/util/rbacutils"
- "yunion.io/x/onecloud/pkg/util/seclib2"
- "yunion.io/x/onecloud/pkg/util/stringutils2"
- )
- // +onecloud:swagger-gen-model-singular=server
- // +onecloud:swagger-gen-model-plural=servers
- type SGuestManager struct {
- db.SVirtualResourceBaseManager
- db.SExternalizedResourceBaseManager
- SDeletePreventableResourceBaseManager
- SHostResourceBaseManager
- SBillingResourceBaseManager
- SNetworkResourceBaseManager
- SDiskResourceBaseManager
- SScalingGroupResourceBaseManager
- db.SMultiArchResourceBaseManager
- db.SRecordChecksumResourceBaseManager
- SHostnameResourceBaseManager
- db.SEncryptedResourceManager
- }
- var GuestManager *SGuestManager
- func init() {
- GuestManager = &SGuestManager{
- SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
- SGuest{},
- "guests_tbl",
- "server",
- "servers",
- ),
- SRecordChecksumResourceBaseManager: *db.NewRecordChecksumResourceBaseManager(),
- }
- GuestManager.SetVirtualObject(GuestManager)
- GuestManager.SetAlias("guest", "guests")
- GuestManager.NameRequireAscii = false
- notifyclient.AddNotifyDBHookResources(GuestManager.KeywordPlural(), GuestManager.AliasPlural())
- }
- type SGuest struct {
- db.SVirtualResourceBase
- db.SExternalizedResourceBase
- SBillingResourceBase
- SDeletePreventableResourceBase
- db.SMultiArchResourceBase
- db.SRecordChecksumResourceBase
- SHostnameResourceBase
- SHostResourceBase `width:"36" charset:"ascii" nullable:"true" list:"user" get:"user" index:"true"`
- db.SEncryptedResource
- // CPU插槽(socket)的数量
- CpuSockets int `nullable:"false" default:"1" list:"user" create:"optional"`
- // CPU核(core)的数量, VcpuCount = CpuSockets * (cores per socket),例如 2颗CPU,每颗CPU8核,则 VcpuCount=2*8=16
- VcpuCount int `nullable:"false" default:"1" list:"user" create:"optional"`
- // 内存大小, 单位MB
- VmemSize int `nullable:"false" list:"user" create:"required"`
- // CPU 内存绑定信息
- CpuNumaPin jsonutils.JSONObject `nullable:"true" get:"user" update:"user" create:"optional"`
- // 额外分配的 CPU 数量
- ExtraCpuCount int `nullable:"false" default:"0" list:"user" create:"optional"`
- // 启动顺序
- BootOrder string `width:"8" charset:"ascii" nullable:"true" default:"cdn" list:"user" update:"user" create:"optional"`
- // 关机操作类型
- // example: stop
- ShutdownBehavior string `width:"16" charset:"ascii" default:"stop" list:"user" update:"user" create:"optional"`
- // 关机收费模式
- // example: keep_charging, stop_charging
- ShutdownMode string `width:"16" charset:"ascii" default:"keep_charging" list:"user"`
- // 秘钥对Id
- KeypairId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"`
- // 备份机所在宿主机Id
- BackupHostId string `width:"36" charset:"ascii" nullable:"true" list:"user" get:"user"`
- BackupGuestStatus string `width:"36" charset:"ascii" nullable:"false" default:"init" list:"user" create:"optional" json:"backup_guest_status"`
- // 迁移或克隆的速度
- ProgressMbps float64 `nullable:"false" default:"0" list:"user" create:"optional" update:"user" log:"skip"`
- Vga string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- Vdi string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- Machine string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- Bios string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" create:"optional"`
- // 操作系统类型
- OsType string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"`
- FlavorId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"`
- // 安全组Id
- // example: default
- SecgrpId string `width:"36" charset:"ascii" nullable:"true" list:"user" get:"user" create:"optional"`
- // 管理员可见安全组Id
- AdminSecgrpId string `width:"36" charset:"ascii" nullable:"true" list:"domain" get:"domain"`
- SrcIpCheck tristate.TriState `default:"true" create:"optional" list:"user" update:"user"`
- SrcMacCheck tristate.TriState `default:"true" create:"optional" list:"user" update:"user"`
- // 虚拟化技术
- // example: kvm
- Hypervisor string `width:"16" charset:"ascii" nullable:"false" default:"kvm" list:"user" create:"required"`
- // 套餐名称
- InstanceType string `width:"64" charset:"utf8" nullable:"true" list:"user" create:"optional"`
- SshableLastState tristate.TriState `default:"false" list:"user"`
- IsDaemon tristate.TriState `default:"false" list:"admin" create:"admin_optional" update:"admin"`
- // 最大内网带宽
- InternetMaxBandwidthOut int `nullable:"true" list:"user" create:"optional"`
- // 磁盘吞吐量
- Throughput int `nullable:"true" list:"user" create:"optional"`
- QgaStatus string `width:"36" charset:"ascii" nullable:"false" default:"unknown" list:"user" create:"optional"`
- // power_states limit in [on, off, unknown]
- PowerStates string `width:"36" charset:"ascii" nullable:"false" default:"unknown" list:"user" create:"optional"`
- // 健康状态, 仅开机中火运行中有效, 目前只支持阿里云
- HealthStatus string `width:"36" charset:"ascii" nullable:"true" default:"ok" list:"user"`
- // Used for guest rescue
- RescueMode bool `nullable:"false" default:"false" list:"user" create:"optional"`
- // 上次开机时间
- LastStartAt time.Time `json:"last_start_at" list:"user"`
- // 资源池,仅vmware指定调度标签时内部使用
- ResourcePool string `width:"64" charset:"utf8" nullable:"true" create:"optional"`
- }
- func (manager *SGuestManager) GetPropertyStatistics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*apis.StatusStatistic, error) {
- ret, err := manager.SVirtualResourceBaseManager.GetPropertyStatistics(ctx, userCred, query)
- if err != nil {
- return nil, err
- }
- q := manager.Query()
- q, err = db.ListItemQueryFilters(manager, ctx, q, userCred, query, policy.PolicyActionList)
- if err != nil {
- return nil, err
- }
- sq := q.SubQuery()
- statQ := sq.Query(sqlchemy.SUM("total_cpu_count", sq.Field("vcpu_count")), sqlchemy.SUM("total_mem_size_mb", sq.Field("vmem_size")))
- err = statQ.First(ret)
- if err != nil {
- return ret, err
- }
- diskQ := DiskManager.Query()
- gdsSQ := GuestdiskManager.Query().SubQuery()
- diskQ = diskQ.Join(gdsSQ, sqlchemy.Equals(diskQ.Field("id"), gdsSQ.Field("disk_id"))).
- Join(sq, sqlchemy.Equals(gdsSQ.Field("guest_id"), sq.Field("id")))
- diskSQ := diskQ.SubQuery()
- return ret, diskSQ.Query(sqlchemy.SUM("total_disk_size_mb", diskSQ.Field("disk_size"))).First(ret)
- }
- // 云主机实例列表
- func (manager *SGuestManager) ListItemFilter(
- ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- query api.ServerListInput,
- ) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SHostResourceBaseManager.ListItemFilter(ctx, q, userCred, query.HostFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SHostResourceBaseManager.ListItemFilter")
- }
- q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
- }
- q, err = manager.SDeletePreventableResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DeletePreventableResourceBaseListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SDeletePreventableResourceBaseManager.ListItemFilter")
- }
- q, err = manager.SBillingResourceBaseManager.ListItemFilter(ctx, q, userCred, query.BillingResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SBillingResourceBaseManager.ListItemFilter")
- }
- q, err = manager.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter")
- }
- q, err = manager.SMultiArchResourceBaseManager.ListItemFilter(ctx, q, userCred, query.MultiArchResourceBaseListInput)
- if err != nil {
- return nil, errors.Wrap(err, "MultiArchResourceBaseListInput.ListItemFilter")
- }
- netQ := GuestnetworkManager.Query("guest_id").Snapshot()
- netQ, err = manager.SNetworkResourceBaseManager.ListItemFilter(ctx, netQ, userCred, query.NetworkFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SNetworkResourceBaseManager.ListItemFilter")
- }
- if netQ.IsAltered() {
- q = q.In("id", netQ.SubQuery())
- }
- //diskQ := GuestdiskManager.Query("guest_id").Snapshot()
- //diskQ, err = manager.SDiskResourceBaseManager.ListItemFilter(ctx, diskQ, userCred, query.DiskFilterListInput)
- //if err != nil {
- // return nil, errors.Wrap(err, "SDiskResourceBaseManager.ListItemFilter")
- //}
- //if diskQ.IsAltered() {
- // q = q.In("id", diskQ.SubQuery())
- //}
- scalingGroupQ := ScalingGroupGuestManager.Query("guest_id").Snapshot()
- scalingGroupQ, err = manager.SScalingGroupResourceBaseManager.ListItemFilter(ctx, scalingGroupQ, userCred, query.ScalingGroupFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SScaligGroupResourceBaseManager.ListItemFilter")
- }
- if scalingGroupQ.IsAltered() {
- q = q.In("id", scalingGroupQ.SubQuery())
- }
- hypervisorList := query.Hypervisor
- if len(hypervisorList) > 0 {
- q = q.In("hypervisor", hypervisorList)
- }
- resourceTypeStr := query.ResourceType
- if len(resourceTypeStr) > 0 {
- hosts := HostManager.Query().SubQuery()
- subq := hosts.Query(hosts.Field("id"))
- switch resourceTypeStr {
- case api.HostResourceTypeShared:
- subq = subq.Filter(
- sqlchemy.OR(
- sqlchemy.IsNullOrEmpty(hosts.Field("resource_type")),
- sqlchemy.Equals(hosts.Field("resource_type"), resourceTypeStr),
- ),
- )
- default:
- subq = subq.Equals("resource_type", resourceTypeStr)
- }
- q = q.In("host_id", subq.SubQuery())
- }
- hostFilter := query.GetAllGuestsOnHost
- if len(hostFilter) > 0 {
- host, _ := HostManager.FetchByIdOrName(ctx, nil, hostFilter)
- if host == nil {
- return nil, httperrors.NewResourceNotFoundError("host %s not found", hostFilter)
- }
- q.Filter(sqlchemy.OR(sqlchemy.Equals(q.Field("host_id"), host.GetId()),
- sqlchemy.Equals(q.Field("backup_host_id"), host.GetId())))
- }
- secgrpFilter := query.SecgroupId
- if len(secgrpFilter) > 0 {
- var notIn = false
- // HACK FOR NOT IN SECGROUP
- if strings.HasPrefix(secgrpFilter, "!") {
- secgrpFilter = secgrpFilter[1:]
- notIn = true
- }
- secgrpIds := []string{}
- secgrps := []SSecurityGroup{}
- sgq := SecurityGroupManager.Query()
- sgq = sgq.Filter(sqlchemy.OR(sqlchemy.Equals(sgq.Field("id"), secgrpFilter), sqlchemy.Equals(sgq.Field("name"), secgrpFilter)))
- if err := db.FetchModelObjects(SecurityGroupManager, sgq, &secgrps); err != nil {
- return nil, err
- }
- if len(secgrps) == 0 {
- return nil, httperrors.NewResourceNotFoundError("secgroup %s not found", secgrpFilter)
- }
- for _, secgrp := range secgrps {
- secgrpIds = append(secgrpIds, secgrp.Id)
- }
- isAdmin := false
- // admin := (query.VirtualResourceListInput.Admin != nil && *query.VirtualResourceListInput.Admin)
- allowScope, _ := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policy.PolicyActionList)
- if allowScope == rbacscope.ScopeSystem || allowScope == rbacscope.ScopeDomain {
- isAdmin = true
- }
- filters := []sqlchemy.ICondition{}
- if notIn {
- filters = append(filters, sqlchemy.NotIn(q.Field("id"),
- GuestsecgroupManager.Query("guest_id").In("secgroup_id", secgrpIds).SubQuery()))
- filters = append(filters, sqlchemy.NotIn(q.Field("secgrp_id"), secgrpIds))
- if isAdmin {
- filters = append(filters, sqlchemy.NotIn(q.Field("admin_secgrp_id"), secgrpIds))
- }
- q = q.Filter(sqlchemy.AND(filters...))
- } else {
- filters = append(filters, sqlchemy.In(q.Field("id"),
- GuestsecgroupManager.Query("guest_id").In("secgroup_id", secgrpIds).SubQuery()))
- filters = append(filters, sqlchemy.In(q.Field("secgrp_id"), secgrpIds))
- if isAdmin {
- filters = append(filters, sqlchemy.In(q.Field("admin_secgrp_id"), secgrpIds))
- }
- q = q.Filter(sqlchemy.OR(filters...))
- }
- }
- var eipMode string
- usableServerForEipFilter := query.UsableServerForEip
- if len(usableServerForEipFilter) > 0 {
- eipObj, err := ElasticipManager.FetchByIdOrName(ctx, userCred, usableServerForEipFilter)
- if err != nil {
- if err == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotFoundError("eip %s not found", usableServerForEipFilter)
- }
- return nil, httperrors.NewGeneralError(err)
- }
- eip := eipObj.(*SElasticip)
- if eip.GetProviderName() == api.CLOUD_PROVIDER_AWS {
- eipMode = api.EIP_MODE_STANDALONE_EIP
- }
- if len(eip.NetworkId) > 0 {
- sq := GuestnetworkManager.Query("guest_id").Equals("network_id", eip.NetworkId).SubQuery()
- q = q.NotIn("id", sq)
- if cp := eip.GetCloudprovider(); cp == nil || cp.Provider == api.CLOUD_PROVIDER_ONECLOUD {
- gnq := GuestnetworkManager.Query().SubQuery()
- nq := NetworkManager.Query().SubQuery()
- wq := WireManager.Query().SubQuery()
- vq := VpcManager.Query().SubQuery()
- q.Join(gnq, sqlchemy.Equals(gnq.Field("guest_id"), q.Field("id")))
- q.Join(nq, sqlchemy.Equals(nq.Field("id"), gnq.Field("network_id")))
- q.Join(wq, sqlchemy.Equals(wq.Field("id"), nq.Field("wire_id")))
- q.Join(vq, sqlchemy.Equals(vq.Field("id"), wq.Field("vpc_id")))
- q.Filter(sqlchemy.IsNullOrEmpty(gnq.Field("eip_id")))
- q.Filter(sqlchemy.NotEquals(vq.Field("id"), api.DEFAULT_VPC_ID))
- // vpc provider thing will be handled ok below
- }
- }
- hostTable := HostManager.Query().SubQuery()
- zoneTable := ZoneManager.Query().SubQuery()
- hostQ := hostTable.Query(hostTable.Field("id"))
- hostQ = hostQ.Join(zoneTable,
- sqlchemy.Equals(zoneTable.Field("id"), hostTable.Field("zone_id")))
- if eip.ManagerId != "" {
- hostQ = hostQ.Equals("manager_id", eip.ManagerId)
- } else {
- hostQ = hostQ.IsNullOrEmpty("manager_id")
- }
- region, err := eip.GetRegion()
- if err != nil {
- return nil, httperrors.NewGeneralError(errors.Wrapf(err, "eip.GetRegion"))
- }
- regionTable := CloudregionManager.Query().SubQuery()
- sq := hostQ.Join(regionTable, sqlchemy.Equals(zoneTable.Field("cloudregion_id"), regionTable.Field("id"))).
- Filter(sqlchemy.Equals(regionTable.Field("id"), region.GetId())).SubQuery()
- q = q.In("host_id", sq)
- }
- if len(query.IpAddrs) > 0 {
- // 如果只有一个ip地址,则使用正则匹配,否则使用等于匹配
- cmpFunc := sqlchemy.Equals
- if len(query.IpAddrs) == 1 {
- cmpFunc = func(f sqlchemy.IQueryField, v interface{}) sqlchemy.ICondition {
- return sqlchemy.Regexp(f, v.(string))
- }
- }
- grpnets := GroupnetworkManager.Query().SubQuery()
- vipq := GroupguestManager.Query("guest_id")
- conditions := []sqlchemy.ICondition{}
- for _, ipAddr := range query.IpAddrs {
- conditions = append(conditions, cmpFunc(grpnets.Field("ip_addr"), ipAddr))
- conditions = append(conditions, cmpFunc(grpnets.Field("ip6_addr"), ipAddr))
- }
- vipq = vipq.Join(grpnets, sqlchemy.Equals(grpnets.Field("group_id"), vipq.Field("group_id"))).Filter(
- sqlchemy.OR(conditions...),
- )
- grpeips := ElasticipManager.Query().Equals("associate_type", api.EIP_ASSOCIATE_TYPE_INSTANCE_GROUP).SubQuery()
- conditions = []sqlchemy.ICondition{}
- for _, ipAddr := range query.IpAddrs {
- conditions = append(conditions, cmpFunc(grpeips.Field("ip_addr"), ipAddr))
- }
- vipeipq := GroupguestManager.Query("guest_id")
- vipeipq = vipeipq.Join(grpeips, sqlchemy.Equals(grpeips.Field("associate_id"), vipeipq.Field("group_id"))).Filter(
- sqlchemy.OR(conditions...),
- )
- gnQ := GuestnetworkManager.Query("guest_id")
- conditions = []sqlchemy.ICondition{}
- for _, ipAddr := range query.IpAddrs {
- conditions = append(conditions, cmpFunc(gnQ.Field("ip_addr"), ipAddr))
- conditions = append(conditions, cmpFunc(gnQ.Field("ip6_addr"), ipAddr))
- }
- gn := gnQ.Filter(sqlchemy.OR(conditions...))
- guestEipQ := ElasticipManager.Query("associate_id").Equals("associate_type", api.EIP_ASSOCIATE_TYPE_SERVER)
- conditions = []sqlchemy.ICondition{}
- for _, ipAddr := range query.IpAddrs {
- conditions = append(conditions, cmpFunc(guestEipQ.Field("ip_addr"), ipAddr))
- }
- guestEip := guestEipQ.Filter(sqlchemy.OR(conditions...))
- metadataQ := db.Metadata.Query("obj_id")
- conditions = []sqlchemy.ICondition{}
- for _, ipAddr := range query.IpAddrs {
- conditions = append(conditions, sqlchemy.AND(
- cmpFunc(metadataQ.Field("value"), ipAddr),
- sqlchemy.Equals(metadataQ.Field("key"), "sync_ips"),
- sqlchemy.Equals(metadataQ.Field("obj_type"), "server"),
- ))
- }
- metadataQ = metadataQ.Filter(sqlchemy.OR(conditions...))
- q = q.Filter(sqlchemy.OR(
- sqlchemy.In(q.Field("id"), gn.SubQuery()),
- sqlchemy.In(q.Field("id"), guestEip.SubQuery()),
- sqlchemy.In(q.Field("id"), vipq.SubQuery()),
- sqlchemy.In(q.Field("id"), vipeipq.SubQuery()),
- sqlchemy.In(q.Field("id"), metadataQ.SubQuery()),
- ))
- }
- diskFilter := query.AttachableServersForDisk
- if len(diskFilter) > 0 {
- diskI, _ := DiskManager.FetchByIdOrName(ctx, userCred, diskFilter)
- if diskI == nil {
- return nil, httperrors.NewResourceNotFoundError("disk %s not found", diskFilter)
- }
- disk := diskI.(*SDisk)
- guestdisks := GuestdiskManager.Query().SubQuery()
- count, err := guestdisks.Query().Equals("disk_id", disk.Id).CountWithError()
- if err != nil {
- return nil, httperrors.NewInternalServerError("checkout guestdisk count fail %s", err)
- }
- if count > 0 {
- sgq := guestdisks.Query(guestdisks.Field("guest_id")).Equals("disk_id", disk.Id).SubQuery()
- q = q.Filter(sqlchemy.In(q.Field("id"), sgq))
- } else {
- hosts := HostManager.Query().SubQuery()
- hoststorages := HoststorageManager.Query().SubQuery()
- storages := StorageManager.Query().SubQuery()
- sq := hosts.Query(hosts.Field("id")).
- Join(hoststorages, sqlchemy.Equals(hoststorages.Field("host_id"), hosts.Field("id"))).
- Join(storages, sqlchemy.Equals(storages.Field("id"), hoststorages.Field("storage_id"))).
- Filter(sqlchemy.Equals(storages.Field("id"), disk.StorageId)).SubQuery()
- q = q.In("host_id", sq)
- }
- }
- withEip := (query.WithEip != nil && *query.WithEip)
- withoutEip := (query.WithoutEip != nil && *query.WithoutEip) || (query.EipAssociable != nil && *query.EipAssociable)
- if withEip || withoutEip {
- eips := ElasticipManager.Query().SubQuery()
- sq := eips.Query(eips.Field("associate_id")).Equals("associate_type", api.EIP_ASSOCIATE_TYPE_SERVER)
- sq = sq.IsNotNull("associate_id").IsNotEmpty("associate_id")
- if len(eipMode) > 0 {
- sq = sq.Equals("mode", eipMode)
- }
- if withEip {
- q = q.In("id", sq)
- } else if withoutEip {
- q = q.NotIn("id", sq)
- }
- }
- if query.EipAssociable != nil {
- sq1 := NetworkManager.Query("id")
- sq2 := WireManager.Query().SubQuery()
- sq3 := VpcManager.Query().SubQuery()
- sq1 = sq1.Join(sq2, sqlchemy.Equals(sq1.Field("wire_id"), sq2.Field("id")))
- sq1 = sq1.Join(sq3, sqlchemy.Equals(sq2.Field("vpc_id"), sq3.Field("id")))
- cond1 := []string{api.VPC_EXTERNAL_ACCESS_MODE_EIP, api.VPC_EXTERNAL_ACCESS_MODE_EIP_DISTGW}
- if *query.EipAssociable {
- sq1 = sq1.Filter(sqlchemy.In(sq3.Field("external_access_mode"), cond1))
- } else {
- sq1 = sq1.Filter(sqlchemy.NotIn(sq3.Field("external_access_mode"), cond1))
- }
- sq := GuestnetworkManager.Query("guest_id").In("network_id", sq1)
- q = q.In("id", sq)
- }
- devTypeQ := func(q *sqlchemy.SQuery, checkType, backup *bool, dType string, conditions []sqlchemy.ICondition) []sqlchemy.ICondition {
- if checkType != nil {
- isodev := IsolatedDeviceManager.Query().SubQuery()
- isodevCons := []sqlchemy.ICondition{sqlchemy.IsNotNull(isodev.Field("guest_id"))}
- if len(dType) > 0 {
- isodevCons = append(isodevCons, sqlchemy.Startswith(isodev.Field("dev_type"), dType))
- }
- sgq := isodev.Query(isodev.Field("guest_id")).Filter(sqlchemy.AND(isodevCons...))
- cond := sqlchemy.NotIn
- if *checkType {
- cond = sqlchemy.In
- }
- if dType == "GPU" {
- sq := ServerSkuManager.Query("name").GT("gpu_count", 0).Distinct().SubQuery()
- if backup != nil {
- afterAnd := sqlchemy.AND
- if *backup {
- backupCond := sqlchemy.IsNotEmpty(q.Field("backup_host_id"))
- conditions = append(conditions, afterAnd(cond(q.Field("instance_type"), sq), backupCond))
- } else {
- backupCond := sqlchemy.IsEmpty(q.Field("backup_host_id"))
- conditions = append(conditions, afterAnd(cond(q.Field("instance_type"), sq), backupCond))
- }
- } else {
- conditions = append(conditions, cond(q.Field("instance_type"), sq))
- }
- } else {
- if backup != nil {
- afterAnd := sqlchemy.AND
- if *backup {
- backupCond := sqlchemy.IsNotEmpty(q.Field("backup_host_id"))
- conditions = append(conditions, afterAnd(cond(q.Field("id"), sgq), backupCond))
- } else {
- backupCond := sqlchemy.IsEmpty(q.Field("backup_host_id"))
- conditions = append(conditions, afterAnd(cond(q.Field("id"), sgq), backupCond))
- }
- } else {
- conditions = append(conditions, cond(q.Field("id"), sgq))
- }
- }
- return conditions
- }
- return conditions
- }
- conditions := []sqlchemy.ICondition{}
- if len(query.ServerType) > 0 {
- var trueVal, falseVal = true, false
- for _, serverType := range query.ServerType {
- switch serverType {
- case "normal":
- query.Normal = &falseVal
- query.Backup = &falseVal
- case "gpu":
- query.Gpu = &trueVal
- query.Backup = &falseVal
- sq := ServerSkuManager.Query("name").IsNotEmpty("gpu_spec").Distinct()
- conditions = append(conditions, sqlchemy.In(q.Field("instance_type"), sq.SubQuery()))
- case "backup":
- query.Gpu = &falseVal
- query.Backup = &trueVal
- case "usb":
- query.Usb = &trueVal
- query.Backup = &falseVal
- default:
- query.CustomDevType = serverType
- query.Backup = &falseVal
- }
- conditions = devTypeQ(q, query.Normal, query.Backup, "", conditions)
- conditions = devTypeQ(q, query.Gpu, query.Backup, "GPU", conditions)
- conditions = devTypeQ(q, query.Usb, query.Backup, api.USB_TYPE, conditions)
- if len(query.CustomDevType) > 0 {
- ct := true
- conditions = devTypeQ(q, &ct, query.Backup, query.CustomDevType, conditions)
- }
- query.Normal = nil
- query.Gpu = nil
- query.Backup = nil
- }
- }
- if len(conditions) > 0 {
- q = q.Filter(sqlchemy.OR(conditions...))
- }
- groupFilter := query.GroupId
- if len(groupFilter) != 0 {
- groupObj, err := GroupManager.FetchByIdOrName(ctx, userCred, groupFilter)
- if err != nil {
- return nil, httperrors.NewNotFoundError("group %s not found", groupFilter)
- }
- // queryDict.Add(jsonutils.NewString(groupObj.GetId()), "group")
- ggSub := GroupguestManager.Query("guest_id").Equals("group_id", groupObj.GetId()).SubQuery()
- q = q.Join(ggSub, sqlchemy.Equals(ggSub.Field("guest_id"), q.Field("id")))
- }
- /*orderByDisk := query.OrderByDisk
- if orderByDisk == "asc" || orderByDisk == "desc" {
- guestdisks := GuestdiskManager.Query().SubQuery()
- disks := DiskManager.Query().SubQuery()
- guestdiskQ := guestdisks.Query(
- guestdisks.Field("guest_id"),
- sqlchemy.SUM("disks_size", disks.Field("disk_size")),
- )
- guestdiskQ = guestdiskQ.LeftJoin(disks, sqlchemy.Equals(guestdiskQ.Field("disk_id"), disks.Field("id")))
- guestdiskSQ := guestdiskQ.GroupBy(guestdiskQ.Field("guest_id")).SubQuery()
- q = q.LeftJoin(guestdiskSQ, sqlchemy.Equals(q.Field("id"), guestdiskSQ.Field("guest_id")))
- switch orderByDisk {
- case "asc":
- q = q.Asc(guestdiskSQ.Field("disks_size"))
- case "desc":
- q = q.Desc(guestdiskSQ.Field("disks_size"))
- }
- }*/
- if len(query.OsType) > 0 {
- q = q.In("os_type", query.OsType)
- }
- if len(query.OsDist) > 0 {
- metaSQ := db.Metadata.Query().Equals("key", "os_distribution").In("value", query.OsDist).SubQuery()
- q = q.Join(metaSQ, sqlchemy.Equals(q.Field("id"), metaSQ.Field("obj_id")))
- }
- if len(query.VcpuCount) > 0 {
- q = q.In("vcpu_count", query.VcpuCount)
- }
- if len(query.VmemSize) > 0 {
- q = q.In("vmem_size", query.VmemSize)
- }
- if len(query.BootOrder) > 0 {
- q = q.In("boot_order", query.BootOrder)
- }
- if len(query.Vga) > 0 {
- q = q.In("vga", query.Vga)
- }
- if len(query.Vdi) > 0 {
- q = q.In("vdi", query.Vdi)
- }
- if len(query.Machine) > 0 {
- q = q.In("machine", query.Machine)
- }
- if len(query.Bios) > 0 {
- q = q.In("bios", query.Bios)
- }
- if query.SrcIpCheck != nil {
- if *query.SrcIpCheck {
- q = q.IsTrue("src_ip_check")
- } else {
- q = q.IsFalse("src_ip_check")
- }
- }
- if query.SrcMacCheck != nil {
- if *query.SrcMacCheck {
- q = q.IsTrue("src_mac_check")
- } else {
- q = q.IsFalse("src_mac_check")
- }
- }
- if len(query.InstanceType) > 0 {
- q = q.In("instance_type", query.InstanceType)
- }
- if query.WithHost != nil {
- if *query.WithHost {
- q = q.IsNotEmpty("host_id")
- } else {
- q = q.IsNullOrEmpty("host_id")
- }
- }
- if len(query.SnapshotpolicyId) > 0 {
- sp := SnapshotPolicyResourceManager.Query("resource_id").
- Equals("resource_type", api.SNAPSHOT_POLICY_TYPE_SERVER).
- Equals("snapshotpolicy_id", query.SnapshotpolicyId).SubQuery()
- q = q.In("id", sp)
- }
- if query.BindingSnapshotpolicy != nil {
- spjsq := SnapshotPolicyResourceManager.Query("resource_id").
- Equals("resource_type", api.SNAPSHOT_POLICY_TYPE_SERVER).
- SubQuery()
- if *query.BindingSnapshotpolicy {
- q = q.In("id", spjsq)
- } else {
- q = q.NotIn("id", spjsq)
- }
- }
- if query.BindingDisksSnapshotpolicy != nil {
- guestDisks := GuestdiskManager.Query("guest_id")
- sq := SnapshotPolicyResourceManager.Query("resource_id").Equals("resource_type", api.SNAPSHOT_POLICY_TYPE_DISK).SubQuery()
- gdsq := guestDisks.Join(sq, sqlchemy.Equals(guestDisks.Field("disk_id"), sq.Field("resource_id"))).SubQuery()
- if *query.BindingDisksSnapshotpolicy {
- q = q.In("id", gdsq)
- } else {
- q = q.NotIn("id", gdsq)
- }
- }
- return q, nil
- }
- func (manager *SGuestManager) ExtraSearchConditions(ctx context.Context, q *sqlchemy.SQuery, like string) []sqlchemy.ICondition {
- var sq *sqlchemy.SSubQuery
- if len(like) > 1 {
- switch {
- case strings.Contains(like, "."):
- sq = GuestnetworkManager.Query("guest_id").Contains("ip_addr", like).SubQuery()
- case strings.Contains(like, ":"):
- sq = GuestnetworkManager.Query("guest_id").Contains("mac_addr", like).SubQuery()
- }
- }
- if sq != nil {
- return []sqlchemy.ICondition{sqlchemy.In(q.Field("id"), sq)}
- }
- return nil
- }
- func (manager *SGuestManager) OrderByExtraFields(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ServerListInput) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields")
- }
- q, err = manager.SHostResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.HostFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SHostResourceBaseManager.OrderByExtraFields")
- }
- fields := manager.SNetworkResourceBaseManager.GetOrderByFields(query.NetworkFilterListInput)
- if db.NeedOrderQuery(fields) {
- netQ := GuestnetworkManager.Query("guest_id", "network_id").SubQuery()
- q = q.LeftJoin(netQ, sqlchemy.Equals(q.Field("id"), netQ.Field("guest_id"))).Distinct()
- q, err = manager.SNetworkResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.NetworkFilterListInput)
- if err != nil {
- return nil, errors.Wrap(err, "SNetworkResourceBaseManager.OrderByExtraFields")
- }
- }
- if db.NeedOrderQuery([]string{query.OrderByOsDist}) {
- meta := db.Metadata.Query().Equals("key", "os_distribution").SubQuery()
- q = q.LeftJoin(meta, sqlchemy.Equals(q.Field("id"), meta.Field("obj_id")))
- db.OrderByFields(q, []string{query.OrderByOsDist}, []sqlchemy.IQueryField{meta.Field("value")})
- }
- if db.NeedOrderQuery([]string{query.OrderByDisk}) {
- guestdisks := GuestdiskManager.Query().SubQuery()
- disks := DiskManager.Query().SubQuery()
- guestdiskQ := guestdisks.Query(
- guestdisks.Field("guest_id"),
- sqlchemy.SUM("disks_size", disks.Field("disk_size")),
- )
- guestdiskQ = guestdiskQ.LeftJoin(disks, sqlchemy.Equals(guestdiskQ.Field("disk_id"), disks.Field("id")))
- guestdiskSQ := guestdiskQ.GroupBy(guestdiskQ.Field("guest_id")).SubQuery()
- q = q.LeftJoin(guestdiskSQ, sqlchemy.Equals(q.Field("id"), guestdiskSQ.Field("guest_id")))
- db.OrderByFields(q, []string{query.OrderByDisk}, []sqlchemy.IQueryField{guestdiskSQ.Field("disks_size")})
- }
- if db.NeedOrderQuery([]string{query.OrderByIp}) {
- guestnet := GuestnetworkManager.Query("guest_id", "ip_addr").SubQuery()
- q.AppendField(q.QueryFields()...)
- q.AppendField(guestnet.Field("ip_addr"))
- q = q.LeftJoin(guestnet, sqlchemy.Equals(q.Field("id"), guestnet.Field("guest_id")))
- db.OrderByFields(q, []string{query.OrderByIp}, []sqlchemy.IQueryField{sqlchemy.INET_ATON(q.Field("ip_addr"))})
- }
- return q, nil
- }
- func (manager *SGuestManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- q, err = manager.SHostResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- if field == "os_dist" {
- metaQuery := db.Metadata.Query("obj_id", "value").Equals("key", "os_distribution").SubQuery()
- q = q.AppendField(metaQuery.Field("value", field)).Distinct()
- q = q.Join(metaQuery, sqlchemy.Equals(q.Field("id"), metaQuery.Field("obj_id")))
- q.GroupBy(metaQuery.Field("value"))
- return q, nil
- }
- guestnets := GuestnetworkManager.Query("guest_id", "network_id").SubQuery()
- q = q.LeftJoin(guestnets, sqlchemy.Equals(q.Field("id"), guestnets.Field("guest_id")))
- q, err = manager.SNetworkResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- guestdisks := GuestdiskManager.Query("guest_id", "disk_id").SubQuery()
- q = q.LeftJoin(guestdisks, sqlchemy.Equals(q.Field("id"), guestdisks.Field("guest_id")))
- q, err = manager.SDiskResourceBaseManager.QueryDistinctExtraField(q, field)
- if err == nil {
- return q, nil
- }
- return q, httperrors.ErrNotFound
- }
- func (manager *SGuestManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
- switch resource {
- case NetworkManager.Keyword():
- guestnets := GuestnetworkManager.Query("guest_id", "network_id").SubQuery()
- q = q.LeftJoin(guestnets, sqlchemy.Equals(q.Field("id"), guestnets.Field("guest_id")))
- return manager.SNetworkResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
- }
- return q, httperrors.ErrNotFound
- }
- func (manager *SGuestManager) initHostname() error {
- guests := []SGuest{}
- q := manager.Query().IsNullOrEmpty("hostname")
- err := db.FetchModelObjects(manager, q, &guests)
- if err != nil {
- return errors.Wrapf(err, "db.FetchModelObjects")
- }
- for i := range guests {
- db.Update(&guests[i], func() error {
- hostname, _ := manager.SHostnameResourceBaseManager.ValidateHostname(
- guests[i].Hostname,
- guests[i].OsType,
- api.HostnameInput{
- Hostname: guests[i].Name,
- },
- )
- guests[i].Hostname = hostname.Hostname
- return nil
- })
- }
- return nil
- }
- func (manager *SGuestManager) clearSecgroups() error {
- guests := make([]SGuest, 0, 10)
- q := manager.Query()
- q = q.In("hypervisor", []string{api.HYPERVISOR_ESXI, api.HYPERVISOR_NUTANIX}).Filter(
- sqlchemy.OR(
- sqlchemy.IsNotEmpty(q.Field("secgrp_id")),
- sqlchemy.IsNotEmpty(q.Field("admin_secgrp_id")),
- ),
- )
- err := db.FetchModelObjects(manager, q, &guests)
- if err != nil {
- return errors.Wrap(err, "db.FetchModelObjects")
- }
- // remove secgroup for esxi nutanix guest
- for i := range guests {
- db.Update(&guests[i], func() error {
- guests[i].SecgrpId = ""
- guests[i].AdminSecgrpId = ""
- return nil
- })
- }
- return nil
- }
- func (manager *SGuestManager) initAdminSecgroupId() error {
- {
- err := manager.initAdminSecgroupIdForHypervisor(api.HYPERVISOR_KVM)
- if err != nil {
- return errors.Wrap(err, "initAdminSecgroupIdForKvm")
- }
- }
- {
- err := manager.initAdminSecgroupIdForHypervisor(api.HYPERVISOR_POD)
- if err != nil {
- return errors.Wrap(err, "initAdminSecgroupIdForContainer")
- }
- }
- return nil
- }
- func (manager *SGuestManager) initAdminSecgroupIdForHypervisor(hypervisor string) error {
- secGrpId := options.Options.GetDefaultAdminSecurityGroupId(hypervisor)
- if len(secGrpId) == 0 {
- return nil
- }
- adminSec, _ := SecurityGroupManager.FetchSecgroupById(secGrpId)
- if adminSec == nil {
- return nil
- }
- adminSecId := adminSec.Id
- guests := make([]SGuest, 0, 10)
- q := manager.Query()
- q = q.Equals("hypervisor", hypervisor).IsNullOrEmpty("admin_secgrp_id")
- err := db.FetchModelObjects(manager, q, &guests)
- if err != nil {
- return errors.Wrap(err, "db.FetchModelObjects")
- }
- // remove secgroup for esxi nutanix guest
- for i := range guests {
- db.Update(&guests[i], func() error {
- guests[i].AdminSecgrpId = adminSecId
- return nil
- })
- }
- return nil
- }
- func (manager *SGuestManager) InitializeData() error {
- if err := manager.initHostname(); err != nil {
- return errors.Wrap(err, "initHostname")
- }
- if err := manager.clearSecgroups(); err != nil {
- return errors.Wrap(err, "cleanSecgroups")
- }
- if err := manager.initAdminSecgroupId(); err != nil {
- return errors.Wrap(err, "initAdminSecgroupId")
- }
- return nil
- }
- func (guest *SGuest) GetHypervisor() string {
- if len(guest.Hypervisor) == 0 {
- return api.HYPERVISOR_DEFAULT
- }
- return guest.Hypervisor
- }
- func (guest *SGuest) GetHostType() string {
- host, err := guest.GetHost()
- if err != nil {
- return ""
- }
- return host.HostType
- }
- func (guest *SGuest) GetRegion() (*SCloudregion, error) {
- hosts := HostManager.Query("zone_id").Equals("id", guest.HostId).SubQuery()
- zones := ZoneManager.Query("cloudregion_id").In("id", hosts).SubQuery()
- q := CloudregionManager.Query().In("id", zones)
- ret := &SCloudregion{}
- ret.SetModelManager(CloudregionManager, ret)
- err := q.First(ret)
- if err != nil {
- return nil, errors.Wrapf(err, "q.First")
- }
- return ret, nil
- }
- func (guest *SGuest) GetZone() (*SZone, error) {
- hosts := HostManager.Query("zone_id").Equals("id", guest.HostId).SubQuery()
- q := ZoneManager.Query().In("id", hosts)
- ret := &SZone{}
- ret.SetModelManager(ZoneManager, ret)
- err := q.First(ret)
- if err != nil {
- return nil, errors.Wrapf(err, "q.First")
- }
- return ret, nil
- }
- func (guest *SGuest) GetDriver() (IGuestDriver, error) {
- hypervisor := guest.GetHypervisor()
- region, err := guest.GetRegion()
- if err != nil {
- return nil, errors.Wrapf(err, "GetRegion")
- }
- return GetDriver(hypervisor, region.Provider)
- }
- func (guest *SGuest) validateDeleteCondition(ctx context.Context, isPurge bool) error {
- if guest.DisableDelete.IsTrue() {
- return httperrors.NewInvalidStatusError("Virtual server is locked, cannot delete")
- }
- if !isPurge && guest.IsNotDeletablePrePaid() {
- return httperrors.NewForbiddenError("not allow to delete prepaid server in valid status")
- }
- return guest.SVirtualResourceBase.ValidateDeleteCondition(ctx, nil)
- }
- func (guest *SGuest) ValidateDeleteCondition(ctx context.Context, info *api.ServerDetails) error {
- if gotypes.IsNil(info) {
- info = &api.ServerDetails{}
- host, err := guest.GetHost()
- if err != nil {
- return err
- }
- info.HostType = host.HostType
- info.HostEnabled = host.Enabled.Bool()
- info.HostStatus = host.Status
- info.HostServiceStatus = host.HostStatus
- }
- if len(info.HostType) > 0 && guest.GetHypervisor() != api.HYPERVISOR_BAREMETAL {
- if !info.HostEnabled {
- return httperrors.NewInputParameterError("Cannot delete server on disabled host")
- }
- if info.HostServiceStatus != api.HOST_ONLINE {
- return httperrors.NewInputParameterError("Cannot delete server on offline host")
- }
- }
- return guest.validateDeleteCondition(ctx, false)
- }
- func (guest *SGuest) GetDisksQuery() *sqlchemy.SQuery {
- return GuestdiskManager.Query().Equals("guest_id", guest.Id)
- }
- func (guest *SGuest) DiskCount() (int, error) {
- return guest.GetDisksQuery().CountWithError()
- }
- func (guest *SGuest) GetSystemDisk() (*SDisk, error) {
- q := DiskManager.Query().Equals("disk_type", api.DISK_TYPE_SYS)
- gs := GuestdiskManager.Query().SubQuery()
- q = q.Join(gs, sqlchemy.Equals(gs.Field("disk_id"), q.Field("id"))).
- Filter(sqlchemy.Equals(gs.Field("guest_id"), guest.Id))
- count, err := q.CountWithError()
- if err != nil {
- return nil, err
- }
- if count > 1 {
- return nil, sqlchemy.ErrDuplicateEntry
- }
- if count == 0 {
- return nil, sql.ErrNoRows
- }
- disk := &SDisk{}
- err = q.First(disk)
- if err != nil {
- return nil, errors.Wrap(err, "q.First(disk)")
- }
- disk.SetModelManager(DiskManager, disk)
- return disk, nil
- }
- func (self *SGuest) GetDisks() ([]SDisk, error) {
- gds := GuestdiskManager.Query().SubQuery()
- sq := DiskManager.Query()
- q := sq.Join(gds, sqlchemy.Equals(gds.Field("disk_id"), sq.Field("id"))).Filter(
- sqlchemy.Equals(gds.Field("guest_id"), self.Id),
- ).Asc(gds.Field("index"))
- disks := []SDisk{}
- err := db.FetchModelObjects(DiskManager, q, &disks)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return disks, nil
- }
- func (guest *SGuest) GetGuestDisks() ([]SGuestdisk, error) {
- disks := make([]SGuestdisk, 0)
- q := guest.GetDisksQuery().Asc("index")
- err := db.FetchModelObjects(GuestdiskManager, q, &disks)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return disks, nil
- }
- func (guest *SGuest) GetGuestDisk(diskId string) *SGuestdisk {
- guestdisk, err := db.NewModelObject(GuestdiskManager)
- if err != nil {
- log.Errorf("new guestdisk model failed: %s", err)
- return nil
- }
- q := guest.GetDisksQuery()
- err = q.Equals("disk_id", diskId).First(guestdisk)
- if err != nil {
- log.Errorf("GetGuestDisk error: %s", err)
- return nil
- }
- return guestdisk.(*SGuestdisk)
- }
- func (guest *SGuest) GetNetworksQuery(netId string) *sqlchemy.SQuery {
- q := GuestnetworkManager.Query().Equals("guest_id", guest.Id)
- if len(netId) > 0 {
- q = q.Equals("network_id", netId)
- }
- return q
- }
- func (guest *SGuest) NetworkCount() (int, error) {
- return guest.GetNetworksQuery("").CountWithError()
- }
- func (guest *SGuest) GetVpc() (*SVpc, error) {
- q := guest.GetNetworksQuery("")
- guestnic := &SGuestnetwork{}
- err := q.First(guestnic)
- if err != nil {
- return nil, errors.Wrapf(err, "failed getting guest network of %s(%s)", guest.Name, guest.Id)
- }
- guestnic.SetModelManager(GuestnetworkManager, guestnic)
- network, err := guestnic.GetNetwork()
- if err != nil {
- return nil, errors.Wrapf(err, "GetVpc")
- }
- vpc, err := network.GetVpc()
- if err != nil {
- return nil, errors.Wrapf(err, "GetVpc")
- }
- return vpc, nil
- }
- func (guest *SGuest) IsOneCloudVpcNetwork() (bool, error) {
- gns, err := guest.GetNetworks("")
- if err != nil {
- return false, errors.Wrap(err, "GetNetworks")
- }
- for _, gn := range gns {
- n, _ := gn.GetNetwork()
- if n != nil && n.isOneCloudVpcNetwork() {
- return true, nil
- }
- }
- return false, nil
- }
- func (guest *SGuest) GetNetworks(netId string) ([]SGuestnetwork, error) {
- guestnics := make([]SGuestnetwork, 0)
- q := guest.GetNetworksQuery(netId).Asc("index")
- err := db.FetchModelObjects(GuestnetworkManager, q, &guestnics)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return guestnics, nil
- }
- func (guest *SGuest) GetSlaveNetworks() ([]SGuestnetwork, error) {
- guestnics := make([]SGuestnetwork, 0)
- q := guest.GetNetworksQuery("").IsNotEmpty("team_with")
- err := db.FetchModelObjects(GuestnetworkManager, q, &guestnics)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return guestnics, nil
- }
- func (guest *SGuest) ConvertEsxiNetworks(targetGuest *SGuest) error {
- gns, err := guest.GetNetworks("")
- if err != nil {
- return err
- }
- var i int
- for ; i < len(gns); i++ {
- _, err = db.Update(&gns[i], func() error {
- gns[i].GuestId = targetGuest.Id
- if gns[i].Driver != "e1000" && gns[i].Driver != "vmxnet3" {
- gns[i].Driver = "e1000"
- }
- return nil
- })
- if err != nil {
- log.Errorf("update guestnetworks failed %s", err)
- break
- }
- }
- if err != nil {
- for j := 0; j < i; j++ {
- _, err = db.Update(&gns[j], func() error {
- gns[j].GuestId = guest.Id
- return nil
- })
- if err != nil {
- log.Errorf("update guestnetworks failed %s", err)
- break
- }
- }
- }
- return err
- }
- func (guest *SGuest) getGuestnetworkByIndex(networkIndex int) (*SGuestnetwork, error) {
- q := guest.GetNetworksQuery("").Equals("index", networkIndex)
- guestnic := SGuestnetwork{}
- err := q.First(&guestnic)
- if err != nil {
- return nil, err
- }
- guestnic.SetModelManager(GuestnetworkManager, &guestnic)
- return &guestnic, nil
- }
- func (guest *SGuest) getGuestnetworkByIpOrMac(ipAddr string, ip6Addr string, macAddr string) (*SGuestnetwork, error) {
- q := guest.GetNetworksQuery("")
- if len(ipAddr) > 0 {
- q = q.Equals("ip_addr", ipAddr)
- }
- if len(ip6Addr) > 0 {
- addr, err := netutils.NewIPV6Addr(ip6Addr)
- if err == nil {
- q = q.Equals("ip6_addr", addr.String())
- }
- }
- if len(macAddr) > 0 {
- macAddr = netutils2.FormatMac(macAddr)
- q = q.Equals("mac_addr", macAddr)
- }
- guestnic := SGuestnetwork{}
- err := q.First(&guestnic)
- if err != nil {
- return nil, err
- }
- guestnic.SetModelManager(GuestnetworkManager, &guestnic)
- return &guestnic, nil
- }
- func (guest *SGuest) GetGuestnetworkByIp(ipAddr string) (*SGuestnetwork, error) {
- return guest.getGuestnetworkByIpOrMac(ipAddr, "", "")
- }
- func (guest *SGuest) GetGuestnetworkByIp6(ip6Addr string) (*SGuestnetwork, error) {
- return guest.getGuestnetworkByIpOrMac("", ip6Addr, "")
- }
- func (guest *SGuest) GetGuestnetworkByMac(macAddr string) (*SGuestnetwork, error) {
- return guest.getGuestnetworkByIpOrMac("", "", macAddr)
- }
- func (guest *SGuest) IsNetworkAllocated() bool {
- guestnics, err := guest.GetNetworks("")
- if err != nil {
- return false
- }
- for _, gn := range guestnics {
- if !gn.IsAllocated() {
- return false
- }
- }
- return true
- }
- func (guest *SGuest) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
- optAdminSecGrpId := options.Options.GetDefaultAdminSecurityGroupId(guest.Hypervisor)
- if len(guest.SecgrpId) > 0 && len(optAdminSecGrpId) > 0 {
- adminSec, _ := SecurityGroupManager.FetchSecgroupById(optAdminSecGrpId)
- if adminSec != nil {
- guest.AdminSecgrpId = adminSec.Id
- }
- }
- guest.HostId = ""
- err := guest.SEncryptedResource.CustomizeCreate(ctx, userCred, ownerId, data, "server-"+pinyinutils.Text2Pinyin(guest.Name))
- if err != nil {
- return errors.Wrap(err, "EncryptResourceBase.CustomizeCreate")
- }
- return guest.SVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
- }
- func (guest *SGuest) GetCloudproviderId() string {
- host, _ := guest.GetHost()
- if host != nil {
- return host.GetCloudproviderId()
- }
- return ""
- }
- func (guest *SGuest) GetHost() (*SHost, error) {
- if len(guest.HostId) > 0 && regutils.MatchUUID(guest.HostId) {
- host, err := HostManager.FetchById(guest.HostId)
- if err != nil {
- return nil, err
- }
- return host.(*SHost), nil
- }
- return nil, fmt.Errorf("empty host id")
- }
- func (guest *SGuest) SetHostId(userCred mcclient.TokenCredential, hostId string) error {
- if guest.HostId != hostId {
- diff, err := db.Update(guest, func() error {
- guest.HostId = hostId
- return nil
- })
- if err != nil {
- return err
- }
- db.OpsLog.LogEvent(guest, db.ACT_UPDATE, diff, userCred)
- }
- return nil
- }
- func (guest *SGuest) SetHostIdWithBackup(userCred mcclient.TokenCredential, master, slave string) error {
- diff, err := db.Update(guest, func() error {
- guest.HostId = master
- guest.BackupHostId = slave
- return nil
- })
- if err != nil {
- return err
- }
- db.OpsLog.LogEvent(guest, db.ACT_UPDATE, diff, userCred)
- return err
- }
- func (guest *SGuest) UpdateCpuNumaPin(
- ctx context.Context, userCred mcclient.TokenCredential,
- schedCpuNumaPin []schedapi.SCpuNumaPin, cpuNumaPinTarget []api.SCpuNumaPin,
- ) error {
- srcSchedCpuNumaPin := make([]schedapi.SCpuNumaPin, 0)
- err := guest.CpuNumaPin.Unmarshal(&srcSchedCpuNumaPin)
- if err != nil {
- return err
- }
- srcSchedCpuNumaPin = append(srcSchedCpuNumaPin, schedCpuNumaPin...)
- srcCpuNumaPin := make([]api.SCpuNumaPin, 0)
- cpuNumaPinStr := guest.GetMetadata(ctx, api.VM_METADATA_CPU_NUMA_PIN, nil)
- cpuNumaPinJson, err := jsonutils.ParseString(cpuNumaPinStr)
- if err != nil {
- return err
- }
- err = cpuNumaPinJson.Unmarshal(&srcCpuNumaPin)
- if err != nil {
- return err
- }
- srcCpuNumaPin = append(srcCpuNumaPin, cpuNumaPinTarget...)
- diff, err := db.Update(guest, func() error {
- guest.CpuNumaPin = jsonutils.Marshal(srcSchedCpuNumaPin)
- return nil
- })
- if err != nil {
- return err
- }
- var jcpuNumaPin = jsonutils.Marshal(srcCpuNumaPin)
- err = guest.SetMetadata(ctx, api.VM_METADATA_CPU_NUMA_PIN, jcpuNumaPin, userCred)
- if err != nil {
- return err
- }
- db.OpsLog.LogEvent(guest, db.ACT_UPDATE, diff, userCred)
- return nil
- }
- func (guest *SGuest) SetCpuNumaPin(
- ctx context.Context, userCred mcclient.TokenCredential,
- schedCpuNumaPin []schedapi.SCpuNumaPin, cpuNumaPin []api.SCpuNumaPin,
- ) error {
- if cpuNumaPin == nil && schedCpuNumaPin != nil {
- cpuNumaPin = make([]api.SCpuNumaPin, len(schedCpuNumaPin))
- vcpuId := 0
- for i := range schedCpuNumaPin {
- cpuNumaPin[i] = api.SCpuNumaPin{
- SizeMB: schedCpuNumaPin[i].MemSizeMB,
- NodeId: schedCpuNumaPin[i].NodeId,
- ExtraCpuCount: schedCpuNumaPin[i].ExtraCpuCount,
- }
- if len(schedCpuNumaPin[i].CpuPin) > 0 {
- cpuNumaPin[i].VcpuPin = make([]api.SVCpuPin, len(schedCpuNumaPin[i].CpuPin))
- for j := range schedCpuNumaPin[i].CpuPin {
- cpuNumaPin[i].VcpuPin[j].Pcpu = schedCpuNumaPin[i].CpuPin[j]
- cpuNumaPin[i].VcpuPin[j].Vcpu = vcpuId
- vcpuId += 1
- }
- }
- }
- }
- var cpuNumaPinType string
- var schedCpuNumaPinJ jsonutils.JSONObject
- if schedCpuNumaPin != nil {
- schedCpuNumaPinJ = jsonutils.Marshal(schedCpuNumaPin)
- cpuNumaPinType = api.VM_CPU_NUMA_PIN_SCHEDULER
- } else if cpuNumaPin != nil {
- schedCpuNumaPinJ = jsonutils.Marshal(cpuNumaPin)
- }
- diff, err := db.Update(guest, func() error {
- guest.CpuNumaPin = schedCpuNumaPinJ
- return nil
- })
- if err != nil {
- return err
- }
- var jcpuNumaPin interface{} = ""
- if cpuNumaPin != nil {
- jcpuNumaPin = jsonutils.Marshal(cpuNumaPin)
- }
- metadataMap := map[string]interface{}{
- api.VM_METADATA_CPU_NUMA_PIN: jcpuNumaPin,
- api.VM_METADATA_CPU_NUMA_PIN_TYPE: cpuNumaPinType,
- }
- err = guest.SetAllMetadata(ctx, metadataMap, userCred)
- if err != nil {
- return err
- }
- db.OpsLog.LogEvent(guest, db.ACT_UPDATE, diff, userCred)
- return err
- }
- func (guest *SGuest) ValidateResizeDisk(disk *SDisk, storage *SStorage) error {
- drv, err := guest.GetDriver()
- if err != nil {
- return err
- }
- return drv.ValidateResizeDisk(guest, disk, storage)
- }
- func ValidateMemData(vmemSize int, driver IGuestDriver) (int, error) {
- if vmemSize > 0 {
- maxVmemGb := driver.GetMaxVMemSizeGB()
- if vmemSize < 8 || vmemSize > maxVmemGb*1024 {
- return 0, httperrors.NewInputParameterError("Memory size must be 8MB ~ %d GB", maxVmemGb)
- }
- }
- return vmemSize, nil
- }
- func ValidateCpuData(vcpuCount int, driver IGuestDriver) (int, error) {
- maxVcpuCount := driver.GetMaxVCpuCount()
- if vcpuCount < 1 || vcpuCount > maxVcpuCount {
- return 0, httperrors.NewInputParameterError("CPU core count must be 1 ~ %d", maxVcpuCount)
- }
- return vcpuCount, nil
- }
- func ValidateMemCpuData(vmemSize, vcpuCount int, hypervisor, provider string) (int, int, error) {
- if len(hypervisor) == 0 {
- hypervisor = api.HYPERVISOR_DEFAULT
- }
- driver, err := GetDriver(hypervisor, provider)
- if err != nil {
- return 0, 0, err
- }
- vmemSize, err = ValidateMemData(vmemSize, driver)
- if err != nil {
- return 0, 0, err
- }
- vcpuCount, err = ValidateCpuData(vcpuCount, driver)
- if err != nil {
- return 0, 0, err
- }
- return vmemSize, vcpuCount, nil
- }
- func (self *SGuest) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ServerUpdateInput) (api.ServerUpdateInput, error) {
- if len(input.Name) > 0 && len(input.Name) < 2 {
- return input, httperrors.NewInputParameterError("name is too short")
- }
- // validate Hostname
- if len(input.Hostname) > 0 {
- if !regutils.MatchDomainName(input.Hostname) {
- return input, httperrors.NewInputParameterError("hostname should be a legal domain name")
- }
- }
- // 避免调度失败的机器修改删除保护时报no rows in result set 错误,导致前端删不掉机器
- if len(self.HostId) > 0 {
- drv, err := self.GetDriver()
- if err != nil {
- return input, err
- }
- input, err = drv.ValidateUpdateData(ctx, self, userCred, input)
- if err != nil {
- return input, errors.Wrap(err, "GetDriver().ValidateUpdateData")
- }
- }
- var err error
- input.VirtualResourceBaseUpdateInput, err = self.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.VirtualResourceBaseUpdateInput)
- if err != nil {
- return input, errors.Wrap(err, "SVirtualResourceBase.ValidateUpdateData")
- }
- return input, nil
- }
- func serverCreateInput2ComputeQuotaKeys(input api.ServerCreateInput, ownerId mcclient.IIdentityProvider) (SComputeResourceKeys, error) {
- var keys SComputeResourceKeys
- if len(input.PreferHost) > 0 {
- hostObj, err := HostManager.FetchById(input.PreferHost)
- if err != nil {
- return keys, err
- }
- host := hostObj.(*SHost)
- input.PreferZone = host.ZoneId
- keys.ZoneId = host.ZoneId
- }
- if len(input.PreferWire) > 0 {
- wireObj, err := WireManager.FetchById(input.PreferWire)
- if err != nil {
- return keys, err
- }
- wire := wireObj.(*SWire)
- if len(wire.ZoneId) > 0 {
- input.PreferZone = wire.ZoneId
- keys.ZoneId = wire.ZoneId
- }
- }
- if len(input.PreferZone) > 0 {
- zoneObj, err := ZoneManager.FetchById(input.PreferZone)
- if err != nil {
- return keys, err
- }
- zone := zoneObj.(*SZone)
- input.PreferRegion = zone.CloudregionId
- keys.ZoneId = zone.Id
- keys.RegionId = zone.CloudregionId
- }
- if len(input.PreferRegion) > 0 {
- regionObj, err := CloudregionManager.FetchById(input.PreferRegion)
- if err != nil {
- return keys, err
- }
- region := regionObj.(*SCloudregion)
- keys.RegionId = region.GetId()
- keys.Brand = region.Provider
- }
- return keys, nil
- }
- func (manager *SGuestManager) BatchPreValidate(
- ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider,
- query jsonutils.JSONObject, data *jsonutils.JSONDict, count int,
- ) error {
- input, err := manager.validateCreateData(ctx, userCred, ownerId, query, data)
- if err != nil {
- return errors.Wrap(err, "manager.validateCreateData")
- }
- if input.IsSystem == nil || !(*input.IsSystem) {
- err := manager.checkCreateQuota(ctx, userCred, ownerId, *input, input.Backup, count)
- if err != nil {
- return errors.Wrap(err, "manager.checkCreateQuota")
- }
- }
- return nil
- }
- func parseInstanceSnapshot(ctx context.Context, input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
- ispi, err := InstanceSnapshotManager.FetchByIdOrName(ctx, nil, input.InstanceSnapshotId)
- if err == sql.ErrNoRows {
- return nil, httperrors.NewBadRequestError("can't find instance snapshot %s", input.InstanceSnapshotId)
- }
- if err != nil {
- return nil, httperrors.NewInternalServerError("fetch instance snapshot error %s", err)
- }
- isp := ispi.(*SInstanceSnapshot)
- if isp.Status != api.INSTANCE_SNAPSHOT_READY {
- return nil, httperrors.NewBadRequestError("Instance snapshot not ready")
- }
- input, err = isp.ToInstanceCreateInput(input)
- if len(input.Disks) == 0 {
- return nil, httperrors.NewInputParameterError("there are no disks in this instance snapshot, try another one")
- }
- return input, nil
- }
- func parseInstanceBackup(ctx context.Context, input *api.ServerCreateInput) (*api.ServerCreateInput, error) {
- ispi, err := InstanceBackupManager.FetchByIdOrName(ctx, nil, input.InstanceBackupId)
- if err == sql.ErrNoRows {
- return nil, httperrors.NewBadRequestError("can't find instance backup %s", input.InstanceBackupId)
- }
- if err != nil {
- return nil, httperrors.NewInternalServerError("fetch instance backup error %s", err)
- }
- isp := ispi.(*SInstanceBackup)
- if isp.Status != api.INSTANCE_BACKUP_STATUS_READY && isp.Status != api.INSTANCE_BACKUP_STATUS_RECOVERY {
- return nil, httperrors.NewBadRequestError("Instance backup not ready")
- }
- input, err = isp.ToInstanceCreateInput(input)
- if len(input.Disks) == 0 {
- return nil, httperrors.NewInputParameterError("there are no disks in this instance backup, try another one")
- }
- return input, nil
- }
- func (manager *SGuestManager) ExpandBatchCreateData(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider,
- query jsonutils.JSONObject,
- data *jsonutils.JSONDict,
- index int,
- ) (*api.ServerCreateInput, error) {
- input, err := cmdline.FetchServerCreateInputByJSON(data)
- if err != nil {
- return nil, err
- }
- for i := range input.Networks {
- if index < len(input.Networks[i].Macs) {
- input.Networks[i].Mac = input.Networks[i].Macs[index]
- }
- if index < len(input.Networks[i].Addresses) {
- input.Networks[i].Address = input.Networks[i].Addresses[index]
- }
- if index < len(input.Networks[i].Addresses6) {
- input.Networks[i].Address6 = input.Networks[i].Addresses6[index]
- }
- }
- log.Debugf("ExpandBatchCreateData %s", jsonutils.Marshal(input))
- return input, nil
- }
- func (manager *SGuestManager) validateCreateData(
- ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider,
- query jsonutils.JSONObject, data *jsonutils.JSONDict) (*api.ServerCreateInput, error) {
- // TODO: 定义 api.ServerCreateInput 的 Unmarshal 函数,直接通过 data.Unmarshal(input) 解析参数
- input, err := cmdline.FetchServerCreateInputByJSON(data)
- if err != nil {
- return nil, err
- }
- if len(input.Metadata) > 20 {
- return nil, httperrors.NewInputParameterError("metdata must less then 20")
- }
- if len(input.InstanceSnapshotId) > 0 {
- inputMem := input.VmemSize
- inputCpu := input.VcpuCount
- inputInstaceType := input.InstanceType
- input, err = parseInstanceSnapshot(ctx, input)
- if err != nil {
- return nil, err
- }
- // keep input cpu mem flavor
- if inputMem > 0 {
- input.VmemSize = inputMem
- }
- if inputMem > 0 {
- input.VcpuCount = inputCpu
- }
- if len(inputInstaceType) > 0 {
- input.InstanceType = inputInstaceType
- }
- } else if len(input.InstanceBackupId) > 0 {
- inputMem := input.VmemSize
- inputCpu := input.VcpuCount
- inputInstaceType := input.InstanceType
- input, err = parseInstanceBackup(ctx, input)
- if err != nil {
- return nil, err
- }
- // keep input cpu mem flavor
- if inputMem > 0 {
- input.VmemSize = inputMem
- }
- if inputMem > 0 {
- input.VcpuCount = inputCpu
- }
- if len(inputInstaceType) > 0 {
- input.InstanceType = inputInstaceType
- }
- }
- resetPassword := true
- if input.ResetPassword != nil {
- resetPassword = *input.ResetPassword
- }
- passwd := input.Password
- if len(passwd) > 0 {
- err = seclib2.ValidatePassword(passwd)
- if err != nil {
- return nil, err
- }
- resetPassword = true
- input.ResetPassword = &resetPassword
- }
- if resetPassword && len(input.LoginAccount) > 0 {
- if len(input.LoginAccount) > 32 {
- return nil, httperrors.NewInputParameterError("login_account is longer than 32 chars")
- }
- if err := manager.ValidateNameLoginAccount(input.LoginAccount); err != nil {
- return nil, err
- }
- }
- // check group
- if len(input.InstanceGroupIds) > 0 {
- newGroupIds := make([]string, len(input.InstanceGroupIds))
- for index, id := range input.InstanceGroupIds {
- model, err := GroupManager.FetchByIdOrName(ctx, userCred, id)
- if err != nil {
- return nil, httperrors.NewResourceNotFoundError("no such group %s", id)
- }
- newGroupIds[index] = model.GetId()
- }
- // list of id or name ==> ids
- input.InstanceGroupIds = newGroupIds
- }
- // check that all image of disk is the part of guest imgae, if use guest image to create guest
- err = manager.checkGuestImage(ctx, input)
- if err != nil {
- return nil, errors.Wrap(err, "checkGuestImage")
- }
- if len(input.PreferManager) > 0 && len(input.Provider) == 0 {
- providerObj, err := CloudproviderManager.FetchById(input.PreferManager)
- if err != nil {
- return nil, errors.Wrapf(err, "zone fetch by id %s", input.PreferZone)
- }
- provider := providerObj.(*SCloudprovider)
- input.Provider = provider.Provider
- }
- if len(input.PreferZone) > 0 && len(input.Provider) == 0 {
- zoneObj, err := ZoneManager.FetchById(input.PreferZone)
- if err != nil {
- return nil, errors.Wrapf(err, "zone fetch by id %s", input.PreferZone)
- }
- zone := zoneObj.(*SZone)
- input.PreferRegion = zone.CloudregionId
- }
- if len(input.PreferRegion) > 0 && len(input.Provider) == 0 {
- regionObj, err := CloudregionManager.FetchById(input.PreferRegion)
- if err != nil {
- return nil, errors.Wrapf(err, "region fetch by id %s", input.PreferRegion)
- }
- region := regionObj.(*SCloudregion)
- input.Provider = region.Provider
- }
- if len(input.Provider) == 0 {
- input.Provider = api.CLOUD_PROVIDER_ONECLOUD
- }
- var hypervisor string
- // var rootStorageType string
- var osProf osprofile.SOSProfile
- hypervisor = input.Hypervisor
- if hypervisor != api.HYPERVISOR_POD {
- if len(input.Disks) == 0 && input.Cdrom == "" {
- return nil, httperrors.NewInputParameterError("No bootable disk information provided")
- }
- var imgProperties map[string]string
- var imgEncryptKeyId string
- var imageDiskFormat string
- if len(input.Disks) > 0 {
- diskConfig := input.Disks[0]
- diskConfig, err = parseDiskInfo(ctx, userCred, diskConfig)
- if err != nil {
- return nil, httperrors.NewInputParameterError("Invalid root image: %s", err)
- }
- input.Disks[0] = diskConfig
- imgEncryptKeyId = diskConfig.ImageEncryptKeyId
- imgProperties = diskConfig.ImageProperties
- imageDiskFormat = imgProperties[imageapi.IMAGE_DISK_FORMAT]
- if imgProperties[imageapi.IMAGE_DISK_FORMAT] == "iso" {
- return nil, httperrors.NewInputParameterError("System disk does not support iso image, please consider using cdrom parameter")
- }
- }
- if input.Cdrom != "" {
- cdromStr := input.Cdrom
- image, err := parseIsoInfo(ctx, userCred, cdromStr)
- if err != nil {
- return nil, httperrors.NewInputParameterError("parse cdrom device info error %s", err)
- }
- input.Cdrom = image.Id
- imageDiskFormat = image.DiskFormat
- if len(imgProperties) == 0 {
- imgProperties = image.Properties
- }
- }
- // check boot indexes
- bm := bitmap.NewBitMap(128)
- if input.CdromBootIndex != nil && *input.CdromBootIndex >= 0 {
- bm.Set(int64(*input.CdromBootIndex))
- }
- for i := 0; i < len(input.Disks); i++ {
- if input.Disks[i].BootIndex != nil && *input.Disks[i].BootIndex >= 0 {
- if bm.Has(int64(*input.Disks[i].BootIndex)) {
- return nil, httperrors.NewInputParameterError("duplicate boot index %d", *input.Disks[i].BootIndex)
- }
- bm.Set(int64(*input.Disks[i].BootIndex))
- }
- }
- arch := imgProperties["os_arch"]
- if strings.Contains(arch, "aarch") || strings.Contains(arch, "arm") {
- input.OsArch = apis.OS_ARCH_AARCH64
- } else if strings.Contains(arch, "riscv") {
- input.OsArch = apis.OS_ARCH_RISCV64
- }
- // enable tpm on windows 11 image
- osDist := imgProperties["os_distribution"]
- osVer := imgProperties["os_version"]
- if strings.Contains(osDist, "Windows 11") || strings.Contains(osVer, "Windows 11") {
- input.EnableTpm = true
- }
- // use uefi boot and q35 machine type on enable tpm
- if input.EnableTpm {
- input.Bios = "UEFI"
- input.Machine = api.VM_MACHINE_TYPE_Q35
- }
- if imageDiskFormat != imageapi.IMAGE_DISK_FORMAT_ISO {
- var imgSupportUEFI *bool
- var imgSupportBIOS *bool
- if desc, ok := imgProperties[imageapi.IMAGE_UEFI_SUPPORT]; ok {
- support := desc == "true"
- imgSupportUEFI = &support
- }
- if biosDesc, ok := imgProperties[imageapi.IMAGE_BIOS_SUPPORT]; ok {
- supportBIOS := biosDesc == "true"
- imgSupportBIOS = &supportBIOS
- }
- // uefi is not support set default support bios
- if imgSupportUEFI == nil || !*imgSupportUEFI {
- supportBIOS := true
- imgSupportBIOS = &supportBIOS
- }
- if apis.IsARM(input.OsArch) || apis.IsRISCV(input.OsArch) {
- // arm image supports UEFI by default
- support := true
- imgSupportUEFI = &support
- }
- switch input.Bios {
- case "UEFI":
- if imgSupportUEFI == nil || !*imgSupportUEFI {
- return nil, httperrors.NewInputParameterError("UEFI boot mode requires UEFI image")
- }
- case "BIOS":
- if imgSupportBIOS == nil || !*imgSupportBIOS {
- return nil, httperrors.NewInputParameterError("BIOS boot mode requires BIOS image")
- }
- default:
- if imgSupportUEFI != nil && *imgSupportUEFI {
- input.Bios = "UEFI"
- } else {
- input.Bios = "BIOS"
- }
- }
- } else {
- if input.Bios == "" {
- // if ISO support uefi and not specified boot mode
- // set default boot mode uefi
- if desc, ok := imgProperties[imageapi.IMAGE_UEFI_SUPPORT]; ok && desc == "true" {
- input.Bios = "UEFI"
- }
- }
- }
- if len(imgProperties) == 0 {
- imgProperties = map[string]string{"os_type": "Linux"}
- }
- input.DisableUsbKbd = imgProperties[imageapi.IMAGE_DISABLE_USB_KBD] == "true"
- imgIsWindows := imgProperties[imageapi.IMAGE_OS_TYPE] == "Windows"
- hasGpuVga := func() bool {
- for i := 0; i < len(input.IsolatedDevices); i++ {
- if input.IsolatedDevices[i].DevType == api.GPU_VGA_TYPE {
- return true
- }
- }
- return false
- }()
- if imgIsWindows && hasGpuVga && input.Bios != "UEFI" {
- return nil, httperrors.NewInputParameterError("Windows use gpu vga requires UEFI image")
- }
- if vdi, ok := imgProperties[imageapi.IMAGE_VDI_PROTOCOL]; ok && len(vdi) > 0 && len(input.Vdi) == 0 {
- input.Vdi = vdi
- }
- if input.EncryptKeyId == nil && len(imgEncryptKeyId) > 0 {
- input.EncryptKeyId = &imgEncryptKeyId
- }
- if input.EncryptKeyId != nil || input.EncryptKeyNew != nil {
- input.EncryptedResourceCreateInput, err = manager.SEncryptedResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EncryptedResourceCreateInput)
- if err != nil {
- return nil, errors.Wrap(err, "SEncryptedResourceManager.ValidateCreateData")
- }
- if len(imgEncryptKeyId) > 0 {
- if imgEncryptKeyId != *input.EncryptKeyId {
- return nil, errors.Wrap(httperrors.ErrConflict, "encryption key inconsist with image")
- }
- }
- }
- osType := input.OsType
- osProf, err = osprofile.GetOSProfileFromImageProperties(imgProperties, hypervisor)
- if err != nil {
- return nil, httperrors.NewInputParameterError("Invalid root image: %s", err)
- }
- if len(osProf.Hypervisor) > 0 && len(hypervisor) == 0 {
- hypervisor = osProf.Hypervisor
- input.Hypervisor = hypervisor
- }
- if len(osProf.OSType) > 0 && len(osType) == 0 {
- osType = osProf.OSType
- input.OsType = osType
- }
- input.OsProfile = jsonutils.Marshal(osProf)
- }
- input, err = ValidateScheduleCreateData(ctx, userCred, input, hypervisor)
- if err != nil {
- return nil, err
- }
- optionSystemHypervisor := []string{api.HYPERVISOR_KVM, api.HYPERVISOR_ESXI, api.HYPERVISOR_POD}
- if !utils.IsInStringArray(input.Hypervisor, optionSystemHypervisor) && len(input.Disks[0].ImageId) == 0 && len(input.Disks[0].SnapshotId) == 0 && input.Cdrom == "" {
- return nil, httperrors.NewBadRequestError("Miss operating system???")
- }
- if input.Hypervisor == api.HYPERVISOR_KVM {
- if input.IsDaemon == nil && options.Options.SetKVMServerAsDaemonOnCreate {
- setDaemon := true
- input.IsDaemon = &setDaemon
- }
- }
- hypervisor = input.Hypervisor
- driver, err := GetDriver(hypervisor, input.Provider)
- if err != nil {
- return nil, err
- }
- if hypervisor != api.HYPERVISOR_POD {
- // support sku here
- var sku *SServerSku
- skuName := input.InstanceType
- if len(skuName) > 0 {
- sku, err = ServerSkuManager.FetchSkuByNameAndProvider(skuName, input.Provider, true)
- if err != nil {
- return nil, err
- }
- input.InstanceType = sku.Name
- input.VmemSize = sku.MemorySizeMB
- input.VcpuCount = sku.CpuCoreCount
- } else {
- vmemSize, vcpuCount, err := ValidateMemCpuData(input.VmemSize, input.VcpuCount, input.Hypervisor, input.Provider)
- if err != nil {
- return nil, err
- }
- if vmemSize == 0 {
- return nil, httperrors.NewMissingParameterError("vmem_size")
- }
- if vcpuCount == 0 {
- vcpuCount = 1
- }
- input.VmemSize = vmemSize
- input.VcpuCount = vcpuCount
- }
- dataDiskDefs := []*api.DiskConfig{}
- if sku != nil && sku.AttachedDiskCount > 0 {
- if sku.AttachedDiskSizeGB == 0 {
- return nil, httperrors.NewInputParameterError("sku %s not indicate attached disk size", sku.Name)
- }
- if len(sku.AttachedDiskType) == 0 {
- return nil, httperrors.NewInputParameterError("sku %s not indicate attached disk backend", sku.Name)
- }
- for i := 0; i < sku.AttachedDiskCount; i += 1 {
- dataDisk := &api.DiskConfig{
- SizeMb: sku.AttachedDiskSizeGB * 1024,
- Backend: strings.ToLower(sku.AttachedDiskType),
- }
- dataDiskDefs = append(dataDiskDefs, dataDisk)
- }
- }
- // start from data disk
- disks := input.Disks
- for idx := 1; idx < len(disks); idx += 1 {
- dataDiskDefs = append(dataDiskDefs, disks[idx])
- }
- rootDiskConfig, err := parseDiskInfo(ctx, userCred, disks[0])
- if err != nil {
- return nil, httperrors.NewGeneralError(err) // should no error
- }
- // validate root disk config
- {
- if rootDiskConfig.NVMEDevice != nil {
- return nil, httperrors.NewBadRequestError("NVMe device can't assign as root disk")
- }
- if input.ResourceType != api.HostResourceTypePrepaidRecycle {
- if len(rootDiskConfig.Backend) == 0 {
- defaultStorageType, _ := data.GetString("default_storage_type")
- if len(defaultStorageType) > 0 {
- rootDiskConfig.Backend = defaultStorageType
- } else {
- rootDiskConfig.Backend = driver.GetDefaultSysDiskBackend()
- }
- }
- sysMinDiskMB := driver.GetMinimalSysDiskSizeGb() * 1024
- if rootDiskConfig.SizeMb != api.DISK_SIZE_AUTOEXTEND && rootDiskConfig.SizeMb < sysMinDiskMB {
- rootDiskConfig.SizeMb = sysMinDiskMB
- }
- }
- if len(rootDiskConfig.Driver) == 0 {
- rootDiskConfig.Driver = osProf.DiskDriver
- }
- log.Debugf("ROOT DISK: %#v", rootDiskConfig)
- input.Disks[0] = rootDiskConfig
- if sku != nil {
- if len(rootDiskConfig.OsArch) > 0 && len(sku.CpuArch) > 0 {
- if !strings.Contains(rootDiskConfig.OsArch, sku.CpuArch) {
- return nil, httperrors.NewConflictError("root disk image(%s) and sku(%s) architecture mismatch", rootDiskConfig.OsArch, sku.CpuArch)
- }
- }
- }
- }
- for i := 0; i < len(dataDiskDefs); i += 1 {
- diskConfig, err := parseDiskInfo(ctx, userCred, dataDiskDefs[i])
- if err != nil {
- return nil, httperrors.NewInputParameterError("parse disk description error %s", err)
- }
- if diskConfig.DiskType == api.DISK_TYPE_SYS {
- log.Warningf("Snapshot error: disk index %d > 0 but disk type is %s", i+1, api.DISK_TYPE_SYS)
- diskConfig.DiskType = api.DISK_TYPE_DATA
- }
- if len(diskConfig.Backend) == 0 {
- diskConfig.Backend = rootDiskConfig.Backend
- }
- if len(diskConfig.Driver) == 0 {
- diskConfig.Driver = osProf.DiskDriver
- }
- if diskConfig.NVMEDevice != nil {
- if input.Backup {
- return nil, httperrors.NewBadRequestError("Cannot create backup with isolated device")
- }
- devConfig, err := IsolatedDeviceManager.parseDeviceInfo(userCred, diskConfig.NVMEDevice)
- if err != nil {
- return nil, httperrors.NewInputParameterError("parse isolated device description error %s", err)
- }
- err = IsolatedDeviceManager.isValidNVMEDeviceInfo(devConfig)
- if err != nil {
- return nil, err
- }
- diskConfig.NVMEDevice = devConfig
- diskConfig.Driver = api.DISK_DRIVER_VFIO
- diskConfig.Backend = api.STORAGE_NVME_PT
- }
- input.Disks[i+1] = diskConfig
- }
- if len(input.Duration) > 0 {
- if input.ResourceType == api.HostResourceTypePrepaidRecycle {
- return nil, httperrors.NewConflictError("cannot create prepaid server on prepaid resource type")
- }
- billingCycle, err := billing.ParseBillingCycle(input.Duration)
- if err != nil {
- return nil, httperrors.NewInputParameterError("invalid duration %s", input.Duration)
- }
- if input.BillingType == billing_api.BILLING_TYPE_POSTPAID {
- if !driver.IsSupportPostpaidExpire() {
- return nil, httperrors.NewBadRequestError("guest %s unsupport postpaid expire", hypervisor)
- }
- } else {
- if !driver.IsSupportedBillingCycle(billingCycle) {
- return nil, httperrors.NewInputParameterError("unsupported duration %s", input.Duration)
- }
- }
- if len(input.BillingType) == 0 {
- input.BillingType = billing_api.BILLING_TYPE_PREPAID
- }
- input.BillingCycle = billingCycle.String()
- input.Duration = billingCycle.String()
- if input.BillingType == billing_api.BILLING_TYPE_POSTPAID {
- input.ReleaseAt = billingCycle.EndAt(time.Now())
- }
- }
- }
- // HACK: if input networks is empty, add one random network config
- if len(input.Networks) == 0 {
- input.Networks = append(input.Networks, &api.NetworkConfig{Exit: false})
- }
- netArray := input.Networks
- defaultGwCnt := 0
- firstExit := -1
- for idx := 0; idx < len(netArray); idx += 1 {
- netConfig, err := parseNetworkInfo(ctx, userCred, netArray[idx])
- if err != nil {
- return nil, httperrors.NewInputParameterError("parse network description error %s", err)
- }
- err = isValidNetworkInfo(ctx, userCred, netConfig, "", "")
- if err != nil {
- return nil, err
- }
- if len(netConfig.Driver) == 0 {
- netConfig.Driver = osProf.NetDriver
- }
- if netConfig.SriovDevice != nil {
- if input.Backup {
- return nil, httperrors.NewBadRequestError("Cannot create backup with isolated device")
- }
- devConfig, err := IsolatedDeviceManager.parseDeviceInfo(userCred, netConfig.SriovDevice)
- if err != nil {
- return nil, httperrors.NewInputParameterError("parse isolated device description error %s", err)
- }
- err = IsolatedDeviceManager.isValidNicDeviceInfo(devConfig)
- if err != nil {
- return nil, err
- }
- netConfig.SriovDevice = devConfig
- netConfig.Driver = api.NETWORK_DRIVER_VFIO
- }
- secgroupIds, err := isValidSecgroups(ctx, userCred, netConfig.Secgroups)
- if err != nil {
- return nil, err
- }
- netConfig.Secgroups = secgroupIds
- netConfig.Project = ownerId.GetProjectId()
- netConfig.Domain = ownerId.GetProjectDomainId()
- if netConfig.IsDefault {
- defaultGwCnt++
- }
- if firstExit < 0 && netConfig.Exit {
- firstExit = idx
- }
- input.Networks[idx] = netConfig
- }
- // check default gateway
- if defaultGwCnt == 0 {
- defIdx := 0
- if firstExit >= 0 {
- // there is a exit network, make it the default
- defIdx = firstExit
- }
- // make the first nic as default
- input.Networks[defIdx].IsDefault = true
- } else if defaultGwCnt > 1 {
- return nil, errors.Wrapf(httperrors.ErrInputParameter, "more than 1 nic(%d) assigned as default gateway", defaultGwCnt)
- }
- isoDevArray := input.IsolatedDevices
- for idx := 0; idx < len(isoDevArray); idx += 1 { // .Contains(fmt.Sprintf("isolated_device.%d", idx)); idx += 1 {
- if input.Backup {
- return nil, httperrors.NewBadRequestError("Cannot create backup with isolated device")
- }
- devConfig, err := IsolatedDeviceManager.parseDeviceInfo(userCred, isoDevArray[idx])
- if err != nil {
- return nil, httperrors.NewInputParameterError("parse isolated device description error %s", err)
- }
- err = IsolatedDeviceManager.isValidDeviceInfo(devConfig)
- if err != nil {
- return nil, err
- }
- input.IsolatedDevices[idx] = devConfig
- }
- nvidiaVgpuCnt := 0
- gpuCnt := 0
- for i := 0; i < len(input.IsolatedDevices); i++ {
- if input.IsolatedDevices[i].DevType == api.LEGACY_VGPU_TYPE {
- nvidiaVgpuCnt += 1
- } else if utils.IsInStringArray(input.IsolatedDevices[i].DevType, api.VALID_GPU_TYPES) {
- gpuCnt += 1
- }
- }
- if nvidiaVgpuCnt > 1 {
- return nil, httperrors.NewBadRequestError("Nvidia vgpu count exceed > 1")
- }
- if nvidiaVgpuCnt > 0 && gpuCnt > 0 {
- return nil, httperrors.NewBadRequestError("Nvidia vgpu can't passthrough with other gpus")
- }
- keypairId := input.KeypairId
- if len(keypairId) > 0 {
- keypairObj, err := KeypairManager.FetchByIdOrName(ctx, userCred, keypairId)
- if err != nil {
- return nil, httperrors.NewResourceNotFoundError("Keypair %s not found", keypairId)
- }
- input.KeypairId = keypairObj.GetId()
- }
- secGrpIds, err := isValidSecgroups(ctx, userCred, input.Secgroups)
- if err != nil {
- return nil, err
- }
- if len(secGrpIds) > 0 {
- input.SecgroupId = secGrpIds[0]
- input.Secgroups = secGrpIds[1:]
- } else if input.SecgroupId != "" {
- secGrpId := input.SecgroupId
- secGrpObj, err := SecurityGroupManager.FetchByIdOrName(ctx, userCred, secGrpId)
- if err != nil {
- return nil, httperrors.NewResourceNotFoundError("Secgroup %s not found", secGrpId)
- }
- input.SecgroupId = secGrpObj.GetId()
- } else {
- input.SecgroupId = options.Options.GetDefaultSecurityGroupId(hypervisor)
- }
- maxSecgrpCount := driver.GetMaxSecurityGroupCount()
- if maxSecgrpCount == 0 { //esxi 不支持安全组
- input.SecgroupId = ""
- input.Secgroups = []string{}
- } else if len(input.Secgroups)+1 > maxSecgrpCount {
- return nil, httperrors.NewInputParameterError("%s shall bind up to %d security groups", hypervisor, maxSecgrpCount)
- }
- preferRegionId, _ := data.GetString("prefer_region_id")
- if err := manager.validateEip(ctx, userCred, input, preferRegionId, input.PreferManager); err != nil {
- return nil, err
- }
- /*
- TODO
- group
- for idx := 0; data.Contains(fmt.Sprintf("srvtag.%d", idx)); idx += 1 {
- }*/
- if input.ResourceType != api.HostResourceTypePrepaidRecycle {
- input, err = driver.ValidateCreateData(ctx, userCred, input)
- if err != nil {
- return nil, err
- }
- }
- input.VirtualResourceCreateInput, err = manager.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.VirtualResourceCreateInput)
- if err != nil {
- return nil, err
- }
- name := input.Name
- if len(name) == 0 {
- name = input.GenerateName
- }
- input.HostnameInput, err = manager.SHostnameResourceBaseManager.ValidateHostname(name, input.OsType, input.HostnameInput)
- if err != nil {
- return nil, err
- }
- // validate UserData
- if err := userdata.ValidateUserdata(input.UserData, input.OsType); err != nil {
- return nil, httperrors.NewInputParameterError("Invalid userdata: %v", err)
- }
- // validate KickstartConfig
- if input.KickstartConfig != nil && input.KickstartConfig.IsEnabled() {
- if err := validateKickstartConfig(input.KickstartConfig); err != nil {
- return nil, httperrors.NewInputParameterError("Invalid kickstart config: %v", err)
- }
- }
- err = manager.ValidatePolicyDefinitions(ctx, userCred, ownerId, query, input)
- if err != nil {
- return nil, err
- }
- input.ProjectId = ownerId.GetProjectId()
- input.ProjectDomainId = ownerId.GetProjectDomainId()
- return input, nil
- }
- func (manager *SGuestManager) ValidatePolicyDefinitions(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input *api.ServerCreateInput) error {
- definitions, err := PolicyDefinitionManager.GetAvailablePolicyDefinitions(ctx, userCred)
- if err != nil {
- return httperrors.NewGeneralError(err)
- }
- for i := range definitions {
- switch definitions[i].Category {
- case api.POLICY_DEFINITION_CATEGORY_CLOUDREGION:
- if len(input.PreferRegion) == 0 {
- return httperrors.NewMissingParameterError(fmt.Sprintf("policy definition %s require prefer_region_id parameter", definitions[i].Name))
- }
- if definitions[i].Parameters == nil {
- return httperrors.NewPolicyDefinitionError("invalid parameters for policy definition %s", definitions[i].Name)
- }
- regionDefinitions := api.SCloudregionPolicyDefinitions{}
- definitions[i].Parameters.Unmarshal(®ionDefinitions)
- regions := []string{}
- for _, region := range regionDefinitions.Cloudregions {
- regions = append(regions, region.Id)
- regions = append(regions, region.Name)
- }
- isIn := utils.IsInStringArray(input.PreferRegion, regions)
- switch definitions[i].Condition {
- case api.POLICY_DEFINITION_CONDITION_IN:
- if !isIn {
- return httperrors.NewPolicyDefinitionError("policy definition %s require cloudregion in %s", definitions[i].Name, definitions[i].Parameters)
- }
- case api.POLICY_DEFINITION_CONDITION_NOT_IN:
- if isIn {
- return httperrors.NewPolicyDefinitionError("policy definition %s require cloudregion not in %s", definitions[i].Name, definitions[i].Parameters)
- }
- default:
- return httperrors.NewPolicyDefinitionError("invalid policy definition %s(%s) condition %s", definitions[i].Name, definitions[i].Id, definitions[i].Condition)
- }
- case api.POLICY_DEFINITION_CATEGORY_TAG:
- tags := []string{}
- if definitions[i].Parameters == nil {
- return httperrors.NewPolicyDefinitionError("invalid parameters for policy definition %s", definitions[i].Name)
- }
- definitions[i].Parameters.Unmarshal(&tags, "tags")
- metadataKeys := []string{}
- for k, _ := range input.Metadata {
- metadataKeys = append(metadataKeys, strings.TrimPrefix(k, db.USER_TAG_PREFIX))
- }
- for _, tag := range tags {
- isIn := utils.IsInStringArray(tag, metadataKeys)
- switch definitions[i].Condition {
- case api.POLICY_DEFINITION_CONDITION_CONTAINS:
- if !isIn {
- return httperrors.NewPolicyDefinitionError("policy definition %s require must contains tag %s", definitions[i].Name, tag)
- }
- case api.POLICY_DEFINITION_CONDITION_EXCEPT:
- if isIn {
- return httperrors.NewPolicyDefinitionError("policy definition %s require except tag %s", definitions[i].Name, tag)
- }
- default:
- return httperrors.NewPolicyDefinitionError("invalid policy definition %s(%s) condition %s", definitions[i].Name, definitions[i].Id, definitions[i].Condition)
- }
- }
- default:
- return httperrors.NewPolicyDefinitionError("invalid category %s for policy definition %s(%s)", definitions[i].Category, definitions[i].Name, definitions[i].Id)
- }
- }
- return nil
- }
- func (manager *SGuestManager) BatchCreateValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
- input, err := manager.validateCreateData(ctx, userCred, ownerId, query, data)
- if err != nil {
- return nil, err
- }
- return input.JSON(input), nil
- }
- // 创建虚拟机实例
- func (manager *SGuestManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, oinput api.ServerCreateInput) (*jsonutils.JSONDict, error) {
- input, err := manager.validateCreateData(ctx, userCred, ownerId, query, oinput.JSON(oinput))
- if err != nil {
- return nil, err
- }
- if input.IsSystem == nil || !(*input.IsSystem) {
- err = manager.checkCreateQuota(ctx, userCred, ownerId, *input, input.Backup, 1)
- if err != nil {
- return nil, err
- }
- }
- return input.JSON(input), nil
- }
- func validateKickstartConfig(config *api.KickstartConfig) error {
- if config.OSType == "" {
- return httperrors.NewMissingParameterError("os_type")
- }
- if !utils.IsInStringArray(config.OSType, api.KICKSTART_VALID_OS_TYPES) {
- return httperrors.NewInputParameterError("unsupported os_type: %s, supported types: %v", config.OSType, api.KICKSTART_VALID_OS_TYPES)
- }
- // 验证配置内容和URL二选一
- if config.Config == "" && config.ConfigURL == "" {
- return httperrors.NewInputParameterError("either config or config_url must be provided")
- }
- if config.Config != "" && config.ConfigURL != "" {
- return httperrors.NewInputParameterError("config and config_url cannot be both provided, choose one")
- }
- if config.Config != "" {
- const maxConfigSize = 64 * 1024
- if len(config.Config) > maxConfigSize {
- return httperrors.NewInputParameterError("config content too large: %d bytes, maximum allowed: %d bytes", len(config.Config), maxConfigSize)
- }
- if len(strings.TrimSpace(config.Config)) == 0 {
- return httperrors.NewInputParameterError("config content cannot be empty")
- }
- }
- if config.ConfigURL != "" {
- if len(config.ConfigURL) > 2048 {
- return httperrors.NewInputParameterError("config URL too long: %d characters, maximum allowed: 2048", len(config.ConfigURL))
- }
- if strings.TrimSpace(config.ConfigURL) == "" {
- return httperrors.NewInputParameterError("config URL cannot be empty")
- }
- parsedURL, err := url.Parse(config.ConfigURL)
- if err != nil {
- return httperrors.NewInputParameterError("invalid URL format: %v", err)
- }
- if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" {
- return httperrors.NewInputParameterError("invalid URL scheme: %s, only http and https are allowed", parsedURL.Scheme)
- }
- if parsedURL.Host == "" {
- return httperrors.NewInputParameterError("URL must specify a host")
- }
- if err := checkKickstartURLContentSize(config.ConfigURL); err != nil {
- return httperrors.NewInputParameterError("URL content validation failed: %v", err)
- }
- }
- // 设置默认值
- if config.Enabled == nil {
- enabled := true
- config.Enabled = &enabled
- }
- if config.MaxRetries <= 0 {
- config.MaxRetries = 3
- }
- if config.TimeoutMinutes <= 0 {
- config.TimeoutMinutes = 60
- }
- return nil
- }
- // determineKickstartType determines kickstart type based on config content
- func determineKickstartType(config *api.KickstartConfig) string {
- if config.Config != "" {
- return api.KICKSTART_TYPE_CONTENT
- }
- return api.KICKSTART_TYPE_URL
- }
- func checkKickstartURLContentSize(configURL string) error {
- const maxURLContentSize = 64 * 1024
- const requestTimeout = 10 * time.Second
- client := &http.Client{Timeout: requestTimeout}
- req, err := http.NewRequest("HEAD", configURL, nil)
- if err != nil {
- return fmt.Errorf("failed to create request: %v", err)
- }
- resp, err := client.Do(req)
- if err != nil {
- log.Warningf("Failed to check URL content size for %s: %v", configURL, err)
- return nil
- }
- defer resp.Body.Close()
- if resp.StatusCode != http.StatusOK {
- return fmt.Errorf("URL returned status code: %d", resp.StatusCode)
- }
- contentLengthStr := resp.Header.Get("Content-Length")
- if contentLengthStr != "" {
- contentLength, err := strconv.ParseInt(contentLengthStr, 10, 64)
- if err != nil {
- log.Warningf("Failed to parse Content-Length header: %v", err)
- return nil
- }
- if contentLength > maxURLContentSize {
- return fmt.Errorf("URL content too large: %d bytes, maximum allowed: %d bytes", contentLength, maxURLContentSize)
- }
- log.Infof("URL content size validated: %d bytes", contentLength)
- } else {
- log.Warningf("URL %s does not provide Content-Length header, size validation skipped", configURL)
- }
- return nil
- }
- func (manager *SGuestManager) validateEip(ctx context.Context, userCred mcclient.TokenCredential, input *api.ServerCreateInput,
- preferRegionId string, preferManagerId string) error {
- driver, err := GetDriver(input.Hypervisor, input.Provider)
- if err != nil {
- return err
- }
- if input.PublicIpBw > 0 {
- if !driver.IsSupportPublicIp() {
- return httperrors.NewNotImplementedError("public ip not supported for %s", input.Hypervisor)
- }
- if len(input.PublicIpChargeType) == 0 {
- input.PublicIpChargeType = billing_api.TNetChargeType(cloudprovider.ElasticipChargeTypeByTraffic)
- }
- if !utils.IsInStringArray(string(input.PublicIpChargeType), []string{
- string(cloudprovider.ElasticipChargeTypeByTraffic),
- string(cloudprovider.ElasticipChargeTypeByBandwidth),
- }) {
- return httperrors.NewInputParameterError("invalid public_ip_charge_type %s", input.PublicIpChargeType)
- }
- return nil
- }
- eipStr := input.Eip
- eipBw := input.EipBw
- if len(eipStr) > 0 || eipBw > 0 {
- if !driver.IsSupportEip() {
- return httperrors.NewNotImplementedError("eip not supported for %s", input.Hypervisor)
- }
- if len(eipStr) > 0 {
- eipObj, err := ElasticipManager.FetchByIdOrName(ctx, userCred, eipStr)
- if err != nil {
- if err == sql.ErrNoRows {
- return httperrors.NewResourceNotFoundError2(ElasticipManager.Keyword(), eipStr)
- } else {
- return httperrors.NewGeneralError(err)
- }
- }
- eip := eipObj.(*SElasticip)
- if eip.Status != api.EIP_STATUS_READY {
- return httperrors.NewInvalidStatusError("eip %s status invalid %s", eipStr, eip.Status)
- }
- if eip.IsAssociated() {
- return httperrors.NewResourceBusyError("eip %s has been associated", eipStr)
- }
- input.Eip = eipObj.GetId()
- eipCloudprovider := eip.GetCloudprovider()
- if eipCloudprovider != nil {
- if len(preferManagerId) > 0 && preferManagerId != eipCloudprovider.Id {
- return httperrors.NewConflictError("cannot assoicate with eip %s: different cloudprovider", eipStr)
- }
- input.PreferManager = eipCloudprovider.Id
- }
- eipRegion, err := eip.GetRegion()
- if err != nil {
- return httperrors.NewGeneralError(errors.Wrapf(err, "eip.GetRegion"))
- }
- // preferRegionId, _ := data.GetString("prefer_region_id")
- if len(preferRegionId) > 0 && preferRegionId != eipRegion.Id {
- return httperrors.NewConflictError("cannot assoicate with eip %s: different region", eipStr)
- }
- input.PreferRegion = eipRegion.Id
- } else {
- // create new eip
- }
- }
- return nil
- }
- func (self *SGuest) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
- self.SVirtualResourceBase.PostUpdate(ctx, userCred, query, data)
- if len(self.ExternalId) > 0 && (data.Contains("name") || data.Contains("__meta__") || data.Contains("description")) || data.Contains("hostname") {
- err := self.StartRemoteUpdateTask(ctx, userCred, false, "")
- if err != nil {
- log.Errorf("StartRemoteUpdateTask fail: %s", err)
- }
- }
- if port, err := data.Int("ssh_port"); err != nil {
- err := self.SetSshPort(ctx, userCred, int(port))
- if err != nil {
- log.Errorf("unable to set sshport for guest %s", self.GetId())
- }
- }
- }
- func (manager *SGuestManager) checkCreateQuota(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider,
- input api.ServerCreateInput,
- hasBackup bool,
- count int,
- ) error {
- req, regionReq := getGuestResourceRequirements(ctx, userCred, input, ownerId, count, hasBackup)
- log.Debugf("computeQuota: %s", jsonutils.Marshal(req))
- log.Debugf("regionQuota: %s", jsonutils.Marshal(regionReq))
- err := quotas.CheckSetPendingQuota(ctx, userCred, &req)
- if err != nil {
- return errors.Wrap(err, "quotas.CheckSetPendingQuota")
- }
- err = quotas.CheckSetPendingQuota(ctx, userCred, ®ionReq)
- if err != nil {
- return errors.Wrap(err, "quotas.CheckSetPendingQuota")
- }
- return nil
- }
- func (self *SGuest) checkUpdateQuota(ctx context.Context, userCred mcclient.TokenCredential, vcpuCount int, vmemSize int) (quotas.IQuota, error) {
- req := SQuota{}
- if vcpuCount > 0 && vcpuCount > int(self.VcpuCount) {
- req.Cpu = vcpuCount - int(self.VcpuCount)
- }
- if vmemSize > 0 && vmemSize > self.VmemSize {
- req.Memory = vmemSize - self.VmemSize
- }
- keys, err := self.GetQuotaKeys()
- if err != nil {
- return nil, errors.Wrap(err, "self.GetQuotaKeys")
- }
- req.SetKeys(keys)
- err = quotas.CheckSetPendingQuota(ctx, userCred, &req)
- if err != nil {
- return nil, errors.Wrap(err, "quotas.CheckSetPendingQuota")
- }
- return &req, nil
- }
- func getGuestResourceRequirements(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- input api.ServerCreateInput,
- ownerId mcclient.IIdentityProvider,
- count int,
- hasBackup bool,
- ) (SQuota, SRegionQuota) {
- vcpuCount := input.VcpuCount
- if vcpuCount == 0 {
- vcpuCount = 1
- }
- vmemSize := input.VmemSize
- diskSize := 0
- for _, diskConfig := range input.Disks {
- if diskConfig.DiskId != "" {
- // disk has been created, ignore resource requirement
- continue
- }
- diskSize += diskConfig.SizeMb
- }
- devCount := len(input.IsolatedDevices)
- eNicCnt := 0
- iNicCnt := 0
- eBw := 0
- iBw := 0
- for _, netConfig := range input.Networks {
- if IsExitNetworkInfo(ctx, userCred, netConfig) {
- eNicCnt += 1
- eBw += netConfig.BwLimit
- } else {
- iNicCnt += 1
- iBw += netConfig.BwLimit
- }
- if netConfig.SriovDevice != nil {
- devCount += 1
- }
- }
- if hasBackup {
- vcpuCount = vcpuCount * 2
- vmemSize = vmemSize * 2
- diskSize = diskSize * 2
- }
- eipCnt := 0
- eipBw := input.EipBw
- if eipBw > 0 {
- eipCnt = 1
- }
- req := SQuota{
- Count: count,
- Cpu: int(vcpuCount) * count,
- Memory: int(vmemSize) * count,
- Storage: diskSize * count,
- IsolatedDevice: devCount * count,
- }
- regionReq := SRegionQuota{
- Port: iNicCnt * count,
- Eport: eNicCnt * count,
- //Bw: iBw * count,
- //Ebw: eBw * count,
- Eip: eipCnt * count,
- }
- keys, _ := serverCreateInput2ComputeQuotaKeys(input, ownerId)
- req.SetKeys(keys)
- regionReq.SetKeys(keys.SRegionalCloudResourceKeys)
- return req, regionReq
- }
- func (guest *SGuest) getGuestBackupResourceRequirements(ctx context.Context, userCred mcclient.TokenCredential) SQuota {
- guestDisksSize := guest.getDiskSize()
- return SQuota{
- Count: 1,
- Cpu: int(guest.VcpuCount),
- Memory: guest.VmemSize,
- Storage: guestDisksSize,
- }
- }
- func (guest *SGuest) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
- guest.SVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
- tags := []string{"cpu_bound", "io_bound", "io_hardlimit"}
- appTags := make([]string, 0)
- for _, tag := range tags {
- if data.Contains(tag) {
- appTags = append(appTags, tag)
- }
- }
- guest.setApptags(ctx, appTags, userCred)
- guest.SetCreateParams(ctx, userCred, data)
- osProfileJson, _ := data.Get("__os_profile__")
- if osProfileJson != nil {
- guest.setOSProfile(ctx, userCred, osProfileJson)
- }
- if jsonutils.QueryBoolean(data, api.VM_METADATA_ENABLE_MEMCLEAN, false) {
- guest.SetMetadata(ctx, api.VM_METADATA_ENABLE_MEMCLEAN, "true", userCred)
- }
- if jsonutils.QueryBoolean(data, api.VM_METADATA_ENABLE_TPM, false) {
- guest.SetMetadata(ctx, api.VM_METADATA_ENABLE_TPM, "true", userCred)
- }
- if jsonutils.QueryBoolean(data, imageapi.IMAGE_DISABLE_USB_KBD, false) {
- guest.SetMetadata(ctx, imageapi.IMAGE_DISABLE_USB_KBD, "true", userCred)
- }
- matcherJson, _ := data.Get(api.BAREMETAL_SERVER_METATA_ROOT_DISK_MATCHER)
- if matcherJson != nil {
- guest.SetMetadata(ctx, api.BAREMETAL_SERVER_METATA_ROOT_DISK_MATCHER, matcherJson, userCred)
- }
- userData, _ := data.GetString("user_data")
- if len(userData) > 0 {
- guest.setUserData(ctx, userCred, userData)
- }
- if guest.Hypervisor == api.HYPERVISOR_ESXI {
- schedtags := []api.SchedtagConfig{}
- data.Unmarshal(&schedtags, "schedtags")
- for _, tag := range schedtags {
- if tag.ResourceType != HostManager.KeywordPlural() {
- continue
- }
- meta := db.SMetadata{}
- db.Metadata.Query().
- Equals("obj_type", SchedtagManager.Keyword()).
- Equals("obj_id", tag.Id).
- Equals("key", cloudprovider.METADATA_POOL_ID).First(&meta)
- if len(meta.Value) > 0 {
- db.Update(guest, func() error {
- guest.ResourcePool = meta.Value
- return nil
- })
- }
- }
- }
- // set kickstart metadata
- kickstartConfigJson, _ := data.Get("kickstart_config")
- if kickstartConfigJson != nil {
- kickstartConfig := &api.KickstartConfig{}
- if err := kickstartConfigJson.Unmarshal(kickstartConfig); err != nil {
- log.Errorf("unmarshal kickstart config fail: %s", err)
- } else if kickstartConfig.IsEnabled() {
- if err := guest.SetKickstartConfig(ctx, kickstartConfig, userCred); err != nil {
- log.Errorf("Failed to set kickstart config for guest %s: %v", guest.Name, err)
- } else {
- //if err := guest.SetKickstartStatus(ctx, api.VM_KICKSTART_PENDING, userCred); err != nil {
- // log.Errorf("Failed to set kickstart status for guest %s: %v", guest.Name, err)
- //}
- if err := guest.SetMetadata(ctx, api.VM_METADATA_KICKSTART_COMPLETED_FLAG, "false", userCred); err != nil {
- log.Errorf("Failed to set kickstart completed flag for guest %s: %v", guest.Name, err)
- }
- // Determine and set kickstart type based on config
- kickstartType := determineKickstartType(kickstartConfig)
- if err := guest.SetKickstartType(ctx, kickstartType, userCred); err != nil {
- log.Errorf("Failed to set kickstart type for guest %s: %v", guest.Name, err)
- }
- log.Debugf("Successfully set kickstart config for guest %s with OS type %s", guest.Name, kickstartConfig.OSType)
- }
- }
- }
- input := struct {
- PreferZone string
- PreferRegion string
- PreferManagerId string
- Provider string
- }{}
- data.Unmarshal(&input)
- if len(input.PreferManagerId) > 0 && len(input.Provider) == 0 {
- manObj, err := CloudproviderManager.FetchById(input.PreferManagerId)
- if err == nil {
- man := manObj.(*SCloudprovider)
- input.Provider = man.Provider
- }
- }
- if len(input.PreferZone) > 0 && len(input.Provider) == 0 {
- zoneObj, err := ZoneManager.FetchById(input.PreferZone)
- if err == nil {
- zone := zoneObj.(*SZone)
- input.PreferRegion = zone.CloudregionId
- }
- }
- if len(input.PreferRegion) > 0 && len(input.Provider) == 0 {
- regionObj, err := CloudregionManager.FetchById(input.PreferRegion)
- if err == nil {
- region := regionObj.(*SCloudregion)
- input.Provider = region.Provider
- }
- }
- if len(input.Provider) == 0 {
- input.Provider = api.CLOUD_PROVIDER_ONECLOUD
- }
- drv, _ := GetDriver(guest.Hypervisor, input.Provider)
- if drv != nil && drv.GetMaxSecurityGroupCount() > 0 {
- secgroups, _ := jsonutils.GetStringArray(data, "secgroups")
- for _, secgroupId := range secgroups {
- if secgroupId != guest.SecgrpId {
- gs := SGuestsecgroup{}
- gs.SecgroupId = secgroupId
- gs.GuestId = guest.Id
- GuestsecgroupManager.TableSpec().Insert(ctx, &gs)
- }
- }
- } else {
- db.Update(guest, func() error {
- guest.SecgrpId = ""
- return nil
- })
- }
- }
- func (guest *SGuest) setApptags(ctx context.Context, appTags []string, userCred mcclient.TokenCredential) {
- err := guest.SetMetadata(ctx, api.VM_METADATA_APP_TAGS, strings.Join(appTags, ","), userCred)
- if err != nil {
- log.Errorln(err)
- }
- }
- func (guest *SGuest) SetCreateParams(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) {
- // delete deploy files info
- createParams := data.(*jsonutils.JSONDict).CopyExcludes("deploy_configs")
- err := guest.SetMetadata(ctx, api.VM_METADATA_CREATE_PARAMS, createParams.String(), userCred)
- if err != nil {
- log.Errorf("Server %s SetCreateParams: %v", guest.Name, err)
- }
- }
- func (guest *SGuest) GetCreateParams(ctx context.Context, userCred mcclient.TokenCredential) (*api.ServerCreateInput, error) {
- input := new(api.ServerCreateInput)
- data := guest.GetMetadataJson(ctx, api.VM_METADATA_CREATE_PARAMS, userCred)
- if data == nil {
- return nil, fmt.Errorf("Not found %s %s in metadata", guest.Name, api.VM_METADATA_CREATE_PARAMS)
- }
- err := data.Unmarshal(input)
- return input, err
- }
- func (manager *SGuestManager) SetPropertiesWithInstanceSnapshot(
- ctx context.Context, userCred mcclient.TokenCredential, ispId string, items []db.IModel,
- ) {
- misp, err := InstanceSnapshotManager.FetchById(ispId)
- if err == nil {
- isp := misp.(*SInstanceSnapshot)
- for i := 0; i < len(items); i++ {
- guest := items[i].(*SGuest)
- if isp.ServerMetadata != nil {
- metadata := make(map[string]interface{}, 0)
- isp.ServerMetadata.Unmarshal(metadata)
- if passwd, ok := metadata["passwd"]; ok {
- delete(metadata, "passwd")
- metadata["login_key"], _ = utils.EncryptAESBase64(guest.Id, passwd.(string))
- }
- metadata[api.BASE_INSTANCE_SNAPSHOT_ID] = isp.Id
- guest.SetAllMetadata(ctx, metadata, userCred)
- }
- }
- }
- }
- func (manager *SGuestManager) OnCreateComplete(ctx context.Context, items []db.IModel, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data []jsonutils.JSONObject) {
- input := api.ServerCreateInput{}
- data[0].Unmarshal(&input)
- if len(input.InstanceSnapshotId) > 0 {
- manager.SetPropertiesWithInstanceSnapshot(ctx, userCred, input.InstanceSnapshotId, items)
- }
- pendingUsage, pendingRegionUsage := getGuestResourceRequirements(ctx, userCred, input, ownerId, len(items), input.Backup)
- err := RunBatchCreateTask(ctx, items, userCred, data, pendingUsage, pendingRegionUsage, "GuestBatchCreateTask", input.ParentTaskId)
- if err != nil {
- for i := range items {
- guest := items[i].(*SGuest)
- guest.SetStatus(ctx, userCred, api.VM_CREATE_FAILED, err.Error())
- }
- }
- }
- func (guest *SGuest) GetGroups() []SGroupguest {
- guestgroups := make([]SGroupguest, 0)
- q := GroupguestManager.Query().Equals("guest_id", guest.Id)
- err := db.FetchModelObjects(GroupguestManager, q, &guestgroups)
- if err != nil {
- log.Errorf("GetGroups fail %s", err)
- return nil
- }
- return guestgroups
- }
- func (self *SGuest) getBandwidth(isExit bool) int {
- bw := 0
- networks, err := self.GetNetworks("")
- if err != nil {
- return bw
- }
- if networks != nil && len(networks) > 0 {
- for i := 0; i < len(networks); i += 1 {
- net, _ := networks[i].GetNetwork()
- if networks[i].IsExit(net) == isExit {
- bw += networks[i].getBandwidth(net, nil)
- }
- }
- }
- return bw
- }
- func (self *SGuest) getExtBandwidth() int {
- return self.getBandwidth(true)
- }
- func (self *SGuestManager) GetMetadataHiddenKeys() []string {
- return []string{
- api.VM_METADATA_CREATE_PARAMS,
- }
- }
- func (manager *SGuestManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, err
- }
- // exportKeys, _ := query.GetString("export_keys")
- // keys := strings.Split(exportKeys, ",")
- // guest_id as filter key
- if keys.Contains("ips") {
- guestIpsQuery := GuestnetworkManager.Query("guest_id").GroupBy("guest_id")
- guestIpsQuery.AppendField(sqlchemy.GROUP_CONCAT("concat_ip_addr", guestIpsQuery.Field("ip_addr")))
- ipsSubQuery := guestIpsQuery.SubQuery()
- q.LeftJoin(ipsSubQuery, sqlchemy.Equals(q.Field("id"), ipsSubQuery.Field("guest_id")))
- q.AppendField(ipsSubQuery.Field("concat_ip_addr"))
- }
- if keys.Contains("disk") {
- guestDisksQuery := GuestdiskManager.Query("guest_id", "disk_id").GroupBy("guest_id")
- diskQuery := DiskManager.Query("id", "disk_size").SubQuery()
- guestDisksQuery.Join(diskQuery, sqlchemy.Equals(diskQuery.Field("id"), guestDisksQuery.Field("disk_id")))
- guestDisksQuery.AppendField(sqlchemy.SUM("disk_size", diskQuery.Field("disk_size")))
- guestDisksSubQuery := guestDisksQuery.SubQuery()
- q.LeftJoin(guestDisksSubQuery, sqlchemy.Equals(q.Field("id"), guestDisksSubQuery.Field("guest_id")))
- q.AppendField(guestDisksSubQuery.Field("disk_size"))
- }
- if keys.Contains("eip") {
- eipsQuery := ElasticipManager.Query("associate_id", "ip_addr").Equals("associate_type", "server").GroupBy("associate_id")
- eipsSubQuery := eipsQuery.SubQuery()
- q.LeftJoin(eipsSubQuery, sqlchemy.Equals(q.Field("id"), eipsSubQuery.Field("associate_id")))
- q.AppendField(eipsSubQuery.Field("ip_addr", "eip"))
- }
- if keys.ContainsAny(manager.SHostResourceBaseManager.GetExportKeys()...) {
- q, err = manager.SHostResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
- if err != nil {
- return nil, errors.Wrap(err, "SHostResourceBaseManager.ListItemExportKeys")
- }
- }
- return q, nil
- }
- func (manager *SGuestManager) GetExportExtraKeys(ctx context.Context, keys stringutils2.SSortedStrings, rowMap map[string]string) *jsonutils.JSONDict {
- res := manager.SVirtualResourceBaseManager.GetExportExtraKeys(ctx, keys, rowMap)
- // exportKeys, _ := query.GetString("export_keys")
- // keys := strings.Split(exportKeys, ",")
- if ips, ok := rowMap["concat_ip_addr"]; ok && len(ips) > 0 {
- res.Set("ips", jsonutils.NewString(ips))
- }
- if eip, ok := rowMap["eip"]; ok && len(eip) > 0 {
- res.Set("eip", jsonutils.NewString(eip))
- }
- if disk, ok := rowMap["disk_size"]; ok {
- res.Set("disk", jsonutils.NewString(disk))
- }
- if host, ok := rowMap["host"]; ok && len(host) > 0 {
- res.Set("host", jsonutils.NewString(host))
- }
- if zone, ok := rowMap["zone"]; ok && len(zone) > 0 {
- res.Set("zone", jsonutils.NewString(zone))
- }
- if region, ok := rowMap["region"]; ok && len(region) > 0 {
- res.Set("region", jsonutils.NewString(region))
- }
- if manager, ok := rowMap["manager"]; ok && len(manager) > 0 {
- res.Set("manager", jsonutils.NewString(manager))
- }
- if keys.Contains("tenant") {
- if projectId, ok := rowMap["tenant_id"]; ok {
- tenant, err := db.TenantCacheManager.FetchTenantById(ctx, projectId)
- if err == nil {
- res.Set("tenant", jsonutils.NewString(tenant.GetName()))
- }
- }
- }
- if keys.Contains("os_distribution") {
- if osType, ok := rowMap["os_type"]; ok {
- res.Set("os_distribution", jsonutils.NewString(osType))
- }
- }
- return res
- }
- func (self *SGuest) getNetworksDetails() string {
- guestnets, err := self.GetNetworks("")
- if err != nil {
- return ""
- }
- var buf bytes.Buffer
- for _, nic := range guestnets {
- buf.WriteString(nic.GetDetailedString())
- buf.WriteString("\n")
- }
- return buf.String()
- }
- func (self *SGuest) GetCdrom() *SGuestcdrom {
- return self.getCdrom(false, 0)
- }
- func (self *SGuest) GetCdromByOrdinal(ordinal int64) *SGuestcdrom {
- return self.getCdrom(false, ordinal)
- }
- func (self *SGuest) getCdrom(create bool, ordinal int64) *SGuestcdrom {
- cdrom := SGuestcdrom{}
- cdrom.SetModelManager(GuestcdromManager, &cdrom)
- err := GuestcdromManager.Query().Equals("id", self.Id).Equals("ordinal", ordinal).First(&cdrom)
- if err != nil {
- if err == sql.ErrNoRows {
- if create {
- cdrom.Id = self.Id
- cdrom.Ordinal = int(ordinal)
- err = GuestcdromManager.TableSpec().Insert(context.TODO(), &cdrom)
- if err != nil {
- log.Errorf("insert cdrom fail %s", err)
- return nil
- }
- return &cdrom
- } else {
- return nil
- }
- } else {
- log.Errorf("getCdrom query fail %s", err)
- return nil
- }
- } else {
- return &cdrom
- }
- }
- func (self *SGuest) getCdroms() ([]SGuestcdrom, error) {
- cdroms := make([]SGuestcdrom, 0)
- q := GuestcdromManager.Query().Equals("id", self.Id)
- err := db.FetchModelObjects(GuestcdromManager, q, &cdroms)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return cdroms, nil
- }
- func (self *SGuest) getFloppys() ([]SGuestfloppy, error) {
- floppys := make([]SGuestfloppy, 0)
- q := GuestFloppyManager.Query().Equals("id", self.Id)
- err := db.FetchModelObjects(GuestFloppyManager, q, &floppys)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return floppys, nil
- }
- func (self *SGuest) getFloppy(create bool, ordinal int64) *SGuestfloppy {
- floppy := SGuestfloppy{}
- floppy.SetModelManager(GuestFloppyManager, &floppy)
- err := GuestFloppyManager.Query().Equals("id", self.Id).Equals("ordinal", ordinal).First(&floppy)
- if err != nil {
- if err == sql.ErrNoRows {
- if create {
- floppy.Id = self.Id
- floppy.Ordinal = int(ordinal)
- err = GuestFloppyManager.TableSpec().Insert(context.TODO(), &floppy)
- if err != nil {
- log.Errorf("insert cdrom fail %s", err)
- return nil
- }
- return &floppy
- } else {
- return nil
- }
- } else {
- log.Errorf("getFloppy query fail %s", err)
- return nil
- }
- } else {
- return &floppy
- }
- }
- func (self *SGuest) getKeypair() *SKeypair {
- if len(self.KeypairId) > 0 {
- keypair, _ := KeypairManager.FetchById(self.KeypairId)
- if keypair != nil {
- return keypair.(*SKeypair)
- }
- }
- return nil
- }
- func (self *SGuest) getKeypairName() string {
- keypair := self.getKeypair()
- if keypair != nil {
- return keypair.Name
- }
- return ""
- }
- func (self *SGuest) getNotifyIps() string {
- ips := self.GetRealIPs()
- vips := self.getVirtualIPs()
- if vips != nil {
- ips = append(ips, vips...)
- }
- return strings.Join(ips, ",")
- }
- /*
- func (self *SGuest) GetRealIPs() []string {
- guestnets, err := self.GetNetworks("")
- if err != nil {
- return nil
- }
- ips := make([]string, 0)
- for _, nic := range guestnets {
- if !nic.Virtual {
- ips = append(ips, nic.IpAddr)
- }
- }
- return ips
- }
- */
- func (self *SGuest) IsExitOnly() bool {
- for _, ip := range self.GetRealIPs() {
- if regutils.MatchIP4Addr(ip) {
- addr, _ := netutils.NewIPV4Addr(ip)
- if !netutils.IsExitAddress(addr) {
- return false
- }
- }
- }
- return true
- }
- func (self *SGuest) getVirtualIPs() []string {
- ips := make([]string, 0)
- for _, guestgroup := range self.GetGroups() {
- group := guestgroup.GetGroup()
- groupnets, err := group.GetNetworks()
- if err != nil {
- continue
- }
- for _, groupnetwork := range groupnets {
- if len(groupnetwork.IpAddr) > 0 {
- ips = append(ips, groupnetwork.IpAddr)
- }
- if len(groupnetwork.Ip6Addr) > 0 {
- ips = append(ips, groupnetwork.Ip6Addr)
- }
- }
- }
- return ips
- }
- func (self *SGuest) GetPrivateIPs() []string {
- ips := self.GetRealIPs()
- for i := len(ips) - 1; i >= 0; i-- {
- if regutils.MatchIP4Addr(ips[i]) {
- ipAddr, err := netutils.NewIPV4Addr(ips[i])
- if err != nil {
- log.Errorf("guest %s(%s) has bad ipv4 address (%s): %v", self.Name, self.Id, ips[i], err)
- continue
- }
- if !netutils.IsPrivate(ipAddr) {
- ips = append(ips[:i], ips[i+1:]...)
- }
- }
- }
- return ips
- }
- func (self *SGuest) getIPs() []string {
- ips := self.GetRealIPs()
- vips := self.getVirtualIPs()
- ips = append(ips, vips...)
- /*eip, _ := self.GetEip()
- if eip != nil {
- ips = append(ips, eip.IpAddr)
- }*/
- return ips
- }
- func (self *SGuest) getZone() (*SZone, error) {
- host, err := self.GetHost()
- if err != nil {
- return nil, err
- }
- return host.GetZone()
- }
- func (self *SGuest) getRegion() (*SCloudregion, error) {
- zone, err := self.getZone()
- if err != nil {
- return nil, err
- }
- return zone.GetRegion()
- }
- func (self *SGuest) GetOS() string {
- if len(self.OsType) > 0 {
- return self.OsType
- }
- return self.GetMetadata(context.Background(), "os_name", nil)
- }
- func (self *SGuest) IsLinux() bool {
- os := self.GetOS()
- if strings.HasPrefix(strings.ToLower(os), "lin") {
- return true
- } else {
- return false
- }
- }
- func (self *SGuest) IsWindows() bool {
- os := self.GetOS()
- if strings.HasPrefix(strings.ToLower(os), "win") {
- return true
- } else {
- return false
- }
- }
- func (self *SGuest) getSecgroupJson() ([]*api.SecgroupJsonDesc, error) {
- ret := []*api.SecgroupJsonDesc{}
- secgroups, err := self.GetSecgroups()
- if err != nil {
- return nil, errors.Wrap(err, "GetSecgroups")
- }
- for _, secGrp := range secgroups {
- ret = append(ret, secGrp.getDesc())
- }
- return ret, nil
- }
- func (self *SGuest) GetSecgroups() ([]SSecurityGroup, error) {
- secgrpQuery := SecurityGroupManager.Query()
- secgrpQuery.Filter(
- sqlchemy.OR(
- sqlchemy.Equals(secgrpQuery.Field("id"), self.SecgrpId),
- sqlchemy.In(secgrpQuery.Field("id"), GuestsecgroupManager.Query("secgroup_id").Equals("guest_id", self.Id).SubQuery()),
- ),
- )
- secgroups := []SSecurityGroup{}
- err := db.FetchModelObjects(SecurityGroupManager, secgrpQuery, &secgroups)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return secgroups, nil
- }
- func (self *SGuest) getAdminSecgroup() *SSecurityGroup {
- secGrp, _ := SecurityGroupManager.FetchSecgroupById(self.AdminSecgrpId)
- return secGrp
- }
- func (self *SGuest) getAdminSecgroupName() string {
- secgrp := self.getAdminSecgroup()
- if secgrp != nil {
- return secgrp.GetName()
- }
- return ""
- }
- // 获取多个安全组规则,优先级降序排序
- func (self *SGuest) getSecurityGroupsRules() string {
- secgroups, _ := self.GetSecgroups()
- secgroupids := []string{}
- for _, secgroup := range secgroups {
- secgroupids = append(secgroupids, secgroup.Id)
- }
- q := SecurityGroupRuleManager.Query()
- q.Filter(sqlchemy.In(q.Field("secgroup_id"), secgroupids)).Desc(q.Field("priority"), q.Field("action"))
- secrules := []SSecurityGroupRule{}
- if err := db.FetchModelObjects(SecurityGroupRuleManager, q, &secrules); err != nil {
- log.Errorf("Get security group rules error: %v", err)
- return ""
- }
- rules := []string{}
- for _, rule := range secrules {
- rules = append(rules, rule.String())
- }
- return strings.Join(rules, SECURITY_GROUP_SEPARATOR)
- }
- func (self *SGuest) getNetworkSecurityGroupsRules(networkIndex int) string {
- gnss, _ := self.GetGuestNetworkSecgroups(networkIndex)
- secgroupids := []string{}
- for _, gns := range gnss {
- secgroupids = append(secgroupids, gns.SecgroupId)
- }
- q := SecurityGroupRuleManager.Query()
- q.Filter(sqlchemy.In(q.Field("secgroup_id"), secgroupids)).Desc(q.Field("priority"), q.Field("action"))
- secrules := []SSecurityGroupRule{}
- if err := db.FetchModelObjects(SecurityGroupRuleManager, q, &secrules); err != nil {
- log.Errorf("Get security group rules error: %v", err)
- return ""
- }
- rules := []string{}
- for _, rule := range secrules {
- rules = append(rules, rule.String())
- }
- return strings.Join(rules, SECURITY_GROUP_SEPARATOR)
- }
- func (self *SGuest) getAdminSecurityRules() string {
- secgrp := self.getAdminSecgroup()
- if secgrp != nil {
- ret, _ := secgrp.getSecurityRuleString()
- return ret
- }
- return ""
- }
- func (self *SGuest) IsFailureStatus() bool {
- return strings.Index(self.Status, "fail") >= 0
- }
- var (
- lostNamePattern = regexp.MustCompile(`-lost@\d{8}$`)
- )
- func (self *SGuest) GetIRegion(ctx context.Context) (cloudprovider.ICloudRegion, error) {
- host, err := self.GetHost()
- if err != nil {
- return nil, errors.Wrapf(err, "GetHost")
- }
- provider, err := host.GetDriver(ctx)
- if err != nil {
- return nil, errors.Wrapf(err, "host.GetDriver")
- }
- if provider.GetFactory().IsOnPremise() {
- return provider.GetOnPremiseIRegion()
- }
- return host.GetIRegion(ctx)
- }
- func (self *SGuest) SyncRemoveCloudVM(ctx context.Context, userCred mcclient.TokenCredential, check bool) error {
- lockman.LockObject(ctx, self)
- defer lockman.ReleaseObject(ctx, self)
- if self.BillingType == billing_api.BILLING_TYPE_PREPAID {
- diff, err := db.Update(self, func() error {
- self.BillingType = billing_api.BILLING_TYPE_POSTPAID
- self.ExpiredAt = time.Time{}
- return nil
- })
- if err != nil {
- return err
- }
- db.OpsLog.LogSyncUpdate(self, diff, userCred)
- }
- if self.IsFailureStatus() {
- return nil
- }
- iregion, err := self.GetIRegion(ctx)
- if err != nil {
- return err
- }
- if check {
- iVM, err := iregion.GetIVMById(self.ExternalId)
- if err == nil { //漂移归位
- if hostId := iVM.GetIHostId(); len(hostId) > 0 {
- host, err := db.FetchByExternalIdAndManagerId(HostManager, hostId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- host, _ := self.GetHost()
- if host != nil {
- return q.Equals("manager_id", host.ManagerId)
- }
- return q
- })
- if err != nil {
- log.Errorf("fetch vm %s(%s) host by id %s error: %v", self.Name, self.ExternalId, hostId, err)
- return nil
- }
- _, err = db.Update(self, func() error {
- self.HostId = host.GetId()
- self.Status = iVM.GetStatus()
- self.PowerStates = iVM.GetPowerStates()
- self.InferPowerStates()
- return nil
- })
- return err
- }
- // 公有云实例, 因为翻页查询导致实例返回结果漏查,且GetIHostId一般返回为空
- return nil
- } else if errors.Cause(err) != cloudprovider.ErrNotFound {
- return errors.Wrap(err, "GetIVMById")
- }
- }
- if self.Status != api.VM_UNKNOWN {
- self.SetStatus(ctx, userCred, api.VM_UNKNOWN, "Sync lost")
- }
- if options.Options.EnableSyncPurge {
- log.Debugf("purge removed resource %s", self.Name)
- err := self.purge(ctx, userCred)
- if err != nil {
- return err
- }
- notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
- Obj: self,
- Action: notifyclient.ActionSyncDelete,
- })
- return nil
- }
- if !lostNamePattern.MatchString(self.Name) {
- db.Update(self, func() error {
- self.Name = fmt.Sprintf("%s-lost@%s", self.Name, timeutils.ShortDate(time.Now()))
- return nil
- })
- }
- return nil
- }
- func (guest *SGuest) SyncAllWithCloudVM(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, extVM cloudprovider.ICloudVM, syncStatus bool) error {
- if host == nil {
- return errors.Error("guest has no host")
- }
- provider := host.GetCloudprovider()
- if provider == nil {
- return errors.Error("host has no provider")
- }
- driver, err := provider.GetProvider(ctx)
- if err != nil {
- return errors.Wrap(err, "provider.GetProvider")
- }
- err = guest.syncWithCloudVM(ctx, userCred, driver, host, extVM, provider.GetOwnerId(), syncStatus)
- if err != nil {
- return errors.Wrap(err, "guest.syncWithCloudVM")
- }
- SyncVMPeripherals(ctx, userCred, guest, extVM, host, provider, driver)
- return nil
- }
- func (g *SGuest) SyncOsInfo(ctx context.Context, userCred mcclient.TokenCredential, extVM cloudprovider.IOSInfo) error {
- drv, err := g.GetDriver()
- if err != nil {
- return err
- }
- return drv.SyncOsInfo(ctx, userCred, g, extVM)
- }
- func (g *SGuest) SyncHostname(ext cloudprovider.ICloudVM) {
- hostname := pinyinutils.Text2Pinyin(ext.GetHostname())
- if len(hostname) > 128 {
- hostname = hostname[:128]
- }
- if len(hostname) > 0 {
- g.Hostname = hostname
- }
- }
- func (g *SGuest) syncWithCloudVM(ctx context.Context, userCred mcclient.TokenCredential, provider cloudprovider.ICloudProvider, host *SHost, extVM cloudprovider.ICloudVM, syncOwnerId mcclient.IIdentityProvider, syncStatus bool) error {
- recycle := false
- if provider.GetFactory().IsSupportPrepaidResources() && g.IsPrepaidRecycle() {
- recycle = true
- }
- diff, err := db.UpdateWithLock(ctx, g, func() error {
- if options.Options.EnableSyncName && !recycle {
- newName, _ := db.GenerateAlterName(g, extVM.GetName())
- if len(newName) > 0 && newName != g.Name {
- g.Name = newName
- }
- }
- g.SyncHostname(extVM)
- if !g.IsFailureStatus() && syncStatus {
- g.Status = extVM.GetStatus()
- if g.Status == api.VM_RUNNING || g.Status == api.VM_STARTING {
- g.HealthStatus = extVM.GetHealthStatus()
- }
- g.PowerStates = extVM.GetPowerStates()
- g.InferPowerStates()
- }
- g.VcpuCount = extVM.GetVcpuCount()
- g.CpuSockets = extVM.GetCpuSockets()
- g.BootOrder = extVM.GetBootOrder()
- g.Vga = extVM.GetVga()
- g.Vdi = extVM.GetVdi()
- if len(extVM.GetOsArch()) > 0 {
- g.OsArch = extVM.GetOsArch()
- }
- if len(g.OsType) == 0 {
- g.OsType = string(extVM.GetOsType())
- }
- if len(g.Bios) == 0 {
- g.Bios = string(extVM.GetBios())
- }
- g.Machine = extVM.GetMachine()
- if !recycle {
- g.HostId = host.Id
- }
- g.InternetMaxBandwidthOut = extVM.GetInternetMaxBandwidthOut()
- g.Throughput = extVM.GetThroughput()
- instanceType := extVM.GetInstanceType()
- if len(instanceType) > 0 {
- g.InstanceType = instanceType
- }
- memSizeMb := extVM.GetVmemSizeMB()
- if g.VmemSize == 0 || g.VmemSize != memSizeMb {
- if memSizeMb > 0 {
- g.VmemSize = memSizeMb
- } else {
- sku, _ := ServerSkuManager.FetchSkuByNameAndProvider(instanceType, provider.GetFactory().GetName(), false)
- if sku != nil && sku.MemorySizeMB > 0 {
- g.VmemSize = sku.MemorySizeMB
- }
- }
- }
- g.Hypervisor = extVM.GetHypervisor()
- if len(extVM.GetDescription()) > 0 {
- g.Description = extVM.GetDescription()
- }
- g.BillingType = billing_api.TBillingType(extVM.GetBillingType())
- g.ExpiredAt = time.Time{}
- g.AutoRenew = false
- if g.BillingType == billing_api.BILLING_TYPE_PREPAID {
- g.ExpiredAt = extVM.GetExpiredAt()
- g.AutoRenew = extVM.IsAutoRenew()
- }
- return nil
- })
- if err != nil {
- log.Errorf("%s", err)
- return err
- }
- db.OpsLog.LogSyncUpdate(g, diff, userCred)
- if len(diff) > 0 {
- notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
- Obj: g,
- Action: notifyclient.ActionSyncUpdate,
- })
- }
- g.SyncOsInfo(ctx, userCred, extVM)
- if account := host.GetCloudaccount(); account != nil {
- syncVirtualResourceMetadata(ctx, userCred, g, extVM, account.ReadOnly)
- }
- if cloudprovider := host.GetCloudprovider(); cloudprovider != nil {
- SyncCloudProject(ctx, userCred, g, syncOwnerId, extVM, cloudprovider)
- }
- if provider.GetFactory().IsSupportPrepaidResources() && recycle {
- vhost, _ := g.GetHost()
- err = vhost.syncWithCloudPrepaidVM(extVM, host)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient.TokenCredential, provider cloudprovider.ICloudProvider, host *SHost, extVM cloudprovider.ICloudVM, syncOwnerId mcclient.IIdentityProvider) (*SGuest, error) {
- guest := SGuest{}
- guest.SetModelManager(manager, &guest)
- guest.Status = extVM.GetStatus()
- guest.PowerStates = extVM.GetPowerStates()
- guest.InferPowerStates()
- guest.ExternalId = extVM.GetGlobalId()
- guest.VcpuCount = extVM.GetVcpuCount()
- guest.CpuSockets = extVM.GetCpuSockets()
- guest.BootOrder = extVM.GetBootOrder()
- guest.Vga = extVM.GetVga()
- guest.Vdi = extVM.GetVdi()
- guest.OsArch = extVM.GetOsArch()
- guest.OsType = string(extVM.GetOsType())
- guest.Bios = string(extVM.GetBios())
- guest.Machine = extVM.GetMachine()
- guest.Hypervisor = extVM.GetHypervisor()
- hostname := extVM.GetHostname()
- if len(hostname) == 0 {
- hostname = extVM.GetName()
- }
- guest.Hostname = pinyinutils.Text2Pinyin(hostname)
- guest.InternetMaxBandwidthOut = extVM.GetInternetMaxBandwidthOut()
- guest.Throughput = extVM.GetThroughput()
- guest.Description = extVM.GetDescription()
- guest.IsEmulated = extVM.IsEmulated()
- guest.BillingType = billing_api.TBillingType(extVM.GetBillingType())
- guest.ExpiredAt = time.Time{}
- guest.AutoRenew = false
- if guest.BillingType == billing_api.BILLING_TYPE_PREPAID {
- guest.ExpiredAt = extVM.GetExpiredAt()
- guest.AutoRenew = extVM.IsAutoRenew()
- }
- if createdAt := extVM.GetCreatedAt(); !createdAt.IsZero() {
- guest.CreatedAt = createdAt
- }
- guest.HostId = host.Id
- instanceType := extVM.GetInstanceType()
- if len(instanceType) > 0 {
- guest.InstanceType = instanceType
- }
- if extVM.GetHypervisor() == api.HYPERVISOR_AWS {
- sku, err := ServerSkuManager.FetchSkuByNameAndProvider(instanceType, api.CLOUD_PROVIDER_AWS, false)
- if err == nil {
- guest.VmemSize = sku.MemorySizeMB
- } else {
- guest.VmemSize = extVM.GetVmemSizeMB()
- }
- } else {
- guest.VmemSize = extVM.GetVmemSizeMB()
- }
- var err = func() error {
- lockman.LockRawObject(ctx, manager.Keyword(), "name")
- defer lockman.ReleaseRawObject(ctx, manager.Keyword(), "name")
- newName, err := db.GenerateName(ctx, manager, syncOwnerId, extVM.GetName())
- if err != nil {
- return errors.Wrapf(err, "db.GenerateName")
- }
- guest.Name = newName
- return manager.TableSpec().Insert(ctx, &guest)
- }()
- if err != nil {
- return nil, errors.Wrapf(err, "Insert")
- }
- guest.SyncOsInfo(ctx, userCred, extVM)
- syncVirtualResourceMetadata(ctx, userCred, &guest, extVM, false)
- if cloudprovider := host.GetCloudprovider(); cloudprovider != nil {
- SyncCloudProject(ctx, userCred, &guest, syncOwnerId, extVM, cloudprovider)
- }
- db.OpsLog.LogEvent(&guest, db.ACT_CREATE, guest.GetShortDesc(ctx), userCred)
- if guest.Status == api.VM_RUNNING {
- db.OpsLog.LogEvent(&guest, db.ACT_START, guest.GetShortDesc(ctx), userCred)
- }
- notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
- Obj: &guest,
- Action: notifyclient.ActionSyncCreate,
- })
- drv, _ := guest.GetDriver()
- if drv != nil && drv.GetMaxSecurityGroupCount() == 0 {
- db.Update(&guest, func() error {
- guest.SecgrpId = ""
- return nil
- })
- }
- if guest.Status == api.VM_RUNNING {
- db.OpsLog.LogEvent(&guest, db.ACT_START, guest.GetShortDesc(ctx), userCred)
- }
- return &guest, nil
- }
- func (manager *SGuestManager) TotalCount(
- ctx context.Context,
- scope rbacscope.TRbacScope,
- ownerId mcclient.IIdentityProvider,
- rangeObjs []db.IStandaloneModel,
- status []string, hypervisors []string,
- includeSystem bool, pendingDelete bool,
- hostTypes []string, resourceTypes []string, providers []string, brands []string, cloudEnv string,
- since *time.Time,
- policyResult rbacutils.SPolicyResult,
- ) map[string]SGuestCountStat {
- return usageTotalGuestResourceCount(ctx, scope, ownerId, rangeObjs, status, hypervisors, includeSystem, pendingDelete, hostTypes, resourceTypes, providers, brands, cloudEnv, since, policyResult)
- }
- func (self *SGuest) detachNetworks(ctx context.Context, userCred mcclient.TokenCredential, gns []SGuestnetwork, reserve bool) error {
- err := GuestnetworkManager.DeleteGuestNics(ctx, userCred, gns, reserve)
- if err != nil {
- return err
- }
- host, _ := self.GetHost()
- if host != nil {
- host.ClearSchedDescCache() // ignore error
- }
- return nil
- }
- func (self *SGuest) getAttach2NetworkCount(net *SNetwork) (int, error) {
- q := GuestnetworkManager.Query()
- q = q.Equals("guest_id", self.Id).Equals("network_id", net.Id)
- return q.CountWithError()
- }
- func (self *SGuest) getUsableNicIndex() int {
- nics, err := self.GetNetworks("")
- if err != nil {
- return -1
- }
- maxIndex := len(nics)
- for i := 0; i <= maxIndex; i++ {
- found := true
- for j := range nics {
- if nics[j].Index == i {
- found = false
- break
- }
- }
- if found {
- return i
- }
- }
- panic(fmt.Sprintf("cannot find usable nic index for guest %s(%s)",
- self.Name, self.Id))
- }
- func (self *SGuest) setOSProfile(ctx context.Context, userCred mcclient.TokenCredential, profile jsonutils.JSONObject) error {
- return self.SetMetadata(ctx, "__os_profile__", profile, userCred)
- }
- func (self *SGuest) GetOSProfile() osprofile.SOSProfile {
- osName := self.GetOS()
- osProf := osprofile.GetOSProfile(osName, self.Hypervisor)
- val := self.GetMetadata(context.Background(), "__os_profile__", nil)
- if len(val) > 0 {
- jsonVal, _ := jsonutils.ParseString(val)
- if jsonVal != nil {
- jsonVal.Unmarshal(&osProf)
- }
- }
- return osProf
- }
- // Summary of network address allocation strategy
- //
- // # IpAddr when specified must be part of the network
- //
- // Use IpAddr without checking if it's already allocated when UseDesignatedIP
- // is true. See b31bc7fa ("feature: 1. baremetal server reuse host ip...")
- //
- // Try IpAddr from reserved pool when allowed by TryReserved. Otherwise
- // fallback to usual allocation method (AllocDir). Error when
- // RequireDesignatedIP is true and the allocated address does not match IpAddr
- type Attach2NetworkArgs struct {
- Network *SNetwork
- IpAddr string
- Ip6Addr string
- AllocDir api.IPAllocationDirection
- TryReserved bool
- RequireDesignatedIP bool
- UseDesignatedIP bool
- RequireIPv6 bool
- StrictIPv6 bool
- BwLimit int
- NicDriver string
- NumQueues int
- RxTrafficLimit int64
- TxTrafficLimit int64
- NicConfs []SNicConfig
- Virtual bool
- IsDefault bool
- PortMappings api.GuestPortMappings
- BillingType billing_api.TBillingType
- ChargeType billing_api.TNetChargeType
- PendingUsage quotas.IQuota
- }
- func (args *Attach2NetworkArgs) onceArgs(i int) attach2NetworkOnceArgs {
- if i < 0 || i > len(args.NicConfs)-1 {
- return attach2NetworkOnceArgs{}
- }
- r := attach2NetworkOnceArgs{
- network: args.Network,
- ipAddr: args.IpAddr,
- ip6Addr: args.Ip6Addr,
- allocDir: args.AllocDir,
- tryReserved: args.TryReserved,
- requireDesignatedIP: args.RequireDesignatedIP,
- useDesignatedIP: args.UseDesignatedIP,
- requireIPv6: args.RequireIPv6,
- strictIPv6: args.StrictIPv6,
- bwLimit: args.BwLimit,
- nicDriver: args.NicDriver,
- numQueues: args.NumQueues,
- txTrafficLimit: args.TxTrafficLimit,
- rxTrafficLimit: args.RxTrafficLimit,
- nicConf: args.NicConfs[i],
- virtual: args.Virtual,
- isDefault: args.IsDefault,
- pendingUsage: args.PendingUsage,
- portMappings: args.PortMappings,
- billingType: args.BillingType,
- chargeType: args.ChargeType,
- }
- if i > 0 {
- r.ipAddr = ""
- r.ip6Addr = ""
- r.bwLimit = 0
- r.virtual = true
- r.tryReserved = false
- r.requireDesignatedIP = false
- r.useDesignatedIP = false
- r.nicConf = args.NicConfs[i]
- r.nicDriver = ""
- r.numQueues = 1
- r.isDefault = false
- r.requireIPv6 = false
- }
- return r
- }
- type attach2NetworkOnceArgs struct {
- network *SNetwork
- ipAddr string
- ip6Addr string
- allocDir api.IPAllocationDirection
- tryReserved bool
- requireDesignatedIP bool
- useDesignatedIP bool
- requireIPv6 bool
- strictIPv6 bool
- bwLimit int
- nicDriver string
- numQueues int
- nicConf SNicConfig
- teamWithMac string
- rxTrafficLimit int64
- txTrafficLimit int64
- virtual bool
- isDefault bool
- pendingUsage quotas.IQuota
- portMappings api.GuestPortMappings
- billingType billing_api.TBillingType
- chargeType billing_api.TNetChargeType
- }
- func (self *SGuest) Attach2Network(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- args Attach2NetworkArgs,
- ) ([]SGuestnetwork, error) {
- log.Debugf("Attach2Network %s", jsonutils.Marshal(args))
- onceArgs := args.onceArgs(0)
- firstNic, err := self.attach2NetworkOnce(ctx, userCred, onceArgs)
- if err != nil {
- return nil, errors.Wrap(err, "self.attach2NetworkOnce")
- }
- retNics := []SGuestnetwork{*firstNic}
- if len(args.NicConfs) > 1 {
- firstMac, _ := netutils.ParseMac(firstNic.MacAddr)
- for i := 1; i < len(args.NicConfs); i += 1 {
- onceArgs := args.onceArgs(i)
- onceArgs.nicDriver = firstNic.Driver
- onceArgs.teamWithMac = firstNic.MacAddr
- if onceArgs.nicConf.Mac == "" {
- onceArgs.nicConf.Mac = firstMac.Add(i).String()
- }
- gn, err := self.attach2NetworkOnce(ctx, userCred, onceArgs)
- if err != nil {
- return retNics, errors.Wrap(err, "self.attach2NetworkOnce")
- }
- retNics = append(retNics, *gn)
- }
- }
- return retNics, nil
- }
- func (self *SGuest) attach2NetworkOnce(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- args attach2NetworkOnceArgs,
- ) (*SGuestnetwork, error) {
- var (
- index = args.nicConf.Index
- nicDriver = args.nicDriver
- )
- if index < 0 {
- index = self.getUsableNicIndex()
- }
- if nicDriver == "" {
- osProf := self.GetOSProfile()
- nicDriver = osProf.NetDriver
- }
- newArgs := newGuestNetworkArgs{
- guest: self,
- network: args.network,
- index: index,
- ipAddr: args.ipAddr,
- ip6Addr: args.ip6Addr,
- allocDir: args.allocDir,
- tryReserved: args.tryReserved,
- requireDesignatedIP: args.requireDesignatedIP,
- useDesignatedIP: args.useDesignatedIP,
- requireIPv6: args.requireIPv6,
- strictIPv6: args.strictIPv6,
- ifname: args.nicConf.Ifname,
- macAddr: args.nicConf.Mac,
- bwLimit: args.bwLimit,
- nicDriver: nicDriver,
- numQueues: args.numQueues,
- teamWithMac: args.teamWithMac,
- rxTrafficLimit: args.rxTrafficLimit,
- txTrafficLimit: args.txTrafficLimit,
- virtual: args.virtual,
- isDefault: args.isDefault,
- portMappings: args.portMappings,
- billingType: args.billingType,
- chargeType: args.chargeType,
- }
- lockman.LockClass(ctx, QuotaManager, self.ProjectId)
- defer lockman.ReleaseClass(ctx, QuotaManager, self.ProjectId)
- guestnic, err := GuestnetworkManager.newGuestNetwork(ctx, userCred, newArgs)
- if err != nil {
- return nil, errors.Wrap(err, "GuestnetworkManager.newGuestNetwork")
- }
- var (
- network = args.network
- pendingUsage = args.pendingUsage
- teamWithMac = args.teamWithMac
- )
- network.updateDnsRecord(guestnic, true)
- if pendingUsage != nil && len(teamWithMac) == 0 {
- cancelUsage := SRegionQuota{}
- if network.IsExitNetwork() {
- cancelUsage.Eport = 1
- } else {
- cancelUsage.Port = 1
- }
- keys, err := self.GetRegionalQuotaKeys()
- if err != nil {
- log.Warningf("self.GetRegionalQuotaKeys fail %s", err)
- }
- cancelUsage.SetKeys(keys)
- err = quotas.CancelPendingUsage(ctx, userCred, pendingUsage, &cancelUsage, true)
- if err != nil {
- log.Warningf("QuotaManager.CancelPendingUsage fail %s", err)
- }
- }
- db.OpsLog.LogAttachEvent(ctx, self, network, userCred, guestnic.GetShortDesc(ctx))
- return guestnic, nil
- }
- func getCloudNicNetwork(ctx context.Context, vnic cloudprovider.ICloudNic, host *SHost, ipList []string, index int) (*SNetwork, error) {
- vnetId := vnic.GetINetworkId()
- if len(vnetId) == 0 {
- if vnic.InClassicNetwork() {
- region, _ := host.GetRegion()
- cloudprovider := host.GetCloudprovider()
- vpc, err := VpcManager.GetOrCreateVpcForClassicNetwork(ctx, cloudprovider, region)
- if err != nil {
- return nil, errors.Wrap(err, "NewVpcForClassicNetwork")
- }
- zone, _ := host.GetZone()
- wire, err := WireManager.GetOrCreateWireForClassicNetwork(ctx, vpc, zone)
- if err != nil {
- return nil, errors.Wrap(err, "NewWireForClassicNetwork")
- }
- return NetworkManager.GetOrCreateClassicNetwork(ctx, wire)
- }
- ip := vnic.GetIP()
- if len(ip) == 0 {
- if index < len(ipList) {
- ip = ipList[index]
- }
- if len(ip) == 0 {
- return nil, fmt.Errorf("Cannot find inetwork for vnics %s: no ip", vnic.GetMAC())
- }
- }
- // find network by IP
- return host.getNetworkOfIPOnHost(ctx, ip)
- }
- localNetObj, err := db.FetchByExternalIdAndManagerId(NetworkManager, vnetId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
- // vpc := VpcManager.Query().SubQuery()
- wire := WireManager.Query().SubQuery()
- return q.Join(wire, sqlchemy.Equals(q.Field("wire_id"), wire.Field("id"))).
- Filter(sqlchemy.Equals(wire.Field("manager_id"), host.ManagerId))
- })
- if err != nil {
- return nil, errors.Wrapf(err, "Cannot find network of external_id %s", vnetId)
- }
- localNet := localNetObj.(*SNetwork)
- return localNet, nil
- }
- func (self *SGuest) SyncVMNics(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- host *SHost,
- vnics []cloudprovider.ICloudNic,
- ipList []string,
- ) compare.SyncResult {
- result := compare.SyncResult{}
- nics, err := self.GetNetworks("")
- if err != nil {
- result.Error(err)
- return result
- }
- removed := make([]SGuestnetwork, 0)
- commondb := make([]SGuestnetwork, 0)
- commonext := make([]cloudprovider.ICloudNic, 0)
- added := make([]cloudprovider.ICloudNic, 0)
- set := compare.SCompareSet{
- DBFunc: "GetMAC",
- DBSet: nics,
- ExtFunc: "GetMAC",
- ExtSet: vnics,
- }
- err = compare.CompareSetsFunc(set, &removed, &commondb, &commonext, &added, nil)
- if err != nil {
- result.Error(errors.Wrapf(err, "compare.CompareSets"))
- return result
- }
- log.Debugf("SyncVMNics: removed: %d common: %d add: %d", len(removed), len(commondb), len(added))
- for i := 0; i < len(removed); i += 1 {
- err = self.detachNetworks(ctx, userCred, []SGuestnetwork{removed[i]}, false)
- if err != nil {
- result.DeleteError(err)
- continue
- }
- result.Delete()
- }
- for i := 0; i < len(commondb); i += 1 {
- err := NetworkAddressManager.syncGuestnetworkICloudNic(ctx, userCred, &commondb[i], commonext[i])
- if err != nil {
- result.UpdateError(err)
- continue
- }
- _, err = db.Update(&commondb[i], func() error {
- network, _ := commondb[i].GetNetwork()
- ip := commonext[i].GetIP()
- ip6 := commonext[i].GetIP6()
- if len(ip) > 0 {
- if !network.Contains(ip) {
- localNet, err := getCloudNicNetwork(ctx, commonext[i], host, ipList, i)
- if err != nil {
- return errors.Wrapf(err, "getCloudNicNetwork")
- }
- commondb[i].NetworkId = localNet.Id
- commondb[i].IpAddr = ip
- } else {
- commondb[i].IpAddr = ip
- commondb[i].Ip6Addr = ip6
- }
- }
- commondb[i].Driver = commonext[i].GetDriver()
- return nil
- })
- if err != nil {
- result.UpdateError(errors.Wrapf(err, "db.Update"))
- continue
- }
- result.Update()
- }
- syncIps := make([]string, 0)
- for i := 0; i < len(added); i += 1 {
- localNet, err := getCloudNicNetwork(ctx, added[i], host, ipList, i)
- if err != nil {
- log.Errorf("SyncVMNics getCloudNicNetwork add fail: %s", err)
- if ip := added[i].GetIP(); len(ip) > 0 {
- syncIps = append(syncIps, ip)
- }
- result.AddError(err)
- continue
- }
- nicConf := SNicConfig{
- Mac: added[i].GetMAC(),
- Index: -1,
- Ifname: "",
- }
- ip := added[i].GetIP()
- // vmware, may be sync fix ip
- if len(ip) == 0 && len(ipList) > 0 {
- ip = ipList[0]
- }
- // always try allocate from reserved pool
- guestnetworks, err := self.Attach2Network(ctx, userCred, Attach2NetworkArgs{
- Network: localNet,
- IpAddr: ip,
- Ip6Addr: added[i].GetIP6(),
- NicDriver: added[i].GetDriver(),
- TryReserved: true,
- AllocDir: api.IPAllocationDefault,
- RequireDesignatedIP: true,
- // UseDesignatedIP: true,
- NicConfs: []SNicConfig{nicConf},
- })
- if err != nil {
- result.AddError(err)
- continue
- }
- if len(ipList) > 0 {
- // shift
- ipList = ipList[1:]
- }
- result.Add()
- for i := range guestnetworks {
- guestnetwork := &guestnetworks[i]
- if NetworkAddressManager.syncGuestnetworkICloudNic(
- ctx, userCred, guestnetwork, added[i]); err != nil {
- result.AddError(err)
- }
- }
- }
- if len(syncIps) > 0 {
- self.SetMetadata(ctx, "sync_ips", strings.Join(syncIps, ","), userCred)
- } else {
- self.SetMetadata(ctx, "sync_ips", "None", userCred)
- }
- return result
- }
- func (self *SGuest) IsAttach2Disk(disk *SDisk) (bool, error) {
- return self.isAttach2Disk(disk)
- }
- func (self *SGuest) isAttach2Disk(disk *SDisk) (bool, error) {
- q := GuestdiskManager.Query().Equals("disk_id", disk.Id).Equals("guest_id", self.Id)
- cnt, err := q.CountWithError()
- if err != nil {
- return false, err
- }
- return cnt > 0, nil
- }
- func (self *SGuest) getDiskIndex() int8 {
- guestdisks, _ := self.GetGuestDisks()
- var max uint
- for i := 0; i < len(guestdisks); i++ {
- if uint(guestdisks[i].Index) > max {
- max = uint(guestdisks[i].Index)
- }
- }
- idxs := make([]int, max+1)
- for i := 0; i < len(guestdisks); i++ {
- idxs[guestdisks[i].Index] = 1
- }
- // find first idx not set
- for i := 0; i < len(idxs); i++ {
- if idxs[i] != 1 {
- return int8(i)
- }
- }
- return int8(max + 1)
- }
- func (self *SGuest) AttachDisk(ctx context.Context, disk *SDisk, userCred mcclient.TokenCredential, driver string, cache string, mountpoint string, bootIndex *int8) error {
- return self.attach2Disk(ctx, disk, userCred, driver, cache, mountpoint, bootIndex)
- }
- func (self *SGuest) attach2Disk(ctx context.Context, disk *SDisk, userCred mcclient.TokenCredential, driver string, cache string, mountpoint string, bootIndex *int8) error {
- attached, err := self.isAttach2Disk(disk)
- if err != nil {
- return errors.Wrap(err, "isAttach2Disk")
- }
- if attached {
- return fmt.Errorf("Guest has been attached to disk")
- }
- if len(driver) == 0 {
- // depends the last disk of this guest
- existingDisks, _ := self.GetGuestDisks()
- if len(existingDisks) > 0 {
- prevDisk := existingDisks[len(existingDisks)-1]
- if prevDisk.Driver == api.DISK_DRIVER_IDE {
- driver = api.DISK_DRIVER_VIRTIO
- } else {
- driver = prevDisk.Driver
- }
- } else {
- osProf := self.GetOSProfile()
- driver = osProf.DiskDriver
- }
- }
- guestdisk := SGuestdisk{}
- guestdisk.SetModelManager(GuestdiskManager, &guestdisk)
- guestdisk.DiskId = disk.Id
- guestdisk.GuestId = self.Id
- lockman.LockObject(ctx, self)
- defer lockman.ReleaseObject(ctx, self)
- guestdisk.Index = self.getDiskIndex()
- if bootIndex != nil {
- guestdisk.BootIndex = *bootIndex
- } else {
- guestdisk.BootIndex = -1
- }
- err = guestdisk.DoSave(ctx, driver, cache, mountpoint)
- if err == nil {
- db.OpsLog.LogAttachEvent(ctx, self, disk, userCred, nil)
- }
- return err
- }
- func (self *SGuest) SyncVMDisks(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- provider cloudprovider.ICloudProvider,
- host *SHost,
- vdisks []cloudprovider.ICloudDisk,
- syncOwnerId mcclient.IIdentityProvider,
- ) compare.SyncResult {
- lockman.LockRawObject(ctx, self.Id, DiskManager.Keyword())
- defer lockman.ReleaseRawObject(ctx, self.Id, DiskManager.Keyword())
- result := compare.SyncResult{}
- dbDisks, err := self.GetDisks()
- if err != nil {
- result.Error(errors.Wrapf(err, "GetDisks"))
- return result
- }
- removed := make([]SDisk, 0)
- commondb := make([]SDisk, 0)
- commonext := make([]cloudprovider.ICloudDisk, 0)
- added := make([]cloudprovider.ICloudDisk, 0)
- err = compare.CompareSets(dbDisks, vdisks, &removed, &commondb, &commonext, &added)
- if err != nil {
- result.Error(errors.Wrapf(err, "compare.CompareSets"))
- return result
- }
- for i := 0; i < len(removed); i += 1 {
- self.DetachDisk(ctx, &removed[i], userCred)
- result.Delete()
- }
- for i := 0; i < len(commondb); i += 1 {
- if commondb[i].PendingDeleted != self.PendingDeleted { //避免主机正常,磁盘在回收站的情况
- db.Update(&commondb[i], func() error {
- commondb[i].PendingDeleted = self.PendingDeleted
- return nil
- })
- }
- commondb[i].SyncCloudProjectId(userCred, self.GetOwnerId())
- result.Update()
- }
- for i := 0; i < len(added); i += 1 {
- disk, err := DiskManager.findOrCreateDisk(ctx, userCred, provider, added[i], -1, self.GetOwnerId(), host.ManagerId)
- if err != nil {
- result.AddError(errors.Wrapf(err, "findOrCreateDisk(%s)", added[i].GetGlobalId()))
- continue
- }
- disk.SyncCloudProjectId(userCred, self.GetOwnerId())
- err = self.attach2Disk(ctx, disk, userCred, added[i].GetDriver(), added[i].GetCacheMode(), added[i].GetMountpoint(), nil)
- if err != nil {
- result.AddError(err)
- continue
- }
- result.Add()
- }
- err = self.fixSysDiskIndex()
- if err != nil {
- result.Error(errors.Wrapf(err, "fixSysDiskIndex"))
- }
- return result
- }
- func (self *SGuest) setSystemDisk() error {
- sq := GuestdiskManager.Query("disk_id").Equals("guest_id", self.Id).Equals("index", 0).SubQuery()
- disks := DiskManager.Query().In("id", sq)
- disk := &SDisk{}
- disk.SetModelManager(DiskManager, disk)
- err := disks.First(disk)
- if err != nil {
- return err
- }
- _, err = db.Update(disk, func() error {
- disk.DiskType = api.DISK_TYPE_SYS
- return nil
- })
- return err
- }
- func (self *SGuest) fixSysDiskIndex() error {
- disks := DiskManager.Query().SubQuery()
- sysQ := GuestdiskManager.Query().Equals("guest_id", self.Id)
- sysQ = sysQ.Join(disks, sqlchemy.Equals(disks.Field("id"), sysQ.Field("disk_id"))).Filter(sqlchemy.Equals(disks.Field("disk_type"), api.DISK_TYPE_SYS))
- sysDisk := &SGuestdisk{}
- sysDisk.SetModelManager(GuestdiskManager, sysDisk)
- err := sysQ.First(sysDisk)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return self.setSystemDisk()
- }
- return err
- }
- if sysDisk.Index == 0 {
- return nil
- }
- q := GuestdiskManager.Query().Equals("guest_id", self.Id).Equals("index", 0)
- firstDisk := &SGuestdisk{}
- firstDisk.SetModelManager(GuestdiskManager, firstDisk)
- err = q.First(firstDisk)
- if err != nil {
- return err
- }
- _, err = db.Update(firstDisk, func() error {
- firstDisk.Index = sysDisk.Index
- return nil
- })
- if err != nil {
- return err
- }
- _, err = db.Update(sysDisk, func() error {
- sysDisk.Index = 0
- return nil
- })
- return err
- }
- func filterGuestByRange(q *sqlchemy.SQuery, rangeObjs []db.IStandaloneModel, hostTypes []string, resourceTypes []string, providers []string, brands []string, cloudEnv string) *sqlchemy.SQuery {
- hosts := HostManager.Query().SubQuery()
- subq := hosts.Query(hosts.Field("id"))
- subq = AttachUsageQuery(subq, hosts, hostTypes, resourceTypes, providers, brands, cloudEnv, rangeObjs)
- q = q.In("host_id", subq.SubQuery())
- return q
- }
- type SGuestCountStat struct {
- TotalGuestCount int
- TotalCpuCount int
- TotalMemSize int
- TotalDiskSize int
- TotalIsolatedCount int
- TotalBackupGuestCount int
- TotalBackupCpuCount int
- TotalBackupMemSize int
- TotalBackupDiskSize int
- }
- func usageTotalGuestResourceCount(
- ctx context.Context,
- scope rbacscope.TRbacScope,
- ownerId mcclient.IIdentityProvider,
- rangeObjs []db.IStandaloneModel,
- status []string,
- hypervisors []string,
- includeSystem bool,
- pendingDelete bool,
- hostTypes []string,
- resourceTypes []string,
- providers []string, brands []string, cloudEnv string,
- since *time.Time,
- policyResult rbacutils.SPolicyResult,
- ) map[string]SGuestCountStat {
- countStat := make(map[string]SGuestCountStat)
- for _, arch := range []string{apis.OS_ARCH_ALL, apis.OS_ARCH_X86_64, apis.OS_ARCH_AARCH64} {
- allStat := usageTotalGuestResourceCountByArch(
- ctx, scope, ownerId, rangeObjs, status,
- hypervisors, includeSystem, pendingDelete,
- hostTypes, resourceTypes, providers, brands,
- cloudEnv, since, policyResult, arch,
- )
- countStat[arch] = allStat
- }
- return countStat
- }
- func usageTotalGuestResourceCountByArch(
- ctx context.Context,
- scope rbacscope.TRbacScope,
- ownerId mcclient.IIdentityProvider,
- rangeObjs []db.IStandaloneModel,
- status []string,
- hypervisors []string,
- includeSystem bool,
- pendingDelete bool,
- hostTypes []string,
- resourceTypes []string,
- providers []string, brands []string, cloudEnv string,
- since *time.Time,
- policyResult rbacutils.SPolicyResult,
- osArch string,
- ) SGuestCountStat {
- q, guests := _guestResourceCountQuery(
- ctx,
- scope, ownerId, rangeObjs, status, hypervisors,
- pendingDelete, hostTypes, resourceTypes, providers, brands, cloudEnv, since,
- policyResult, osArch,
- )
- if !includeSystem {
- q = q.Filter(sqlchemy.OR(
- sqlchemy.IsNull(guests.Field("is_system")), sqlchemy.IsFalse(guests.Field("is_system"))))
- }
- stat := SGuestCountStat{}
- row := q.Row()
- err := q.Row2Struct(row, &stat)
- if err != nil {
- log.Errorf("%s", err)
- }
- stat.TotalCpuCount += stat.TotalBackupCpuCount
- stat.TotalMemSize += stat.TotalBackupMemSize
- stat.TotalDiskSize += stat.TotalBackupDiskSize
- return stat
- }
- func _guestResourceCountQuery(
- ctx context.Context,
- scope rbacscope.TRbacScope,
- ownerId mcclient.IIdentityProvider,
- rangeObjs []db.IStandaloneModel,
- status []string,
- hypervisors []string,
- pendingDelete bool,
- hostTypes []string,
- resourceTypes []string,
- providers []string, brands []string, cloudEnv string,
- since *time.Time,
- policyResult rbacutils.SPolicyResult,
- osArch string,
- ) (*sqlchemy.SQuery, *sqlchemy.SSubQuery) {
- guestdisks := GuestdiskManager.Query().SubQuery()
- disks := DiskManager.Query().SubQuery()
- diskQuery := guestdisks.Query(guestdisks.Field("guest_id"), sqlchemy.SUM("guest_disk_size", disks.Field("disk_size")))
- diskQuery = diskQuery.Join(disks, sqlchemy.Equals(guestdisks.Field("disk_id"), disks.Field("id")))
- diskQuery = diskQuery.GroupBy(guestdisks.Field("guest_id"))
- diskSubQuery := diskQuery.SubQuery()
- backupDiskQuery := guestdisks.Query(guestdisks.Field("guest_id"), sqlchemy.SUM("guest_disk_size", disks.Field("disk_size")))
- backupDiskQuery = backupDiskQuery.LeftJoin(disks, sqlchemy.Equals(guestdisks.Field("disk_id"), disks.Field("id")))
- backupDiskQuery = backupDiskQuery.Filter(sqlchemy.IsNotEmpty(disks.Field("backup_storage_id")))
- backupDiskQuery = backupDiskQuery.GroupBy(guestdisks.Field("guest_id"))
- diskBackupSubQuery := backupDiskQuery.SubQuery()
- // diskBackupSubQuery := diskQuery.IsNotEmpty("backup_storage_id").SubQuery()
- isolated := IsolatedDeviceManager.Query().SubQuery()
- isoDevQuery := isolated.Query(isolated.Field("guest_id"), sqlchemy.COUNT("device_sum"))
- isoDevQuery = isoDevQuery.Filter(sqlchemy.IsNotNull(isolated.Field("guest_id")))
- isoDevQuery = isoDevQuery.GroupBy(isolated.Field("guest_id"))
- isoDevSubQuery := isoDevQuery.SubQuery()
- var gq *sqlchemy.SQuery
- if since != nil && !since.IsZero() {
- gq = GuestManager.RawQuery()
- } else {
- gq = GuestManager.Query()
- }
- if osArch != "" && osArch != apis.OS_ARCH_ALL {
- gq = gq.Equals("os_arch", osArch)
- }
- if len(rangeObjs) > 0 || len(hostTypes) > 0 || len(resourceTypes) > 0 || len(providers) > 0 || len(brands) > 0 || len(cloudEnv) > 0 {
- gq = filterGuestByRange(gq, rangeObjs, hostTypes, resourceTypes, providers, brands, cloudEnv)
- }
- switch scope {
- case rbacscope.ScopeSystem:
- case rbacscope.ScopeDomain:
- gq = gq.Filter(sqlchemy.Equals(gq.Field("domain_id"), ownerId.GetProjectDomainId()))
- case rbacscope.ScopeProject:
- gq = gq.Filter(sqlchemy.Equals(gq.Field("tenant_id"), ownerId.GetProjectId()))
- }
- if len(status) > 0 {
- gq = gq.Filter(sqlchemy.In(gq.Field("status"), status))
- }
- if len(hypervisors) > 0 {
- gq = gq.Filter(sqlchemy.In(gq.Field("hypervisor"), hypervisors))
- }
- if pendingDelete {
- gq = gq.Filter(sqlchemy.IsTrue(gq.Field("pending_deleted")))
- } else {
- gq = gq.Filter(sqlchemy.OR(sqlchemy.IsNull(gq.Field("pending_deleted")), sqlchemy.IsFalse(gq.Field("pending_deleted"))))
- }
- if since != nil && !since.IsZero() {
- gq = gq.Filter(sqlchemy.GT(gq.Field("created_at"), *since))
- }
- gq = db.ObjectIdQueryWithPolicyResult(ctx, gq, GuestManager, policyResult)
- guests := gq.SubQuery()
- guestBackupSubQuery := GuestManager.Query(
- "id",
- "vcpu_count",
- "vmem_size",
- ).IsNotEmpty("backup_host_id").SubQuery()
- q := guests.Query(sqlchemy.COUNT("total_guest_count"),
- sqlchemy.SUM("total_cpu_count", guests.Field("vcpu_count")),
- sqlchemy.SUM("total_mem_size", guests.Field("vmem_size")),
- sqlchemy.SUM("total_disk_size", diskSubQuery.Field("guest_disk_size")),
- sqlchemy.SUM("total_isolated_count", isoDevSubQuery.Field("device_sum")),
- sqlchemy.SUM("total_backup_disk_size", diskBackupSubQuery.Field("guest_disk_size")),
- sqlchemy.SUM("total_backup_cpu_count", guestBackupSubQuery.Field("vcpu_count")),
- sqlchemy.SUM("total_backup_mem_size", guestBackupSubQuery.Field("vmem_size")),
- sqlchemy.COUNT("total_backup_guest_count", guestBackupSubQuery.Field("id")),
- )
- q = q.LeftJoin(guestBackupSubQuery, sqlchemy.Equals(guestBackupSubQuery.Field("id"), guests.Field("id")))
- q = q.LeftJoin(diskSubQuery, sqlchemy.Equals(diskSubQuery.Field("guest_id"), guests.Field("id")))
- q = q.LeftJoin(diskBackupSubQuery, sqlchemy.Equals(diskBackupSubQuery.Field("guest_id"), guests.Field("id")))
- q = q.LeftJoin(isoDevSubQuery, sqlchemy.Equals(isoDevSubQuery.Field("guest_id"), guests.Field("id")))
- return q, guests
- }
- func (self *SGuest) getDefaultNetworkConfig() *api.NetworkConfig {
- netConf := api.NetworkConfig{}
- netConf.BwLimit = options.Options.DefaultBandwidth
- osProf := self.GetOSProfile()
- netConf.Driver = osProf.NetDriver
- return &netConf
- }
- func (self *SGuest) CreateNetworksOnHost(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- host *SHost,
- netArray []*api.NetworkConfig,
- pendingUsage, pendingUsageZone quotas.IQuota,
- candidateNets []*schedapi.CandidateNet,
- ) error {
- if len(netArray) == 0 {
- netConfig := self.getDefaultNetworkConfig()
- _, err := self.attach2RandomNetwork(ctx, userCred, host, netConfig, pendingUsage)
- return errors.Wrap(err, "self.attach2RandomNetwork")
- }
- for idx := range netArray {
- netConfig, err := parseNetworkInfo(ctx, userCred, netArray[idx])
- if err != nil {
- return errors.Wrapf(err, "parseNetworkInfo at %d", idx)
- }
- var candidateNet *schedapi.CandidateNet
- if len(candidateNets) > idx {
- candidateNet = candidateNets[idx]
- }
- networkIds := []string{}
- if candidateNet != nil {
- networkIds = candidateNet.NetworkIds
- }
- if idx == 0 && netConfig.NumQueues == 0 {
- numQueues := self.VcpuCount / 2
- if numQueues > 16 {
- numQueues = 16
- }
- netConfig.NumQueues = numQueues
- }
- gns, err := self.attach2NetworkDesc(ctx, userCred, host, netConfig, pendingUsage, networkIds)
- if err != nil {
- return errors.Wrap(err, "self.attach2NetworkDesc")
- }
- if netConfig.SriovDevice != nil {
- err = self.allocSriovNicDevice(ctx, userCred, host, &gns[0], netConfig, pendingUsageZone)
- if err != nil {
- return errors.Wrap(err, "self.allocSriovNicDevice")
- }
- }
- if len(netConfig.Secgroups) > 0 {
- err = self.SaveNetworkSecgroups(ctx, userCred, netConfig.Secgroups, gns[0].Index)
- if err != nil {
- return errors.Wrap(err, "SaveNetworkSecgroups")
- }
- }
- }
- return nil
- }
- func (self *SGuest) allocSriovNicDevice(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- host *SHost,
- gn *SGuestnetwork, netConfig *api.NetworkConfig,
- pendingUsageZone quotas.IQuota,
- ) error {
- net, err := gn.GetNetwork()
- if err != nil {
- return errors.Wrapf(err, "GetNetwork")
- }
- netConfig.SriovDevice.NetworkIndex = &gn.Index
- netConfig.SriovDevice.WireId = net.WireId
- err = self.createIsolatedDeviceOnHost(ctx, userCred, host, netConfig.SriovDevice, pendingUsageZone, nil, nil)
- if err != nil {
- return errors.Wrap(err, "self.createIsolatedDeviceOnHost")
- }
- dev, err := self.GetIsolatedDeviceByNetworkIndex(gn.Index)
- if err != nil {
- return errors.Wrap(err, "self.GetIsolatedDeviceByNetworkIndex")
- }
- if dev.OvsOffloadInterface != "" {
- _, err = db.Update(gn, func() error {
- gn.Ifname = dev.OvsOffloadInterface
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "update sriov network ifname")
- }
- }
- return nil
- }
- func (self *SGuest) attach2NetworkDesc(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- host *SHost,
- netConfig *api.NetworkConfig,
- pendingUsage quotas.IQuota,
- candiateNetIds []string,
- ) ([]SGuestnetwork, error) {
- var gns []SGuestnetwork
- var errs []error
- tryNetworkIds := []string{}
- if len(netConfig.Network) > 0 {
- tryNetworkIds = append(tryNetworkIds, netConfig.Network)
- }
- if len(candiateNetIds) > 0 {
- // suggestion by scheduler
- tryNetworkIds = append(tryNetworkIds, candiateNetIds...)
- }
- if len(tryNetworkIds) > 0 {
- for _, tryNetwork := range tryNetworkIds {
- var err error
- netConfig.Network = tryNetwork
- gns, err = self.attach2NamedNetworkDesc(ctx, userCred, host, netConfig, pendingUsage)
- if err == nil {
- return gns, nil
- }
- errs = append(errs, err)
- }
- return nil, errors.NewAggregate(errs)
- } else {
- netConfig.Network = ""
- return self.attach2RandomNetwork(ctx, userCred, host, netConfig, pendingUsage)
- }
- }
- func (self *SGuest) attach2NamedNetworkDesc(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, netConfig *api.NetworkConfig, pendingUsage quotas.IQuota) ([]SGuestnetwork, error) {
- driver, err := self.GetDriver()
- if err != nil {
- return nil, errors.Wrapf(err, "GetDriver")
- }
- net, nicConfs, allocDir, reuseAddr, err := driver.GetNamedNetworkConfiguration(self, ctx, userCred, host, netConfig)
- if err != nil {
- if errors.Cause(err) == sql.ErrNoRows {
- return nil, errors.Wrapf(httperrors.ErrResourceNotReady, "Network not avaiable on host %q", host.GetName())
- } else {
- return nil, errors.Wrapf(err, "GetNamedNetworkConfiguration on host %q", host.GetName())
- }
- }
- if net != nil {
- if len(nicConfs) == 0 {
- return nil, fmt.Errorf("no available network interface?")
- }
- var sriovWires []string
- if netConfig.SriovDevice != nil {
- if netConfig.SriovDevice.Id != "" {
- idev, err := IsolatedDeviceManager.FetchById(netConfig.SriovDevice.Id)
- if err != nil {
- return nil, errors.Wrap(err, "fetch isolated device")
- }
- dev, _ := idev.(*SIsolatedDevice)
- sriovWires = []string{dev.WireId}
- } else {
- wires, err := IsolatedDeviceManager.FindUnusedNicWiresByModel(netConfig.SriovDevice.Model)
- if err != nil {
- return nil, errors.Wrap(err, "FindUnusedNicWiresByModel")
- }
- sriovWires = wires
- }
- vpc, err := net.GetVpc()
- if err != nil {
- return nil, errors.Wrap(err, "attach2NamedNetworkDesc get vpc by network")
- }
- if vpc.Id == api.DEFAULT_VPC_ID && !utils.IsInStringArray(net.WireId, sriovWires) {
- return nil, fmt.Errorf("no available sriov nic for wire %s", net.WireId)
- }
- }
- gn, err := self.Attach2Network(ctx, userCred, Attach2NetworkArgs{
- Network: net,
- PendingUsage: pendingUsage,
- IpAddr: netConfig.Address,
- Ip6Addr: netConfig.Address6,
- RequireIPv6: netConfig.RequireIPv6,
- StrictIPv6: netConfig.StrictIPv6,
- NicDriver: netConfig.Driver,
- NumQueues: netConfig.NumQueues,
- BwLimit: netConfig.BwLimit,
- RxTrafficLimit: netConfig.RxTrafficLimit,
- TxTrafficLimit: netConfig.TxTrafficLimit,
- Virtual: netConfig.Vip,
- TryReserved: netConfig.Reserved,
- AllocDir: allocDir,
- RequireDesignatedIP: netConfig.RequireDesignatedIP,
- UseDesignatedIP: reuseAddr,
- NicConfs: nicConfs,
- IsDefault: netConfig.IsDefault,
- PortMappings: netConfig.PortMappings,
- BillingType: netConfig.BillingType,
- ChargeType: netConfig.ChargeType,
- })
- if err != nil {
- return nil, errors.Wrap(err, "Attach2Network fail")
- } else {
- return gn, nil
- }
- } else {
- return nil, fmt.Errorf("Network %s not available", netConfig.Network)
- }
- }
- func (self *SGuest) attach2RandomNetwork(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, netConfig *api.NetworkConfig, pendingUsage quotas.IQuota) ([]SGuestnetwork, error) {
- driver, err := self.GetDriver()
- if err != nil {
- return nil, err
- }
- return driver.Attach2RandomNetwork(self, ctx, userCred, host, netConfig, pendingUsage)
- }
- func (self *SGuest) CreateDisksOnHost(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- host *SHost,
- disks []*api.DiskConfig,
- pendingUsage quotas.IQuota,
- inheritBilling bool,
- isWithServerCreate bool,
- candidateDisks []*schedapi.CandidateDisk,
- backupCandidateDisks []*schedapi.CandidateDisk,
- autoAttach bool,
- ) error {
- for idx := 0; idx < len(disks); idx += 1 {
- if len(disks[idx].DiskId) > 0 && len(disks[idx].Storage) > 0 {
- continue
- }
- diskConfig, err := parseDiskInfo(ctx, userCred, disks[idx])
- if err != nil {
- return errors.Wrap(err, "parseDiskInfo")
- }
- var candidateDisk *schedapi.CandidateDisk
- var backupCandidateDisk *schedapi.CandidateDisk
- if len(candidateDisks) > idx {
- candidateDisk = candidateDisks[idx]
- }
- if len(backupCandidateDisks) != 0 && len(backupCandidateDisks) > idx {
- backupCandidateDisk = backupCandidateDisks[idx]
- }
- disk, err := self.createDiskOnHost(ctx, userCred, host, diskConfig, pendingUsage, inheritBilling, isWithServerCreate, candidateDisk, backupCandidateDisk, autoAttach)
- if err != nil {
- return err
- }
- diskConfig.DiskId = disk.Id
- disks[idx] = diskConfig
- if diskConfig.NVMEDevice != nil {
- err = self.attachNVMEDevice(ctx, userCred, host, pendingUsage, disk, diskConfig)
- if err != nil {
- return err
- }
- }
- }
- return nil
- }
- func (self *SGuest) attachNVMEDevice(
- ctx context.Context, userCred mcclient.TokenCredential,
- host *SHost, pendingUsage quotas.IQuota,
- disk *SDisk, diskConfig *api.DiskConfig,
- ) error {
- gd := self.GetGuestDisk(disk.Id)
- diskConfig.NVMEDevice.DiskIndex = &gd.Index
- err := self.createIsolatedDeviceOnHost(ctx, userCred, host, diskConfig.NVMEDevice, pendingUsage, nil, nil)
- if err != nil {
- return errors.Wrap(err, "self.createIsolatedDeviceOnHost")
- }
- dev, err := self.GetIsolatedDeviceByDiskIndex(gd.Index)
- if err != nil {
- return errors.Wrap(err, "self.GetIsolatedDeviceByDiskIndex")
- }
- diskConfig.SizeMb = dev.NvmeSizeMB
- _, err = db.Update(disk, func() error {
- disk.DiskSize = dev.NvmeSizeMB
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "update nvme disk size")
- }
- return nil
- }
- func (self *SGuest) CreateDiskOnStorage(ctx context.Context, userCred mcclient.TokenCredential, storage *SStorage,
- diskConfig *api.DiskConfig, pendingUsage quotas.IQuota, inheritBilling bool, isWithServerCreate bool) (*SDisk, error) {
- lockman.LockObject(ctx, storage)
- defer lockman.ReleaseObject(ctx, storage)
- lockman.LockClass(ctx, QuotaManager, self.ProjectId)
- defer lockman.ReleaseClass(ctx, QuotaManager, self.ProjectId)
- diskName := fmt.Sprintf("vdisk-%s-%d", pinyinutils.Text2Pinyin(self.Name), time.Now().UnixNano())
- billingType := billing_api.BILLING_TYPE_POSTPAID
- billingCycle := ""
- if inheritBilling {
- billingType = self.BillingType
- billingCycle = self.BillingCycle
- }
- autoDelete := false
- if storage.IsLocal() || billingType == billing_api.BILLING_TYPE_PREPAID || isWithServerCreate {
- autoDelete = true
- }
- if diskConfig.AutoDelete != nil {
- autoDelete = *diskConfig.AutoDelete
- }
- disk, err := storage.createDisk(ctx, diskName, diskConfig, userCred, self.GetOwnerId(), autoDelete, self.IsSystem,
- billingType, billingCycle, self.EncryptKeyId)
- if err != nil {
- return nil, err
- }
- if isWithServerCreate {
- meta, _ := self.GetAllUserMetadata()
- if len(meta) > 0 {
- disk.SetUserMetadataAll(ctx, meta, userCred)
- }
- }
- if pendingUsage != nil {
- cancelUsage := SQuota{}
- cancelUsage.Storage = disk.DiskSize
- keys, err := self.GetQuotaKeys()
- if err != nil {
- return nil, err
- }
- cancelUsage.SetKeys(keys)
- err = quotas.CancelPendingUsage(ctx, userCred, pendingUsage, &cancelUsage, true)
- if err != nil {
- return nil, err
- }
- }
- return disk, nil
- }
- func (self *SGuest) ChooseHostStorage(host *SHost, diskConfig *api.DiskConfig, candidate *schedapi.CandidateDisk) (*SStorage, error) {
- drv, err := self.GetDriver()
- if err != nil {
- return nil, err
- }
- if candidate == nil || len(candidate.StorageIds) == 0 {
- return drv.ChooseHostStorage(host, self, diskConfig, nil)
- }
- return drv.ChooseHostStorage(host, self, diskConfig, candidate.StorageIds)
- }
- func (self *SGuest) createDiskOnHost(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- host *SHost,
- diskConfig *api.DiskConfig,
- pendingUsage quotas.IQuota,
- inheritBilling bool,
- isWithServerCreate bool,
- candidate *schedapi.CandidateDisk,
- backupCandidate *schedapi.CandidateDisk,
- autoAttach bool,
- ) (*SDisk, error) {
- var (
- storage *SStorage
- err error
- )
- if len(diskConfig.Storage) > 0 {
- _storage, err := StorageManager.FetchByIdOrName(ctx, userCred, diskConfig.Storage)
- if err != nil {
- if err == sql.ErrNoRows {
- return nil, httperrors.NewResourceNotFoundError2("storage", diskConfig.Storage)
- }
- return nil, fmt.Errorf("get storage(%s) error: %v", diskConfig.Storage, err)
- }
- storage = _storage.(*SStorage)
- } else {
- storage, err = self.ChooseHostStorage(host, diskConfig, candidate)
- if err != nil {
- return nil, errors.Wrap(err, "ChooseHostStorage")
- }
- }
- if storage == nil {
- return nil, fmt.Errorf("No storage on %s to create disk for %s", host.GetName(), diskConfig.Backend)
- }
- log.Debugf("Choose storage %s:%s for disk %#v", storage.Name, storage.Id, diskConfig)
- disk, err := self.CreateDiskOnStorage(ctx, userCred, storage, diskConfig, pendingUsage, inheritBilling, isWithServerCreate)
- if err != nil {
- return nil, err
- }
- if diskConfig.ExistingPath != "" {
- disk.SetMetadata(ctx, api.DISK_META_EXISTING_PATH, diskConfig.ExistingPath, userCred)
- }
- if len(self.BackupHostId) > 0 {
- backupHost := HostManager.FetchHostById(self.BackupHostId)
- backupStorage, err := self.ChooseHostStorage(backupHost, diskConfig, backupCandidate)
- if err != nil {
- return nil, errors.Wrap(err, "ChooseHostStorage")
- }
- diff, err := db.Update(disk, func() error {
- disk.BackupStorageId = backupStorage.Id
- return nil
- })
- if err != nil {
- log.Errorf("Disk save backup storage error")
- return disk, err
- }
- db.OpsLog.LogEvent(disk, db.ACT_UPDATE, diff, userCred)
- }
- if autoAttach {
- err = self.attach2Disk(ctx, disk, userCred, diskConfig.Driver, diskConfig.Cache, diskConfig.Mountpoint, diskConfig.BootIndex)
- }
- err = self.InheritTo(ctx, userCred, disk)
- if err != nil {
- return nil, errors.Wrapf(err, "unable to inherit from guest %s to disk %s", self.GetId(), disk.GetId())
- }
- return disk, err
- }
- func (self *SGuest) CreateIsolatedDeviceOnHost(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, devs []*api.IsolatedDeviceConfig, pendingUsage quotas.IQuota) error {
- var numaNodes []int
- if self.IsSchedulerNumaAllocate() {
- numaNodes = make([]int, 0)
- cpuNumaPin := make([]schedapi.SCpuNumaPin, 0)
- self.CpuNumaPin.Unmarshal(&cpuNumaPin)
- for i := range cpuNumaPin {
- numaNodes = append(numaNodes, cpuNumaPin[i].NodeId)
- }
- }
- lockman.LockObject(ctx, host)
- defer lockman.ReleaseObject(ctx, host)
- usedDeviceMap := map[string]*SIsolatedDevice{}
- for _, devConfig := range devs {
- if devConfig.DevType == api.NIC_TYPE || devConfig.DevType == api.NVME_PT_TYPE {
- continue
- }
- err := self.createIsolatedDeviceOnHost(ctx, userCred, host, devConfig, pendingUsage, usedDeviceMap, numaNodes)
- if err != nil {
- return err
- }
- }
- return nil
- }
- func (self *SGuest) createIsolatedDeviceOnHost(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, devConfig *api.IsolatedDeviceConfig, pendingUsage quotas.IQuota, usedDevMap map[string]*SIsolatedDevice, preferNumaNodes []int) error {
- lockman.LockClass(ctx, QuotaManager, self.ProjectId)
- defer lockman.ReleaseClass(ctx, QuotaManager, self.ProjectId)
- err := IsolatedDeviceManager.attachHostDeviceToGuestByDesc(ctx, self, host, devConfig, userCred, usedDevMap, preferNumaNodes)
- if err != nil {
- return err
- }
- cancelUsage := SQuota{IsolatedDevice: 1}
- keys, err := self.GetQuotaKeys()
- if err != nil {
- return err
- }
- cancelUsage.SetKeys(keys)
- err = quotas.CancelPendingUsage(ctx, userCred, pendingUsage, &cancelUsage, true) // success
- return err
- }
- func (self *SGuest) JoinGroups(ctx context.Context, userCred mcclient.TokenCredential, groupIds []string) error {
- for _, id := range groupIds {
- _, err := GroupguestManager.Attach(ctx, id, self.Id)
- if err != nil {
- return err
- }
- }
- return nil
- }
- type SGuestDiskCategory struct {
- Root *SDisk
- Swap []*SDisk
- Data []*SDisk
- }
- func (self *SGuest) CategorizeDisks() SGuestDiskCategory {
- diskCat := SGuestDiskCategory{}
- guestdisks, err := self.GetGuestDisks()
- if err != nil {
- log.Errorf("no disk for this server!!!")
- return diskCat
- }
- for _, gd := range guestdisks {
- if diskCat.Root == nil {
- diskCat.Root = gd.GetDisk()
- } else {
- disk := gd.GetDisk()
- if disk.FsFormat == "swap" {
- diskCat.Swap = append(diskCat.Swap, disk)
- } else {
- diskCat.Data = append(diskCat.Data, disk)
- }
- }
- }
- return diskCat
- }
- type SGuestNicCategory struct {
- InternalNics []SGuestnetwork
- ExternalNics []SGuestnetwork
- }
- func (self *SGuest) CategorizeNics() SGuestNicCategory {
- netCat := SGuestNicCategory{}
- guestnics, err := self.GetNetworks("")
- if err != nil {
- log.Errorf("no nics for this server!!! %s", err)
- return netCat
- }
- for _, gn := range guestnics {
- if gn.IsExit(nil) {
- netCat.ExternalNics = append(netCat.ExternalNics, gn)
- } else {
- netCat.InternalNics = append(netCat.InternalNics, gn)
- }
- }
- return netCat
- }
- func (self *SGuest) LeaveAllGroups(ctx context.Context, userCred mcclient.TokenCredential) {
- groupGuests := make([]SGroupguest, 0)
- q := GroupguestManager.Query()
- err := q.Filter(sqlchemy.Equals(q.Field("guest_id"), self.Id)).All(&groupGuests)
- if err != nil {
- log.Errorf("query by guest_id %s: %v", self.Id, err)
- return
- }
- for _, gg := range groupGuests {
- gg.SetModelManager(GroupguestManager, &gg)
- gg.Delete(context.Background(), userCred)
- var group SGroup
- gq := GroupManager.Query()
- err := gq.Filter(sqlchemy.Equals(gq.Field("id"), gg.GroupId)).First(&group)
- if err != nil {
- log.Errorf("get by group id %s: %v", gg.GroupId, err)
- return
- }
- group.SetModelManager(GroupManager, &group)
- db.OpsLog.LogDetachEvent(ctx, self, &group, userCred, nil)
- }
- }
- func (self *SGuest) DetachAllNetworks(ctx context.Context, userCred mcclient.TokenCredential) error {
- // from clouds.models.portmaps import Portmaps
- // Portmaps.delete_guest_network_portmaps(self, user_cred)
- gns, err := self.GetNetworks("")
- if err != nil {
- return err
- }
- return GuestnetworkManager.DeleteGuestNics(ctx, userCred, gns, false)
- }
- func (self *SGuest) EjectIso(cdromOrdinal int64, userCred mcclient.TokenCredential) bool {
- cdrom := self.getCdrom(false, cdromOrdinal)
- if cdrom != nil && len(cdrom.ImageId) > 0 {
- imageId := cdrom.ImageId
- if cdrom.ejectIso() {
- db.OpsLog.LogEvent(self, db.ACT_ISO_DETACH, imageId, userCred)
- return true
- }
- }
- return false
- }
- func (self *SGuest) EjectAllIso(userCred mcclient.TokenCredential) bool {
- cdroms, _ := self.getCdroms()
- for _, cdrom := range cdroms {
- if len(cdrom.ImageId) > 0 {
- imageId := cdrom.ImageId
- if cdrom.ejectIso() {
- db.OpsLog.LogEvent(self, db.ACT_ISO_DETACH, imageId, userCred)
- } else {
- return false
- }
- }
- }
- return true
- }
- func (self *SGuest) EjectVfd(floppyOrdinal int64, userCred mcclient.TokenCredential) bool {
- floppy := self.getFloppy(false, floppyOrdinal)
- if floppy != nil && len(floppy.ImageId) > 0 {
- imageId := floppy.ImageId
- if floppy.ejectVfd() {
- db.OpsLog.LogEvent(self, db.ACT_VFD_DETACH, imageId, userCred)
- return true
- }
- }
- return false
- }
- func (self *SGuest) EjectAllVfd(userCred mcclient.TokenCredential) bool {
- floppys, _ := self.getFloppys()
- for _, floppy := range floppys {
- if len(floppy.ImageId) > 0 {
- imageId := floppy.ImageId
- if floppy.ejectVfd() {
- db.OpsLog.LogEvent(self, db.ACT_ISO_DETACH, imageId, userCred)
- } else {
- return false
- }
- }
- }
- return true
- }
- func (self *SGuest) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
- // self.SVirtualResourceBase.Delete(ctx, userCred)
- // override
- log.Infof("guest delete do nothing")
- return nil
- }
- func (self *SGuest) CleanTapRecords(ctx context.Context, userCred mcclient.TokenCredential) error {
- // delete tap devices
- if err := NetTapServiceManager.removeTapServicesByGuestId(ctx, userCred, self.Id); err != nil {
- return errors.Wrap(err, "NetTapServiceManager.getTapServicesByGuestId")
- }
- if err := NetTapFlowManager.removeTapFlowsByGuestId(ctx, userCred, self.Id); err != nil {
- return errors.Wrap(err, "NetTapFlowManager.getTapServicesByGuestId")
- }
- return nil
- }
- func (self *SGuest) GetLoadbalancerBackends() ([]SLoadbalancerBackend, error) {
- q := LoadbalancerBackendManager.Query().Equals("backend_id", self.Id)
- ret := []SLoadbalancerBackend{}
- return ret, db.FetchModelObjects(LoadbalancerBackendManager, q, &ret)
- }
- func (self *SGuest) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
- SnapshotPolicyResourceManager.RemoveByResource(self.Id, api.SNAPSHOT_POLICY_TYPE_SERVER)
- return self.purge(ctx, userCred)
- }
- func (self *SGuest) AllowDeleteItem(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) bool {
- overridePendingDelete := false
- purge := false
- if query != nil {
- overridePendingDelete = jsonutils.QueryBoolean(query, "override_pending_delete", false)
- purge = jsonutils.QueryBoolean(query, "purge", false)
- }
- if (overridePendingDelete || purge) && !db.IsAdminAllowDelete(ctx, userCred, self) {
- return false
- }
- return self.IsOwner(userCred) || db.IsAdminAllowDelete(ctx, userCred, self)
- }
- // 删除虚拟机
- func (self *SGuest) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query api.ServerDeleteInput, data jsonutils.JSONObject) error {
- return self.StartDeleteGuestTask(ctx, userCred, "", query)
- }
- func (self *SGuest) DeleteAllDisksInDB(ctx context.Context, userCred mcclient.TokenCredential) error {
- guestDisks, err := self.GetGuestDisks()
- if err != nil {
- return errors.Wrapf(err, "GetGuestDisks")
- }
- for _, guestdisk := range guestDisks {
- disk := guestdisk.GetDisk()
- err := guestdisk.Detach(ctx, userCred)
- if err != nil {
- return errors.Wrapf(err, "guestdisk.Detach guest_id: %s disk_id: %s", guestdisk.GuestId, guestdisk.DiskId)
- }
- if disk != nil {
- cnt, err := disk.GetGuestDiskCount()
- if err != nil {
- return errors.Wrap(err, "disk.GetGuestDiskCount")
- }
- if cnt == 0 {
- db.OpsLog.LogEvent(disk, db.ACT_DELETE, nil, userCred)
- db.OpsLog.LogEvent(disk, db.ACT_DELOCATE, nil, userCred)
- err = disk.RealDelete(ctx, userCred)
- if err != nil {
- return errors.Wrap(err, "disk.RealDelete")
- }
- }
- }
- }
- return nil
- }
- func (self *SGuest) DeleteAllInstanceSnapshotInDB(ctx context.Context, userCred mcclient.TokenCredential) error {
- isps, err := self.GetInstanceSnapshots()
- if err != nil {
- return errors.Wrap(err, "unable to GetInstanceSnapshots")
- }
- for i := range isps {
- err = isps[i].RealDelete(ctx, userCred)
- return errors.Wrapf(err, "unable to real delete instance snapshot %q for guest %q", isps[i].GetName(), self.GetId())
- }
- return nil
- }
- func (self *SGuest) isNeedDoResetPasswd() bool {
- guestdisks, _ := self.GetGuestDisks()
- if len(guestdisks) > 0 {
- disk := guestdisks[0].GetDisk()
- if len(disk.SnapshotId) > 0 {
- return false
- }
- }
- return true
- }
- func (self *SGuest) IsSchedulerNumaAllocate() bool {
- cpuNumaPinType := self.GetMetadata(context.Background(), api.VM_METADATA_CPU_NUMA_PIN_TYPE, nil)
- return cpuNumaPinType == api.VM_CPU_NUMA_PIN_SCHEDULER && self.CpuNumaPin != nil
- }
- func (self *SGuest) GetDeployConfigOnHost(ctx context.Context, userCred mcclient.TokenCredential, host *SHost, params *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
- config := jsonutils.NewDict()
- drv, err := self.GetDriver()
- if err != nil {
- return nil, err
- }
- desc, err := drv.GetJsonDescAtHost(ctx, userCred, self, host, params)
- if err != nil {
- return nil, errors.Wrapf(err, "GetJsonDescAtHost")
- }
- config.Add(desc, "desc")
- deploys, err := cmdline.FetchDeployConfigsByJSON(params)
- if err != nil {
- return nil, err
- }
- if len(deploys) > 0 {
- config.Add(jsonutils.Marshal(deploys), "deploys")
- }
- deployAction, _ := params.GetString("deploy_action")
- if len(deployAction) == 0 {
- deployAction = "deploy"
- }
- config.Add(jsonutils.NewBool(jsonutils.QueryBoolean(params, "enable_cloud_init", false)), "enable_cloud_init")
- if account, _ := params.GetString("login_account"); len(account) > 0 {
- config.Set("login_account", jsonutils.NewString(account))
- }
- resetPasswd := jsonutils.QueryBoolean(params, "reset_password", true)
- if deployAction == "create" && resetPasswd {
- resetPasswd = self.isNeedDoResetPasswd()
- }
- if resetPasswd {
- config.Add(jsonutils.JSONTrue, "reset_password")
- passwd, _ := params.GetString("password")
- if len(passwd) > 0 {
- config.Add(jsonutils.NewString(passwd), "password")
- }
- keypair := self.getKeypair()
- if keypair != nil {
- config.Add(jsonutils.NewString(keypair.PublicKey), "public_key")
- config.Add(jsonutils.NewString(keypair.Name), "keypair_name")
- }
- deletePubKey, _ := params.GetString("delete_public_key")
- if len(deletePubKey) > 0 {
- config.Add(jsonutils.NewString(deletePubKey), "delete_public_key")
- }
- } else {
- config.Add(jsonutils.JSONFalse, "reset_password")
- }
- // add default public keys
- _, adminPubKey, err := sshkeys.GetSshAdminKeypair(ctx)
- if err != nil {
- log.Errorf("fail to get ssh admin public key %s", err)
- }
- _, projPubKey, err := sshkeys.GetSshProjectKeypair(ctx, self.ProjectId)
- if err != nil {
- log.Errorf("fail to get ssh project public key %s", err)
- }
- config.Add(jsonutils.NewString(adminPubKey), "admin_public_key")
- config.Add(jsonutils.NewString(projPubKey), "project_public_key")
- config.Add(jsonutils.NewString(deployAction), "action")
- onFinish := "shutdown"
- if jsonutils.QueryBoolean(params, "auto_start", false) || jsonutils.QueryBoolean(params, "restart", false) {
- onFinish = "none"
- } else if utils.IsInStringArray(self.Status, []string{api.VM_ADMIN}) {
- onFinish = "none"
- }
- config.Add(jsonutils.NewString(onFinish), "on_finish")
- if jsonutils.QueryBoolean(params, "deploy_telegraf", false) {
- influxdbUrl := drv.FetchMonitorUrl(ctx, self)
- config.Add(jsonutils.JSONTrue, "deploy_telegraf")
- serverDetails, err := self.getDetails(ctx, userCred)
- if err != nil {
- return nil, errors.Wrap(err, "get details")
- }
- telegrafConf, err := devtool_utils.GenerateTelegrafConf(
- serverDetails, influxdbUrl, self.OsType, self.Hypervisor)
- if err != nil {
- return nil, errors.Wrap(err, "get telegraf conf")
- }
- config.Add(jsonutils.NewString(telegrafConf), "telegraf_conf")
- }
- return config, nil
- }
- func (self *SGuest) getDetails(ctx context.Context, userCred mcclient.TokenCredential) (*api.ServerDetails, error) {
- res := GuestManager.FetchCustomizeColumns(ctx, userCred, jsonutils.NewDict(), []interface{}{self}, nil, false)
- jsonDict := jsonutils.Marshal(res[0]).(*jsonutils.JSONDict)
- jsonDict.Update(jsonutils.Marshal(self).(*jsonutils.JSONDict))
- serverDetails := new(api.ServerDetails)
- err := jsonDict.Unmarshal(serverDetails)
- if err != nil {
- return nil, err
- }
- return serverDetails, nil
- }
- func (self *SGuest) isBootIndexDuplicated(bootIndex int8) (bool, error) {
- if bootIndex < 0 {
- return false, nil
- }
- cdroms, err := self.getCdroms()
- if err != nil {
- return true, err
- }
- for i := 0; i < len(cdroms); i++ {
- if cdroms[i].BootIndex == bootIndex {
- return true, nil
- }
- }
- gd, err := self.GetGuestDisks()
- if err != nil {
- return true, err
- }
- for i := 0; i < len(gd); i++ {
- if gd[i].BootIndex == bootIndex {
- return true, nil
- }
- }
- return false, nil
- }
- func (self *SGuest) getVga() string {
- if utils.IsInStringArray(self.Vga, []string{"cirrus", "vmware", "qxl", "virtio", "std"}) {
- return self.Vga
- }
- return "std"
- }
- func (self *SGuest) GetVdi() string {
- if utils.IsInStringArray(self.Vdi, []string{"vnc", "spice"}) {
- return self.Vdi
- }
- return "vnc"
- }
- func (self *SGuest) getMachine() string {
- if utils.IsInStringArray(self.Machine, []string{"pc", "q35"}) {
- return self.Machine
- }
- return "pc"
- }
- func (self *SGuest) getBios() string {
- if utils.IsInStringArray(self.Bios, []string{"BIOS", "UEFI"}) {
- return self.Bios
- }
- return "BIOS"
- }
- func (self *SGuest) getKvmOptions() string {
- return self.GetMetadata(context.Background(), "kvm", nil)
- }
- func (self *SGuest) getExtraOptions(ctx context.Context) jsonutils.JSONObject {
- return self.GetMetadataJson(ctx, "extra_options", nil)
- }
- func (self *SGuest) GetIsolatedDevices() ([]SIsolatedDevice, error) {
- q := IsolatedDeviceManager.Query().Equals("guest_id", self.Id)
- devs := []SIsolatedDevice{}
- err := db.FetchModelObjects(IsolatedDeviceManager, q, &devs)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return devs, nil
- }
- func (self *SGuest) GetIsolatedDeviceByNetworkIndex(index int) (*SIsolatedDevice, error) {
- dev := SIsolatedDevice{}
- q := IsolatedDeviceManager.Query().Equals("guest_id", self.Id).Equals("network_index", index)
- if cnt, err := q.CountWithError(); err != nil {
- return nil, err
- } else if cnt == 0 {
- return nil, nil
- }
- err := q.First(&dev)
- if err != nil {
- return nil, err
- }
- dev.SetModelManager(IsolatedDeviceManager, &dev)
- return &dev, nil
- }
- func (self *SGuest) GetIsolatedDeviceByDiskIndex(index int8) (*SIsolatedDevice, error) {
- dev := SIsolatedDevice{}
- q := IsolatedDeviceManager.Query().Equals("guest_id", self.Id).Equals("disk_index", index)
- if cnt, err := q.CountWithError(); err != nil {
- return nil, err
- } else if cnt == 0 {
- return nil, nil
- }
- err := q.First(&dev)
- if err != nil {
- return nil, err
- }
- dev.SetModelManager(IsolatedDeviceManager, &dev)
- return &dev, nil
- }
- func (self *SGuest) GetJsonDescAtHypervisor(ctx context.Context, host *SHost) *api.GuestJsonDesc {
- desc := &api.GuestJsonDesc{
- Name: self.Name,
- Hostname: self.Hostname,
- Description: self.Description,
- UUID: self.Id,
- Mem: self.VmemSize,
- Cpu: self.VcpuCount,
- CpuSockets: self.CpuSockets,
- Vga: self.getVga(),
- Vdi: self.GetVdi(),
- Machine: self.getMachine(),
- Bios: self.getBios(),
- BootOrder: self.BootOrder,
- SrcIpCheck: self.SrcIpCheck.Bool(),
- SrcMacCheck: self.SrcMacCheck.Bool(),
- HostId: host.Id,
- HostAccessIp: host.AccessIp,
- HostEIP: host.PublicIp,
- EncryptKeyId: self.EncryptKeyId,
- IsDaemon: self.IsDaemon.Bool(),
- LightMode: self.RescueMode,
- Hypervisor: self.GetHypervisor(),
- EnableEsxiSwap: options.Options.EnableEsxiSwap,
- }
- if len(self.BackupHostId) > 0 {
- if self.HostId == host.Id {
- isMaster := true
- desc.IsMaster = &isMaster
- } else if self.BackupHostId == host.Id {
- isSlave := true
- desc.IsSlave = &isSlave
- }
- }
- if self.HostId != host.Id {
- desc.IsVolatileHost = true
- }
- // isolated devices
- isolatedDevs, _ := self.GetIsolatedDevices()
- for _, dev := range isolatedDevs {
- desc.IsolatedDevices = append(desc.IsolatedDevices, dev.getDesc())
- }
- if self.IsSchedulerNumaAllocate() {
- cpuNumaPin := make([]api.SCpuNumaPin, 0)
- cpuNumaPinStr := self.GetMetadata(ctx, api.VM_METADATA_CPU_NUMA_PIN, nil)
- cpuNumaPinJson, err := jsonutils.ParseString(cpuNumaPinStr)
- if err != nil {
- log.Errorf("failed parse cpu numa pin %s: %s", cpuNumaPinStr, err)
- } else {
- cpuNumaPinJson.Unmarshal(&cpuNumaPin)
- desc.CpuNumaPin = cpuNumaPin
- }
- }
- // nics, domain
- desc.Domain = options.Options.DNSDomain
- nics, _ := self.GetNetworks("")
- changed, _ := self.fixDefaultGatewayByNics(ctx, auth.AdminCredential(), nics)
- if changed {
- nics, _ = self.GetNetworks("")
- }
- for _, nic := range nics {
- nicDesc := nic.getJsonDescAtHost(ctx, host)
- desc.Nics = append(desc.Nics, nicDesc)
- if len(nicDesc.Domain) > 0 {
- desc.Domain = nicDesc.Domain
- }
- secgroupDesc := nic.getSecgroupDesc()
- if secgroupDesc != nil {
- if desc.NicSecgroups == nil {
- desc.NicSecgroups = make([]*api.GuestnetworkSecgroupDesc, 0)
- }
- desc.NicSecgroups = append(desc.NicSecgroups, secgroupDesc)
- }
- }
- {
- var prevNicDesc *api.GuestnetworkJsonDesc
- if len(desc.Nics) > 0 {
- prevNicDesc = desc.Nics[len(desc.Nics)-1]
- }
- // append tap nic
- tapNicDesc := self.getTapNicJsonDesc(ctx, prevNicDesc)
- if tapNicDesc != nil {
- desc.Nics = append(desc.Nics, tapNicDesc)
- }
- }
- // disks
- disks, _ := self.GetGuestDisks()
- for _, disk := range disks {
- diskDesc := disk.GetJsonDescAtHost(ctx, host)
- desc.Disks = append(desc.Disks, diskDesc)
- }
- cdroms, _ := self.getCdroms()
- for _, cdrom := range cdroms {
- cdromDesc := cdrom.getJsonDesc()
- desc.Cdroms = append(desc.Cdroms, cdromDesc)
- }
- if len(desc.Cdroms) > 0 {
- desc.Cdrom = desc.Cdroms[0]
- }
- //floppy
- floppys, _ := self.getFloppys()
- for _, floppy := range floppys {
- floppyDesc := floppy.getJsonDesc()
- desc.Floppys = append(desc.Floppys, floppyDesc)
- }
- // tenant
- tc, _ := self.GetTenantCache(ctx)
- if tc != nil {
- desc.Tenant = tc.GetName()
- desc.DomainId = tc.DomainId
- desc.ProjectDomain = tc.Domain
- }
- desc.TenantId = self.ProjectId
- keypair := self.getKeypair()
- if keypair != nil {
- desc.Keypair = keypair.Name
- desc.Pubkey = keypair.PublicKey
- }
- desc.NetworkRoles = self.getNetworkRoles()
- desc.Secgroups, _ = self.getSecgroupJson()
- desc.SecurityRules = self.getSecurityGroupsRules()
- desc.AdminSecurityRules = self.getAdminSecurityRules()
- desc.ExtraOptions = self.getExtraOptions(ctx)
- desc.Kvm = self.getKvmOptions()
- zone, _ := self.getZone()
- if zone != nil {
- desc.ZoneId = zone.Id
- desc.Zone = zone.Name
- }
- desc.OsName = self.GetOS()
- desc.Metadata, _ = self.GetAllMetadata(ctx, nil)
- userData, _ := desc.Metadata["user_data"]
- if len(userData) > 0 {
- decodeData, _ := userdata.Decode(userData)
- if len(decodeData) > 0 {
- userData = decodeData
- }
- desc.UserData = userData
- }
- desc.PendingDeleted = self.PendingDeleted
- // add scaling group
- sggs, err := ScalingGroupGuestManager.Fetch("", self.Id)
- if err == nil && len(sggs) > 0 {
- desc.ScalingGroupId = sggs[0].ScalingGroupId
- }
- return desc
- }
- func (self *SGuest) GetJsonDescAtBaremetal(ctx context.Context, host *SHost) *api.GuestJsonDesc {
- desc := &api.GuestJsonDesc{
- Name: self.Name,
- Description: self.Description,
- UUID: self.Id,
- Mem: self.VmemSize,
- Cpu: self.VcpuCount,
- }
- desc.DiskConfig = host.getDiskConfig()
- self.fixDefaultGateway(ctx, auth.AdminCredential())
- netifs := host.GetAllNetInterfaces()
- desc.Domain = options.Options.DNSDomain
- for _, nic := range netifs {
- nicDesc := nic.getServerJsonDesc()
- if len(nicDesc.Ip) > 0 {
- desc.Nics = append(desc.Nics, nicDesc)
- if len(nicDesc.Domain) > 0 {
- desc.Domain = nicDesc.Domain
- }
- } else {
- desc.NicsStandby = append(desc.NicsStandby, nicDesc)
- }
- }
- disks, _ := self.GetGuestDisks()
- for _, disk := range disks {
- diskDesc := disk.GetJsonDescAtHost(ctx, host)
- desc.Disks = append(desc.Disks, diskDesc)
- }
- tc, _ := self.GetTenantCache(ctx)
- if tc != nil {
- desc.Tenant = tc.GetName()
- desc.DomainId = tc.DomainId
- desc.ProjectDomain = tc.Domain
- }
- desc.TenantId = self.ProjectId
- keypair := self.getKeypair()
- if keypair != nil {
- desc.Keypair = keypair.Name
- desc.Pubkey = keypair.PublicKey
- }
- desc.NetworkRoles = self.getNetworkRoles()
- desc.SecurityRules = self.getSecurityGroupsRules()
- desc.AdminSecurityRules = self.getAdminSecurityRules()
- zone, _ := self.getZone()
- if zone != nil {
- desc.ZoneId = zone.Id
- desc.Zone = zone.Name
- }
- desc.OsName = self.GetOS()
- desc.Metadata, _ = self.GetAllMetadata(ctx, nil)
- desc.UserData, _ = desc.Metadata["user_data"]
- desc.PendingDeleted = self.PendingDeleted
- return desc
- }
- func (self *SGuest) getNetworkRoles() []string {
- key := db.Metadata.GetSysadminKey("network_role")
- roleStr := self.GetMetadata(context.Background(), key, auth.AdminCredential())
- if len(roleStr) > 0 {
- return strings.Split(roleStr, ",")
- }
- return nil
- }
- func (manager *SGuestManager) FetchGuestById(guestId string) *SGuest {
- guest, err := manager.FetchById(guestId)
- if err != nil {
- log.Errorf("FetchById fail %s", err)
- return nil
- }
- return guest.(*SGuest)
- }
- func (manager *SGuestManager) GetSpecShouldCheckStatus(query *jsonutils.JSONDict) (bool, error) {
- return true, nil
- }
- func (self *SGuest) GetSpec(checkStatus bool) *jsonutils.JSONDict {
- if checkStatus {
- if utils.IsInStringArray(self.Status, []string{api.VM_SCHEDULE_FAILED}) {
- return nil
- }
- }
- spec := jsonutils.NewDict()
- spec.Set("cpu", jsonutils.NewInt(int64(self.VcpuCount)))
- spec.Set("mem", jsonutils.NewInt(int64(self.VmemSize)))
- // get disk spec
- guestdisks, _ := self.GetGuestDisks()
- diskSpecs := jsonutils.NewArray()
- for _, guestdisk := range guestdisks {
- info := guestdisk.ToDiskInfo()
- diskSpec := jsonutils.NewDict()
- diskSpec.Set("size", jsonutils.NewInt(info.Size))
- diskSpec.Set("backend", jsonutils.NewString(info.Backend))
- diskSpec.Set("medium_type", jsonutils.NewString(info.MediumType))
- diskSpec.Set("disk_type", jsonutils.NewString(info.DiskType))
- diskSpecs.Add(diskSpec)
- }
- spec.Set("disk", diskSpecs)
- // get nic spec
- guestnics, _ := self.GetNetworks("")
- nicSpecs := jsonutils.NewArray()
- for _, guestnic := range guestnics {
- nicSpec := jsonutils.NewDict()
- net, _ := guestnic.GetNetwork()
- nicSpec.Set("bandwidth", jsonutils.NewInt(int64(guestnic.getBandwidth(net, nil))))
- t := "int"
- if guestnic.IsExit(net) {
- t = "ext"
- }
- nicSpec.Set("type", jsonutils.NewString(t))
- nicSpecs.Add(nicSpec)
- }
- spec.Set("nic", nicSpecs)
- // get isolate device spec
- guestgpus, _ := self.GetIsolatedDevices()
- gpuSpecs := []GpuSpec{}
- for _, guestgpu := range guestgpus {
- if strings.HasPrefix(guestgpu.DevType, "GPU") {
- gs := guestgpu.GetGpuSpec()
- gpuSpecs = append(gpuSpecs, *gs)
- }
- }
- spec.Set("gpu", jsonutils.Marshal(gpuSpecs))
- return spec
- }
- func (manager *SGuestManager) GetSpecIdent(spec *jsonutils.JSONDict) []string {
- cpuCount, _ := spec.Int("cpu")
- memSize, _ := spec.Int("mem")
- memSizeMB, _ := utils.GetSizeMB(fmt.Sprintf("%d", memSize), "M")
- specKeys := []string{
- fmt.Sprintf("cpu:%d", cpuCount),
- fmt.Sprintf("mem:%dM", memSizeMB),
- }
- countKey := func(kf func(*jsonutils.JSONDict) string, dataArray jsonutils.JSONObject) map[string]int64 {
- countMap := make(map[string]int64)
- datas, _ := dataArray.GetArray()
- for _, data := range datas {
- key := kf(data.(*jsonutils.JSONDict))
- if count, ok := countMap[key]; !ok {
- countMap[key] = 1
- } else {
- count++
- countMap[key] = count
- }
- }
- return countMap
- }
- kfuncs := map[string]func(*jsonutils.JSONDict) string{
- "disk": func(data *jsonutils.JSONDict) string {
- backend, _ := data.GetString("backend")
- mediumType, _ := data.GetString("medium_type")
- size, _ := data.Int("size")
- sizeGB, _ := utils.GetSizeGB(fmt.Sprintf("%d", size), "M")
- return fmt.Sprintf("disk:%s_%s_%dG", backend, mediumType, sizeGB)
- },
- "nic": func(data *jsonutils.JSONDict) string {
- typ, _ := data.GetString("type")
- bw, _ := data.Int("bandwidth")
- return fmt.Sprintf("nic:%s_%dM", typ, bw)
- },
- "gpu": func(data *jsonutils.JSONDict) string {
- vendor, _ := data.GetString("vendor")
- model, _ := data.GetString("model")
- return fmt.Sprintf("gpu:%s_%s", vendor, model)
- },
- }
- for sKey, kf := range kfuncs {
- sArrary, err := spec.Get(sKey)
- if err != nil {
- log.Errorf("Get key %s array error: %v", sKey, err)
- continue
- }
- for key, count := range countKey(kf, sArrary) {
- specKeys = append(specKeys, fmt.Sprintf("%sx%d", key, count))
- }
- }
- return specKeys
- }
- func (self *SGuest) GetGpuSpec() *GpuSpec {
- if len(self.InstanceType) == 0 {
- return nil
- }
- host, err := self.GetHost()
- if err != nil {
- return nil
- }
- zone, err := host.GetZone()
- if err != nil {
- return nil
- }
- q := ServerSkuManager.Query().Equals("name", self.InstanceType).Equals("cloudregion_id", zone.CloudregionId).IsNotEmpty("gpu_spec")
- sku := &SServerSku{}
- err = q.First(sku)
- if err != nil {
- return nil
- }
- return &GpuSpec{
- Model: sku.GpuSpec,
- Amount: sku.GpuCount,
- }
- }
- func (self *SGuest) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
- desc := self.SVirtualResourceBase.GetShortDesc(ctx)
- desc.Set("mem", jsonutils.NewInt(int64(self.VmemSize)))
- desc.Set("cpu", jsonutils.NewInt(int64(self.VcpuCount)))
- desc.Set("status", jsonutils.NewString(self.Status))
- desc.Set("shutdown_mode", jsonutils.NewString(self.ShutdownMode))
- if len(self.InstanceType) > 0 {
- desc.Set("instance_type", jsonutils.NewString(self.InstanceType))
- }
- if gp := self.GetGpuSpec(); gp != nil {
- desc.Set("gpu_model", jsonutils.NewString(gp.Model))
- desc.Set("gpu_count", jsonutils.NewString(gp.Amount))
- }
- address := jsonutils.NewString(strings.Join(self.GetRealIPs(), ","))
- desc.Set("ip_addr", address)
- if len(self.OsType) > 0 {
- desc.Add(jsonutils.NewString(self.OsType), "os_type")
- }
- if osDist := self.GetMetadata(ctx, "os_distribution", nil); len(osDist) > 0 {
- desc.Add(jsonutils.NewString(osDist), "os_distribution")
- }
- if osVer := self.GetMetadata(ctx, "os_version", nil); len(osVer) > 0 {
- desc.Add(jsonutils.NewString(osVer), "os_version")
- }
- templateId := self.GetTemplateId()
- if len(templateId) > 0 {
- desc.Set("template_id", jsonutils.NewString(templateId))
- }
- extBw := self.getBandwidth(true)
- intBw := self.getBandwidth(false)
- if extBw > 0 {
- desc.Set("ext_bandwidth", jsonutils.NewInt(int64(extBw)))
- }
- if intBw > 0 {
- desc.Set("int_bandwidth", jsonutils.NewInt(int64(intBw)))
- }
- if len(self.OsType) > 0 {
- desc.Add(jsonutils.NewString(self.OsType), "os_type")
- }
- if len(self.ExternalId) > 0 {
- desc.Add(jsonutils.NewString(self.ExternalId), "externalId")
- }
- desc.Set("hypervisor", jsonutils.NewString(self.GetHypervisor()))
- host, _ := self.GetHost()
- spec := self.GetSpec(false)
- if self.GetHypervisor() == api.HYPERVISOR_BAREMETAL {
- if host != nil {
- hostSpec := host.GetSpec(false)
- hostSpecIdent := HostManager.GetSpecIdent(hostSpec)
- spec.Set("host_spec", jsonutils.NewString(strings.Join(hostSpecIdent, "/")))
- }
- }
- if spec != nil {
- desc.Update(spec)
- }
- var billingInfo SCloudBillingInfo
- if host != nil {
- desc.Set("host", jsonutils.NewString(host.Name))
- desc.Set("host_id", jsonutils.NewString(host.Id))
- billingInfo.SCloudProviderInfo = host.getCloudProviderInfo()
- }
- if len(self.BackupHostId) > 0 {
- backupHost := HostManager.FetchHostById(self.BackupHostId)
- if backupHost != nil {
- desc.Set("backup_host", jsonutils.NewString(backupHost.Name))
- desc.Set("backup_host_id", jsonutils.NewString(backupHost.Id))
- }
- }
- if priceKey := self.GetMetadata(ctx, "ext:price_key", nil); len(priceKey) > 0 {
- billingInfo.PriceKey = priceKey
- }
- billingInfo.SBillingBaseInfo = self.getBillingBaseInfo()
- desc.Update(jsonutils.Marshal(billingInfo))
- return desc
- }
- func (self *SGuest) saveOsType(userCred mcclient.TokenCredential, osType string) error {
- diff, err := db.Update(self, func() error {
- self.OsType = osType
- return nil
- })
- if err != nil {
- return err
- }
- db.OpsLog.LogEvent(self, db.ACT_UPDATE, diff, userCred)
- return err
- }
- type sDeployInfo struct {
- Os string
- Account string
- Key string
- Distro string
- Version string
- Arch string
- Language string
- TelegrafDeployed bool
- CurrentVersion string
- }
- func (self *SGuest) SaveDeployInfo(ctx context.Context, userCred mcclient.TokenCredential, data jsonutils.JSONObject) {
- deployInfo := sDeployInfo{}
- data.Unmarshal(&deployInfo)
- info := make(map[string]interface{})
- if len(deployInfo.Os) > 0 {
- self.saveOsType(userCred, deployInfo.Os)
- info["os_name"] = deployInfo.Os
- }
- driver, _ := self.GetDriver()
- if len(deployInfo.Account) > 0 {
- info["login_account"] = deployInfo.Account
- if len(deployInfo.Key) > 0 {
- info["login_key"] = deployInfo.Key
- if len(self.KeypairId) > 0 && (driver != nil && !driver.IsSupportdDcryptPasswordFromSecretKey()) { // Tencent Cloud does not support simultaneous setting of secret keys and passwords
- info["login_key"], _ = seclib2.EncryptBase64(self.GetKeypairPublicKey(), "")
- }
- info["login_key_timestamp"] = timeutils.UtcNow()
- } else {
- info["login_key"] = "none"
- info["login_key_timestamp"] = "none"
- }
- }
- if len(deployInfo.Distro) > 0 {
- info["os_distribution"] = deployInfo.Distro
- }
- if len(deployInfo.Version) > 0 {
- info["os_version"] = deployInfo.Version
- }
- if len(deployInfo.Arch) > 0 {
- info["os_arch"] = deployInfo.Arch
- }
- if len(deployInfo.Language) > 0 {
- info["os_language"] = deployInfo.Language
- }
- if deployInfo.TelegrafDeployed {
- info["telegraf_deployed"] = true
- }
- if len(deployInfo.CurrentVersion) > 0 {
- info["current_version"] = deployInfo.CurrentVersion
- }
- self.SetAllMetadata(ctx, info, userCred)
- self.saveOldPassword(ctx, userCred)
- }
- func (self *SGuest) isAllDisksReady() bool {
- ready := true
- disks, _ := self.GetGuestDisks()
- if disks == nil || len(disks) == 0 {
- return true
- }
- for i := 0; i < len(disks); i += 1 {
- disk := disks[i].GetDisk()
- if !(disk.isReady() || disk.Status == api.DISK_START_MIGRATE) {
- ready = false
- break
- }
- }
- return ready
- }
- func (self *SGuest) GetKeypairPublicKey() string {
- keypair := self.getKeypair()
- if keypair != nil {
- return keypair.PublicKey
- }
- return ""
- }
- func (self *SGuest) GetKeypair() *SKeypair {
- return self.getKeypair()
- }
- func (manager *SGuestManager) GetIpsInProjectWithName(projectId, name string, isExitOnly bool, addrType api.TAddressType) []string {
- name = strings.TrimSuffix(name, ".")
- ipField := "ip_addr"
- gwField := "guest_gateway"
- if addrType == api.AddressTypeIPv6 {
- ipField = "ip6_addr"
- gwField = "guest_gateway6"
- }
- guestnics := GuestnetworkManager.Query().IsNotEmpty(ipField).SubQuery()
- guestsQ := manager.Query().IsFalse("pending_deleted").Equals("hostname", name)
- if len(projectId) > 0 {
- guestsQ = guestsQ.Equals("tenant_id", projectId)
- }
- guests := guestsQ.SubQuery()
- networks := NetworkManager.Query().IsNotNull(gwField).SubQuery()
- q := guestnics.Query(guestnics.Field(ipField))
- q = q.Join(guests, sqlchemy.Equals(guests.Field("id"), guestnics.Field("guest_id")))
- q = q.Join(networks, sqlchemy.Equals(networks.Field("id"), guestnics.Field("network_id")))
- ips := make([]string, 0)
- rows, err := q.Rows()
- if err != nil {
- log.Errorf("Get guest ip with name query err: %v", err)
- return ips
- }
- defer rows.Close()
- for rows.Next() {
- var ip string
- err = rows.Scan(&ip)
- if err != nil {
- log.Errorf("Get guest ip with name scan err: %v", err)
- return ips
- }
- ips = append(ips, ip)
- }
- if addrType == api.AddressTypeIPv6 {
- return ips
- }
- return manager.getIpsByExit(ips, isExitOnly)
- }
- func (manager *SGuestManager) getIpsByExit(ips []string, isExitOnly bool) []string {
- intRet := make([]string, 0)
- extRet := make([]string, 0)
- for _, ip := range ips {
- addr, _ := netutils.NewIPV4Addr(ip)
- if netutils.IsExitAddress(addr) {
- extRet = append(extRet, ip)
- continue
- }
- intRet = append(intRet, ip)
- }
- if isExitOnly {
- return extRet
- } else if len(intRet) > 0 {
- return intRet
- }
- return extRet
- }
- func (manager *SGuestManager) getExpiredPendingDeleteGuests() []SGuest {
- deadline := time.Now().Add(time.Duration(options.Options.PendingDeleteExpireSeconds*-1) * time.Second)
- q := manager.Query()
- q = q.IsTrue("pending_deleted").LT("pending_deleted_at", deadline).Limit(options.Options.PendingDeleteMaxCleanBatchSize)
- guests := make([]SGuest, 0)
- err := db.FetchModelObjects(GuestManager, q, &guests)
- if err != nil {
- log.Errorf("fetch guests error %s", err)
- return nil
- }
- return guests
- }
- func (manager *SGuestManager) CleanPendingDeleteServers(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
- guests := manager.getExpiredPendingDeleteGuests()
- if guests == nil {
- return
- }
- for i := 0; i < len(guests); i += 1 {
- opts := api.ServerDeleteInput{
- OverridePendingDelete: true,
- DeleteSnapshots: options.Options.DeleteSnapshotExpiredRelease,
- DeleteEip: options.Options.DeleteEipExpiredRelease,
- DeleteDisks: options.Options.DeleteDisksExpiredRelease,
- }
- // 跳过单独在云上开机过的虚拟机,避免误清理
- if len(guests[i].GetExternalId()) > 0 {
- iVm, err := guests[i].GetIVM(ctx)
- if err == nil && iVm.GetStatus() == api.VM_RUNNING {
- if guests[i].Status != api.VM_DELETE_FAIL {
- guests[i].SetStatus(ctx, userCred, api.VM_DELETE_FAIL, "vm status is running")
- }
- continue
- }
- }
- guests[i].StartDeleteGuestTask(ctx, userCred, "", opts)
- }
- }
- func (manager *SGuestManager) getExpiredPrepaidGuests() []SGuest {
- deadline := time.Now().Add(time.Duration(options.Options.PrepaidExpireCheckSeconds*-1) * time.Second)
- q := manager.Query()
- q = q.Equals("billing_type", billing_api.BILLING_TYPE_PREPAID).LT("expired_at", deadline).
- IsFalse("pending_deleted").Limit(options.Options.ExpiredPrepaidMaxCleanBatchSize)
- guests := make([]SGuest, 0)
- err := db.FetchModelObjects(GuestManager, q, &guests)
- if err != nil {
- log.Errorf("fetch guests error %s", err)
- return nil
- }
- return guests
- }
- func (manager *SGuestManager) getNeedRenewPrepaidGuests() ([]SGuest, error) {
- deadline := time.Now().Add(time.Duration(options.Options.PrepaidAutoRenewHours)*time.Hour + 20*time.Minute)
- q := manager.Query()
- q = q.Equals("billing_type", billing_api.BILLING_TYPE_PREPAID).LT("expired_at", deadline).
- IsFalse("pending_deleted").In("hypervisor", GetNotSupportAutoRenewHypervisors()).IsTrue("auto_renew")
- guests := make([]SGuest, 0)
- err := db.FetchModelObjects(GuestManager, q, &guests)
- if err != nil {
- return nil, errors.Wrap(err, "db.FetchModelObjects")
- }
- return guests, nil
- }
- func (manager *SGuestManager) getExpiredPostpaidGuests() []SGuest {
- q := ListExpiredPostpaidResources(manager.Query(), options.Options.ExpiredPrepaidMaxCleanBatchSize)
- q = q.IsFalse("pending_deleted")
- guests := make([]SGuest, 0)
- err := db.FetchModelObjects(GuestManager, q, &guests)
- if err != nil {
- log.Errorf("fetch guests error %s", err)
- return nil
- }
- return guests
- }
- func (self *SGuest) doExternalSync(ctx context.Context, userCred mcclient.TokenCredential) error {
- host, _ := self.GetHost()
- if host == nil {
- return fmt.Errorf("no host???")
- }
- ihost, iprovider, err := host.GetIHostAndProvider(ctx)
- if err != nil {
- return err
- }
- iVM, err := ihost.GetIVMById(self.ExternalId)
- if err != nil {
- return err
- }
- return self.syncWithCloudVM(ctx, userCred, iprovider, host, iVM, nil, true)
- }
- func (manager *SGuestManager) DeleteExpiredPrepaidServers(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
- guests := manager.getExpiredPrepaidGuests()
- if guests == nil {
- return
- }
- for i := 0; i < len(guests); i += 1 {
- // fake delete expired prepaid servers
- if len(guests[i].ExternalId) > 0 {
- err := guests[i].doExternalSync(ctx, userCred)
- if err == nil && guests[i].IsValidPrePaid() {
- continue
- }
- }
- guests[i].SetDisableDelete(userCred, false)
- opts := api.ServerDeleteInput{
- DeleteSnapshots: options.Options.DeleteSnapshotExpiredRelease,
- DeleteEip: options.Options.DeleteEipExpiredRelease,
- DeleteDisks: options.Options.DeleteDisksExpiredRelease,
- }
- guests[i].StartDeleteGuestTask(ctx, userCred, "", opts)
- }
- }
- func (manager *SGuestManager) AutoRenewPrepaidServer(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
- guests, err := manager.getNeedRenewPrepaidGuests()
- if err != nil {
- log.Errorf("failed to get need renew prepaid guests error: %v", err)
- return
- }
- for i := 0; i < len(guests); i += 1 {
- drv, err := guests[i].GetDriver()
- if err != nil {
- continue
- }
- if len(guests[i].ExternalId) > 0 && !drv.IsSupportSetAutoRenew() {
- err := guests[i].doExternalSync(ctx, userCred)
- if err == nil && guests[i].IsValidPrePaid() {
- continue
- }
- }
- guests[i].startGuestRenewTask(ctx, userCred, guests[i].BillingCycle, "")
- }
- }
- func (manager *SGuestManager) DeleteExpiredPostpaidServers(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
- guests := manager.getExpiredPostpaidGuests()
- if len(guests) == 0 {
- log.Infof("No expired postpaid guest")
- return
- }
- for i := 0; i < len(guests); i++ {
- if len(guests[i].ExternalId) > 0 {
- err := guests[i].doExternalSync(ctx, userCred)
- if err == nil && guests[i].IsValidPostPaid() {
- continue
- }
- }
- guests[i].SetDisableDelete(userCred, false)
- opts := api.ServerDeleteInput{
- DeleteSnapshots: options.Options.DeleteSnapshotExpiredRelease,
- DeleteEip: options.Options.DeleteEipExpiredRelease,
- DeleteDisks: options.Options.DeleteDisksExpiredRelease,
- }
- guests[i].StartDeleteGuestTask(ctx, userCred, "", opts)
- }
- }
- func (self *SGuest) IsEipAssociable() error {
- if !utils.IsInStringArray(self.Status, []string{api.VM_READY, api.VM_RUNNING}) {
- return errors.Wrapf(httperrors.ErrInvalidStatus, "cannot associate eip in status %s", self.Status)
- }
- err := ValidateAssociateEip(self)
- if err != nil {
- return errors.Wrap(err, "ValidateAssociateEip")
- }
- var eip *SElasticip
- switch self.Hypervisor {
- case api.HYPERVISOR_AWS:
- eip, err = self.GetElasticIp()
- default:
- eip, err = self.GetEipOrPublicIp()
- }
- if err != nil {
- log.Errorf("Fail to get Eip %s", err)
- return errors.Wrap(err, "IsEipAssociable")
- }
- if eip != nil {
- return httperrors.NewInvalidStatusError("already associate with eip")
- }
- return nil
- }
- func (self *SGuest) GetEipOrPublicIp() (*SElasticip, error) {
- return ElasticipManager.getEip(api.EIP_ASSOCIATE_TYPE_SERVER, self.Id, "")
- }
- func (self *SGuest) GetElasticIp() (*SElasticip, error) {
- return ElasticipManager.getEip(api.EIP_ASSOCIATE_TYPE_SERVER, self.Id, api.EIP_MODE_STANDALONE_EIP)
- }
- func (self *SGuest) GetPublicIp() (*SElasticip, error) {
- return ElasticipManager.getEip(api.EIP_ASSOCIATE_TYPE_SERVER, self.Id, api.EIP_MODE_INSTANCE_PUBLICIP)
- }
- func (self *SGuest) SyncVMEip(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extEip cloudprovider.ICloudEIP, syncOwnerId mcclient.IIdentityProvider) compare.SyncResult {
- result := compare.SyncResult{}
- eip, err := self.GetEipOrPublicIp()
- if err != nil {
- result.Error(fmt.Errorf("GetEipOrPublicIp error %s", err))
- return result
- }
- region, err := self.getRegion()
- if err != nil {
- result.Error(fmt.Errorf("getRegion error %s", err))
- return result
- }
- if eip == nil && extEip == nil {
- // do nothing
- return result
- }
- if eip == nil && extEip != nil {
- // add
- neip, err := ElasticipManager.getEipByExtEip(ctx, userCred, extEip, provider, region, syncOwnerId)
- if err != nil {
- result.AddError(errors.Wrapf(err, "getEipByExtEip"))
- return result
- }
- err = neip.AssociateInstance(ctx, userCred, api.EIP_ASSOCIATE_TYPE_SERVER, self)
- if err != nil {
- result.AddError(errors.Wrapf(err, "neip.AssociateInstance"))
- return result
- }
- result.Add()
- return result
- }
- if eip != nil && extEip == nil {
- // remove
- err = eip.Dissociate(ctx, userCred)
- if err != nil {
- result.DeleteError(err)
- return result
- }
- result.Delete()
- return result
- }
- // sync
- if eip.IpAddr != extEip.GetIpAddr() {
- // remove then add
- err = eip.Dissociate(ctx, userCred)
- if err != nil {
- // fail to remove
- result.DeleteError(err)
- return result
- }
- result.Delete()
- neip, err := ElasticipManager.getEipByExtEip(ctx, userCred, extEip, provider, region, syncOwnerId)
- if err != nil {
- result.AddError(err)
- return result
- }
- err = neip.AssociateInstance(ctx, userCred, api.EIP_ASSOCIATE_TYPE_SERVER, self)
- if err != nil {
- result.AddError(err)
- } else {
- result.Add()
- }
- return result
- }
- // do nothing
- err = eip.SyncWithCloudEip(ctx, userCred, provider, extEip, syncOwnerId)
- if err != nil {
- result.UpdateError(err)
- } else {
- result.Update()
- }
- return result
- }
- func (self *SGuest) getSecgroupsBySecgroupExternalIds(externalIds []string) ([]SSecurityGroup, error) {
- vpc, err := self.GetVpc()
- if err != nil {
- return nil, errors.Wrapf(err, "GetVpc")
- }
- region, err := vpc.GetRegion()
- if err != nil {
- return nil, errors.Wrapf(err, "GetRegion")
- }
- filter, err := region.GetDriver().GetSecurityGroupFilter(vpc)
- if err != nil {
- return nil, errors.Wrapf(err, "GetSecurityGroupFilter")
- }
- q := SecurityGroupManager.Query().In("external_id", externalIds)
- q = filter(q)
- secgroups := []SSecurityGroup{}
- err = db.FetchModelObjects(SecurityGroupManager, q, &secgroups)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return secgroups, nil
- }
- func (self *SGuest) SyncVMSecgroups(ctx context.Context, userCred mcclient.TokenCredential, externalIds []string) error {
- // clear secgroup if vm not support security group
- drv, err := self.GetDriver()
- if err != nil {
- return err
- }
- if drv.GetMaxSecurityGroupCount() == 0 || len(externalIds) == 0 {
- _, err := db.Update(self, func() error {
- self.SecgrpId = ""
- self.AdminSecgrpId = ""
- return nil
- })
- return err
- }
- secgroups, err := self.getSecgroupsBySecgroupExternalIds(externalIds)
- if err != nil {
- return errors.Wrap(err, "getSecgroupsBySecgroupExternalIds")
- }
- secgroupIds := []string{}
- for _, secgroup := range secgroups {
- secgroupIds = append(secgroupIds, secgroup.Id)
- }
- return self.SaveSecgroups(ctx, userCred, secgroupIds)
- }
- func (self *SGuest) GetIVM(ctx context.Context) (cloudprovider.ICloudVM, error) {
- if len(self.ExternalId) == 0 {
- return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty externalId")
- }
- host, err := self.GetHost()
- if err != nil {
- return nil, errors.Wrapf(err, "GetHost")
- }
- iregion, err := host.GetIRegion(ctx)
- if err != nil {
- return nil, errors.Wrapf(err, "GetIRegion")
- }
- ihost, err := iregion.GetIHostById(host.ExternalId)
- if err != nil {
- return nil, errors.Wrapf(err, "GetIHost")
- }
- ivm, err := ihost.GetIVMById(self.ExternalId)
- if err != nil {
- if errors.Cause(err) != cloudprovider.ErrNotFound {
- return nil, errors.Wrapf(err, "GetIVMById(%s)", self.ExternalId)
- }
- return iregion.GetIVMById(self.ExternalId)
- }
- return ivm, nil
- }
- func (self *SGuest) PendingDetachScalingGroup() error {
- sggs, err := ScalingGroupGuestManager.Fetch("", self.GetId())
- if err != nil {
- return err
- }
- for i := range sggs {
- sggs[i].SetGuestStatus(api.SG_GUEST_STATUS_PENDING_REMOVE)
- }
- return nil
- }
- func (self *SGuest) DeleteEip(ctx context.Context, userCred mcclient.TokenCredential) error {
- eip, err := self.GetEipOrPublicIp()
- if err != nil {
- log.Errorf("Delete eip fail for get Eip %s", err)
- return err
- }
- if eip == nil {
- return nil
- }
- if eip.Mode == api.EIP_MODE_INSTANCE_PUBLICIP {
- err = eip.RealDelete(ctx, userCred)
- if err != nil {
- log.Errorf("Delete eip on delete server fail %s", err)
- return err
- }
- } else {
- err = eip.Dissociate(ctx, userCred)
- if err != nil {
- log.Errorf("Dissociate eip on delete server fail %s", err)
- return err
- }
- }
- return nil
- }
- func (self *SGuest) SetDisableDelete(userCred mcclient.TokenCredential, val bool) error {
- diff, err := db.Update(self, func() error {
- if val {
- self.DisableDelete = tristate.True
- } else {
- self.DisableDelete = tristate.False
- }
- return nil
- })
- if err != nil {
- return err
- }
- db.OpsLog.LogEvent(self, db.ACT_UPDATE, diff, userCred)
- logclient.AddSimpleActionLog(self, logclient.ACT_UPDATE, diff, userCred, true)
- return err
- }
- func (self *SGuest) getDefaultStorageType() string {
- diskCat := self.CategorizeDisks()
- if diskCat.Root != nil {
- rootStorage, _ := diskCat.Root.GetStorage()
- if rootStorage != nil {
- return rootStorage.StorageType
- }
- }
- return api.STORAGE_LOCAL
- }
- func (self *SGuest) GetApptags() []string {
- tagsStr := self.GetMetadata(context.Background(), api.VM_METADATA_APP_TAGS, nil)
- if len(tagsStr) > 0 {
- return strings.Split(tagsStr, ",")
- }
- return nil
- }
- func (self *SGuest) ToSchedDesc() *schedapi.ScheduleInput {
- desc := new(schedapi.ScheduleInput)
- config := &schedapi.ServerConfig{
- Name: self.Name,
- Memory: self.VmemSize,
- Ncpu: int(self.VcpuCount),
- ServerConfigs: new(api.ServerConfigs),
- }
- desc.Id = self.Id
- self.FillGroupSchedDesc(config.ServerConfigs)
- self.FillDiskSchedDesc(config.ServerConfigs)
- self.FillNetSchedDesc(config.ServerConfigs)
- if len(self.HostId) > 0 && regutils.MatchUUID(self.HostId) {
- desc.HostId = self.HostId
- }
- config.Project = self.ProjectId
- config.Domain = self.DomainId
- /*tags := self.GetApptags()
- for i := 0; i < len(tags); i++ {
- desc.Set(tags[i], jsonutils.JSONTrue)
- }*/
- config.Hypervisor = self.GetHypervisor()
- desc.ServerConfig = *config
- desc.OsArch = self.OsArch
- desc.ExtraCpuCount = self.ExtraCpuCount
- return desc
- }
- func (self *SGuest) FillGroupSchedDesc(desc *api.ServerConfigs) {
- groups := make([]SGroupguest, 0)
- err := GroupguestManager.Query().Equals("guest_id", self.Id).All(&groups)
- if err != nil {
- log.Errorln(err)
- return
- }
- groupids := make([]string, len(groups))
- for i := range groups {
- groupids[i] = groups[i].GroupId
- }
- desc.InstanceGroupIds = groupids
- }
- func (self *SGuest) FillDiskSchedDesc(desc *api.ServerConfigs) {
- guestDisks := make([]SGuestdisk, 0)
- err := GuestdiskManager.Query().Equals("guest_id", self.Id).All(&guestDisks)
- if err != nil {
- log.Errorf("FillDiskSchedDesc: %v", err)
- return
- }
- for i := 0; i < len(guestDisks); i++ {
- diskConf := guestDisks[i].ToDiskConfig()
- // HACK: storage used by self, so earse it
- if !utils.IsInStringArray(diskConf.Backend, api.SHARED_STORAGE) {
- diskConf.Storage = ""
- }
- desc.Disks = append(desc.Disks, diskConf)
- }
- }
- func (self *SGuest) FillNetSchedDesc(desc *api.ServerConfigs) {
- guestNetworks := make([]SGuestnetwork, 0)
- err := GuestnetworkManager.Query().Equals("guest_id", self.Id).All(&guestNetworks)
- if err != nil {
- log.Errorf("FillNetSchedDesc: %v", err)
- return
- }
- if desc.Networks == nil {
- desc.Networks = make([]*api.NetworkConfig, 0)
- }
- for i := 0; i < len(guestNetworks); i++ {
- desc.Networks = append(desc.Networks, guestNetworks[i].ToNetworkConfig())
- }
- }
- func (self *SGuest) GuestDisksHasSnapshot() (bool, error) {
- guestDisks, err := self.GetGuestDisks()
- if err != nil {
- return false, errors.Wrapf(err, "GetGuestDisks")
- }
- for i := 0; i < len(guestDisks); i++ {
- cnt, err := SnapshotManager.GetDiskSnapshotCount(guestDisks[i].DiskId)
- if err != nil {
- return false, err
- }
- if cnt > 0 {
- return true, nil
- }
- }
- return false, nil
- }
- func (self *SGuest) OnScheduleToHost(ctx context.Context, userCred mcclient.TokenCredential, hostId string) error {
- err := self.SetHostId(userCred, hostId)
- if err != nil {
- return err
- }
- notes := jsonutils.NewDict()
- notes.Add(jsonutils.NewString(hostId), "host_id")
- db.OpsLog.LogEvent(self, db.ACT_SCHEDULE, notes, userCred)
- host, _ := self.GetHost()
- return host.ClearSchedDescCache()
- }
- func (guest *SGuest) GetDetailsTasks(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- since := time.Time{}
- if query.Contains("since") {
- since, _ = query.GetTime("since")
- }
- var isOpen *bool = nil
- if query.Contains("is_open") {
- isOpenVal, _ := query.Bool("is_open")
- isOpen = &isOpenVal
- }
- q := taskman.TaskManager.QueryTasksOfObject(guest, since, isOpen)
- objs, err := db.Query2List(taskman.TaskManager, ctx, userCred, q, query, false)
- if err != nil {
- return nil, err
- }
- ret := jsonutils.NewDict()
- ret.Add(jsonutils.NewArray(objs...), "tasks")
- return ret, nil
- }
- func (guest *SGuest) GetDynamicConditionInput() *jsonutils.JSONDict {
- return guest.ToSchedDesc().ToConditionInput()
- }
- func (self *SGuest) ToCreateInput(ctx context.Context, userCred mcclient.TokenCredential) *api.ServerCreateInput {
- genInput := self.toCreateInput()
- userInput, err := self.GetCreateParams(ctx, userCred)
- if err != nil {
- return genInput
- }
- if self.GetHypervisor() != api.HYPERVISOR_BAREMETAL {
- // fill missing create params like schedtags
- disks := []*api.DiskConfig{}
- for idx, disk := range genInput.Disks {
- tmpD := disk
- if idx < len(userInput.Disks) {
- inputDisk := userInput.Disks[idx]
- tmpD.Schedtags = inputDisk.Schedtags
- tmpD.Storage = inputDisk.Storage
- }
- disks = append(disks, tmpD)
- }
- userInput.Disks = disks
- }
- nets := []*api.NetworkConfig{}
- for idx, net := range genInput.Networks {
- tmpN := net
- if idx < len(userInput.Networks) {
- inputNet := userInput.Networks[idx]
- tmpN.Schedtags = inputNet.Schedtags
- tmpN.Network = inputNet.Network
- }
- nets = append(nets, tmpN)
- }
- userInput.Networks = nets
- userInput.IsolatedDevices = genInput.IsolatedDevices
- userInput.Count = 1
- // override some old userInput properties via genInput because of change config behavior
- userInput.VmemSize = genInput.VmemSize
- userInput.VcpuCount = genInput.VcpuCount
- userInput.Vga = genInput.Vga
- userInput.Vdi = genInput.Vdi
- userInput.Bios = genInput.Bios
- userInput.Cdrom = genInput.Cdrom
- userInput.Description = genInput.Description
- userInput.BootOrder = genInput.BootOrder
- userInput.DisableDelete = genInput.DisableDelete
- userInput.ShutdownBehavior = genInput.ShutdownBehavior
- userInput.IsSystem = genInput.IsSystem
- userInput.SecgroupId = genInput.SecgroupId
- userInput.KeypairId = genInput.KeypairId
- userInput.EipBw = genInput.EipBw
- userInput.EipChargeType = genInput.EipChargeType
- drv, _ := self.GetDriver()
- if drv != nil && drv.IsSupportPublicIp() {
- userInput.PublicIpBw = genInput.PublicIpBw
- userInput.PublicIpChargeType = genInput.PublicIpChargeType
- }
- userInput.AutoRenew = genInput.AutoRenew
- // cloned server should belongs to the project creating it
- userInput.ProjectId = userCred.GetProjectId()
- userInput.ProjectDomainId = userCred.GetProjectDomainId()
- userInput.Secgroups = []string{}
- secgroups, _ := self.GetSecgroups()
- for _, secgroup := range secgroups {
- userInput.Secgroups = append(userInput.Secgroups, secgroup.Id)
- }
- if genInput.ResourceType != "" {
- userInput.ResourceType = genInput.ResourceType
- }
- if genInput.InstanceType != "" {
- userInput.InstanceType = genInput.InstanceType
- }
- if genInput.PreferRegion != "" {
- userInput.PreferRegion = genInput.PreferRegion
- }
- if genInput.PreferZone != "" {
- userInput.PreferZone = genInput.PreferZone
- }
- // clean some of user input
- userInput.GenerateName = ""
- userInput.Description = ""
- userInput.Hostname = ""
- return userInput
- }
- func (self *SGuest) toCreateInput() *api.ServerCreateInput {
- r := new(api.ServerCreateInput)
- r.VmemSize = self.VmemSize
- r.VcpuCount = int(self.VcpuCount)
- if guestCdrom := self.getCdrom(false, 0); guestCdrom != nil {
- r.Cdrom = guestCdrom.ImageId
- }
- r.Vga = self.Vga
- r.Vdi = self.Vdi
- r.Bios = self.Bios
- r.Description = self.Description
- r.BootOrder = self.BootOrder
- r.DisableDelete = new(bool)
- *r.DisableDelete = self.DisableDelete.Bool()
- r.ShutdownBehavior = self.ShutdownBehavior
- // ignore r.DeployConfigs
- r.IsSystem = &self.IsSystem
- r.SecgroupId = self.SecgrpId
- r.ServerConfigs = new(api.ServerConfigs)
- r.Hypervisor = self.Hypervisor
- r.InstanceType = self.InstanceType
- r.ProjectId = self.ProjectId
- r.ProjectDomainId = self.DomainId
- r.Count = 1
- r.Disks = self.ToDisksConfig()
- r.Networks = self.ToNetworksConfig()
- r.IsolatedDevices = self.ToIsolatedDevicesConfig()
- r.AutoRenew = self.AutoRenew
- if keypair := self.getKeypair(); keypair != nil {
- r.KeypairId = keypair.Id
- }
- if host, _ := self.GetHost(); host != nil {
- r.ResourceType = host.ResourceType
- }
- if eip, _ := self.GetEipOrPublicIp(); eip != nil {
- switch eip.Mode {
- case api.EIP_MODE_STANDALONE_EIP:
- r.EipBw = eip.Bandwidth
- r.EipChargeType = eip.ChargeType
- case api.EIP_MODE_INSTANCE_PUBLICIP:
- drv, _ := self.GetDriver()
- if drv != nil && drv.IsSupportPublicIp() {
- r.PublicIpBw = eip.Bandwidth
- r.PublicIpChargeType = eip.ChargeType
- }
- }
- }
- if zone, _ := self.getZone(); zone != nil {
- region, _ := zone.GetRegion()
- r.PreferRegion = region.GetId()
- r.PreferZone = zone.GetId()
- }
- return r
- }
- func (self *SGuest) ToDisksConfig() []*api.DiskConfig {
- guestDisks, err := self.GetGuestDisks()
- if err != nil {
- return nil
- }
- ret := make([]*api.DiskConfig, len(guestDisks))
- for idx, guestDisk := range guestDisks {
- diskConf := new(api.DiskConfig)
- disk := guestDisk.GetDisk()
- diskConf.Index = int(guestDisk.Index)
- diskConf.ImageId = disk.GetTemplateId()
- diskConf.SnapshotId = disk.SnapshotId
- diskConf.DiskType = disk.DiskType
- diskConf.SizeMb = disk.DiskSize
- diskConf.Fs = disk.FsFormat
- diskConf.Format = disk.DiskFormat
- diskConf.Driver = guestDisk.Driver
- diskConf.Cache = guestDisk.CacheMode
- diskConf.Mountpoint = guestDisk.Mountpoint
- storage, _ := disk.GetStorage()
- diskConf.Backend = storage.StorageType
- diskConf.Medium = storage.MediumType
- ret[idx] = diskConf
- }
- return ret
- }
- func (self *SGuest) ToNetworksConfig() []*api.NetworkConfig {
- guestNetworks, _ := self.GetNetworks("")
- if len(guestNetworks) == 0 {
- return nil
- }
- ret := make([]*api.NetworkConfig, 0)
- teamMacs := []string{}
- for _, gn := range guestNetworks {
- if tg, _ := gn.GetTeamGuestnetwork(); tg != nil {
- teamMacs = append(teamMacs, gn.TeamWith)
- }
- }
- for _, guestNetwork := range guestNetworks {
- netConf := new(api.NetworkConfig)
- network, err := guestNetwork.GetNetwork()
- if err != nil {
- continue
- }
- requireTeaming := false
- if tg, _ := guestNetwork.GetTeamGuestnetwork(); tg != nil {
- requireTeaming = true
- }
- if utils.IsInStringArray(guestNetwork.MacAddr, teamMacs) {
- continue
- }
- // XXX: same wire
- netConf.Wire = network.WireId
- netConf.Network = network.Id
- netConf.Exit = guestNetwork.IsExit(nil)
- if len(guestNetwork.Ip6Addr) > 0 {
- netConf.RequireIPv6 = true
- if len(guestNetwork.IpAddr) == 0 {
- netConf.StrictIPv6 = true
- }
- }
- // netConf.Private
- // netConf.Reserved
- netConf.Driver = guestNetwork.Driver
- netConf.BwLimit = guestNetwork.BwLimit
- netConf.RequireTeaming = requireTeaming
- // netConf.NetType
- ret = append(ret, netConf)
- }
- return ret
- }
- func (self *SGuest) ToIsolatedDevicesConfig() []*api.IsolatedDeviceConfig {
- guestIsolatedDevices, _ := self.GetIsolatedDevices()
- if len(guestIsolatedDevices) == 0 {
- return nil
- }
- ret := make([]*api.IsolatedDeviceConfig, len(guestIsolatedDevices))
- for idx, guestIsolatedDevice := range guestIsolatedDevices {
- devConf := new(api.IsolatedDeviceConfig)
- devConf.Model = guestIsolatedDevice.Model
- devConf.Vendor = guestIsolatedDevice.getVendor()
- devConf.DevType = guestIsolatedDevice.DevType
- ret[idx] = devConf
- }
- return ret
- }
- func (self *SGuest) IsImport(ctx context.Context, userCred mcclient.TokenCredential) bool {
- return self.GetMetadata(ctx, "__is_import", userCred) == "true"
- }
- func (guest *SGuest) GetDetailsRemoteNics(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
- iVM, err := guest.GetIVM(ctx)
- if err != nil {
- return nil, httperrors.NewGeneralError(err)
- }
- iNics, err := iVM.GetINics()
- if err != nil {
- return nil, httperrors.NewGeneralError(err)
- }
- type SVNic struct {
- Index int
- Ip string
- Mac string
- Driver string
- }
- nics := make([]SVNic, len(iNics))
- for i := range iNics {
- nics[i] = SVNic{
- Index: i,
- Ip: iNics[i].GetIP(),
- Mac: iNics[i].GetMAC(),
- Driver: iNics[i].GetDriver(),
- }
- }
- // ret := jsonutils.NewDict()
- // ret.Set("vnics", jsonutils.Marshal(nics))
- return jsonutils.Marshal(nics), nil
- }
- func (self *SGuest) GetInstanceSnapshots() ([]SInstanceSnapshot, error) {
- instanceSnapshots := make([]SInstanceSnapshot, 0)
- q := InstanceSnapshotManager.Query().Equals("guest_id", self.Id)
- err := db.FetchModelObjects(InstanceSnapshotManager, q, &instanceSnapshots)
- if err != nil {
- return nil, err
- }
- return instanceSnapshots, nil
- }
- func (self *SGuest) GetInstanceSnapshotCount() (int, error) {
- q := InstanceSnapshotManager.Query().Equals("guest_id", self.Id)
- return q.CountWithError()
- }
- func (self *SGuest) GetDiskSnapshotsNotInInstanceSnapshots() ([]SSnapshot, error) {
- guestDisks, err := self.GetGuestDisks()
- if err != nil {
- return nil, errors.Wrapf(err, "GetGuestDisks")
- }
- diskIds := make([]string, len(guestDisks))
- for i := 0; i < len(guestDisks); i++ {
- diskIds[i] = guestDisks[i].DiskId
- }
- snapshots := make([]SSnapshot, 0)
- q := SnapshotManager.Query().IsFalse("fake_deleted").In("disk_id", diskIds)
- sq := InstanceSnapshotJointManager.Query("snapshot_id").SubQuery()
- q = q.LeftJoin(sq, sqlchemy.Equals(q.Field("id"), sq.Field("snapshot_id"))).
- Filter(sqlchemy.IsNull(sq.Field("snapshot_id")))
- err = db.FetchModelObjects(SnapshotManager, q, &snapshots)
- if err != nil {
- return nil, errors.Wrapf(err, "db.FetchModelObjects")
- }
- return snapshots, nil
- }
- func (self *SGuest) getGuestUsage(guestCount int) (SQuota, SRegionQuota, error) {
- usage := SQuota{}
- regionUsage := SRegionQuota{}
- usage.Count = guestCount
- usage.Cpu = int(self.VcpuCount) * guestCount
- usage.Memory = int(self.VmemSize * guestCount)
- diskSize := self.getDiskSize()
- if diskSize < 0 {
- return usage, regionUsage, httperrors.NewInternalServerError("fetch disk size failed")
- }
- usage.Storage = self.getDiskSize() * guestCount
- netCount, err := self.NetworkCount()
- if err != nil && errors.Cause(err) != sql.ErrNoRows {
- return usage, regionUsage, err
- }
- regionUsage.Port = netCount
- // regionUsage.Bw = self.getBandwidth(false)
- eip, err := self.GetEipOrPublicIp()
- if err != nil && errors.Cause(err) != sql.ErrNoRows {
- return usage, regionUsage, err
- }
- if eip != nil {
- regionUsage.Eip = 1
- }
- return usage, regionUsage, nil
- }
- func (self *SGuestManager) checkGuestImage(ctx context.Context, input *api.ServerCreateInput) error {
- if len(input.GuestImageID) == 0 {
- return nil
- }
- guestImageId := input.GuestImageID
- params := jsonutils.NewDict()
- params.Add(jsonutils.JSONTrue, "details")
- s := auth.GetAdminSession(ctx, options.Options.Region)
- ret, err := image.GuestImages.Get(s, guestImageId, params)
- if err != nil {
- return errors.Wrap(err, "get guest image from glance error")
- }
- images := &api.SImagesInGuest{}
- err = ret.Unmarshal(images)
- if err != nil {
- return errors.Wrap(err, "unmarshal guest image")
- }
- input.GuestImageID = images.Id
- log.Infof("usage guest image %s(%s)", images.Name, images.Id)
- if len(input.Disks) > 0 {
- input.Disks[0].ImageId = images.RootImage.Id
- } else {
- input.Disks = append(input.Disks,
- &api.DiskConfig{
- ImageId: images.RootImage.Id,
- },
- )
- }
- for i := range images.DataImages {
- if len(input.Disks) > i+1 {
- input.Disks[i+1].ImageId = images.DataImages[i].Id
- } else {
- input.Disks = append(input.Disks,
- &api.DiskConfig{
- ImageId: images.DataImages[i].Id,
- },
- )
- }
- }
- return nil
- }
- func (self *SGuest) GetDiskIndex(diskId string) int8 {
- guestDisks, _ := self.GetGuestDisks()
- for _, gd := range guestDisks {
- if gd.DiskId == diskId {
- return gd.Index
- }
- }
- return -1
- }
- func (guest *SGuest) GetRegionalQuotaKeys() (quotas.IQuotaKeys, error) {
- host, _ := guest.GetHost()
- if host == nil {
- return nil, errors.Wrap(httperrors.ErrInvalidStatus, "no valid host")
- }
- provider := host.GetCloudprovider()
- if provider == nil && len(host.ManagerId) > 0 {
- return nil, errors.Wrap(httperrors.ErrInvalidStatus, "no valid manager")
- }
- region, _ := host.GetRegion()
- if region == nil {
- return nil, errors.Wrap(httperrors.ErrInvalidStatus, "no valid region")
- }
- return fetchRegionalQuotaKeys(rbacscope.ScopeProject, guest.GetOwnerId(), region, provider), nil
- }
- func (guest *SGuest) GetCloudprovider() (*SCloudprovider, error) {
- hosts := HostManager.Query("manager_id").Equals("id", guest.HostId).SubQuery()
- q := CloudproviderManager.Query().In("id", hosts)
- ret := &SCloudprovider{}
- ret.SetModelManager(CloudproviderManager, ret)
- err := q.First(ret)
- if err != nil {
- return nil, errors.Wrapf(err, "q.First")
- }
- return ret, nil
- }
- func (guest *SGuest) GetQuotaKeys() (quotas.IQuotaKeys, error) {
- provider, _ := guest.GetCloudprovider()
- zone, _ := guest.GetZone()
- hypervisor := guest.Hypervisor
- return fetchComputeQuotaKeys(
- rbacscope.ScopeProject,
- guest.GetOwnerId(),
- zone,
- provider,
- hypervisor,
- ), nil
- }
- func (guest *SGuest) GetUsages() []db.IUsage {
- if guest.PendingDeleted || guest.Deleted {
- return nil
- }
- usage, regionUsage, err := guest.getGuestUsage(1)
- if err != nil {
- log.Errorf("guest.getGuestUsage fail %s", err)
- return nil
- }
- keys, err := guest.GetQuotaKeys()
- if err != nil {
- log.Errorf("guest.GetQuotaKeys fail %s", err)
- return nil
- }
- usage.SetKeys(keys)
- regionUsage.SetKeys(keys.(SComputeResourceKeys).SRegionalCloudResourceKeys)
- return []db.IUsage{
- &usage,
- ®ionUsage,
- }
- }
- var (
- // `^[a-zA-Z][a-zA-Z0-9._@-]*$`)
- serverNameREG = regexp.MustCompile(`^[a-zA-Z$][a-zA-Z0-9-${}.]*$`)
- hostnameREG = regexp.MustCompile(`^[a-z$][a-z0-9-${}.]*$`)
- )
- func (manager *SGuestManager) ValidateNameLoginAccount(name string) error {
- if serverNameREG.MatchString(name) {
- return nil
- }
- return httperrors.NewInputParameterError("name starts with letter, and contains letter, number and - only")
- }
- func (guest *SGuest) StartRemoteUpdateTask(ctx context.Context, userCred mcclient.TokenCredential, replaceTags bool, parentTaskId string) error {
- data := jsonutils.NewDict()
- if replaceTags {
- data.Add(jsonutils.JSONTrue, "replace_tags")
- }
- if task, err := taskman.TaskManager.NewTask(ctx, "GuestRemoteUpdateTask", guest, userCred, data, parentTaskId, "", nil); err != nil {
- log.Errorln(err)
- return errors.Wrap(err, "Start GuestRemoteUpdateTask")
- } else {
- guest.SetStatus(ctx, userCred, api.VM_UPDATE_TAGS, "StartRemoteUpdateTask")
- task.ScheduleRun(nil)
- }
- return nil
- }
- func (guest *SGuest) OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential) {
- if len(guest.ExternalId) == 0 || options.Options.KeepTagLocalization {
- return
- }
- host, err := guest.GetHost()
- if err != nil {
- return
- }
- if account := host.GetCloudaccount(); account != nil && account.ReadOnly {
- return
- }
- err = guest.StartRemoteUpdateTask(ctx, userCred, true, "")
- if err != nil {
- log.Errorf("StartRemoteUpdateTask fail: %s", err)
- }
- }
- func (self *SGuest) GetAddress() (string, error) {
- gns, err := self.GetNetworks("")
- if err != nil {
- return "", errors.Wrapf(err, "GetNetworks")
- }
- for _, gn := range gns {
- if !gn.IsExit(nil) {
- return gn.IpAddr, nil
- }
- }
- return "", errors.Wrapf(cloudprovider.ErrNotFound, "guest %s address", self.Name)
- }
- func (guest *SGuest) InferPowerStates() {
- if len(guest.PowerStates) == 0 {
- switch guest.Status {
- case api.VM_READY:
- guest.PowerStates = api.VM_POWER_STATES_OFF
- case api.VM_UNKNOWN:
- guest.PowerStates = api.VM_POWER_STATES_UNKNOWN
- case api.VM_INIT:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_SCHEDULE:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_SCHEDULE_FAILED:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_CREATE_NETWORK:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_NETWORK_FAILED:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_DEVICE_FAILED:
- guest.PowerStates = api.VM_POWER_STATES_UNKNOWN
- case api.VM_CREATE_FAILED:
- guest.PowerStates = api.VM_POWER_STATES_OFF
- case api.VM_CREATE_DISK:
- guest.PowerStates = api.VM_POWER_STATES_OFF
- case api.VM_DISK_FAILED:
- guest.PowerStates = api.VM_POWER_STATES_OFF
- case api.VM_IMAGE_CACHING:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_START_DEPLOY:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_DEPLOYING:
- guest.PowerStates = api.VM_POWER_STATES_OFF
- case api.VM_START_START:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_STARTING:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_START_FAILED:
- guest.PowerStates = api.VM_POWER_STATES_OFF
- case api.VM_RUNNING:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_START_STOP:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_STOPPING:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_STOP_FAILED:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_RENEWING:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_RENEW_FAILED:
- guest.PowerStates = api.VM_POWER_STATES_ON
- case api.VM_ATTACH_DISK:
- guest.PowerStates = api.VM_POWER_STATES_UNKNOWN
- case api.VM_DETACH_DISK:
- guest.PowerStates = api.VM_POWER_STATES_UNKNOWN
- default:
- guest.PowerStates = api.VM_POWER_STATES_UNKNOWN
- }
- }
- }
- func (guest *SGuest) HasBackupGuest() bool {
- return guest.BackupHostId != ""
- }
- func (guest *SGuest) SetGuestBackupMirrorJobInProgress(ctx context.Context, userCred mcclient.TokenCredential) error {
- return guest.SetMetadata(ctx, api.MIRROR_JOB, api.MIRROR_JOB_INPROGRESS, userCred)
- }
- func (guest *SGuest) SetKickstartConfig(ctx context.Context, config *api.KickstartConfig, userCred mcclient.TokenCredential) error {
- if config == nil {
- return guest.RemoveMetadata(ctx, api.VM_METADATA_KICKSTART_CONFIG, userCred)
- }
- if err := validateKickstartConfig(config); err != nil {
- return errors.Wrap(err, "validate kickstart config")
- }
- configJson := jsonutils.Marshal(config)
- return guest.SetMetadata(ctx, api.VM_METADATA_KICKSTART_CONFIG, configJson, userCred)
- }
- func (guest *SGuest) GetKickstartConfig(ctx context.Context, userCred mcclient.TokenCredential) (*api.KickstartConfig, error) {
- configJson := guest.GetMetadataJson(ctx, api.VM_METADATA_KICKSTART_CONFIG, userCred)
- if configJson == nil {
- return nil, nil
- }
- config := &api.KickstartConfig{}
- if err := configJson.Unmarshal(config); err != nil {
- return nil, errors.Wrap(err, "unmarshal kickstart config")
- }
- return config, nil
- }
- func (guest *SGuest) SetKickstartStatus(ctx context.Context, status string, userCred mcclient.TokenCredential) error {
- if !utils.IsInStringArray(status, api.VM_KICKSTART_STATUS) {
- return errors.Errorf("invalid kickstart status: %s", status)
- }
- return guest.SetStatus(ctx, userCred, status, "")
- }
- func (guest *SGuest) GetKickstartStatus(ctx context.Context, userCred mcclient.TokenCredential) string {
- if utils.IsInStringArray(guest.Status, api.VM_KICKSTART_STATUS) {
- return guest.Status
- }
- return ""
- }
- func (guest *SGuest) IsInKickstartStatus() bool {
- return utils.IsInStringArray(guest.Status, api.VM_KICKSTART_STATUS)
- }
- func (guest *SGuest) SetKickstartType(ctx context.Context, kickstartType string, userCred mcclient.TokenCredential) error {
- if !utils.IsInStringArray(kickstartType, api.KICKSTART_VALID_TYPES) {
- return errors.Errorf("invalid kickstart type: %s", kickstartType)
- }
- return guest.SetMetadata(ctx, api.VM_METADATA_KICKSTART_TYPE, kickstartType, userCred)
- }
- func (guest *SGuest) GetKickstartType(ctx context.Context, userCred mcclient.TokenCredential) string {
- kickstartType := guest.GetMetadata(ctx, api.VM_METADATA_KICKSTART_TYPE, userCred)
- if kickstartType == "" {
- return api.KICKSTART_TYPE_URL
- }
- return kickstartType
- }
- func (guest *SGuest) IsKickstartEnabled(ctx context.Context, userCred mcclient.TokenCredential) bool {
- config, err := guest.GetKickstartConfig(ctx, userCred)
- if err != nil || config == nil {
- return false
- }
- if config.Enabled == nil {
- return true
- }
- return *config.Enabled
- }
- func (guest *SGuest) SetGuestBackupMirrorJobNotReady(ctx context.Context, userCred mcclient.TokenCredential) error {
- return guest.SetMetadata(ctx, api.MIRROR_JOB, "", userCred)
- }
- func (guest *SGuest) TrySetGuestBackupMirrorJobReady(ctx context.Context, userCred mcclient.TokenCredential) error {
- if guest.IsGuestBackupMirrorJobFailed(ctx, userCred) {
- // can't update guest backup mirror job status from failed to ready
- return nil
- }
- return guest.SetMetadata(ctx, api.MIRROR_JOB, api.MIRROR_JOB_READY, userCred)
- }
- func (guest *SGuest) SetGuestBackupMirrorJobFailed(ctx context.Context, userCred mcclient.TokenCredential) error {
- return guest.SetMetadata(ctx, api.MIRROR_JOB, api.MIRROR_JOB_FAILED, userCred)
- }
- func (guest *SGuest) IsGuestBackupMirrorJobFailed(ctx context.Context, userCred mcclient.TokenCredential) bool {
- return guest.GetMetadata(ctx, api.MIRROR_JOB, userCred) == api.MIRROR_JOB_FAILED
- }
- func (guest *SGuest) IsGuestBackupMirrorJobReady(ctx context.Context, userCred mcclient.TokenCredential) bool {
- return guest.GetMetadata(ctx, api.MIRROR_JOB, userCred) == api.MIRROR_JOB_READY
- }
- func (guest *SGuest) GetGuestBackupMirrorJobStatus(ctx context.Context, userCred mcclient.TokenCredential) string {
- return guest.GetMetadata(ctx, api.MIRROR_JOB, userCred)
- }
- func (guest *SGuest) ResetGuestQuorumChildIndex(ctx context.Context, userCred mcclient.TokenCredential) error {
- return guest.SetMetadata(ctx, api.QUORUM_CHILD_INDEX, "", userCred)
- }
- type SGuestTotalCount struct {
- apis.TotalCountBase
- CpuCount int
- MemMb int
- DiskMb int64
- DiskCount int
- }
- func (manager *SGuestManager) CustomizedTotalCount(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, totalQ *sqlchemy.SQuery) (int, jsonutils.JSONObject, error) {
- results := SGuestTotalCount{}
- totalQ = totalQ.AppendField(sqlchemy.SUM("cpu_count", totalQ.Field("vcpu_count")))
- totalQ = totalQ.AppendField(sqlchemy.SUM("mem_mb", totalQ.Field("vmem_size")))
- err := totalQ.First(&results)
- if err != nil {
- return -1, nil, errors.Wrap(err, "SGuestManager query total")
- }
- log.Debugf("CustomizedTotalCount %s", jsonutils.Marshal(results))
- diskQ := DiskManager.Query()
- diskGuestQ := GuestdiskManager.Query().SubQuery()
- diskQ = diskQ.Join(diskGuestQ, sqlchemy.Equals(diskQ.Field("id"), diskGuestQ.Field("disk_id")))
- totalSQ := totalQ.ResetFields().SubQuery()
- diskQ = diskQ.Join(totalSQ, sqlchemy.Equals(diskGuestQ.Field("guest_id"), totalSQ.Field("id")))
- diskQ = diskQ.AppendField(sqlchemy.COUNT("disk_count"))
- diskQ = diskQ.AppendField(sqlchemy.SUM("disk_mb", diskQ.Field("disk_size")))
- err = diskQ.First(&results)
- if err != nil {
- return -1, nil, errors.Wrap(err, "SGuestManager query total_disk")
- }
- _, statusInfo, err := manager.SVirtualResourceBaseManager.CustomizedTotalCount(ctx, userCred, query, totalQ)
- if err != nil {
- return -1, nil, errors.Wrapf(err, "virt.CustomizedTotalCount")
- }
- ret := jsonutils.Marshal(results).(*jsonutils.JSONDict)
- ret.Update(statusInfo)
- return results.Count, ret, nil
- }
- func (guest *SGuest) IsSriov() bool {
- nics, err := guest.GetNetworks("")
- if err != nil {
- log.Errorf("guest.GetNetworks fail %s", err)
- return false
- }
- for i := range nics {
- if nics[i].Driver == api.NETWORK_DRIVER_VFIO {
- return true
- }
- }
- return false
- }
- func (guest *SGuest) getDisksCandidateHostIds() ([]string, error) {
- disks, err := guest.GetDisks()
- if err != nil {
- return nil, errors.Wrap(err, "guest.GetDisks")
- }
- ret := stringutils2.NewSortedStrings(nil)
- for i := range disks {
- candidates, err := disks[i].getCandidateHostIds()
- if err != nil {
- return nil, errors.Wrap(err, "getCandidateHostIds")
- }
- sorted := stringutils2.NewSortedStrings(candidates)
- if i > 0 {
- ret = stringutils2.Intersect(ret, sorted)
- } else {
- ret = sorted
- }
- }
- return ret, nil
- }
- func (guest *SGuest) SaveLastStartAt() error {
- _, err := db.Update(guest, func() error {
- guest.LastStartAt = time.Now().UTC()
- return nil
- })
- return errors.Wrap(err, "SaveLastStartAt")
- }
- func (guest *SGuest) finalizeFakeDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, task taskman.ITask) {
- db.OpsLog.LogEvent(guest, db.ACT_PENDING_DELETE, guest.GetShortDesc(ctx), userCred)
- logclient.AddActionLogWithStartable(task, guest, logclient.ACT_PENDING_DELETE, guest.GetShortDesc(ctx), userCred, true)
- if !guest.IsSystem {
- guest.EventNotify(ctx, userCred, notifyclient.ActionPendingDelete)
- }
- }
- func (guest *SGuest) finalizeRealDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, task taskman.ITask) {
- guest.RealDelete(ctx, userCred)
- guest.RemoveAllMetadata(ctx, userCred)
- db.OpsLog.LogEvent(guest, db.ACT_DELOCATE, guest.GetShortDesc(ctx), userCred)
- logclient.AddActionLogWithStartable(task, guest, logclient.ACT_DELOCATE, nil, userCred, true)
- if !guest.IsSystem {
- guest.EventNotify(ctx, userCred, notifyclient.ActionDelete)
- }
- HostManager.ClearSchedDescCache(guest.HostId)
- }
- func (guest *SGuest) FinalizeDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, task taskman.ITask, data jsonutils.JSONObject) {
- if jsonutils.QueryBoolean(data, "real_delete", false) {
- guest.finalizeRealDeleteTask(ctx, userCred, task)
- } else {
- guest.finalizeFakeDeleteTask(ctx, userCred, task)
- }
- }
- func (guest *SGuest) StartBaseDeleteTask(ctx context.Context, t taskman.ITask) error {
- task, err := taskman.TaskManager.NewTask(ctx, "BaseGuestDeleteTask", guest, t.GetUserCred(), t.GetParams(), t.GetTaskId(), "", nil)
- if err != nil {
- return errors.Wrap(err, "StartBaseDeleteTask")
- }
- err = task.ScheduleRun(nil)
- if err != nil {
- return errors.Wrap(err, "ScheduleRun")
- }
- return nil
- }
|