PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/saltstack/salt/lib/python3.10/site-packages/salt/modules
Viewing File: /opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/smartos_vmadm.py
""" Module for running vmadm command on SmartOS """ import logging import os import shlex import salt.utils.args import salt.utils.files import salt.utils.json import salt.utils.path import salt.utils.platform import salt.utils.stringutils from salt.utils.odict import OrderedDict log = logging.getLogger(__name__) # Function aliases __func_alias__ = {"list_vms": "list"} # Define the module's virtual name __virtualname__ = "vmadm" def __virtual__(): """ Provides vmadm on SmartOS """ if ( salt.utils.platform.is_smartos_globalzone() and salt.utils.path.which("vmadm") and salt.utils.path.which("zfs") ): return __virtualname__ return ( False, f"{__virtualname__} module can only be loaded on SmartOS compute nodes", ) def _exit_status(retcode): """ Translate exit status of vmadm """ if retcode == 0: return "Successful completion." if retcode == 1: return "An error occurred." if retcode == 2: return "Usage error." def _create_update_from_file(mode="create", uuid=None, path=None): """ Create vm from file """ ret = {} if not os.path.isfile(path) or path is None: ret["Error"] = f"File ({path}) does not exists!" return ret # vmadm validate create|update [-f <filename>] cmd = "vmadm validate {mode} {brand} -f {path}".format( mode=mode, brand=get(uuid)["brand"] if uuid is not None else "", path=path ) res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: ret["Error"] = _exit_status(retcode) if "stderr" in res: if res["stderr"][0] == "{": ret["Error"] = salt.utils.json.loads(res["stderr"]) else: ret["Error"] = res["stderr"] return ret # vmadm create|update [-f <filename>] cmd = "vmadm {mode} {uuid} -f {path}".format( mode=mode, uuid=uuid if uuid is not None else "", path=path ) res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: ret["Error"] = _exit_status(retcode) if "stderr" in res: if res["stderr"][0] == "{": ret["Error"] = salt.utils.json.loads(res["stderr"]) else: ret["Error"] = res["stderr"] return ret else: if res["stderr"].startswith("Successfully created VM"): return res["stderr"][24:] return True def _create_update_from_cfg(mode="create", uuid=None, vmcfg=None): """ Create vm from configuration """ ret = {} # write json file vmadm_json_file = __salt__["temp.file"](prefix="vmadm-") with salt.utils.files.fopen(vmadm_json_file, "w") as vmadm_json: salt.utils.json.dump(vmcfg, vmadm_json) # vmadm validate create|update [-f <filename>] cmd = "vmadm validate {mode} {brand} -f {vmadm_json_file}".format( mode=mode, brand=get(uuid)["brand"] if uuid is not None else "", vmadm_json_file=vmadm_json_file, ) res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] if retcode != 0: ret["Error"] = _exit_status(retcode) if "stderr" in res: if res["stderr"][0] == "{": ret["Error"] = salt.utils.json.loads(res["stderr"]) else: ret["Error"] = res["stderr"] return ret # vmadm create|update [-f <filename>] cmd = "vmadm {mode} {uuid} -f {vmadm_json_file}".format( mode=mode, uuid=uuid if uuid is not None else "", vmadm_json_file=vmadm_json_file, ) res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] if retcode != 0: ret["Error"] = _exit_status(retcode) if "stderr" in res: if res["stderr"][0] == "{": ret["Error"] = salt.utils.json.loads(res["stderr"]) else: ret["Error"] = res["stderr"] return ret else: # cleanup json file (only when successful to help troubleshooting) salt.utils.files.safe_rm(vmadm_json_file) # return uuid if res["stderr"].startswith("Successfully created VM"): return res["stderr"][24:] return True def start(vm, options=None, key="uuid"): """ Start a vm vm : string vm to be started options : string optional additional options key : string [uuid|alias|hostname] value type of 'vm' parameter CLI Example: .. code-block:: bash salt '*' vmadm.start 186da9ab-7392-4f55-91a5-b8f1fe770543 salt '*' vmadm.start 186da9ab-7392-4f55-91a5-b8f1fe770543 'order=c,once=d cdrom=/path/to/image.iso,ide' salt '*' vmadm.start vm=nacl key=alias salt '*' vmadm.start vm=nina.example.org key=hostname """ ret = {} if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm start <uuid> [option=value ...] cmd = "vmadm start {uuid} {options}".format( uuid=vm, options=options if options else "" ) res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return True def stop(vm, force=False, key="uuid"): """ Stop a vm vm : string vm to be stopped force : boolean force stop of vm if true key : string [uuid|alias|hostname] value type of 'vm' parameter CLI Example: .. code-block:: bash salt '*' vmadm.stop 186da9ab-7392-4f55-91a5-b8f1fe770543 salt '*' vmadm.stop 186da9ab-7392-4f55-91a5-b8f1fe770543 True salt '*' vmadm.stop vm=nacl key=alias salt '*' vmadm.stop vm=nina.example.org key=hostname """ ret = {} if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm stop <uuid> [-F] cmd = "vmadm stop {force} {uuid}".format(force="-F" if force else "", uuid=vm) res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: ret["Error"] = _exit_status(retcode) return ret return True def reboot(vm, force=False, key="uuid"): """ Reboot a vm vm : string vm to be rebooted force : boolean force reboot of vm if true key : string [uuid|alias|hostname] value type of 'vm' parameter CLI Example: .. code-block:: bash salt '*' vmadm.reboot 186da9ab-7392-4f55-91a5-b8f1fe770543 salt '*' vmadm.reboot 186da9ab-7392-4f55-91a5-b8f1fe770543 True salt '*' vmadm.reboot vm=nacl key=alias salt '*' vmadm.reboot vm=nina.example.org key=hostname """ ret = {} if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm reboot <uuid> [-F] cmd = "vmadm reboot {force} {uuid}".format(force="-F" if force else "", uuid=vm) res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return True def list_vms(search=None, sort=None, order="uuid,type,ram,state,alias", keyed=True): """ Return a list of VMs search : string vmadm filter property sort : string vmadm sort (-s) property order : string vmadm order (-o) property -- Default: uuid,type,ram,state,alias keyed : boolean specified if the output should be an array (False) or dict (True) For a dict the key is the first item from the order parameter. Note: If key is not unique last vm wins. CLI Example: .. code-block:: bash salt '*' vmadm.list salt '*' vmadm.list order=alias,ram,cpu_cap sort=-ram,-cpu_cap salt '*' vmadm.list search='type=KVM' """ ret = {} # vmadm list [-p] [-H] [-o field,...] [-s field,...] [field=value ...] cmd = "vmadm list -p -H {order} {sort} {search}".format( order=f"-o {order}" if order else "", sort=f"-s {sort}" if sort else "", search=search if search else "", ) res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] result = OrderedDict() if keyed else [] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret fields = order.split(",") for vm in res["stdout"].splitlines(): vm_data = OrderedDict() vm = vm.split(":") if keyed: for field in fields: if fields.index(field) == 0: continue vm_data[field.strip()] = vm[fields.index(field)].strip() result[vm[0]] = vm_data else: if len(vm) > 1: for field in fields: vm_data[field.strip()] = vm[fields.index(field)].strip() else: vm_data = vm[0] result.append(vm_data) return result def lookup(search=None, order=None, one=False): """ Return a list of VMs using lookup search : string vmadm filter property order : string vmadm order (-o) property -- Default: uuid,type,ram,state,alias one : boolean return only one result (vmadm's -1) CLI Example: .. code-block:: bash salt '*' vmadm.lookup search='state=running' salt '*' vmadm.lookup search='state=running' order=uuid,alias,hostname salt '*' vmadm.lookup search='alias=nacl' one=True """ ret = {} # vmadm lookup [-j|-1] [-o field,...] [field=value ...] cmd = "vmadm lookup {one} {order} {search}".format( one="-1" if one else "-j", order=f"-o {order}" if order else "", search=search if search else "", ) res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] result = [] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret if one: result = res["stdout"] else: for vm in salt.utils.json.loads(res["stdout"]): result.append(vm) return result def sysrq(vm, action="nmi", key="uuid"): """ Send non-maskable interrupt to vm or capture a screenshot vm : string vm to be targeted action : string nmi or screenshot -- Default: nmi key : string [uuid|alias|hostname] value type of 'vm' parameter CLI Example: .. code-block:: bash salt '*' vmadm.sysrq 186da9ab-7392-4f55-91a5-b8f1fe770543 nmi salt '*' vmadm.sysrq 186da9ab-7392-4f55-91a5-b8f1fe770543 screenshot salt '*' vmadm.sysrq nacl nmi key=alias """ ret = {} if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret if action not in ["nmi", "screenshot"]: ret["Error"] = "Action must be either nmi or screenshot" return ret vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm sysrq <uuid> <nmi|screenshot> cmd = f"vmadm sysrq {vm} {action}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return True def delete(vm, key="uuid"): """ Delete a vm vm : string vm to be deleted key : string [uuid|alias|hostname] value type of 'vm' parameter CLI Example: .. code-block:: bash salt '*' vmadm.delete 186da9ab-7392-4f55-91a5-b8f1fe770543 salt '*' vmadm.delete nacl key=alias """ ret = {} if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm delete <uuid> cmd = f"vmadm delete {vm}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return True def get(vm, key="uuid"): """ Output the JSON object describing a VM vm : string vm to be targeted key : string [uuid|alias|hostname] value type of 'vm' parameter CLI Example: .. code-block:: bash salt '*' vmadm.get 186da9ab-7392-4f55-91a5-b8f1fe770543 salt '*' vmadm.get nacl key=alias """ ret = {} if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm get <uuid> cmd = f"vmadm get {vm}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return salt.utils.json.loads(res["stdout"]) def info(vm, info_type="all", key="uuid"): """ Lookup info on running kvm vm : string vm to be targeted info_type : string [all|block|blockstats|chardev|cpus|kvm|pci|spice|version|vnc] info type to return key : string [uuid|alias|hostname] value type of 'vm' parameter CLI Example: .. code-block:: bash salt '*' vmadm.info 186da9ab-7392-4f55-91a5-b8f1fe770543 salt '*' vmadm.info 186da9ab-7392-4f55-91a5-b8f1fe770543 vnc salt '*' vmadm.info nacl key=alias salt '*' vmadm.info nacl vnc key=alias """ ret = {} if info_type not in [ "all", "block", "blockstats", "chardev", "cpus", "kvm", "pci", "spice", "version", "vnc", ]: ret["Error"] = "Requested info_type is not available" return ret if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm info <uuid> [type,...] cmd = f"vmadm info {vm} {info_type}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return salt.utils.json.loads(res["stdout"]) def create_snapshot(vm, name, key="uuid"): """ Create snapshot of a vm vm : string vm to be targeted name : string snapshot name The snapname must be 64 characters or less and must only contain alphanumeric characters and characters in the set [-_.:%] to comply with ZFS restrictions. key : string [uuid|alias|hostname] value type of 'vm' parameter CLI Example: .. code-block:: bash salt '*' vmadm.create_snapshot 186da9ab-7392-4f55-91a5-b8f1fe770543 baseline salt '*' vmadm.create_snapshot nacl baseline key=alias """ ret = {} if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm vmobj = get(vm) if "datasets" in vmobj: ret["Error"] = "VM cannot have datasets" return ret if vmobj["brand"] in ["kvm"]: ret["Error"] = "VM must be of type OS" return ret if vmobj["zone_state"] not in ["running"]: # work around a vmadm bug ret["Error"] = "VM must be running to take a snapshot" return ret # vmadm create-snapshot <uuid> <snapname> cmd = f"vmadm create-snapshot {vm} {name}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return True def delete_snapshot(vm, name, key="uuid"): """ Delete snapshot of a vm vm : string vm to be targeted name : string snapshot name The snapname must be 64 characters or less and must only contain alphanumeric characters and characters in the set [-_.:%] to comply with ZFS restrictions. key : string [uuid|alias|hostname] value type of 'vm' parameter CLI Example: .. code-block:: bash salt '*' vmadm.delete_snapshot 186da9ab-7392-4f55-91a5-b8f1fe770543 baseline salt '*' vmadm.delete_snapshot nacl baseline key=alias """ ret = {} if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm vmobj = get(vm) if "datasets" in vmobj: ret["Error"] = "VM cannot have datasets" return ret if vmobj["brand"] in ["kvm"]: ret["Error"] = "VM must be of type OS" return ret # vmadm delete-snapshot <uuid> <snapname> cmd = f"vmadm delete-snapshot {vm} {name}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return True def rollback_snapshot(vm, name, key="uuid"): """ Rollback snapshot of a vm vm : string vm to be targeted name : string snapshot name The snapname must be 64 characters or less and must only contain alphanumeric characters and characters in the set [-_.:%] to comply with ZFS restrictions. key : string [uuid|alias|hostname] value type of 'vm' parameter CLI Example: .. code-block:: bash salt '*' vmadm.rollback_snapshot 186da9ab-7392-4f55-91a5-b8f1fe770543 baseline salt '*' vmadm.rollback_snapshot nacl baseline key=alias """ ret = {} if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm vmobj = get(vm) if "datasets" in vmobj: ret["Error"] = "VM cannot have datasets" return ret if vmobj["brand"] in ["kvm"]: ret["Error"] = "VM must be of type OS" return ret # vmadm rollback-snapshot <uuid> <snapname> cmd = f"vmadm rollback-snapshot {vm} {name}" res = __salt__["cmd.run_all"](cmd) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return True def reprovision(vm, image, key="uuid"): """ Reprovision a vm vm : string vm to be reprovisioned image : string uuid of new image key : string [uuid|alias|hostname] value type of 'vm' parameter CLI Example: .. code-block:: bash salt '*' vmadm.reprovision 186da9ab-7392-4f55-91a5-b8f1fe770543 c02a2044-c1bd-11e4-bd8c-dfc1db8b0182 salt '*' vmadm.reprovision nacl c02a2044-c1bd-11e4-bd8c-dfc1db8b0182 key=alias """ ret = {} if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm if image not in __salt__["imgadm.list"](): ret["Error"] = f"Image ({image}) is not present on this host" return ret # vmadm reprovision <uuid> [-f <filename>] cmd = "echo {image} | vmadm reprovision {uuid}".format( uuid=salt.utils.stringutils.to_unicode(vm), image=shlex.quote(salt.utils.json.dumps({"image_uuid": image})), ) res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return True def create(from_file=None, **kwargs): """ Create a new vm from_file : string json file to create the vm from -- if present, all other options will be ignored kwargs : string|int|... options to set for the vm CLI Example: .. code-block:: bash salt '*' vmadm.create from_file=/tmp/new_vm.json salt '*' vmadm.create image_uuid='...' alias='...' nics='[{ "nic_tag": "admin", "ip": "198.51.100.123", ...}, {...}]' [...] """ ret = {} # prepare vmcfg vmcfg = {} kwargs = salt.utils.args.clean_kwargs(**kwargs) for k, v in kwargs.items(): vmcfg[k] = v if from_file: return _create_update_from_file("create", path=from_file) else: return _create_update_from_cfg("create", vmcfg=vmcfg) def update(vm, from_file=None, key="uuid", **kwargs): """ Update a new vm vm : string vm to be updated from_file : string json file to update the vm with -- if present, all other options will be ignored key : string [uuid|alias|hostname] value type of 'vm' parameter kwargs : string|int|... options to update for the vm CLI Example: .. code-block:: bash salt '*' vmadm.update vm=186da9ab-7392-4f55-91a5-b8f1fe770543 from_file=/tmp/new_vm.json salt '*' vmadm.update vm=nacl key=alias from_file=/tmp/new_vm.json salt '*' vmadm.update vm=186da9ab-7392-4f55-91a5-b8f1fe770543 max_physical_memory=1024 """ ret = {} # prepare vmcfg vmcfg = {} kwargs = salt.utils.args.clean_kwargs(**kwargs) for k, v in kwargs.items(): vmcfg[k] = v if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret uuid = lookup(f"{key}={vm}", one=True) if "Error" in uuid: return uuid if from_file: return _create_update_from_file("update", uuid, path=from_file) else: return _create_update_from_cfg("update", uuid, vmcfg=vmcfg) def send(vm, target, key="uuid"): """ Send a vm to a directory vm : string vm to be sent target : string target directory key : string [uuid|alias|hostname] value type of 'vm' parameter CLI Example: .. code-block:: bash salt '*' vmadm.send 186da9ab-7392-4f55-91a5-b8f1fe770543 /opt/backups salt '*' vmadm.send vm=nacl target=/opt/backups key=alias """ ret = {} if key not in ["uuid", "alias", "hostname"]: ret["Error"] = "Key must be either uuid, alias or hostname" return ret if not os.path.isdir(target): ret["Error"] = "Target must be a directory or host" return ret vm = lookup(f"{key}={vm}", one=True) if "Error" in vm: return vm # vmadm send <uuid> [target] cmd = "vmadm send {uuid} > {target}".format( uuid=vm, target=os.path.join(target, f"{vm}.vmdata") ) res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret vmobj = get(vm) if "datasets" not in vmobj: return True log.warning("one or more datasets detected, this is not supported!") log.warning("trying to zfs send datasets...") for dataset in vmobj["datasets"]: name = dataset.split("/") name = name[-1] cmd = "zfs send {dataset} > {target}".format( dataset=dataset, target=os.path.join(target, f"{vm}-{name}.zfsds"), ) res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return True def receive(uuid, source): """ Receive a vm from a directory uuid : string uuid of vm to be received source : string source directory CLI Example: .. code-block:: bash salt '*' vmadm.receive 186da9ab-7392-4f55-91a5-b8f1fe770543 /opt/backups """ ret = {} if not os.path.isdir(source): ret["Error"] = "Source must be a directory or host" return ret if not os.path.exists(os.path.join(source, f"{uuid}.vmdata")): ret["Error"] = f"Unknow vm with uuid in {source}" return ret # vmadm receive cmd = "vmadm receive < {source}".format( source=os.path.join(source, f"{uuid}.vmdata") ) res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] if retcode != 0 and not res["stderr"].endswith("datasets"): ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret vmobj = get(uuid) if "datasets" not in vmobj: return True log.warning("one or more datasets detected, this is not supported!") log.warning("trying to restore datasets, mountpoints will need to be set again...") for dataset in vmobj["datasets"]: name = dataset.split("/") name = name[-1] cmd = "zfs receive {dataset} < {source}".format( dataset=dataset, source=os.path.join(source, f"{uuid}-{name}.zfsds"), ) res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] if retcode != 0: ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret cmd = f"vmadm install {uuid}" res = __salt__["cmd.run_all"](cmd, python_shell=True) retcode = res["retcode"] if retcode != 0 and not res["stderr"].endswith("datasets"): ret["Error"] = res["stderr"] if "stderr" in res else _exit_status(retcode) return ret return True