From 593ebdd59e3bba048c2e348f6ba8cc357081cb7e Mon Sep 17 00:00:00 2001 From: "yolanda.robla@canonical.com" <> Date: Mon, 31 Mar 2014 10:35:19 +0200 Subject: [PATCH] added postgresql support --- .../charmhelpers/contrib/openstack/context.py | 32 ++++- hooks/keystone_context.pyc | Bin 0 -> 4240 bytes hooks/keystone_hooks.py | 38 ++++++ hooks/keystone_hooks.pyc | Bin 0 -> 9520 bytes hooks/keystone_ssl.py | 2 - hooks/keystone_ssl.pyc | Bin 0 -> 11714 bytes hooks/keystone_utils.py | 2 + hooks/keystone_utils.pyc | Bin 0 -> 24196 bytes hooks/lib/apache_utils.py | 8 +- hooks/lib/cluster_utils.py | 12 +- hooks/lib/haproxy_utils.py | 6 +- hooks/lib/unison.py | 15 +-- hooks/lib/utils.py | 55 +++----- hooks/pgsql-db-relation-changed | 1 + hooks/pgsql-db-relation-joined | 1 + metadata.yaml | 2 + revision | 2 +- templates/essex/keystone.conf | 2 +- templates/folsom/keystone.conf | 2 +- templates/grizzly/keystone.conf | 2 +- templates/havana/keystone.conf | 2 +- unit_tests/__init__.py | 0 unit_tests/test_keystone_hooks.py | 120 ++++++++++++++++++ unit_tests/test_utils.py | 119 +++++++++++++++++ 24 files changed, 354 insertions(+), 69 deletions(-) create mode 100644 hooks/keystone_context.pyc create mode 100644 hooks/keystone_hooks.pyc create mode 100644 hooks/keystone_ssl.pyc create mode 100644 hooks/keystone_utils.pyc create mode 120000 hooks/pgsql-db-relation-changed create mode 120000 hooks/pgsql-db-relation-joined create mode 100644 unit_tests/__init__.py create mode 100644 unit_tests/test_keystone_hooks.py create mode 100644 unit_tests/test_utils.py diff --git a/hooks/charmhelpers/contrib/openstack/context.py b/hooks/charmhelpers/contrib/openstack/context.py index d254de18..e4ad6c2a 100644 --- a/hooks/charmhelpers/contrib/openstack/context.py +++ b/hooks/charmhelpers/contrib/openstack/context.py @@ -147,7 +147,8 @@ class SharedDBContext(OSContextGenerator): 'database_host': rdata.get('db_host'), 'database': self.database, 'database_user': self.user, - 'database_password': rdata.get(password_setting) + 'database_password': rdata.get(password_setting), + 'database_type': 'mysql', } if context_complete(ctxt): db_ssl(rdata, ctxt, self.ssl_dir) @@ -155,6 +156,35 @@ class SharedDBContext(OSContextGenerator): return {} +class PostgresqlDBContext(OSContextGenerator): + interfaces = ['pgsql-db'] + + def __init__(self, database=None): + self.database = database + + def __call__(self): + self.database = self.database or config('database') + if self.database is None: + log('Could not generate postgresql_db context. ' + 'Missing required charm config options. ' + '(database name)') + raise OSContextError + ctxt = {} + + for rid in relation_ids(self.interfaces[0]): + for unit in related_units(rid): + ctxt = { + 'database_host': relation_get('host', rid=rid, unit=unit), + 'database': self.database, + 'database_user': relation_get('user', rid=rid, unit=unit), + 'database_password': relation_get('password', rid=rid, unit=unit), + 'database_type': 'postgresql', + } + if context_complete(ctxt): + return ctxt + return {} + + def db_ssl(rdata, ctxt, ssl_dir): if 'ssl_ca' in rdata and ssl_dir: ca_path = os.path.join(ssl_dir, 'db-client.ca') diff --git a/hooks/keystone_context.pyc b/hooks/keystone_context.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f88afe16f2cbb7d4aebd35003607d54228e96c59 GIT binary patch literal 4240 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 literal 0 HcmV?d00001 diff --git a/hooks/keystone_ssl.py b/hooks/keystone_ssl.py index 1cbdfad7..45e0029d 100644 --- a/hooks/keystone_ssl.py +++ b/hooks/keystone_ssl.py @@ -1,12 +1,10 @@ #!/usr/bin/python -import base64 import os import shutil import subprocess import tarfile import tempfile -import zipfile CA_EXPIRY = '365' ORG_NAME = 'Ubuntu' diff --git a/hooks/keystone_ssl.pyc b/hooks/keystone_ssl.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bcdbbf62d7826da464cacbb152502ae1d7d50872 GIT binary patch literal 11714 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 literal 0 HcmV?d00001 diff --git a/hooks/keystone_utils.py b/hooks/keystone_utils.py index 54f0d00e..efc97407 100644 --- a/hooks/keystone_utils.py +++ b/hooks/keystone_utils.py @@ -64,6 +64,7 @@ BASE_PACKAGES = [ 'openssl', 'python-keystoneclient', 'python-mysqldb', + 'python-psycopg2', 'pwgen', 'unison', 'uuid', @@ -98,6 +99,7 @@ BASE_RESOURCE_MAP = OrderedDict([ 'services': BASE_SERVICES, 'contexts': [keystone_context.KeystoneContext(), context.SharedDBContext(ssl_dir=KEYSTONE_CONF_DIR), + context.PostgresqlDBContext(), context.SyslogContext(), keystone_context.HAProxyContext()], }), diff --git a/hooks/keystone_utils.pyc b/hooks/keystone_utils.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec566613d27ae489f13bc4bcd66cd59de9d6bd37 GIT binary patch literal 24196 zcmc(HdvILWdEePx5FkK2_yh%!lCB<z_`Wy1(D=yZ7z_q^v%mDak!N_uTXR&iDS#xrIL-8TyF#Lb2+SKZE%HW&EP?ea;2= zmveRJN?AVVO1ZQ=?@IYJUvQ;@@_AS9bB%qjw9n<(zToQpt})ib<|(3J-5 zd7rBfxyAukI^Y_^t~Bf#Bd#>!8l$c>YBl;@eatluy3#?{IOIx)taQND54*+@S32Sv zM_uWtYaDZ>W3DmoO5?6^+?DRLdYJ!&Tf5(_op7ZSn&Ey|Kj|6|xY7fz@t`X`=o$~X z(nGG{xsvA^54+OCuJMQ~J!0(#UHwtlc+8a^bB$B3bjmdzccsVe-H@w4;Tn^!H0c^o zy3&)b@suk)W$zBS`f1lV<4R{-W6G7Lve`_#(sT;78CUv<3$W~`T`=N;Q5TH4;Ghc* zx!|x1j=12c3y!%JKwiEc_ELz`{T2f=6BHWfx%4 zvo64*&%1Dd{cz-GUGO-@oOWw-?v8WeLAQ3n1y8u}c|7L$IG>ikq6})j%FN0>7fiad z%jn}p^@OT=!M>~pun9E)1}v1Lu}h1diZK5K=5G@F0a3ZJvWvsU;qD}3Gx0d>{{ z*xCFAD+Ksi2>7$`B`d@Zun=3o!k4WOo4~^JRyb>gb5;o0v*x@NzG8*1TH$L}h*h)s zr>yXG;K=JPxa8giSzmI&Wo0hAU_qG$7c45X=z=TCTyeo0%DmwMUzy`BC@SN-;Hol3 z7hF^3stZ2tg6r;GVB9qqys1KzVB6kO;hQcfsqifqd`6j)3*J`dGpdG~H{82mEpNNv zvns#gg0eE7b;0M9DZ8Me%;#JPFfOU*iVLbLTyjC6Ow|RUGJ#vcVndP;|1GQkWf!dI z?MgcCs>)YgP*Zu$1#8NzxnNzHb=E9Sf+4!v_wi?8GKXwTp1E}Pxv*Jn1)&ukK+$45 z2-{(Bp;nEpa6bxzFx;rNHnu1G*m4X>Sg)|uHCG} z7<(fo$Sy9tvN*|ZVuHAWVUne2(R}V~1gM|A?rf~I0at57&_!YUX03`@#;uKbWJf_I zf%C?#m9S}GvKehcT&b>?MNQ@9Hi@PgMCbl*TN)Syrn|tf)>-S6vF9^_ z^|hr=GwyhE^;RbkzP7`tydITr0=bEas-1#ao0+a%_=A4RL9MM938_am?M?*nx2hG4 zvs!6~Gu6se6|AJTT&sc>qHH(H8lhS#^X+sM=x%JIvC#p^h$U@rgwavVWubMm;?1@6 z#w!}ls74S*Rb`r}AuPPvs&^V;bR=!{X+5WnA`&X=P9^n-{&Te^c%8Sirf~|r5vK^N z&qT*jd4BF0%>?XXsaCJW+uo(hHWom>R%=vNY{IYBE6r-?U1UKzwt8IAiMfOcmy_~r2r{N> z_FnkaYJ)FDaa(*h8b^iK!U`7FTkOqVxv1@3#VhgjD$#Yh)oxfb?ueQRjbBO2*)HM) z*>0-3+^iz+C?5&(swinsyLUhX`^ehxm}`!t&jWhK z%c7Wa1ZnPuJp8$^4Y>pyuh+Ldz%RtgLa*XADjQyF*#mV+vPE9Jie=ua)$86;h__Ab zU*KU$s2c&6^-#U7wp#06xD{4A6pPa;>$1O;p^)iy`N<@g>`MY4Lhk%*alY)&7Zy+~UG30($cN%yTL-{ekQ{ zT~irroW!$J5}ikGW)-L~v)ux^2bGxs!l~ZcXh5vYY_!8_EebO>fSRrK9VQ!+$fL)RS z64G5hp6DO`<0zdZVfh4<&y9%>B3UfXN&E1@<)JUNrRZFpzkKD=?A7_A)~q53iZ*_Y zNDQ_eu3(eGwkc}tHq~>OClb_FYzrZFw7u=98twU(Xa(t9powYNZ(#=FR4zB18_Nym zPUh~jO(G&v-_j<%j0`pj)IyTO9^{!`xbe95z&Y#>V2wSTXdmI0B@eK=KAU%&M@V!= za0~up=t?S-Pl^`I{8w1U0sT)Q!4S^f-23&DIDqsqbTi`oKgDCj6}nu1Zo(GLkqh`~ z(VRhsnap6(Iky6g(;PvML{2fBqE-~WfEKe+6gHq9conaXZ725tKl7wGiBY72*t>-~ z?SzSt4U^6GXj!{eDgzqzI^hUA7u`e0HKHa-X_&nS9kscDVnLRK2KhFMB2u!;17ip{ z{)=FXu_`} zL;QB`IQDmIdKacYAWVm_(XK<-fZGt?vH!Wv``vZy3ABhFgy1*{wiC(3d(M-mgFU}K z`)a~2g!&05r|#%4qON}hiJ2LkK5T$>swSd~b^kJ7; z%D#sT0G^1>93c0P}An73N71b5KQKiev2d*NOWqYN9>&ntXU6 zqCCwc?^LS|*F`gW6ops9HdRFGxQj4zi?p!3#P;^$mUk+e7D`S{LE(XR6+MJT7dF;c z&YfGdf^+9ynwml%)o_Ypt{L9?z&b&=EIyQUDT83S0>_4UZ2(^DzlmY|IV6+h!M+kM z#V2$0>ACTVTRxRxwYu8wgg$Z8htu1<4B*w7lY=d8QB5dA>GTU}mAOmTidW}-s(zB# zjT*cTs03F;WvLQ{(jxqetWHG0;>uCGDjSe_^P)%#2>_Ea7PR+BDvAqQ=p2@YEZ}5+ zeit*6=|Od3I5!HeF;M8w4d*9vCkqF2L;2w@2gx+R>s*V_m|7nZIF}>(iizaFLV%-q z0PX=b;rk``kg{*wHb>00y1?5tU@K4+I1i*PPEw{u^GN(oGx9QCV2V4jsRqwbtx~Uj zKJ+Rc0O+M~_Mp=zu!klO1fYoa(9>mY2+=cM4YMw@cGJS0I(24KI!UroCum9XOm%iL zC7XzLGFU1{+s$f?Q(iD*K$t~i*r%zaJ&rm{a06At$h>#3!r*^^mknmOPj`keFRsCo zBYdMeoP?$w5W%VqxV-U4$zEytE9mfl;%5vik6rFNmK(_pb$6N&AmNA#!L8OXO>ir5 zDD0H|!>(dK6Ge*lo#%&fr;S}Bn6LSlq&zV%_k;&w2~Sh48GB3H^bB!BQa29V8(u`$ z79BI^X3U|n3ft-27jDnod}jJ1Gxrc9CU7aM$$l!a&uL2(7ywD|8oG?3HS(UrQc{?% z(w*asKNn(xmY%WI1l=<1_5;x=az;UC}uPy~$E3$Fc;$Vyr(IWv^>=1-|8p%z(M zP-V~|_MrU^Z71Z%DL&ATH3S}^3?vAn>c=KzZGre;SA+G#npU^hL7Q*9*?gW-0yIhj zbU6%{v>jC2``qn5_fB6bFmfiDtSN+($%P2>bj2|CqzHpR;mq?Y)oQC9h~ipa5N_04 z+cZW!vtdZ6orvVyhPm2m)VF1B!=_K|_#o-0w(KeK^} zPwZ_#?FF?l9ALW*I~PQi;NwDc3QfATm*IrHyK=1w)KyH!2XM_eN;Q1*Tv0nB;<4|@ zux|tF^?wNEK1HPY3*KdGPO|>t;1rp0&r(lgsOT_;bA5-Ql1~7iPT(j10mTIwamI}Q z4jzC*z>qq)r13u4Mv#2K1~OYPV)JkHxhQgK5;5~!rReRG%YrjOr#tmx*&Hag9r=~(h^{#aSp@Bz*4wK%C; zrg^nx=B4cYvi!Mi|0eqJVViP;miVc-XjMbXhTSnouFn@g>G9>1 z74;zhY~6yJ+5ZU+BQo4CD?bcveFlc+Xl_5O{C;rB zDyK-k&L6QMx{3x}d^W6nKYX^gz;zg8z59jUOL_($P0)Rbk#fUil)%eqM(&WiJ?OS@U_v+zt8}FxALVV>r|5FXO#ox= zfXI-ee)JwqR5aOqkN>W}Gw9miBe@pYJ8Hs+Am!PF5kf$>!->ad$!#v7MfMiwZA5(} zG8xYxFVYo+00t-b-6|&5?8&GB5POEa3C*QyrkA>`d)Fv&DCwXdeB3m$b z{x2KUoGzVqT`WMHln=xysP19AS*hbWqV98z(RNPt?sea)#j7Id>=heLgO8${AezR1 zy=0%&+5x!UxlPKlBI)^GX3`~iGIvHs>O6gr0mJ`E6l+0g-;sIheu}NtS(P;iGwJRo zvRjGPGG|9R%V!sHj2Xi`6ioR~tWHHI6q{W=>ExO4=B z{#&T9_pE{jWWp-ab(T{YUL?CXg9=oq$S%gfFg&n|Q5YrTP^Cuje_vrJ_h6n3gnz+A z$k-?t2?H^aZz9uWB63)*y&n^SvmL|=Rcg0Hlw&KAh%Y53$uLX@Fax$A)gP3n7DNax z!Wcx=tq-{N*Lu1GH5FXCWI?|@QdPSb&0rOtK`H{Z!gGuGEJ?B!|6obj zB{%=a(1!@YT9+j){t^o1AxQCgY1{i0BL8C4X&FVEH97}1N^!-jHUr`KPP&{n<^LYI zZb(ga#X9RnX(Fod+T2Z?Ygbam{@=v&-lHE~p9%WejDQ(VM+j08HJN(~;%NY4sxMb9 zpgLzyz9roH6J)x$1(zob)%U}#LV_uG;g;!XrfmVYB*=PjYoFnkYVE|W-`04hSiuD= z6)pO!l2phiGO8)`Oa>j=t&>4w5Z!28_tAq2Aq3pRbFa8y`S4DhB;X=~pa&;mrnY-9 zviSsT>R#3Cj8`G*HV~{rMMS9#_rq4t z;e-Tjp|pItV5%g@6ovshCi$U*0^G^e)Ck0A7D*4GwOa`Gc3J;jgf>n494GQTRWt_@ zC{w3CcZma?=j$Z^H6a0rG-j;}3W|GTz1cr^QR!z+MQ0!<_`5O5u*(l74361D7+vg_ zsg#lk(GMiMql_(4=F{+%A5G*V)kPpEvw~n~!jFmp`|^h11dv+;FN+4tKsMybRVps{{e_DxD#Yt zfljCu{fxAt|J>8Tut*RNU$llFO0>a9AEznZXy-JW$K@TCj?TdN(~pr_uCP5)MrQB7*UG?vCYP!X#ahK>S}peREf$hA=96D(wQ~^1(gG zjJTE!lnTpLh{^XGbdrMip42qP7xc#azr;ioK^wwwdlWhL8I|GdD06E5UqO-12vmYV zB|XH#rTM?gq)RB@oPX%@i^+l^X$ zF^ODb@68L)FN{QJ0<{#N0BHb^F$6mhona_?&Hjs;3ag=Zp@KSq(gpp>F3~VFj$jD9 zu|pCq>15I69YsE%0+2GsG#XkRB#oN*(tdJ<>Ketoi-V=+A?QZ6s`LeBnxnWu-NT$l z)`-<1dhiZ6c{e4hZ#j&#eX4`F}s7Sb?C{eHbf z2nzL+H(Rf({}X((hErS)9OPrvi4g$C9U!nB+yP>D53&aC0D<`go=P582|VHOfy4K) z`HynfaU-ZW`6!Sf`XwNOH{XolnzryBe95&2&bOKaJBmBY%jUp{;JNm0;mjrCsqHMr z>fH*TXxm9kp55#)_-El8K3-i#fCruqxx`n)`UYAqcbZkX2x*~J5pYKhp1lfbw?QW3 zFlQ~GZyhWJigGi^{3z{C(+eyLl-v)X;(RN_2~hl>ya|@3s;iYI&Vo)SM#M}&blZ{}i~Xjq;915ubj~3yDcVBy z!Xo>W_`n*7sCZl9=CrDJF)2-tP)Ad!D#dPxgNvT-?D9<(uF>IWd7g2aU#BUumN;yI z6S?g!V#trQ!|5!uiYzzT7~T0%Y(Cv79^aF|sC44ha%P6i@hZLmEDQWQ~99{=yL>?jhu zcw=HP!=QhN7yi#Op-}M;Gx-rDagWz(J&DtHL-eXke3Y?f2;@g>`)f@8ITQNg_FPPX^P5M53|@ zM@3Qu`>0?=@QCfMh2vm&5B83>skL;+F6I^$$g`laZo)i-i6DkA%}oW}Xi>`0e45~L zbe)QDKm*CCNGCHyS#}hURScoNhMd_A+O%);g?8@OndA0}DdAvD+!9im+qq0vGeIQ& zpeGVW>Ud_so^QMVn;7B0a*K(e4%^Gk8^mVvFSd<7YZ^XW-5h?=PavT!4$m=E3IG{; zi?$5_$1VmqpOJ+Lp^IP(us5kmjJlbXAcq&aS>Ny40SzebRZbqT1nvcCm3%pdSIN9nDoa2d+9}rENTbi5jp; zemEZ06zzdtXuAlSkaJsS341#Z#mGG23Kk4H1^MX=BWR9928ssRlA`mu&1Z049Iaqh zsB4{!-3OZE_|daSJUe8F8)eNY96nvoRKpZ=p*FWXULW-cTwWqm46S=MF>A=nrd?9H zs~u)w7d6Qzzi>O*ByHeL#OA^U3m4vG%L483q0pUg})C&!gNv zR%*hx(}b8`H{Sjq`G!HP59v5NM=nDp*3sEa6QZt3Oc*C7P!u>^OCookKqRY5!Xq>? z&U_sYnEf5lDX0s`U}T34rYzK^8oy4ME>2;9k80QN;QSkq0A>|-9eWQdv%NP)oQTY5 z2hja(j8}UZiT~S7{u2_TsqgWTaP&_w5qG1aD*)TMMf&y9b*9YB{P4VT487<>qPC+L zmxpB1u~P)~y2LgB{f1f#)8ter8ab|g4!;P{BbcG9fJ#81fOQc7P81iC2y~gx3AQ2^ z80d7~qC}B-$TA2rh%b;FzxJTB>M*(?`58vp{G7BN9x&vNNADt$9do`7CQ+^6icT_j z`gEnYBWjzHSH#nWIA<8)S}N?x7EV6t2H+}gr^9Fr&9qxey8@*lU`M(e zQ>6=m=!ci;%|Kg_x3-8AzpJ=6T>CsL&dtgUgK5bwaL)ZWCMykUDw*R{sz614m0+Wg zh;hzbH~n;-T-wcY1-J0&HBGDw(K9a%M&>8uE0~f?SdZOM_>2o8glV)7 zT!c|T_@ywXar+EOE~$nf2CBhJwDToq2}e^VVz5&9r*IwX5SAVN86={Ei@Q(20}Jim zvWKV!T?BA}_C_^`_Be!%Pay<`%5u2K;Q3WTXE?N(<)1{*Gz;)=~EGoUGWN97}PKb_8E~-aE4YZMqbruPoi2Xm3r$I9K6(!By4dwT}xwFAH8?2VNzFRgG|GM?$VL| zgw6OS&;bF>saolh(q2&!haexXRz6PZIf+NNk80Av+=Eb(hH;{QICrox0d?sClx4z_ z9742o9vPZ3kc{X_zFcGKKz@^zAQrf7K|6`iG$$-RWdo1_`HTEtD_@A{S5Lp{F~ysX zwu5c|pWua#9Q*$Yxi0VoUI|7Mhn!X$p(tAV0v|k$IOM(eaO<6EnKShXKGQ7vXNdNv)NB2_b0WAg*1ZeSjm~m=GQ4rnw`XKwu7GH2|Ua#l!9)%=R`Gha-l=3hOoV*mmSmLdek4)5F9&*pbcq^Vfkrx3PYt z2i(@*;M)r~zUt6_f@oG7-L}7+PnzN-!GkI61P=-l@YpMY2e|}1$R*%GE(On+TRYy{ z6F?H3EhMl?>g|Np=GnsLm-F~{Jplm1E~o(^`N5R%R)Ki6Rp18W{Act<<={IcP8}4E zJi>#ah9eWqvhPDK2I?TZi41V~Q5Gt!0;IvlqUbRe?Rd9^doW!TeCqvBFlnE4x%oSV z>-e15J5Yd6;nu834r2W*`xdQ$P}1TdD;7y1taKKA@hfMTCBC1g7V1_XID1l`c1u4| z_LRd{%Fgm>0{3t;p76K&I84R^?!^+aqW^E1{5vN9o{8+Of5x1gj=#nnWxo_)bDPuiSZ&pHV>2^_l0yIApzf~Q z{r<1BOa@63KcTDL|29iMNa^=~AGJ)6A4N{~0WCau0`Scks`kled2})`iygGXP3ZSL z8qZ({V<)CRr613NwETH?{1qm@z~qmSNFB0kAgAz{^>#0tDLuG)4(b9Nd$ z4{!jQ(Yk)GQECycTjB(-c{94!&tcXg2KarzApZ}M6E2tnRmQiO0<00G<|$!u2K^*N zFMCQM4Qk`P!2-BlYH(f|T7Z$zeH~;04b2OVYu&=p0|Pj6T~fpJ{|6HxY>rd=5+8q$ z34<#N;S1uLDd1N|Jc+QIq;lf(qG5s*4MalABntz#dGjNwQudvjuJ=YuPqj7OQ}zq& zXb@cj6BB6sDhJSx??=v%w%YW+%Hm%{B5PpFE?Rt%g`@1F4>|6$JR*Cqy^+)i-3-@S z86iP^a?yA2-r>q6T^D2d(}jM7Vh$n{GXiy(e*F;yWe~){-@`Z*MEAy#!V##*qj)<2 zy>Aq6SYs%6fbVj{hj~>9fgRKxfpX1L(j$FG@NP7Be^T!d$`~uac<2FVsxjs$u4s(I zgk@d!eQ3X3WaBm45sWmDq`2JHrx|u<2M^a6zUczxU4J?6Dj@6lE8sVWpT2blB?t;B zyj+loJS&aw?Le84eriGyS}6(&rU3S z1J&)zM&x7WY#?3e=Iw`bFUB7S1pbtpOnh|Mj8Onlw_eCXX~+pQ*N_2RV8ToQ7!wv< z(^DQ#GVk#OLBx{|1?Y={5r9dp5elt5e^7stcnekVefG@@j=SJLiPR@%zwea*^O!z{ z>00>nYp85Kc?qklY`cqdtJ5E6J^c36z3v~!Joj{qP#NzK;ke!nS89mZ6q0Q#(Bn;Om$`K7}3O zzaxX)RZo0TeCEtTS2*w{wLKc&BpWrnJBg+4Jpg$xb(8?){_}j{K}3G^B~UYGKaNuW zKJNA=a^kp4l_)&>oCy>nCNzyYJ~YQGZ~BUou}ORjl*XrvA7>SOy{}=1Um{-h1Pqs^ zS1VbGeezSEov@4U5@!@~`d;Tfn`fVU@JS&)=N~`zeq&{or}a%R`#=UAG(J~gAJ(EZ z?0*(Xd;-Zm$4tIU$pMp9`0_o{{k^L}JDjGQ6`y7?AEiXB1UgxX9T;HX0w%_;w#)b^ z<*I$ELuVbvS&PZNMu3S=v7xUm*kx$%?wST~bBZcHW3dn}Q}Q=e*Z3VSeQ1?(J}ZPm z<9{Co{ydXUvk^gceiok(O2RHhzsPrgfys-kKnTGVMNL3w*>_y0r9;;L7pw~kbpG$K z0Y`jo_KLsw=3BaQ>wl83US{$KO#YO~GLt_wE-9N$z+3Ip(AgNk95oK9ZOEUuPoyNDA36^YOb(ev`>> zF!?Pe-(&K7O#X<;e`C@|LLFf8C=&`5u}Gg}-en%j?Uk>Ng!dwxmYsU|2@-t7Nif2K zzxe(J{^lPU7|%}*9L`Sob92KNt- q4~`9w4L*!_N5)Q|?CHS~lnf6J4IUUA=`V~O9~>V0%HY7@(EkFOz2W!( literal 0 HcmV?d00001 diff --git a/hooks/lib/apache_utils.py b/hooks/lib/apache_utils.py index 131f8ac0..3890582c 100644 --- a/hooks/lib/apache_utils.py +++ b/hooks/lib/apache_utils.py @@ -17,8 +17,7 @@ from lib.utils import ( config_get, install, get_host_ip, - restart - ) + restart) from lib.cluster_utils import https import os @@ -136,8 +135,7 @@ def enable_https(port_maps, namespace, cert, key, ca_cert=None): "ext": ext_port, "int": int_port, "namespace": namespace, - "private_address": get_host_ip() - } + "private_address": get_host_ip()} fsite.write(render_template(SITE_TEMPLATE, context)) @@ -160,7 +158,7 @@ def disable_https(port_maps, namespace): juju_log('INFO', 'Ensuring HTTPS disabled for {}'.format(port_maps)) if (not os.path.exists('/etc/apache2') or - not os.path.exists(os.path.join('/etc/apache2/ssl', namespace))): + not os.path.exists(os.path.join('/etc/apache2/ssl', namespace))): return http_restart = False diff --git a/hooks/lib/cluster_utils.py b/hooks/lib/cluster_utils.py index b7d00f8b..1405d6fb 100644 --- a/hooks/lib/cluster_utils.py +++ b/hooks/lib/cluster_utils.py @@ -14,8 +14,7 @@ from lib.utils import ( relation_list, relation_get, get_unit_hostname, - config_get - ) + config_get) import subprocess import os @@ -34,8 +33,7 @@ def is_clustered(): def is_leader(resource): cmd = [ "crm", "resource", - "show", resource - ] + "show", resource] try: status = subprocess.check_output(cmd) except subprocess.CalledProcessError: @@ -91,9 +89,9 @@ def https(): for r_id in relation_ids('identity-service'): for unit in relation_list(r_id): if (relation_get('https_keystone', rid=r_id, unit=unit) and - relation_get('ssl_cert', rid=r_id, unit=unit) and - relation_get('ssl_key', rid=r_id, unit=unit) and - relation_get('ca_cert', rid=r_id, unit=unit)): + relation_get('ssl_cert', rid=r_id, unit=unit) and + relation_get('ssl_key', rid=r_id, unit=unit) and + relation_get('ca_cert', rid=r_id, unit=unit)): return True return False diff --git a/hooks/lib/haproxy_utils.py b/hooks/lib/haproxy_utils.py index 721bb7f2..f14a20c1 100644 --- a/hooks/lib/haproxy_utils.py +++ b/hooks/lib/haproxy_utils.py @@ -14,8 +14,7 @@ from lib.utils import ( relation_get, unit_get, reload, - render_template - ) + render_template) import os HAPROXY_CONF = '/etc/haproxy/haproxy.cfg' @@ -44,8 +43,7 @@ def configure_haproxy(service_ports): unit=unit) context = { 'units': cluster_hosts, - 'service_ports': service_ports - } + 'service_ports': service_ports} with open(HAPROXY_CONF, 'w') as f: f.write(render_template(os.path.basename(HAPROXY_CONF), context)) diff --git a/hooks/lib/unison.py b/hooks/lib/unison.py index 06dd8b4c..fdef449d 100755 --- a/hooks/lib/unison.py +++ b/hooks/lib/unison.py @@ -73,15 +73,14 @@ def get_keypair(user): pub_key = '%s.pub' % priv_key if not os.path.isfile(pub_key): - utils.juju_log('INFO', 'Generatring missing ssh public key @ %s.' % \ + utils.juju_log('INFO', 'Generatring missing ssh public key @ %s.' % pub_key) cmd = ['ssh-keygen', '-y', '-f', priv_key] p = subprocess.check_output(cmd).strip() with open(pub_key, 'wb') as out: out.write(p) subprocess.check_call(['chown', '-R', user, ssh_dir]) - return open(priv_key, 'r').read().strip(), \ - open(pub_key, 'r').read().strip() + return open(priv_key, 'r').read().strip(), open(pub_key, 'r').read().strip() def write_authorized_keys(user, keys): @@ -149,7 +148,7 @@ def ssh_authorized_peers(peer_interface, user, group=None, ensure_local_user=Fal hosts.append(settings['private-address']) else: utils.juju_log('INFO', - 'ssh_authorized_peers(): ssh_pub_key '\ + 'ssh_authorized_peers(): ssh_pub_key ' 'missing for unit %s, skipping.' % unit) write_authorized_keys(user, keys) write_known_hosts(user, hosts) @@ -204,8 +203,7 @@ def sync_to_peers(peer_interface, user, paths=[], verbose=False): hosts.append(settings['private-address']) else: print 'unison sync_to_peers: peer (%s) has not authorized '\ - '*this* host yet, skipping.' %\ - settings['private-address'] + '*this* host yet, skipping.' % settings['private-address'] for path in paths: # removing trailing slash from directory paths, unison @@ -214,7 +212,6 @@ def sync_to_peers(peer_interface, user, paths=[], verbose=False): path = path[:(len(path) - 1)] for host in hosts: cmd = base_cmd + [path, 'ssh://%s@%s/%s' % (user, host, path)] - utils.juju_log('INFO', 'Syncing local path %s to %s@%s:%s' %\ - (path, user, host, path)) - print ' '.join(cmd) + utils.juju_log('INFO', 'Syncing local path %s to %s@%s:%s' % + (path, user, host, path)) run_as_user(user, cmd) diff --git a/hooks/lib/utils.py b/hooks/lib/utils.py index 8095e86a..018ac9e4 100644 --- a/hooks/lib/utils.py +++ b/hooks/lib/utils.py @@ -32,8 +32,7 @@ def install(*pkgs): cmd = [ 'apt-get', '-y', - 'install' - ] + 'install'] for pkg in pkgs: cmd.append(pkg) subprocess.check_call(cmd) @@ -54,16 +53,14 @@ except ImportError: def render_template(template_name, context, template_dir=TEMPLATES_DIR): - templates = jinja2.Environment( - loader=jinja2.FileSystemLoader(template_dir) - ) + templates = jinja2.Environment(loader=jinja2.FileSystemLoader(template_dir)) template = templates.get_template(template_name) return template.render(context) CLOUD_ARCHIVE = \ -""" # Ubuntu Cloud Archive -deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main -""" + """ # Ubuntu Cloud Archive + deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main + """ CLOUD_ARCHIVE_POCKETS = { 'folsom': 'precise-updates/folsom', @@ -77,8 +74,7 @@ CLOUD_ARCHIVE_POCKETS = { 'havana/proposed': 'precise-proposed/havana', 'icehouse': 'precise-updates/icehouse', 'icehouse/updates': 'precise-updates/icehouse', - 'icehouse/proposed': 'precise-proposed/icehouse', - } + 'icehouse/proposed': 'precise-proposed/icehouse'} def configure_source(): @@ -88,8 +84,7 @@ def configure_source(): if source.startswith('ppa:'): cmd = [ 'add-apt-repository', - source - ] + source] subprocess.check_call(cmd) if source.startswith('cloud:'): # CA values should be formatted as cloud:ubuntu-openstack/pocket, eg: @@ -106,8 +101,7 @@ def configure_source(): cmd = [ 'apt-key', 'adv', '--keyserver keyserver.ubuntu.com', - '--recv-keys', key - ] + '--recv-keys', key] subprocess.check_call(cmd) elif l == 1: apt_line = source @@ -116,8 +110,7 @@ def configure_source(): apt.write(apt_line + "\n") cmd = [ 'apt-get', - 'update' - ] + 'update'] subprocess.check_call(cmd) # Protocols @@ -128,8 +121,7 @@ UDP = 'UDP' def expose(port, protocol='TCP'): cmd = [ 'open-port', - '{}/{}'.format(port, protocol) - ] + '{}/{}'.format(port, protocol)] subprocess.check_call(cmd) @@ -137,8 +129,7 @@ def juju_log(severity, message): cmd = [ 'juju-log', '--log-level', severity, - message - ] + message] subprocess.check_call(cmd) @@ -162,8 +153,7 @@ def cached(func): def relation_ids(relation): cmd = [ 'relation-ids', - relation - ] + relation] result = str(subprocess.check_output(cmd)).split() if result == "": return None @@ -175,8 +165,7 @@ def relation_ids(relation): def relation_list(rid): cmd = [ 'relation-list', - '-r', rid, - ] + '-r', rid] result = str(subprocess.check_output(cmd)).split() if result == "": return None @@ -187,8 +176,7 @@ def relation_list(rid): @cached def relation_get(attribute, unit=None, rid=None): cmd = [ - 'relation-get', - ] + 'relation-get'] if rid: cmd.append('-r') cmd.append(rid) @@ -206,8 +194,7 @@ def relation_get(attribute, unit=None, rid=None): def relation_get_dict(relation_id=None, remote_unit=None): """Obtain all relation data as dict by way of JSON""" cmd = [ - 'relation-get', '--format=json' - ] + 'relation-get', '--format=json'] if relation_id: cmd.append('-r') cmd.append(relation_id) @@ -225,8 +212,7 @@ def relation_get_dict(relation_id=None, remote_unit=None): def relation_set(**kwargs): cmd = [ - 'relation-set' - ] + 'relation-set'] args = [] for k, v in kwargs.items(): if k == 'rid': @@ -243,8 +229,7 @@ def relation_set(**kwargs): def unit_get(attribute): cmd = [ 'unit-get', - attribute - ] + attribute] value = subprocess.check_output(cmd).strip() # IGNORE:E1103 if value == "": return None @@ -257,8 +242,7 @@ def config_get(attribute): cmd = [ 'config-get', '--format', - 'json', - ] + 'json'] out = subprocess.check_output(cmd).strip() # IGNORE:E1103 cfg = json.loads(out) @@ -321,8 +305,7 @@ def running(service): except subprocess.CalledProcessError: return False else: - if ("start/running" in output or - "is running" in output): + if ("start/running" in output or "is running" in output): return True else: return False diff --git a/hooks/pgsql-db-relation-changed b/hooks/pgsql-db-relation-changed new file mode 120000 index 00000000..dd3b3eff --- /dev/null +++ b/hooks/pgsql-db-relation-changed @@ -0,0 +1 @@ +keystone_hooks.py \ No newline at end of file diff --git a/hooks/pgsql-db-relation-joined b/hooks/pgsql-db-relation-joined new file mode 120000 index 00000000..dd3b3eff --- /dev/null +++ b/hooks/pgsql-db-relation-joined @@ -0,0 +1 @@ +keystone_hooks.py \ No newline at end of file diff --git a/metadata.yaml b/metadata.yaml index 42d82ab2..498b197b 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -12,6 +12,8 @@ provides: requires: shared-db: interface: mysql-shared + pgsql-db: + interface: pgsql ha: interface: hacluster scope: container diff --git a/revision b/revision index bf18240e..dcb6b5ba 100644 --- a/revision +++ b/revision @@ -1 +1 @@ -229 +230 diff --git a/templates/essex/keystone.conf b/templates/essex/keystone.conf index 9580f959..f514d9bb 100644 --- a/templates/essex/keystone.conf +++ b/templates/essex/keystone.conf @@ -14,7 +14,7 @@ verbose = {{ verbose }} [sql] {% if database_host -%} -connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} +connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} {% else -%} connection = sqlite:////var/lib/keystone/keystone.db {% endif -%} diff --git a/templates/folsom/keystone.conf b/templates/folsom/keystone.conf index 8d1c560c..1daa88ec 100644 --- a/templates/folsom/keystone.conf +++ b/templates/folsom/keystone.conf @@ -14,7 +14,7 @@ verbose = {{ verbose }} [sql] {% if database_host -%} -connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} +connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} {% else -%} connection = sqlite:////var/lib/keystone/keystone.db {% endif -%} diff --git a/templates/grizzly/keystone.conf b/templates/grizzly/keystone.conf index 0ffb2bfa..370f78a4 100644 --- a/templates/grizzly/keystone.conf +++ b/templates/grizzly/keystone.conf @@ -14,7 +14,7 @@ verbose = {{ verbose }} [sql] {% if database_host -%} -connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} +connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} {% else -%} connection = sqlite:////var/lib/keystone/keystone.db {% endif -%} diff --git a/templates/havana/keystone.conf b/templates/havana/keystone.conf index ca28d9b0..f53310e2 100644 --- a/templates/havana/keystone.conf +++ b/templates/havana/keystone.conf @@ -14,7 +14,7 @@ verbose = {{ verbose }} [sql] {% if database_host -%} -connection = mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} +connection = {{ database_type }}://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}{% if database_ssl_ca %}?ssl_ca={{ database_ssl_ca }}{% if database_ssl_cert %}&ssl_cert={{ database_ssl_cert }}&ssl_key={{ database_ssl_key }}{% endif %}{% endif %} {% else -%} connection = sqlite:////var/lib/keystone/keystone.db {% endif -%} diff --git a/unit_tests/__init__.py b/unit_tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/unit_tests/test_keystone_hooks.py b/unit_tests/test_keystone_hooks.py new file mode 100644 index 00000000..9e2de575 --- /dev/null +++ b/unit_tests/test_keystone_hooks.py @@ -0,0 +1,120 @@ +from mock import call, patch, MagicMock +import os + +from test_utils import CharmTestCase + +os.environ['JUJU_UNIT_NAME'] = 'keystone' +with patch('charmhelpers.core.hookenv.config') as config: + config.return_value = 'keystone' + import keystone_utils as utils + +_reg = utils.register_configs +_map = utils.restart_map + +utils.register_configs = MagicMock() +utils.restart_map = MagicMock() + +import keystone_hooks as hooks + +utils.register_configs = _reg +utils.restart_map = _map + +TO_PATCH = [ + # charmhelpers.core.hookenv + 'Hooks', + 'config', + 'is_relation_made', + 'log', + 'relation_ids', + 'relation_set', + 'relation_get', + 'unit_get', + # charmhelpers.core.host + 'apt_install', + 'apt_update', + 'restart_on_change', + # charmhelpers.contrib.openstack.utils + 'configure_installation_source', + # charmhelpers.contrib.hahelpers.cluster_utils + 'eligible_leader', + # keystone_utils + 'restart_map', + 'register_configs', + 'do_openstack_upgrade', + 'migrate_database', + # other + 'check_call', + 'execd_preinstall', + 'mkdir' +] + + +class KeystoneRelationTests(CharmTestCase): + + def setUp(self): + super(KeystoneRelationTests, self).setUp(hooks, TO_PATCH) + self.config.side_effect = self.test_config.get + + + def test_db_joined(self): + self.unit_get.return_value = 'keystone.foohost.com' + self.is_relation_made.return_value = False + hooks.db_joined() + self.relation_set.assert_called_with(database='keystone', + username='keystone', + hostname='keystone.foohost.com') + self.unit_get.assert_called_with('private-address') + + def test_postgresql_db_joined(self): + self.unit_get.return_value = 'keystone.foohost.com' + self.is_relation_made.return_value = False + hooks.pgsql_db_joined() + self.relation_set.assert_called_with(database='keystone'), + + def test_db_joined_with_postgresql(self): + self.is_relation_made.return_value = True + + with self.assertRaises(Exception) as context: + hooks.db_joined() + self.assertEqual(context.exception.message, + 'Attempting to associate a mysql database when there ' + 'is already associated a postgresql one') + + def test_postgresql_joined_with_db(self): + self.is_relation_made.return_value = True + + with self.assertRaises(Exception) as context: + hooks.pgsql_db_joined() + self.assertEqual(context.exception.message, + 'Attempting to associate a postgresql database when there ' + 'is already associated a mysql one') + + @patch.object(hooks, 'CONFIGS') + def test_db_changed_missing_relation_data(self, configs): + configs.complete_contexts = MagicMock() + configs.complete_contexts.return_value = [] + hooks.db_changed() + self.log.assert_called_with( + 'shared-db relation incomplete. Peer not ready?' + ) + + @patch.object(hooks, 'CONFIGS') + def test_postgresql_db_changed_missing_relation_data(self, configs): + configs.complete_contexts = MagicMock() + configs.complete_contexts.return_value = [] + hooks.pgsql_db_changed() + self.log.assert_called_with( + 'pgsql-db relation incomplete. Peer not ready?' + ) + + def _shared_db_test(self, configs): + configs.complete_contexts = MagicMock() + configs.complete_contexts.return_value = ['shared-db'] + configs.write = MagicMock() + hooks.db_changed() + + def _postgresql_db_test(self, configs): + configs.complete_contexts = MagicMock() + configs.complete_contexts.return_value = ['pgsql-db'] + configs.write = MagicMock() + hooks.pgsql_db_changed() diff --git a/unit_tests/test_utils.py b/unit_tests/test_utils.py new file mode 100644 index 00000000..e1e346b1 --- /dev/null +++ b/unit_tests/test_utils.py @@ -0,0 +1,119 @@ +import logging +import os +import unittest +import yaml + +from contextlib import contextmanager +from mock import patch, MagicMock + + +def load_config(): + '''Walk backwords from __file__ looking for config.yaml, + load and return the 'options' section' + ''' + config = None + f = __file__ + while config is None: + d = os.path.dirname(f) + if os.path.isfile(os.path.join(d, 'config.yaml')): + config = os.path.join(d, 'config.yaml') + break + f = d + + if not config: + logging.error('Could not find config.yaml in any parent directory ' + 'of %s. ' % file) + raise Exception + + return yaml.safe_load(open(config).read())['options'] + + +def get_default_config(): + '''Load default charm config from config.yaml return as a dict. + If no default is set in config.yaml, its value is None. + ''' + default_config = {} + config = load_config() + for k, v in config.iteritems(): + if 'default' in v: + default_config[k] = v['default'] + else: + default_config[k] = None + return default_config + + +class CharmTestCase(unittest.TestCase): + + def setUp(self, obj, patches): + super(CharmTestCase, self).setUp() + self.patches = patches + self.obj = obj + self.test_config = TestConfig() + self.test_relation = TestRelation() + self.patch_all() + + def patch(self, method): + _m = patch.object(self.obj, method) + mock = _m.start() + self.addCleanup(_m.stop) + return mock + + def patch_all(self): + for method in self.patches: + setattr(self, method, self.patch(method)) + + +class TestConfig(object): + + def __init__(self): + self.config = get_default_config() + + def get(self, attr=None): + if not attr: + return self.get_all() + try: + return self.config[attr] + except KeyError: + return None + + def get_all(self): + return self.config + + def set(self, attr, value): + if attr not in self.config: + raise KeyError + self.config[attr] = value + + +class TestRelation(object): + + def __init__(self, relation_data={}): + self.relation_data = relation_data + + def set(self, relation_data): + self.relation_data = relation_data + + def get(self, attr=None, unit=None, rid=None): + if attr is None: + return self.relation_data + elif attr in self.relation_data: + return self.relation_data[attr] + return None + + +@contextmanager +def patch_open(): + '''Patch open() to allow mocking both open() itself and the file that is + yielded. + Yields the mock for "open" and "file", respectively. + ''' + mock_open = MagicMock(spec=open) + mock_file = MagicMock(spec=file) + + @contextmanager + def stub_open(*args, **kwargs): + mock_open(*args, **kwargs) + yield mock_file + + with patch('__builtin__.open', stub_open): + yield mock_open, mock_file