jgdBddlmZddlmZddlmZddlZddlZddlZddlmZm Z ddl m Z ddl m Z ddl Z ddlmZddlmZdd lmZdd lmZmZdd lmZmZmZdd lmZdd lmZmZm Z m!Z!ddl"m#Z#ddlm$Z$m%Z%ddlm&Z&ddlm'Z'Gdde'ee(Z)dS))absolute_import)print_function)divisionN)ABCMetaabstractmethod)datetime iteritems)unicode)ClPwd)get_file_lineswrite_file_lines) pretty_jsondelete_using_realpath_keys get_abs_rel)ClSelectExcept)BaseSelectorErrorAbsentFileErrorMissingVirtualenvErrorMissingAppRootError)BaseSelectorManager)file_readlinesfile_writelines)get_using_realpath_keys)with_metaclasscLeZdZdZdZdZdZdZdZdZ e dZ dZ dZ dZd'd Zed(d Zd Zeed Zd(dZd(dZdZdZdZdZdZdZdZdZdZdZ dZ!dZ"edZ#d(dZ$d(dZ%dZ&d Z'd!Z(d(d"Z)d)d$Z*d%Z+d&Z,dS)*BaseApplicationsManagerz[ Base class that responsible for gathering and set information about applications. Nz/var/log/selectorctl.logc:||_t|_dSN)_managerr _pwd)selfmanagers Y/opt/cloudlinux/venv/lib64/python3.11/site-packages/clselect/baseclselect/apps_manager.py__init__z BaseApplicationsManager.__init__2s GG c tjd}t|j|d|dgddS#t t f$rYdSwxYw)zi Writes string to log file :param log_str: String to write :return: None z%Y-%m-%d %H:%M:%Sz:  aN)rnowstrftimer_LOG_FILE_NAMEIOErrorOSError)clslog_str dt_strings r%write_string_to_logz+BaseApplicationsManager.write_string_to_log6st  //0CDDI S/ 7772S1TVY Z Z Z Z Z!    DD sAAAAcf||}|||<|||dS)a Add data to user's config (update info for an app with app_directory specified) :param str user: name of unix user :param str app_directory: Application root directory :param dict app_data: Application data :return: None N)get_user_config_datawrite_full_user_config_data)r#user app_directoryapp_data current_dicts r%add_app_to_configz)BaseApplicationsManager.add_app_to_configCs=0066 &. ]# ((|<<<<zEBaseApplicationsManager.add_env_vars_for_htaccess.._sJJJdTJTJJJr'r)rzzSetEnv {0} {1}z w) get_htaccess_by_appdiropenreadsplitindexappenditemsformatwritejoin)r# user_namer8env_varsdoc_rootenv_section_beginenv_section_end htaccess_filehtaccesslinesstartendenv_varvalues r%add_env_vars_for_htaccessz1BaseApplicationsManager.add_env_vars_for_htaccessPs:a\33I}hX\]]  F --> ? ? ? .8JJhmmoo&;&;D&A&AJJJE E))o.F.F $566kk/22%q.)# ./// 3444&.nn&6&6JJNGULL!1!8!8%!H!HIIII ]+++ _--- . . . . . . . . . . . . . . .--> ? ? ? -8 NN499U++ , , , - - - - - - - - - - - - - - - - - -s$DEE E!)FFFc||} t||||||dS#t$rYdSwxYw)z Removes application from config :param user: User name :param app_dir: Application directory :return: True if app is exists in config, False - if app is not exists in config TF)r5rr6KeyError)r#r7app_dir config_datas r%remove_app_from_configz.BaseApplicationsManager.remove_app_from_confignso//55   &tWk B B B  , ,T; ? ? ?4   55 s'A A AFc ||}|sdSt|D]\}}|rtjd|z|d}ntjd|z|d}|Bt d|ddt | ||d<|||dS)a Replace domain in config files when it is renamed. :param username: domain owner :param domain: previous name :param new_domain: name after rename :param include_subdomains: whether we should also rename subdomains :return: Nz (\.|^)%s$domainz^%s$z{}{})r5r researchr rNlenr6) r#usernamerd new_domaininclude_subdomains full_configappconfigmatchs r%replace_domain_in_configsz1BaseApplicationsManager.replace_domain_in_configss//99   F%[11 ! !KC! F ,"79IJJ 'F"2F84DEE #*6==8$]s6{{l]3, , $!$!x  ((;?????r'cFt||\}fd|DS)z6 Return list of detected config files cg|]A}tjtj|?|BSrB)ospathexistsrP)rCrmabs_paths r%rEz>BaseApplicationsManager._find_config_files..s=```6 XW]@^@^1_1_````r')r)rQr8patternsrel_pathrus @r%_find_config_filesz*BaseApplicationsManager._find_config_filess3 )MBB(````X````r'c $|||}|j|}|||||}dt jdtj ||d|dg}| | | ||||| dd}|r|d|z|t jdz| t!|d t j|}t%||d d dS) z Creates .htaccess file for application based on application config data :param str user_name: User's name :param str app_root: Application root :param doc_root: Document root for the domain :return: None z{} zPassengerAppRoot "{}" zPassengerBaseURI "/{}" app_uripassenger_log_fileNzPassengerAppLogFile "%s" r)r>r?rF)get_app_configr" get_homedirrGrN clpassengerHTACCESS_BEGINrrrsrPextend(get_interpreter_specific_passenger_linesget_binary_pathgetrL HTACCESS_ENDrrm_double_empty_linesr) r#rQapp_rootrS app_configuser_dirrV new_linesr{s r%update_htaccess_filez,BaseApplicationsManager.update_htaccess_files((H== 9((3333IxS]^^ MM+4 5 5 % , ,RW\\(H-M-M N N & - -j.C D D FF  Hh ? ?    (^^,@$GG  P   9OPPPQQQ5i@@  y#>OPPPPPPr'ct)zu Return list of lines that needs to be added to htaccess and are specific to the interpreter )NotImplementedError) binary_pathrs r%rz@BaseApplicationsManager.get_interpreter_specific_passenger_liness "!r'c|||}||j}tj||j||d|S)a Return a path to the environment's interpreter binary Get interpreter path for application :param user: owner of the application :param app_root: app path relative to user home (app-root) :param user_dir: User's home directory :param binary_name: name of binary in virtual environemnt (python, npm, node) :return: path to interpreter binary in virtual environment Nbin)get_interpreter_version_for_app BINARY_NAMErrrsrPVENV_DIR)r#r7rr binary_nameversions r%rz'BaseApplicationsManager.get_binary_pathsG66tXFF  *Kw||HdmXw{[[[r'cp||jS||j|iS)z Retrives info about user(s). :param str | None username: Username to retrive information. :return: Dictionary with user info. Example: {'user1': pw_struct} )r" get_user_dictget_pw_by_name)r#rhs r%get_users_dictz&BaseApplicationsManager.get_users_dicts9  9**,, ,$)228<<==r'chi}||}tj|r{t |}d|} t j|}nA#ttf$r-tj d |j wxYw|S)z Get all data from user's config :param user: name of unix user :return: json data from user's config as dictionary zUser config "{}" is broken)_get_path_to_user_configrrrsisfiler rPjsonloads ValueError TypeErrorr WrongDatarN _USER_CONFIG)r#r7_user_config_data user_configdata joined_datas r%r5z,BaseApplicationsManager.get_user_config_datas 33D99 7>>+ & & g!+..D''$--K g$(J{$;$;!! * g g g$./K/R/RSWSd/e/efff g  s A11>B/cr||} t|||S#t$rYdSwxYw)z Retrieves full application config :param user: User name :param app_dir: Application directory :return: Application data as dictionary If None - No application data found in config N)r5rr_)r#r7r`user_config_datas r%r|z&BaseApplicationsManager.get_app_configsR 44T:: *4:JKK K   44 s ( 66c>|||}|dS)z Retrieves domain for provided user's application :param username: user name :param app_directory: application root directory :return str: application domain rdr|)r#rhr8rs r%get_app_domainz&BaseApplicationsManager.get_app_domains$((=AA (##r'c>|||}|dS)z Retrieves uri for provided user's application :param username: user name :param app_directory: application root directory :return str: application uri rzrr#rhr8r9s r% get_app_uriz#BaseApplicationsManager.get_app_uri s$&&x?? ""r'c>|||}|dS)z Retrieves name of startup file for provided user's application :param username: user name :param app_directory: application root directory :return str: name of startup file of application startup_filerrs r%get_app_startup_filez,BaseApplicationsManager.get_app_startup_files$&&x??''r'c>|||}|dS)z Retrieves status for provided user's app_directory :param username: user name :param app_directory: application root directory :return str: status of application app_statusrrs r%get_app_statusz&BaseApplicationsManager.get_app_status!s$&&x?? %%r'c|||}|'tjd||d|jzS)z Retrieves interpreter version for provided user and application :param username: user name :param app_directory: application root directory :return str: major interpreter version Nz)Application config is missed for user: {} %s_version)r|rConfigMissingErrorrN INTERPRETERrs r%rz7BaseApplicationsManager.get_interpreter_version_for_app+s]&&x??   35CCI6(CSCSUU U t'7788r'c|j|}tj||j}|S)z Get full path to user config ~/${_USER_CONFIG} :param username: name of unix user :return: full path to config )r"r}rrrsrPr)r#rh user_homeapplication_configs r%rz0BaseApplicationsManager._get_path_to_user_config8s8 I))(33 W\\)T5FGG!!r'cT|jj|}||kr|SdS)z Retrieves full version for supplied major version. :return: str - Full version or None if full version not found N)r!pkgget_full_version)r# major_version full_versions r%_get_full_version_for_shortz3BaseApplicationsManager._get_full_version_for_shortCs2 }(99-HH = ( ( tr'ct|j|vr|||jd|<dS|j||id}|||j<dS)a@ Add single application data to user_data_dest_dict :param users_data_dest_dict: Destination dictionary with application data :param user_pw_entry: User's passwd entry :param app_root_dir: Application root directory :param app_data: Application data :return: None applications)homedirrN)pw_namepw_dir)r#users_data_dest_dict user_pw_entry app_root_dirr9 user_datas r%_add_single_user_appz,BaseApplicationsManager._add_single_user_appMsd  $8 8 8X` !6 7 G U U U)/!-x 8I;D !6 7 7 7r'c||j|}t|d|z}t||d<dS)z&> Y Y "L('+'G'GQ]`d`pQpHq'r'r $'/3KSf3f3f12JKKKIK#$<=gF !5!5!)<9M *"6",",&H\ " (889,-EFwOJ  : :8\S` a a a  % %j-x X X X X' Y Yr'cLt|D]\}}d|vrd|d<|||<|S)z Append absent 'passenger_log_file' key with None value to each application :param user_config_dict: Sourse dictionary to modify :return: Modified dict with 'passenger_log_file' keys r{Nr )user_config_dictrr9s r%_add_absent_passenger_log_filez6BaseApplicationsManager._add_absent_passenger_log_filesK#,,<"="= 2 2 Hh#83315-.)1 X & &r'cL|tj}tj||j}tj|st | |dkr&dt_tj |||dd}nt|}| tj d|S#ttt t"f$r'}t%d|t'|dd d}~wwxYw) a] Read [python|ruby|node]-selector.json file from user's directory. :param euid: current effective uid :param user_homedir: user's home directory :param uid: uid for drop rights :param gid: gid for drop rights :return: Cortege contents_dict. None - there is no [python|ruby|node]-selector.json file in user's directory :raises BaseSelectorError if error. Exception contents: {'message': "File %(file)s read/parse error: %(error)s", 'context': {'file': node_json_path, 'error': 'some message'}} NrTF) exit_on_error write_logrz)File %(file)s read/parse error: %(error)s)fileerror)messagecontext)rrgeteuidrsrPrrtrsecureio SILENT_FLAGread_file_securer rrrr.r/rrrstr)r# user_homediruidgideuidjson_config_path file_lineses r%read_user_selector_config_jsonz6BaseApplicationsManager.read_user_selector_config_jsons+ <:<A AAc||} t|||}||d<n#t$rYdSwxYw|||dS)z Retrieves application status :param user: User name :param app_dir: Application directory :param new_status: New appication status :type new_status: str :return: None rN)r5rr_r6)r#r7r` new_statusrrs r%set_app_statusz&BaseApplicationsManager.set_app_statuss} 44T:: 0w@PQQJ'1J| $ $    FF  ((/?@@@@@s . <<c||}tjdkstjdkrt jdt |} tj||dddS#tttf$r-}t j |d |d}~wwxYw)z Write data to user's config :param user: name of unix user :param config_data: data in json format :return: None rz$root should not write to user configi_tmp)content dest_pathpermsuffixz%Could not write json user config ({})N)rrrrgetegidrSelectorExceptionrrwrite_file_via_tempfiler.r/rUnableToSaveDatarN)r#r7rar dumped_datars r%r6z3BaseApplicationsManager.write_full_user_config_datas 88>> :<<1    1 1 2688 8!+..  C  ,#*        ), C C C 1 7>>qAACC C Cs(BC(CCc|}t|D]\}} ||j|j|j}|<|D]'}|d|jz|krdS(k#t$rYwt$r,}| |j |j zYd}~d}~wwxYwdS)z Returns True if specified NodeJS version is in use by any app of any user. It will stop search on the first match. :param version: NodeJS interpreter major version :return True | False NrTF)rr rrpw_uidpw_gidvaluesrrrrr3rr)r#r user_inforQruser_apps_datarlrs r%is_version_in_usez)BaseApplicationsManager.is_version_in_uses'')) (1)(<(< @ @ $I} @!%!D!D]EY[h[oEREY"["[!--4466((77<$2B#BCCwNN#'444O"   $ @ @ @((QY)>???????? @us$A B B C C$"C  CcR ||}n,#tjj$rt j|wxYw|}|d}t|D]\}} ||j |j |j }| |||D#t$rYPt$r\}tjdkr9||j|jzd|jd|jd|d<n|Yd}~d}~wwxYw|S)a Retrieves info about all installed NodeJS interpreters and user(s) applictions :param user: User name for read applictions. If None and current euid == 0 - all users will be processed. If current euid != 0 (called under some user), this argument will be ignored and only user with uid == euid will be processed :return: Dictionary with user(s) applications info :raises ClSelectExcept.NoSuchUser or BaseSelectorError available_versionsrz Some user's zD can't be read. Some user(s) data absent in output. Please see file z for detailswarningN)rrclpwdNoSuchUserExceptionr NoSuchUser_get_interpreter_infor rrrrrrrrrrr3rrrr-) r#r7rusers_apps_infor rQrrrs r%get_applications_users_infoz3BaseApplicationsManager.get_applications_users_info s 2++D11II~1 2 2 2 +D11 1 24466,-AB)2)(<(<   $I} !%!D!D]EY[h[oEREY"["['' 7I>ZZZZ"   $   :<<1$$,,QY-BCCCC372C2C2CTEXEXEX2ZOI.. G /.... s()A5=B33 D$? D$ADD$Tc|j|j}tj||j|}|r.tj|st|tj||}|r.tj|st|||fS)a Calculate, check exists and return application folders This method does not check that application exists in config. :raises: NoSuchUserException, MissingVirtualenvError, MissingAppRootError :return: tuple(app_root, app_venv) with absolute paths ) r"rrrrrsrPrrtrr)r#rhrchk_env chk_app_rootrapp_venvs r%get_app_foldersz'BaseApplicationsManager.get_app_folders3sI,,X66= 7<< 4=(CC  327>>(33 3(22 27<< 844  0x 8 8 0%h// /!!r'c8|j}|S)z)Get initial information about interpreter)r! get_summary)r#rs r%rz-BaseApplicationsManager._get_interpreter_infoEs-3355r'c@|jj|S)zi Just a public proxy to internal method that blocks any actions with interpreter )r!racquire_interpreter_lock)r# it_versions r%rz0BaseApplicationsManager.acquire_interpreter_lockJs } 99*EEEr')Fr )TT)-__name__ __module__ __qualname____doc__rr-rrrr& classmethodr3r;r]rbro staticmethodrxrrrrrr5r|rrrrrrrrrrrrrGrr6r rrrrrBr'r%rr&s L/NKHK  [  = = =---<$@@@@6aaa\aQQQ:""^\" \ \ \ \ > > > >!!!"   $$$###(((&&& 9 9 9 " " "DDD(666 YYY:   \   ^ ^ ^ ^D AAA$CCC26((((T""""$ FFFFFr'r)* __future__rrrrrrreabcrrrclselect.clpassengerr~r future.utilsr past.builtinsr clcommonr clcommon.utilsr rclselect.utilsrrrclselectrclselect.baseclselectrrrrselector_managerrrrrrobjectrrBr'r%r/s'&&&&&%%%%%% ''''''''******""""""!!!!!!;;;;;;;;OOOOOOOOOO###### 211111::::::::222222''''''iFiFiFiFiFnnWf==iFiFiFiFiFr'