l:9+ddlmZddlZddlZddlZddlZddlZddlmZddl m Z m Z m Z m Z mZmZddlmZmZddlmZddlmZmZddlmZmZdd lmZmZdd lmZm Z dd l!m"Z"dd l#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)dd l*m+Z+ddl,m-Z-ddl.m/Z/ddl0m1Z2ddl3m4Z4m5Z5m6Z6e-e7Z8Gdde/Z9GddZ:GddZ;dS))absolute_importN) pid_exists)OptionalDictTextIOUnionListTuple)write_file_via_tempfile disable_quota)_add_wp_path_info)ClPwddrop_privileges)FeatureStatusEnumextract_suites) acquire_lockget_server_wide_options) userdomainscpusers)"convert_features_dict_to_interface)get_admin_suites_configextract_featuresAWPSuite PremiumSuiteCDNSuite CDNSuitePro) UserConfig) setup_logging) WposError)gettext)SCANNING_STATUSLAST_SCANNED_TS SCAN_CACHEceZdZdZdS)ReportGeneratorErrorzH Raised when some bad happened during report generating/getting N)__name__ __module__ __qualname____doc__py/clwpos/report_generator.pyr%r%1s Dr+r%ceZdZdZd deefdZdZdZdZ dZ e d edfd Z d e fd Zd efd ZdS) ScanStatusz3 Type for handly scan status manipulations Npidc||_ t|tr7tt|d\|_|_dSt|tr$tt|\|_|_dSttdt|t|d#t$r.ttddt|iwxYw)N/z:Unable to parse scan status: %(status)s, type of: %(type)s)statustypemessagecontextz'Unable to parse scan status: %(status)sr2) r/ isinstancestrmapintsplitcurrenttotaltupler%_r3 ValueError)selfr2r/s r,__init__zScanStatus.__init__<s &#&& +.sFLL4E4E+F+F( djjjFE** +.sF+;+;( djjj*Z[['*6{{DLLII   &CDD!3v;;/  sA C 7C ;C 8Dc8t|j|jfSN)hashr<r=rAs r,__hash__zScanStatus.__hash__NsT\4:.///r+c.t|tr|j|j|jk|jfSt|tr%t ||kSt|t rt ||kSdS)NF)r7r.r<r=r8stripr>)rAothers r,__eq__zScanStatus.__eq__Qs eZ ( ( (<u}! Read status file, with shared blocking flock Nrr/r<r=z Can't parse scan status json: %s)ospathexistsr!openfcntlflockfilenoLOCK_SHreadLOCK_UNjsonloadsgetr.r: Exceptionloggererror)stfdatar/es r,r]zScanStatus.readas  7>>/ * * Ios++ Iq AHHJJ 666vvxx AHHJJ 666 I I I I I I I II:d++D((5//C#i$w-8$'1CTBB!IIILL!DaHHHHHHHHI! I I I I I I I I I I I I I I I$ s=A:EADE E (EEE  EE #E cPtj|j|j|jdS)z5 Status JSON representation to write )r<r=r/)r_dumpsr<r=r/rFs r,to_jsonzScanStatus.to_json|s1z|Z8     r+cRt|jot|jS)z< Return True if scan process is still alive )boolr/rrFs r, check_pidzScanStatus.check_pids!DH~~6*TX"6"66r+rD)r&r'r(r)rr:rBrGrKrNrQ staticmethodr]r8rkrmrnr*r+r,r.r.8sHSM$000...(<(\4     74777777r+r.cTeZdZdZdZedefdZedee fdZ ddee e de e effdZd e e ddfd Zdefd Zedeefd Zed e e de e fd Zede e fdZedefdZd dZd dZddZedZedZde dede fdee eeeeeeeeeef fdZd!de dededee e dffdZede dedee e dffdZ dZ!dS)"ReportGeneratorz3 Class for admin report generation/getting ct|_td|_did|_d|_t |_dS)Nrr1)versionusers)r_clpwdr.r2resultscan_status_fdrcrFs r,rBzReportGenerator.__init__sEgg  ((    # r+rRcht}|r|rdSdS)z Checks: 1) SCANNING_STATUS file exists 2) SCANNING_STATUS has the scan process pid and it is still alive TF)r.r]rn)r2s r,is_scan_runningzReportGenerator.is_scan_runnings9""  !! tur+c4tS)z1 Read status file and get status )r.r]r*r+r,get_scan_statuszReportGenerator.get_scan_statuss    r+N user_listc|r?ttddt|i|}|jd||r1|||}|jd|t||j _ tj }|r*|jd|d|j j dS ||tjdd S#t"$r:}|jd |tjd Yd }~d Sd }~wwxYw) z Public entry point for the scan procedure Do some checks, prepare users list, fork process to actually do scan, and return initial scan progress `user_list` - users to scan; if None - scan all z$Another scan in progress: %(status)sr2r4zFound usernames: %szFiltered usernames: %szScan forked to: %dr)total_users_scannedtotal_users_to_scanz Error during user sites scan: %sN)r{r%r?r8r}_ReportGenerator__get_usernamesrcdebug"_ReportGenerator__filter_usernameslenr2r=rUfork_scansysexitrb exception)rAr~ usernamesfprhs r,scanzReportGenerator.scans    ! ! X&q1W/X/X08#d>R>R>T>T:U:U/VXXX X((**  /;;;  C// 9EEI K  6 B B B NN WYY  K  2B 7 7 7+,T[EVWW W  9%%%     %%&H!LLL  s)D:: E>/E99E>rcttd|_tj|j_|jd|jj|D]}i}|jxj dz c_ | t|D].\}}| |g |/t|5t|}dddn #1swxYwYd|D}|jd|dt'|ii||jtjt|}|jd|dS) a Executes in forked process Get domain and docroots list for usernames Count user sites, write to SCAN_CACHE Create and remove SCANNING_STATUS file `userdomains` examples: [{'domain': 'res1.com', 'docroot': '/home/res1/public_html'}], [{'domain': 'cltest1.com', 'docroot': '/home/cltest1/public_html'}, {'domain': 'mk.cltest1.com', 'docroot': '/home/cltest1/public_html/mk'}] wzSet status pid to: %drNch|]Q\}}|dgD]5}tj||d6RS)wp_pathsr1)rarUrVjoinrstrip).0 _doc_rootvalues_wp_paths r, z(ReportGenerator._scan..smBS)V & :r : : Y1188==r+rvwp_sites_countzNew scan timestamp: %d)rXr!ryrUgetpidr2r/rcrr<$_ReportGenerator__update_scan_statusr setdefaultappendrr itemsrxupdater#_ReportGenerator__write_scan_resultcloseunlink'_ReportGenerator__update_scan_timestamp)rArusername user_data domain_namedoc_rootr_tss r,rzReportGenerator._scans#?C88)++  14;?CCC!  HI K  1 $    % % ' ' ')4X)>)> G G% X$$Xr2299+FFFF ** 9 9-i88  9 9 9 9 9 9 9 9 9 9 9 9 9 9 9W`WfWfWhWhH K ' '+S]];)       """ !!### /"""**,, 2C88888sC55C9 <C9 cddddd}tjts2|dt t i|S|r8|}|d|j |j dntjtsD|t t | dnk|d td t t | d tjt|S) z CLI command to get scan status Cases: 1) no previous scans 2) scan in progress 3) scan finished (success) 4) scan process crashed idlerN) scan_statusrrlast_scan_timer in_progress)rrr)rrrdzFailed to generate report)r scan_errorrr)rUrVrWr#rrrr{r}r<r=r!_get_scan_timestampr?r)rArxr2s r, get_statuszReportGenerator.get_statusso"#$#'"    w~~j))  MM0#gii..A B B BM    ! ! +))++F MM,'-~'-|     7>>/22 + +.wyy>>&*&>&>&@&@  #*"#$?"@"@+.wyy>>&*&>&>&@&@   /*** r+c2 ttd5}|}t |cdddS#1swxYwYn2#t $r%}t d|Yd}~nd}~wwxYwdS)z_ Read timestamp from LAST_SCANNED_TS Returns None in case of any error rtNz"Can't read last scan timestamp: %s)rXr"r]rIr:rbrcrd)rftrhs r,rz#ReportGenerator._get_scan_timestamps  Cot,, FFHHNN$$1vv                  C C C LL> B B B B B B B B Cts:A%5A A%AA% A!A%% B/BBcDttfd|S)z< Return usernames from --users cli argument c |vSrDr*)xto_scans r,z4ReportGenerator.__filter_usernames..1s Q'\r+)listfilter)rrs` r,__filter_usernamesz"ReportGenerator.__filter_usernames,s' F11119==>>>r+c8ttS)z* Get usernames from cpapi )rrr*r+r,__get_usernameszReportGenerator.__get_usernames3s GIIr+cttj}tt|td|S)zr Write current timestamp to LAST_SCANNED_TS Return timestamp for the later use, if needed )r:timer r8r")tss r,__update_scan_timestampz'ReportGenerator.__update_scan_timestamp:s4   B%@@@ r+c||j}|}|dtj|tjtjz||j | tj|tj dS)zq Write current status to SCANNING_STATUS Data example: "0/10", without any other symbols rN) ryr[seekrYrZLOCK_EXLOCK_NBwriter2rkflushr^)rArff_nos r,__update_scan_statusz$ReportGenerator.__update_scan_statusDs  xxzz q  D%-%-7888  ##%%&&&   D%-(((((r+c`ttj|jtddS)zJ Write final scan result to SCANNING_STATUS via temp file rN)r r_rjrxr#rFs r,__write_scan_resultz#ReportGenerator.__write_scan_resultQs(  4; 7 7UKKKKKr+c 6i}|td}|}|s|s|}|S|r|j|d<|j|d<|r||d<|d}|||\ |d<|d<|d<}}} } } } } }tj |tj |tj | tj | i|d <tj | tj | tj | tj |i|d <|S) a 1. get-report when there is no cache file: - start generating report - return total_users_scanned, total_users_to_scan keys 2. get-report when there is no cache file, but scanning in progress: - return total_users_scanned, total_users_to_scan keys 3. get-report when cache present, no scanning running - return data from cache - no keys total_users_scanned, total_users_to_scan in response 4. get-report when cache present, scanning is running - return data from cache - return total_users_scanned, total_users_to_scan keys T)is_jsonrrrrvtotal_wordpress_counttotal_users_counttotal_users_count_activetotal_sites_count_active) _get_from_file_with_lockingr#r}rr<r=r_get_users_reportrnamerrr)rA target_usersreport scanned_cachescanning_statusr users_cachetotal_users_with_active_awptotal_users_with_active_premiumtotal_users_with_active_cdntotal_users_with_active_cdn_prototal_sites_with_active_awptotal_sites_with_active_premiumtotal_sites_with_active_cdntotal_sites_with_active_cdn_pros r,razReportGenerator.getXs]88T8RR ..00 _ 99;;DK  B,;,CF( ),;,AF( )  '+'?'?'A'AF# $(0K&&{LAA w./*++/+/+/+/ :!#B : "A 2F- . :!#B : "A 2F- .  r+c||jjtjk}|ot fd|jDS)Ncg|]m}|jo>|jjtjknSr*)raNAMElowerr2rALLOWED)rfeatureuser_features_datas r, z5ReportGenerator._is_allowed_suite..sv)3)3)3*<)?)? @R@R@T@T)U)U*e&**7<+=+=+?+?@@GK\Kdd)3)3)3r+)rarr2rranyfeatures)user_suites_datarsuiteis_suite_alloweds ` r,_is_allowed_suitez!ReportGenerator._is_allowed_suitesf+// ;;BFWF__4C)3)3)3)3#(>)3)3)3%4%4 4r+ct|5t5t|tj}t|t j}t|tj}dddn #1swxYwYdddn #1swxYwY|||fSrD) rr r#wp_paths_with_active_suite_featuresrrrrprimary)rwps_with_enabled_awp_features%wps_with_enabled_awp_premium_featureswps_with_enabled_cdn_featuress r,_sites_with_active_featuresz+ReportGenerator._sites_with_active_featuressY X & & F F  F F,6x,@,@33H4EFF *4>x4H4H33L4IJJ 2,6x,@,@33H4DEE *  F F F F F F F F F F F F F F F F F F F F F F F F F F F F F F-.SUrrrs5CBB0$ C0B4 4C7B4 8CC C user_scanned_datarc g}d\}}d}d}d}d} d} d} d} d} t}|D]\}}d}d}d}d}|r||vr||}|s|jd|H t |t ||}tt ||}n.#t$r!|j di}i}YnwxYw | |\}}}nE#t$r8}|jdt|ggg}}}Yd}~nd}~wwxYw|dz }|t|d z }| ||tr(|r&|dz }| t|z } t|}| ||t r(|r&|dz }| t|z } t|}|r| ||t"r'| dz } | t|z } t|}nB| ||t$r&|dz }| t|z } t|}||||d ||||d |r"t|t|krn||||||| | | | | f S) z Returns list of final users data: example: [ {"username": "user1", "features": {"object_cache": true}, "wp_sites_count": "1"}, .... ] rsrzCannot get user %s uid)server_wide_optionsz-Unable to get features data from admin configz9Unable to get information for report from user config: %sNrr)rsuitesr accelerate_wp_active_sites_count!accelerate_wp_premium_sites_countaccelerate_wp_cdn_sites_count!accelerate_wp_cdn_pro_sites_count)rr _uid_by_namercwarningrrrrbrrr8r:rrrrrrr)rArrall_users_infototal_wp_sites_countrrrrrrrrrdefault_configr scanned_data&wps_per_user_with_enabled_awp_features.wps_per_user_with_enabled_awp_premium_featureswps_per_user_with_enabled_cdn!wps_per_user_with_enabled_cdn_prouidrrrrrrhs r,rz!ReportGenerator._get_users_reports 26//&'#*+'&'#*+'&'#*+'&'#*+'022&7&=&=&?&?F F  "Hl56 2=> :,- )01 -  < <##H--C  ##$>t-/TVsVs    ##$_adefagaghhhBWt/T------   "  C 5E(F$G$G G %%&68JHUU \Zw \+q0++s3P/Q/QQ+9<=Z9[9[6%%&68JLYY l_D l/14//37\3]3]]/ADEjAkAk>, W))*:PRZ[[W/14//37T3U3UU/478U4V4V1  ! !$*"./?"@4Z5c1N5V##    L 1 1S5H5H H H 46G+-L+-L+-L+-L N Ns*=C(C,+C,0D  E .EE FrVr with_lockcttj|sdS |r?t|5|||cdddS#1swxYwYdS|||S#t $r3}t td|t|dd}~wwxYw)z3 Reads file with locking if needed Nz&Can`t read %(file)s. Reason: %(error)s)filerdr4) rUrVrWr_read_report_filerbr%r?r8)rArVrr rhs r,rz+ReportGenerator._get_from_file_with_lockings8w~~d## 4 P =!$''AA11$@@AAAAAAAAAAAAAAAAAA--dG<<< P P P&q1Y/Z/Z8$9tCy$9T$9$9$9$9L(D((((T #   \ ?tCy?T#Y???\? T#Y\ S\ ) ) ) )LLLL????B44\4 ss\shN#hN d +hN tS#sCc3S#E F hNhNhNhNTPPPdPtP`efjloqufu`vPPPP ++d+uT3_7M+++\+r+rq)< __future__rrUrrrYr_psutilrtypingrrrrr r secureior r clwpos.data_collector_utilsr clcommon.clpwdrr$clwpos.feature_suites.configurationsrr clwpos.utilsrrclcommon.cpapirrclwpos.optimization_featuresrclwpos.feature_suitesrrrrrrclwpos.user.configrclwpos.logsetuprclwpos.cl_wpos_exceptionsrclwposr r?clwpos.constantsr!r"r#r&rcr%r.rqr*r+r,r&s'&&&&& ================;;;;;;;;99999911111111RRRRRRRR>>>>>>>>////////KKKKKK*)))))))))))////// x      9   R7R7R7R7R7R7R7R7jggggggggggr+