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: /usr/share/ruby/vendor_ruby/puppet
Viewing File: /usr/share/ruby/vendor_ruby/puppet/property.rb
# The virtual base class for properties, which are the self-contained building # blocks for actually doing work on the system. require 'puppet' require 'puppet/parameter' # The Property class is the implementation of a resource's attributes of _property_ kind. # A Property is a specialized Resource Type Parameter that has both an 'is' (current) state, and # a 'should' (wanted state). However, even if this is conceptually true, the current _is_ value is # obtained by asking the associated provider for the value, and hence it is not actually part of a # property's state, and only available when a provider has been selected and can obtain the value (i.e. when # running on an agent). # # A Property (also in contrast to a parameter) is intended to describe a managed attribute of # some system entity, such as the name or mode of a file. # # The current value _(is)_ is read and written with the methods {#retrieve} and {#set}, and the wanted # value _(should)_ is read and written with the methods {#value} and {#value=} which delegate to # {#should} and {#should=}, i.e. when a property is used like any other parameter, it is the _should_ value # that is operated on. # # All resource type properties in the puppet system are derived from this class. # # The intention is that new parameters are created by using the DSL method {Puppet::Type.newproperty}. # # @abstract # @note Properties of Types are expressed using subclasses of this class. Such a class describes one # named property of a particular Type (as opposed to describing a type of property in general). This # limits the use of one (concrete) property class instance to occur only once for a given type's inheritance # chain. An instance of a Property class is the value holder of one instance of the resource type (e.g. the # mode of a file resource instance). # A Property class may server as the superclass _(parent)_ of another; e.g. a Size property that describes # handling of measurements such as kb, mb, gb. If a type requires two different size measurements it requires # one concrete class per such measure; e.g. MinSize (:parent => Size), and MaxSize (:parent => Size). # # @todo Describe meta-parameter shadowing. This concept can not be understood by just looking at the descriptions # of the methods involved. # # @see Puppet::Type # @see Puppet::Parameter # # @api public # class Puppet::Property < Puppet::Parameter require 'puppet/property/ensure' # Returns the original wanted value(s) _(should)_ unprocessed by munging/unmunging. # The original values are set by {#value=} or {#should=}. # @return (see #should) # attr_reader :shouldorig # The noop mode for this property. # By setting a property's noop mode to `true`, any management of this property is inhibited. Calculation # and reporting still takes place, but if a change of the underlying managed entity's state # should take place it will not be carried out. This noop # setting overrides the overall `Puppet[:noop]` mode as well as the noop mode in the _associated resource_ # attr_writer :noop class << self # @todo Figure out what this is used for. Can not find any logic in the puppet code base that # reads or writes this attribute. # ??? Probably Unused attr_accessor :unmanaged # @return [Symbol] The name of the property as given when the property was created. # attr_reader :name # @!attribute [rw] array_matching # @comment note that $#46; is a period - char code require to not terminate sentence. # The `is` vs&#46; `should` array matching mode; `:first`, or `:all`. # # @comment there are two blank chars after the symbols to cause a break - do not remove these. # * `:first` # This is primarily used for single value properties. When matched against an array of values # a match is true if the `is` value matches any of the values in the `should` array. When the `is` value # is also an array, the matching is performed against the entire array as the `is` value. # * `:all` # : This is primarily used for multi-valued properties. When matched against an array of # `should` values, the size of `is` and `should` must be the same, and all values in `is` must match # a value in `should`. # # @note The semantics of these modes are implemented by the method {#insync?}. That method is the default # implementation and it has a backwards compatible behavior that imposes additional constraints # on what constitutes a positive match. A derived property may override that method. # @return [Symbol] (:first) the mode in which matching is performed # @see #insync? # @dsl type # @api public # def array_matching @array_matching ||= :first end # @comment This is documented as an attribute - see the {array_matching} method. # def array_matching=(value) value = value.intern if value.is_a?(String) raise ArgumentError, "Supported values for Property#array_matching are 'first' and 'all'" unless [:first, :all].include?(value) @array_matching = value end end # Looks up a value's name among valid values, to enable option lookup with result as a key. # @param name [Object] the parameter value to match against valid values (names). # @return {Symbol, Regexp} a value matching predicate # @api private # def self.value_name(name) if value = value_collection.match?(name) value.name end end # Returns the value of the given option (set when a valid value with the given "name" was defined). # @param name [Symbol, Regexp] the valid value predicate as returned by {value_name} # @param option [Symbol] the name of the wanted option # @return [Object] value of the option # @raise [NoMethodError] if the option is not supported # @todo Guessing on result of passing a non supported option (it performs send(option)). # @api private # def self.value_option(name, option) if value = value_collection.value(name) value.send(option) end end # Defines a new valid value for this property. # A valid value is specified as a literal (typically a Symbol), but can also be # specified with a Regexp. # # @param name [Symbol, Regexp] a valid literal value, or a regexp that matches a value # @param options [Hash] a hash with options # @option options [Symbol] :event The event that should be emitted when this value is set. # @todo Option :event original comment says "event should be returned...", is "returned" the correct word # to use? # @option options [Symbol] :call When to call any associated block. The default value is `:instead` which # means that the block should be called instead of the provider. In earlier versions (before 20081031) it # was possible to specify a value of `:before` or `:after` for the purpose of calling # both the block and the provider. Use of these deprecated options will now raise an exception later # in the process when the _is_ value is set (see #set). # @option options [Symbol] :invalidate_refreshes Indicates a change on this property should invalidate and # remove any scheduled refreshes (from notify or subscribe) targeted at the same resource. For example, if # a change in this property takes into account any changes that a scheduled refresh would have performed, # then the scheduled refresh would be deleted. # @option options [Object] any Any other option is treated as a call to a setter having the given # option name (e.g. `:required_features` calls `required_features=` with the option's value as an # argument). # @todo The original documentation states that the option `:method` will set the name of the generated # setter method, but this is not implemented. Is the documentatin or the implementation in error? # (The implementation is in Puppet::Parameter::ValueCollection#new_value). # @todo verify that the use of :before and :after have been deprecated (or rather - never worked, and # was never in use. (This means, that the option :call could be removed since calls are always :instead). # # @dsl type # @api public def self.newvalue(name, options = {}, &block) value = value_collection.newvalue(name, options, &block) define_method(value.method, &value.block) if value.method and value.block value end # Calls the provider setter method for this property with the given value as argument. # @return [Object] what the provider returns when calling a setter for this property's name # @raise [Puppet::Error] when the provider can not handle this property. # @see #set # @api private # def call_provider(value) method = self.class.name.to_s + "=" unless provider.respond_to? method self.fail "The #{provider.class.name} provider can not handle attribute #{self.class.name}" end provider.send(method, value) end # Sets the value of this property to the given value by calling the dynamically created setter method associated with the "valid value" referenced by the given name. # @param name [Symbol, Regexp] a valid value "name" as returned by {value_name} # @param value [Object] the value to set as the value of the property # @raise [Puppet::DevError] if there was no method to call # @raise [Puppet::Error] if there were problems setting the value # @raise [Puppet::ResourceError] if there was a problem setting the value and it was not raised # as a Puppet::Error. The original exception is wrapped and logged. # @todo The check for a valid value option called `:method` does not seem to be fully supported # as it seems that this option is never consulted when the method is dynamically created. Needs to # be investigated. (Bug, or documentation needs to be changed). # @see #set # @api private # def call_valuemethod(name, value) if method = self.class.value_option(name, :method) and self.respond_to?(method) begin self.send(method) rescue Puppet::Error raise rescue => detail error = Puppet::ResourceError.new("Could not set '#{value}' on #{self.class.name}: #{detail}", @resource.line, @resource.file, detail) error.set_backtrace detail.backtrace Puppet.log_exception(detail, error.message) raise error end elsif block = self.class.value_option(name, :block) # FIXME It'd be better here to define a method, so that # the blocks could return values. self.instance_eval(&block) else devfail "Could not find method for value '#{name}'" end end # Formats a message for a property change from the given `current_value` to the given `newvalue`. # @return [String] a message describing the property change. # @note If called with equal values, this is reported as a change. # @raise [Puppet::DevError] if there were issues formatting the message # def change_to_s(current_value, newvalue) begin if current_value == :absent return "defined '#{name}' as #{self.class.format_value_for_display should_to_s(newvalue)}" elsif newvalue == :absent or newvalue == [:absent] return "undefined '#{name}' from #{self.class.format_value_for_display is_to_s(current_value)}" else return "#{name} changed #{self.class.format_value_for_display is_to_s(current_value)} to #{self.class.format_value_for_display should_to_s(newvalue)}" end rescue Puppet::Error, Puppet::DevError raise rescue => detail message = "Could not convert change '#{name}' to string: #{detail}" Puppet.log_exception(detail, message) raise Puppet::DevError, message, detail.backtrace end end # Produces the name of the event to use to describe a change of this property's value. # The produced event name is either the event name configured for this property, or a generic # event based on the name of the property with suffix `_changed`, or if the property is # `:ensure`, the name of the resource type and one of the suffixes `_created`, `_removed`, or `_changed`. # @return [String] the name of the event that describes the change # def event_name value = self.should event_name = self.class.value_option(value, :event) and return event_name name == :ensure or return (name.to_s + "_changed").to_sym return (resource.type.to_s + case value when :present; "_created" when :absent; "_removed" else "_changed" end).to_sym end # Produces an event describing a change of this property. # In addition to the event attributes set by the resource type, this method adds: # # * `:name` - the event_name # * `:desired_value` - a.k.a _should_ or _wanted value_ # * `:property` - reference to this property # * `:source_description` - the _path_ (?? See todo) # * `:invalidate_refreshes` - if scheduled refreshes should be invalidated # # @todo What is the intent of this method? What is the meaning of the :source_description passed in the # options to the created event? # @return [Puppet::Transaction::Event] the created event # @see Puppet::Type#event def event attrs = { :name => event_name, :desired_value => should, :property => self, :source_description => path } if should and value = self.class.value_collection.match?(should) attrs[:invalidate_refreshes] = true if value.invalidate_refreshes end resource.event attrs end # @todo What is this? # What is this used for? attr_reader :shadow # Initializes a Property the same way as a Parameter and handles the special case when a property is shadowing a meta-parameter. # @todo There is some special initialization when a property is not a metaparameter but # Puppet::Type.metaparamclass(for this class's name) is not nil - if that is the case a # setup_shadow is performed for that class. # # @param hash [Hash] options passed to the super initializer {Puppet::Parameter#initialize} # @note New properties of a type should be created via the DSL method {Puppet::Type.newproperty}. # @see Puppet::Parameter#initialize description of Parameter initialize options. # @api private def initialize(hash = {}) super if ! self.metaparam? and klass = Puppet::Type.metaparamclass(self.class.name) setup_shadow(klass) end end # Determines whether the property is in-sync or not in a way that is protected against missing value. # @note If the wanted value _(should)_ is not defined or is set to a non-true value then this is # a state that can not be fixed and the property is reported to be in sync. # @return [Boolean] the protected result of `true` or the result of calling {#insync?}. # # @api private # @note Do not override this method. # def safe_insync?(is) # If there is no @should value, consider the property to be in sync. return true unless @should # Otherwise delegate to the (possibly derived) insync? method. insync?(is) end # Protects against override of the {#safe_insync?} method. # @raise [RuntimeError] if the added method is `:safe_insync?` # @api private # def self.method_added(sym) raise "Puppet::Property#safe_insync? shouldn't be overridden; please override insync? instead" if sym == :safe_insync? end # Checks if the current _(is)_ value is in sync with the wanted _(should)_ value. # The check if the two values are in sync is controlled by the result of {#match_all?} which # specifies a match of `:first` or `:all`). The matching of the _is_ value against the entire _should_ value # or each of the _should_ values (as controlled by {#match_all?} is performed by {#property_matches?}. # # A derived property typically only needs to override the {#property_matches?} method, but may also # override this method if there is a need to have more control over the array matching logic. # # @note The array matching logic in this method contains backwards compatible logic that performs the # comparison in `:all` mode by checking equality and equality of _is_ against _should_ converted to array of String, # and that the lengths are equal, and in `:first` mode by checking if one of the _should_ values # is included in the _is_ values. This means that the _is_ value needs to be carefully arranged to # match the _should_. # @todo The implementation should really do return is.zip(@should).all? {|a, b| property_matches?(a, b) } # instead of using equality check and then check against an array with converted strings. # @param is [Object] The current _(is)_ value to check if it is in sync with the wanted _(should)_ value(s) # @return [Boolean] whether the values are in sync or not. # @raise [Puppet::DevError] if wanted value _(should)_ is not an array. # @api public # def insync?(is) self.devfail "#{self.class.name}'s should is not array" unless @should.is_a?(Array) # an empty array is analogous to no should values return true if @should.empty? # Look for a matching value, either for all the @should values, or any of # them, depending on the configuration of this property. if match_all? then # Emulate Array#== using our own comparison function. # A non-array was not equal to an array, which @should always is. return false unless is.is_a? Array # If they were different lengths, they are not equal. return false unless is.length == @should.length # Finally, are all the elements equal? In order to preserve the # behaviour of previous 2.7.x releases, we need to impose some fun rules # on "equality" here. # # Specifically, we need to implement *this* comparison: the two arrays # are identical if the is values are == the should values, or if the is # values are == the should values, stringified. # # This does mean that property equality is not commutative, and will not # work unless the `is` value is carefully arranged to match the should. return (is == @should or is == @should.map(&:to_s)) # When we stop being idiots about this, and actually have meaningful # semantics, this version is the thing we actually want to do. # # return is.zip(@should).all? {|a, b| property_matches?(a, b) } else return @should.any? {|want| property_matches?(is, want) } end end # Checks if the given current and desired values are equal. # This default implementation performs this check in a backwards compatible way where # the equality of the two values is checked, and then the equality of current with desired # converted to a string. # # A derived implementation may override this method to perform a property specific equality check. # # The intent of this method is to provide an equality check suitable for checking if the property # value is in sync or not. It is typically called from {#insync?}. # def property_matches?(current, desired) # This preserves the older Puppet behaviour of doing raw and string # equality comparisons for all equality. I am not clear this is globally # desirable, but at least it is not a breaking change. --daniel 2011-11-11 current == desired or current == desired.to_s end # Produces a pretty printing string for the given value. # This default implementation simply returns the given argument. A derived implementation # may perform property specific pretty printing when the _is_ and _should_ values are not # already in suitable form. # @return [String] a pretty printing string def is_to_s(currentvalue) currentvalue end # Emits a log message at the log level specified for the associated resource. # The log entry is associated with this property. # @param msg [String] the message to log # @return [void] # def log(msg) Puppet::Util::Log.create( :level => resource[:loglevel], :message => msg, :source => self ) end # @return [Boolean] whether the {array_matching} mode is set to `:all` or not def match_all? self.class.array_matching == :all end # (see Puppet::Parameter#munge) # If this property is a meta-parameter shadow, the shadow's munge is also called. # @todo Incomprehensible ! The concept of "meta-parameter-shadowing" needs to be explained. # def munge(value) self.shadow.munge(value) if self.shadow super end # @return [Symbol] the name of the property as stated when the property was created. # @note A property class (just like a parameter class) describes one specific property and # can only be used once within one type's inheritance chain. def name self.class.name end # @return [Boolean] whether this property is in noop mode or not. # Returns whether this property is in noop mode or not; if a difference between the # _is_ and _should_ values should be acted on or not. # The noop mode is a transitive setting. The mode is checked in this property, then in # the _associated resource_ and finally in Puppet[:noop]. # @todo This logic is different than Parameter#noop in that the resource noop mode overrides # the property's mode - in parameter it is the other way around. Bug or feature? # def noop # This is only here to make testing easier. if @resource.respond_to?(:noop?) @resource.noop? else if defined?(@noop) @noop else Puppet[:noop] end end end # Retrieves the current value _(is)_ of this property from the provider. # This implementation performs this operation by calling a provider method with the # same name as this property (i.e. if the property name is 'gid', a call to the # 'provider.gid' is expected to return the current value. # @return [Object] what the provider returns as the current value of the property # def retrieve provider.send(self.class.name) end # Sets the current _(is)_ value of this property. # The value is set using the provider's setter method for this property ({#call_provider}) if nothing # else has been specified. If the _valid value_ for the given value defines a `:call` option with the # value `:instead`, the # value is set with {#call_valuemethod} which invokes a block specified for the valid value. # # @note In older versions (before 20081031) it was possible to specify the call types `:before` and `:after` # which had the effect that both the provider method and the _valid value_ block were called. # This is no longer supported. # # @param value [Object] the value to set as the value of this property # @return [Object] returns what {#call_valuemethod} or {#call_provider} returns # @raise [Puppet::Error] when the provider setter should be used but there is no provider set in the _associated # resource_ # @raise [Puppet::DevError] when a deprecated call form was specified (e.g. `:before` or `:after`). # @api public # def set(value) # Set a name for looking up associated options like the event. name = self.class.value_name(value) call = self.class.value_option(name, :call) || :none if call == :instead call_valuemethod(name, value) elsif call == :none # They haven't provided a block, and our parent does not have # a provider, so we have no idea how to handle this. self.fail "#{self.class.name} cannot handle values of type #{value.inspect}" unless @resource.provider call_provider(value) else # LAK:NOTE 20081031 This is a change in behaviour -- you could # previously specify :call => [;before|:after], which would call # the setter *in addition to* the block. I'm convinced this # was never used, and it makes things unecessarily complicated. # If you want to specify a block and still call the setter, then # do so in the block. devfail "Cannot use obsolete :call value '#{call}' for property '#{self.class.name}'" end end # Sets up a shadow property for a shadowing meta-parameter. # This construct allows the creation of a property with the # same name as a meta-parameter. The metaparam will only be stored as a shadow. # @param klass [Class<inherits Puppet::Parameter>] the class of the shadowed meta-parameter # @return [Puppet::Parameter] an instance of the given class (a parameter or property) # def setup_shadow(klass) @shadow = klass.new(:resource => self.resource) end # Returns the wanted _(should)_ value of this property. # If the _array matching mode_ {#match_all?} is true, an array of the wanted values in unmunged format # is returned, else the first value in the array of wanted values in unmunged format is returned. # @return [Array<Object>, Object, nil] Array of values if {#match_all?} else a single value, or nil if there are no # wanted values. # @raise [Puppet::DevError] if the wanted value is non nil and not an array # # @note This method will potentially return different values than the original values as they are # converted via munging/unmunging. If the original values are wanted, call {#shouldorig}. # # @see #shouldorig # @api public # def should return nil unless defined?(@should) self.devfail "should for #{self.class.name} on #{resource.name} is not an array" unless @should.is_a?(Array) if match_all? return @should.collect { |val| self.unmunge(val) } else return self.unmunge(@should[0]) end end # Sets the wanted _(should)_ value of this property. # If the given value is not already an Array, it will be wrapped in one before being set. # This method also sets the cached original _should_ values returned by {#shouldorig}. # # @param values [Array<Object>, Object] the value(s) to set as the wanted value(s) # @raise [StandardError] when validation of a value fails (see {#validate}). # @api public # def should=(values) values = [values] unless values.is_a?(Array) @shouldorig = values values.each { |val| validate(val) } @should = values.collect { |val| self.munge(val) } end # Formats the given newvalue (following _should_ type conventions) for inclusion in a string describing a change. # @return [String] Returns the given newvalue in string form with space separated entries if it is an array. # @see #change_to_s # def should_to_s(newvalue) [newvalue].flatten.join(" ") end # Synchronizes the current value _(is)_ and the wanted value _(should)_ by calling {#set}. # @raise [Puppet::DevError] if {#should} is nil # @todo The implementation of this method is somewhat inefficient as it computes the should # array twice. def sync devfail "Got a nil value for should" unless should set(should) end # Asserts that the given value is valid. # If the developer uses a 'validate' hook, this method will get overridden. # @raise [Exception] if the value is invalid, or value can not be handled. # @return [void] # @api private # def unsafe_validate(value) super validate_features_per_value(value) end # Asserts that all required provider features are present for the given property value. # @raise [ArgumentError] if a required feature is not present # @return [void] # @api private # def validate_features_per_value(value) if features = self.class.value_option(self.class.value_name(value), :required_features) features = Array(features) needed_features = features.collect { |f| f.to_s }.join(", ") raise ArgumentError, "Provider must have features '#{needed_features}' to set '#{self.class.name}' to '#{value}'" unless provider.satisfies?(features) end end # @return [Object, nil] Returns the wanted _(should)_ value of this property. def value self.should end # (see #should=) def value=(values) self.should = values end end