PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB`Mini Shell

HOME


Mini Shell 1.0
DIR:/lib/Acronis/BackupAndRecovery/
Upload File :
Current File : //lib/Acronis/BackupAndRecovery/create_hosting_panel_client.py
#!/usr/sbin/acropsh
from argparse import ArgumentParser
import subprocess
import base64
import json
import uuid
import sys
import os

import xml.etree.ElementTree as ET

try:
    from urllib.parse import urlencode
    from urllib.request import urlopen, Request
    from urllib.error import HTTPError
except ImportError:
    from urllib import urlencode
    from urllib2 import urlopen, Request, HTTPError


class ClientCreator:
    def __init__(self, cred1, cred2, bearer_token, ve_ids):
        self.cred1 = cred1
        self.cred2 = cred2
        self.bearer_token = bearer_token
        self.group_id = ''
        self.tenant_id = ''
        self.ve_ids = ve_ids
        self.headers = {}
        self.dc_url = ''
        self.mc_url = ''

    def run(self):
        print('\nConnecting to the Cyber Protect service...')
        try:
            self.identify_url_and_group()
        except Exception as e:
            print("Failed to identify agent registration details, please confirm the agent is registered and try again")
            sys.exit()
        if not self.bearer_token:
            self.dc_login()
            print('Successfully authenticated with the Cyber Protection service.')
        else:
            self.headers = {'Authorization': 'Bearer {}'.format(self.bearer_token),
                'Content-Type': 'application/json'}
        self.group_to_tenant()
        self.id_vz_ve_to_process()
        self.process_api_clients()

    def identify_url_and_group(self):
        parts = subprocess.check_output(['aakore', 'info']).decode('utf-8').strip().split('cloud server: ')[1].split(' ')
        self.dc_url = parts[0]
        self.mc_url = '{}/api/2/'.format(self.dc_url)
        self.group_id = parts[-1]

    def dc_login(self):
        is_client_auth = False
        try:
            uuid.UUID(str(self.cred1))
            is_client_auth = True
        except:
            pass

        try:
            if not is_client_auth:
                payload = {'grant_type': 'password', 'username': self.cred1, 'password': self.cred2}
                login_response = urlopen(Request('{}idp/token'.format(self.mc_url),
                                                data=urlencode(payload).encode('utf-8')))
            else:
                payload = {'grant_type': 'client_credentials'}
                req = Request('{}idp/token'.format(self.mc_url), data=urlencode(payload).encode('utf-8'))
                req.add_header("Authorization", "Basic {}".format(base64.b64encode('{}:{}'.format(self.cred1, self.cred2).encode('utf-8')).decode('utf-8')))
                login_response = urlopen(req)
        except HTTPError as e:
            if 'totp_required' in e.read().decode('utf-8'):
                totp_code = input(
                    '\nThis account is protected with two-factor authentication. Please enter the TOTP code: ')
                login_response = urlopen(Request('{}idp/token'.format(self.mc_url), data=urlencode(
                    {'grant_type': 'password', 'username': self.cred1,
                        'password': self.cred2, 'totp_code': totp_code}
                ).encode('utf-8')))
                if login_response.getcode() != 200:
                    print(
                        "Failed to obtain an access token. Please check your credentials and try again.")
                    sys.exit()
            else:
                raise e
        except Exception as e:
            print("Failed to create an access token: {}".format(e))
            sys.exit()
        if login_response.getcode() != 200:
            if json.loads(login_response.read().decode('utf-8')).get("error") == "totp_required":
                totp_code = input(
                    '\nThis account is protected with two-factor authentication. Please enter the TOTP code: ')
                login_response = urlopen(Request('{}idp/token'.format(self.mc_url), data=urlencode(
                    {'grant_type': 'password', 'username': self.username,
                        'password': self.password, 'totp_code': totp_code}
                ).encode('utf-8')))
                if login_response.getcode() != 200:
                    print(
                        "Failed to obtain an access token. Please check your credentials and try again.")
                    sys.exit()
            else:
                print("Failed to obtain an access token. Please check your credentials and try again.")
                sys.exit()
        self.headers = {'Authorization': 'Bearer {}'.format(json.loads(login_response.read().decode('utf-8')).get('access_token', '')),
                        'Content-Type': 'application/json'}

    def group_to_tenant(self):
        group_req = Request('{}/api/1/groups/{}'.format(self.dc_url, self.group_id), None, self.headers)
        self.tenant_id = json.loads(urlopen(group_req).read().decode('utf-8')).get('uuid')

    def id_vz_ve_to_process(self):
        if self.ve_ids:
            self.ve_ids = self.ve_ids.split(',')
            return
        else:
            self.ve_ids = []
            if os.path.isdir("/vz/root/"):
                try:
                    for line in subprocess.check_output(['prlctl', 'list', '-o', 'uuid', '-H']).decode('utf-8').splitlines():
                        self.ve_ids.append(line.strip().strip('{}'))
                except FileNotFoundError:
                    return

    def process_api_clients(self):
        if self.ve_ids:
            for ve in self.ve_ids:
                try:
                    self.process_api_client(ve)
                except Exception as err:
                    print("Failed to create client for VE {}: {}".format(ve, err))

        else:
            try:
                self.process_api_client()
            except Exception as err:
                print("Failed to create an agent client or save it to file. {}".format(err))

    def process_api_client(self, ve_id=None):
        plugin_srv_path = self.get_secret_file_path(ve_id)
        if not plugin_srv_path:
            print('Unable to detect a hosting control panel. Skipping...')
            return
        client_path = os.path.join(plugin_srv_path, 'client_secret.json')
        res_id = ve_id if ve_id else self.get_res_id_from_agent_config()
        client_id_from_existing_sw_pol = self.client_id_from_existing_sw_policy(res_id)
        client_data = self.get_client_creds(client_path, ve_id)
        if client_data:
            client_id = client_data.get('client_id')
            if client_id:
                if client_id_from_existing_sw_pol and client_id == client_id_from_existing_sw_pol:
                    if self.client_exists(client_id_from_existing_sw_pol):
                        if self.client_is_authorizable(client_data):
                            return
                        else:
                            self.recreate_and_save(client_id, client_path, ve_id)
                            return
                else:
                    if self.client_exists(client_id) and self.is_hosting_panel_agent_type(client_id):
                        self.delete_client_from_cloud(client_id)
        if client_id_from_existing_sw_pol and self.client_exists(client_id_from_existing_sw_pol):
            self.recreate_and_save(client_id_from_existing_sw_pol, client_path, ve_id)
            return
        self.create_client_and_save(client_path, ve_id, client_id_from_existing_sw_pol)

    def get_client_creds(self, client_path, ve_id=None):
        if not ve_id:
            try:
                with open(client_path) as client_file:
                    return json.load(client_file)
            except:
                return {}
        else:
            try:
                return json.loads(subprocess.check_output(['prlctl', 'exec', ve_id, 'cat', client_path, '2>/dev/null']).decode('utf-8').strip())
            except subprocess.CalledProcessError:
                return {}

    def client_exists(self, client_id):
        client_request = Request('{}/api/2/clients/{}'.format(self.dc_url, client_id), None, self.headers)
        try:
            return urlopen(client_request).getcode() == 200
        except HTTPError:
            return False

    def client_is_authorizable(self, client_data):
        payload = {'grant_type': 'client_credentials'}
        req = Request('{}idp/token'.format(self.mc_url), data=urlencode(payload).encode('utf-8'))
        req.add_header("Authorization", "Basic {}".format(base64.b64encode('{}:{}'.format(client_data.get('client_id'), client_data.get('client_secret')).encode('utf-8')).decode('utf-8')))
        try:
            return urlopen(req).getcode() == 200
        except HTTPError:
            return False

    def create_client_and_save(self, path, ve_id=None, client_id=None):
        client_data = self.create_client(ve_id, client_id)
        try:
            self.save_client(client_data, path, ve_id)
        except Exception as e:
            self.delete_client_from_cloud(client_data['client_id'])
            raise e

    def recreate_and_save(self, client_id, path, ve_id=None):
        self.delete_client_from_cloud(client_id)
        self.create_client_and_save(client_id, path, ve_id)

    def check_file_exists(self, path, ve_id=None):
        if not ve_id:
            return os.path.exists(path)
        try:
            subprocess.check_output(['prlctl', 'exec', ve_id, 'ls', path])
            return True
        except subprocess.CalledProcessError:
            return False

    def get_res_id_from_agent_config(self):
        tree = ET.parse('/etc/Acronis/BackupAndRecovery.config')
        root = tree.getroot()
        return root.findall(".//value[@name='InstanceID']")[0].text.replace('"','')

    def compile_client_name(self, ve_id=None):
        if not ve_id:
            return "Instance ID: {}".format(self.get_res_id_from_agent_config())
        else:
            return "Virtuozzo Instance ID: {}".format(ve_id.upper())

    def is_hosting_panel_agent_type(self, client_id):
        client_request = Request('{}/api/2/clients/{}'.format(self.dc_url, client_id), None, self.headers)
        client_response = urlopen(client_request)
        parsed_response = json.loads(client_response.read().decode('utf-8'))
        return parsed_response.get('data', {}).get('agent_type', '') == 'hosting_panel'

    def client_id_from_existing_sw_policy(self, ve_id):
        if not ve_id:
            return None
        app_request = Request(
            '{}/api/policy_management/v4/applications?context_id={}&policy_type=policy.backup.machine'.format(self.dc_url, ve_id),
            None,
            self.headers
        )
        app_response = urlopen(app_request)
        parsed_app_response = json.loads(app_response.read().decode('utf-8'))
        for comp_app in parsed_app_response.get('items', []):
            for app in comp_app:
                if 'policy.backup.' in app.get('policy', {}).get('type', ''):
                    pol_request = Request(
                        '{}/api/policy_management/v4/policies/{}'.format(self.dc_url, app.get('policy', {}).get('id')),
                        None,
                        self.headers
                    )
                    pol_response = urlopen(pol_request)
                    parsed_pol_response = json.loads(pol_response.read().decode('utf-8'))
                    policy = parsed_pol_response.get('policy', [])[0]
                    if 'client_id' in policy:
                        return policy['client_id']
        return None

    def create_client(self, ve_id=None, client_id=None):
        creation_request_body = {
            "type": "agent",
            "tenant_id": self.tenant_id,
            "data": {
                "client_name": self.compile_client_name(ve_id),
                "agent_type": "hosting_panel"
            },
            "token_endpoint_auth_method": "client_secret_basic"
        }
        if client_id:
            creation_request_body['client_id'] = client_id
        creation_request = Request(
            '{}/bc/api/account_server/v2/clients'.format(self.dc_url),
            json.dumps(creation_request_body).encode('utf-8'),
            self.headers
        )
        creation_response = urlopen(creation_request)
        if creation_response.getcode() == 201:
            parsed_response = json.loads(creation_response.read().decode('utf-8'))
            return {key:parsed_response[key] for key in ['client_id', 'client_secret']}
        else:
            raise Exception("Internal error occurred while creating an agent client: {}".format(
                creation_response.getcode()))

    def delete_client_from_cloud(self, client_id):
        client_deletion_request = Request('{}/api/2/clients/{}'.format(self.dc_url, client_id), None, self.headers)
        client_deletion_request.get_method = lambda: 'DELETE'
        client_deletion_response = urlopen(client_deletion_request)
        if client_deletion_response.getcode() != 204:
            print("Failed to delete API client {} from the Cyber Protection service.".format(client_id))

    def get_secret_file_path(self, ve):
        paths = [
            '/usr/local/cpanel/base/3rdparty/acronisbackup/srv',
            '/usr/local/directadmin/plugins/acronisbackup/srv',
            '/usr/local/psa/var/modules/acronis-backup/srv'
        ]
        if not ve:
            for path in paths:
                if os.path.isdir(path):
                    return path
        else:
            for path in paths:
                try:
                    subprocess.check_output(['prlctl', 'exec', ve, 'ls', path, '>/dev/null', '2>&1'])
                    return path
                except subprocess.CalledProcessError:
                    pass
        return None

    def save_client(self, client_data, path, ve_id):
        client_data['url'] = self.dc_url
        client_secret_file_content = json.dumps(client_data, sort_keys=True, separators=(',', ':'))
        if not ve_id:
            try:
                with open(path, 'w') as f:
                    f.write(client_secret_file_content)
                os.chmod(path, 0o660)
            except Exception as e:
                raise Exception(
                    "Failed to save credentials to file {}".format(path))
        else:
            try:
                subprocess.check_output(['prlctl', 'exec', ve_id, 'echo', "'{}'".format(client_secret_file_content), '>', path])
            except Exception as e:
                raise Exception(
                    "Failed to save credentials for VE {}".format(ve_id))

        if self.check_file_exists(path, ve_id):
            print("Agent client was successfully created{}".format(' for ' + ve_id if ve_id else '.'))


def main(args):
    cred1 = ''
    cred2 = os.environ.get('ACRONIS_HOSTING_SECRET', '')
    bearer_token = os.environ.get('ACRONIS_HOSTING_BEARER_TOKEN', '')
    if args.username:
        cred1 = args.username
        if not cred2 and args.password_file:
            with open(args.password_file) as f:
                cred2 = f.readline().strip()

    if args.client_id:
        cred1 = args.client_id
        if not cred2 and args.secret_file:
            with open(args.secret_file) as f:
                cred2 = f.readline().strip()

    if not cred1 and not cred2 and not bearer_token:
        print('Authentication with the Cyber Protection service is required. \
              Please use either --username and --password-file or --client-id and --secret-file.')
        sys.exit()

    cl_creator = ClientCreator(cred1, cred2, bearer_token, args.ve_id)
    cl_creator.run()
    print('Done! Good bye.')


def parse_arguments():
    parser = ArgumentParser(
        description='This script generates unique API Clients necessary to ensure the connectivity of hosting control panel integrations with Acronis Cyber Protect Cloud. Make sure to run this script on the host where the protection agent is installed. This applies to both agent-based and agentless deployments.')
    parser.add_argument('-u', '--username', help='Account name (login) used during the protection agent installation and registration process.')
    parser.add_argument('-p', '--password-file',
                        help='Path to the file with the password.')
    parser.add_argument('-i', '--client-id', help='Client ID used during the protection agent installation and registration process.')
    parser.add_argument('-s', '--secret-file', help='Path to the file with the Client Secret.')
    parser.add_argument('-c', '--ve-id',
                        help='Comma-separated list of virtual environment (container, virtual machine) IDs. If not defined, all virtual environments will be processed.')

    return parser.parse_args()


if __name__ == '__main__':
    main(parse_arguments())