9eddlmZddlmZddlmZddlZddlZddlZddlZddlm Z ddl Z ddl Z ddl Z ddl Z ddlZddlmZddlmZddlmZddlmZdd lmZdd lmZdd lmZdd lmZdd lm Z m!Z!m"Z"ddl#m$Z$m%Z%ddl&m'Z'm(Z(ddl)m*Z*ddl+m,Z,ddl-m.Z.ddl/m0Z0ddl1m2Z2ddl3m4Z4ddl5m6Z6m7Z7m8Z8ddl5m9Z9ddl:m;Z;mm=Z?dZ@dZAGddeBZCdS))print_function)absolute_import)divisionN)AnyStr) iteritems)ClPwd)FormattedException) MailHelper)is_ascii_string)CloudlinuxLicenseLib) clselectctl) get_abs_relmkdir_prun_process_in_cagefs)BaseSelectorErrorAcquireApplicationLockError)print_dictionaryreplace_params) CONFIG_DIR) PkgManager)is_clpassenger_active) defaultdict)MIMEText)mkstemp)NODEJSPYTHONPHP)parse_cloudlinux_selector_opts)CloudlinuxSelectorLib OK_RES_DICTClSelectExcept)r"z.lockc"t||SN)open) file_namemodes M/opt/cloudlinux/venv/lib64/python3.11/site-packages/clselector/cl_selector.py_openr);s  4  ceZdZdZdZ d1dZdZdZedZ dZ d Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZd2dZedZd3dZe d Z!e d!Z"d"Z#e$j%d#Z&d$Z'd%Z(d&Z)d'Z*d(Z+d)Z,d*Z-d+Z.d,Z/d-Z0d.Z1ed/Z2d0S)4CloudlinuxSelectorcd|_i|_d|_tjdk|_d|_d|_d|_d|_ tj td|_ dS)NFrz --backgroundzcloudlinux-selector_bkg.pid)_is_json_opts _selector_libosgeteuid _is_root_user_lock_is_bkg_option_present _bkg_option_nj_ver_move_frompathjoinr_pid_file_nameselfs r(__init__zCloudlinuxSelector.__init__Asi  !Z\\Q. &+#)!# gll:7TUUr*c|jdttfvrdSt|jd|jdgrdSt|jd|jd|jd|jd|jd |jd |jd |jd |jd |jd|jd|jd|jd|jd|jdgrdSdS)zx Check if cloudlinux-selector called with application operations :return: True if lock is need --interpreterFchange-version-multiplecreatestartrestartdestroymigratestopinstall-modulesuninstall-modules run-script --app-mode --env-vars--new-app-root --new-domain --new-app-uri --new-version--startup-fileT)r0rranyr<s r(is_app_lock_neededz%CloudlinuxSelector.is_app_lock_neededMs :o &vv.> > >5  45tz(7KL M M 5  Jw  Jy ! Jy ! Jy ! Jv  J( ) J* + J| $ J| $ J| $ J' ( J~ & J ' J ' J' (* + +  4ur*Fc|sdS|jd|jd}}|jj||| | \}}t j|sdSt j|t} t|d|_ tj |j tjtjzdS#t"$r<}|jt$jkrd} t)|| t)|d}~wwxYw)z[ Acquire lock for application if this lock is needed :return: None N--user --app-root) chk_app_rootchk_envza+z6Disk quota exceeded. Please, free space and try again.)reason)rSr0r1 apps_managerget_app_foldersr2r9existsr:LOCKr%r5fcntlflockfilenoLOCK_EXLOCK_NBIOErrorerrnoEDQUOTr) r=ignore_missing_app_rootignore_missing_doc_rootusernameapp_root_app_venv lock_fileerYs r(acquire_app_lock_if_neededz-CloudlinuxSelector.acquire_app_lock_if_neededks5&&((  F!Z14:l3K((5EE h1H-H//F11 8w~~h''  FGLL400  8i..DJ K ))++U]U]-J K K K K K 8 8 8w%,&&Q1(6JJJJ-h77 7  8s AC:: E7D;;Ec^|jr#|jdr|dSdSdS)NrP)r4r0send_notificationr<s r(send_notification_if_neededz.CloudlinuxSelector.send_notification_if_neededsG   %$*_"= %  " " $ $ $ $ $ % % % %r*cdSr$) rr0cpapicpinfor sendmail IndexErrorKeyErrorcpapiexceptions NotSupported)r=MSG_TEMPmsgme cp_userinfouser_data_email mailhelpers r(rpz$CloudlinuxSelector.send_notifications  r*cl|sdSd|dDS)Ncg|]}||Srr).0modules r( z4CloudlinuxSelector.parse_modules..sRRR66RRRRr*,)stripsplit)modules_optionss r( parse_modulesz CloudlinuxSelector.parse_moduless= 2RR_%:%:%<%<%B%B3%G%GRRRRr*c d|v|_|j|v|_|jr||j t }|sGd|_|ddi|jr" tj|jS#YSxYwS| ||_ t|j d|_ |j |j |j r|5t!|j d|j j|}|d}||d|d d d n #1swxYwY||jr" tj|jS#YSxYwS|j |j rd d |j d|j jg|z}|5t+j|i }||d d d n #1swxYwY|j|jr" tj|jS#YSxYwS||j d |j d |j drc||j d|j d\}}|dkr ||j d<n#|t7||j dr|n|j dr|n|j dr|n|j dr|n`|j d r| n=|j dr|!n|j dr|"n|j dr|#n|j dr|$n|j dr|%n|j dr|&nk|j dr|'nH|j ds |j dr|(n|j ds |j d r|)n|j d!r]|*|j +|j d|j d"|j d#|j d$n|j d%r|,n]|j d&r|j -n6|j d'r|.n|/n#t`j1t`j2t`j3f$r;} |t7ti| Yd } ~ nd } ~ wt`j5t`j6f$rU} |j d&s.|t7| j7| j8(tsd)Yd } ~ nd } ~ wtt$rt} | j;r5|t7| j7| j8| j;*n.|t7| j7| j8(Yd } ~ nd } ~ wtx$r} t{j>} t{j?t| | } t| trd+C| } n| } |t7| | ,Yd } ~ nd } ~ wwxYw|jr" tj|jn6#Yn2xYwn.#|jr" tj|jw#YwxYwwxYwd)S)-z$ Run command action --jsonTresultzCloudlinux license isn't validr@rU returncodeoutputNz /usr/bin/sudoz-u)envrE)rfrg--passenger-log-fileOKrsetrFimport-applicationsrBrCrDrGz read-configz save-configrHrIinstall-versionzuninstall-versionenable-versionzdisable-versionrJrVz --script-namez rAzmake-defaults-configsetuprcontextr)rrdetails )rr)Dr/r7r6remover get_license_status_error_and_exitr2r; _parse_argsr0r r1check_selector_is_availableshould_be_runned_as_user_lock_interpreter_if_neededrCLOUDLINUX_SELECTOR_UTILITY_print_raw_datarqshould_run_user_without_cagefs subprocessPopen communicaterrn!_passenger_log_filename_validatordictrun_setrun_migrate_applicationrun_import_applications run_create run_destroy run_start run_restartrun_stoprun_read_configrun_save_configrun_install_modulesrun_uninstall_modulesrun_manage_versionrun_disable_or_enable_version _print_data run_script_start_change_all_apps_versionsreplace_mysqli run_setuprun_getClSelectExcept_oldConfigNotFound WrongDataNoSuchAlternativeVersionstrNativeNotInstalledMissingCagefsPackagemessagerexitr r Exception traceback format_excformat_exception_onlytype isinstancelistr:)r=argvlicencerr user_run_cmdprocessr log_filenamermerrr{ list_err_msgerr_msgs r(runzCloudlinuxSelector.runsp !D( &*&6$&>#  & * KK( ) ) )y *,,G--// Z $ ++X7W,XYY`* Id12222D  [))$//DJ!6tz/7R!S!SD    : : < < <!::4:FF *5577772 8,*FF "( !5J(()9:::44666777777777777777"~* Id12222D  }#BB4:NN * /tz(7K $ 2 N PRV W 557777(.|DDDG'')))44666777777777777777)n* Id12222D  k  + +(, 9(=(, 9(= ,    z01 ?(,(N(NtzZbOcOSzZpOq)s)s%d??9EDJ566((W)=)=)=>>>z% *  I&( ,,....12& ,,....H%$ !!!!I&"   """"G$     I&   """"F#  M* $$&&&&M* $$&&&&-. ((****/0 **,,,,-. $*=P2Q '')))),- >tz.?Y[_[efq[rss t t t t t Z $ 0TZ 5L5X   T/;;DJ{  @ @ @ @ @ @ @r*c8|jdSr$)r1setup_selectorr<s r(rzCloudlinuxSelector.run_setupNs ))+++++r*c ||ddi|e|j|||}|}|ddkr)||t jd||d|j||||}|ddkr)||t jdt||| | | du| dufr| d| dD} |j ||||| | | | }|ddkr)||t jd|d|j |||| }|ddkr)||t jd|idS) a Call selectorctl to change application parameter :param config_files: names of config files (such as requirements.txt or etc) (only for python) :param entry_point: the specified entrypoint for application (only for python) :param user: application owner :param app_root: application main directory (application name) :param app_mode: application mode :param env_vars: dict with environment variables :param new_app_root: new application main directory (new application name) :param new_domain: new application domain :param new_app_uri: new application uri :param new_version: new version for nodejs interpreter :param startup_file: new startup file for application :param skip_web_check: skip check web application after change it's properties :param passenger_log_file: Passenger log filename :return: None NrzERROR: User is not specifiedstatusrrcg|] }|dk| S)r.r)ritems r(rz1CloudlinuxSelector.run_change..zsWWWDTVJJJJJr*r) rr1relocateupperrsysrtransitrRr set_variableschange_version)r=userriapp_modeenv_vars new_app_root new_domain new_app_uri new_version startup_fileskip_web_check entry_point config_filespassenger_log_filers r(rzCloudlinuxSelector.run_changeQs(( <  8": ; ; ;  #"++D(LIIA#H{  ""d**  ###  "j&<"**4; SSA{  ""d**  ### (L+|SW?W"$.0 1 1 'WW1C1CC1H1HWWW "00x81={LZlnnA{  ""d**  ###  ""11$+~^^A{  ""d**  ###  r*c^||jdSr$)rr1rr<s r(rz*CloudlinuxSelector.run_import_applicationss+ +CCEEFFFFFr*c||j|jd|jddS)NrUrV)rr1rr0r<s r(rz*CloudlinuxSelector.run_migrate_applicationsL +CC Jx $*\":<< = = = = =r*c|jdr.||jdS|jdr.||jdS|jdr.||jdS|jdr:||j|jddS|jdtkr.||jdSdti}|jdtkr^| |j |jd| \}}| | ||d<||d <nN|jdtkr8| |j |jdd |vr|||d  dS||dS) Nz--get-default-versionz--get-selector-statusz--get-supported-versionsz--get-current-versionrUr@passenger_activeremaining_apps_counttotal_apps_countrr)r0rr1get_default_versionget_selector_statusget_supported_versionsget_current_versionrget_fullrrupdateget_apps_users_info_get_apps_count_from_pid_filer)r=resrrs r(rzCloudlinuxSelector.run_gets4 :- . &   T/CCEE F F F F F Z/ 0 &   T/CCEE F F F F F Z2 3 &   T/FFHH I I I I I Z/ 0 &   T/CCDJxDXYY Z Z Z Z Z Z (C / /   T/88:: ; ; ; ; ;%'<'>'>?Cz/*f44 4-AA$*XBVWWXXX9=9[9[9]9]6$&6'38H8T2FC./.>C*+O,66 4-AA$*XBVWWXXX3  S] ;;;;;  %%%%%r*c^||jdr%|dd|jdidts5|jdtkrd}nd}|dd |id||j|jd |jd |jd|jd |jd |jd|jd|jd|jd|jd dS)NrzTCan't create application: Nodejs version %(version)s is locked by background processversionrr@z9https://docs.cloudlinux.com/python_selector/#installationz8https://docs.cloudlinux.com/index.html?installation.htmlz`Application creation not allowed, Phusion Passenger seems absent, please see %(url)s for detailsurlrVz --app-urirU--domainrKrQrLrr)(_is_version_locked_by_background_processr0rrrrr1 create_app)r=rs r(rzCloudlinuxSelector.run_createsU  8 8K9P Q Q   q%tz+'>?""   %&& z/*f44QP  [3""       ) ) <( ;' ;' 8$ :& <( +, <( ?+ 12       r*c||j|jd|jddSNrVrU)rr1 destroy_appr0r<s r(rzCloudlinuxSelector.run_destroyS +77 <8P8< 88LNN O O O O Or*c||j|jd|jddSr)rr1 start_appr0r<s r(rzCloudlinuxSelector.run_startsS +55dj6N6:j6JLL M M M M Mr*c||j|jd|jddSr)rr1 restart_appr0r<s r(rzCloudlinuxSelector.run_restartrr*c||j|jd|jddSr)rr1stop_appr0r<s r(rzCloudlinuxSelector.run_stopsS +44TZ 5M59Z5IKK L L L L Lr*c||j|jd|jd|jddS)NrV --config-filerU)rr1read_app_configr0r<s r(rz"CloudlinuxSelector.run_read_configsX    . . <( ?+ 8$ & & ' ' ' ' 'r*c ||j|jd|jd|jd|jddS)NrVr z --contentrU)rr1save_app_configr0r<s r(rz"CloudlinuxSelector.run_save_configsb    . . <( ?+ ;' 8$  & & ' ' ' ' 'r*c ||j|jd|jd|jd|jd|jd||jddS)NrVrUrrz--requirements-file --modules)rdomainr spec_filemodules)rr1install_modulesr0rr<s r(rz&CloudlinuxSelector.run_install_moduless    . . <(Z)z*-#z*<=*%:;**4:k+BCC /   r*c ||j|jd||jd|jd|jd|jddS)NrVr%rUrr)r(rr&r)rr1uninstall_modulesr0rr<s r(rz(CloudlinuxSelector.run_uninstall_moduless    0 0 <(**4:k+BCCZ)z*-#z*<= 1       r*c|jd}|jd} ||j||dS#t$r/}|dt |iYd}~dSd}~wwxYw)zM Disable or enable interpreter version :return: None rrrN)r0rr1set_version_statusrrr)r=rtarget_version_statusrms r(rz0CloudlinuxSelector.run_disable_or_enable_versions *[) $ +; <    T/BBCXZabb c c c c c      #a&&"          s.A B$BBct|jd} |jdr |jj|}n|jj|}n&#t $r}t|}Yd}~nd}~wwxYw||tdSt|tr| |dS| d|idS)Nrrr) rr0r1selector_managerinstall_versionuninstall_versionrrr!rrr)r=verrrms r(rz%CloudlinuxSelector.run_manage_versions$*[)** z+, Q(9II#NN(9KKCPP   a&&CCCCCC  ;   [ ) ) ) ) ) T " " 2   % % % % %  (C 1 1 1 1 1sA A)) B 3BB c |t||j|j\}}|s"|t ||ddkrb|drX t }||dn-#t j$rtdd|didwxYw|Stj ds(|d s|d r|d d d tj |d|d\|d<}dD]}||st|d||\}} t!j|nG#t$$r:}|t't)|Yd}~nd}~wwxYw|||<|S)z% Parse CLI arguments ) as_from_rootr@phprUzNo such user (%s)r)rrz/usr/local/cpanelrrFsuccessz?Import/migrate of Python Selector applications is not supported)rwarningr)rVrMrN)rr/r4rrrget_pw_by_nameNoSuchUserExceptionr"r2r9isdirr $safely_resolve_username_and_doc_rootgetrr check_directory ValueErrorrr) r=rrdatapwdrj app_root_arg directoryrms r(rzCloudlinuxSelector._parse_args$sS6 $-d.@BBB  7  !5!5 6 6 6  E ) )H~  ''C&&tH~66660(': &X(K w}}011 qt 2 2 2  u%z2""    * \t/Z/Z/\/\ \  (,Y!Z [ [ [Z''r*c|\}}|jsP|jjd|d|d|jd}t j|dd|tdS| |\}}|r|d krdS| |||| |||dS) zM Change all applications all users versions :return: zD change-version-multiple --json --interpreter=nodejs --from-version=z --new-version= z >/dev/null &Tz /bin/bash)shell executableNr) rer6r1rr7rrrr!_get_all_apps_by_version_write_pid_file_move_apps_by_list)r=r]r^commandusers_apps_listrs r(rz2CloudlinuxSelector._start_change_all_apps_versionss $(#H#H#J#J j*  )EEE|||U_U_U_aeaqaqaqsG N7$; G G G G   [ ) ) ) F-1,I,I,,W,W)) "2a"7"7 F \:7GHHH =MNNNNNr*c t|D]|\}}|D]t}|jjdddtd|d|d|g }t j|}||dz}||tj du}d S) a Move applications from list from one NodeJS version to another :type dict :param apps_dict: Application list. List example: {'cltest1': [u'modjsapp_root'], 'cltest2': [u'app2', u'main_app']} :param to_version: Move applications to this version :param total_apps_count: Total applications count for move :return: None rrr@rUrVrPrN) rr1rrrrr_change_pid_filerFsleep) r= apps_dictr^r user_name user_app_listricmdrs r(rlz%CloudlinuxSelector._move_apps_by_lists)2)(<(<   $I})  *FxYhjp )\8_V`c$*3//##%%% A% %%&6777 2   r*ctt}|jj}d}t |D]\}} |jj|j|j|j }t |D]1\}} | d|kr || ||dz }2x#ttttf$rYwxYw||fS)aB Retrives list of all NodeJS applications for all users, which uses supplied version of NodeJS :param from_version: Required NodeJS version :return: Cortege: (application_list, application_count). Example: ({'cltest1': [u'modjsapp_root'], 'cltest2': [u'app2', u'main_app']}, 3) rnodejs_versionr)rrr1rZget_users_dictrread_user_selector_config_jsonpw_dirpw_uidpw_gidappendr TypeErrorrwAttributeError) r=r]users_apps_dict user_inforrt user_pw_entry user_app_datariapp_infos r(rjz+CloudlinuxSelector._get_all_apps_by_version s&d++&3BBDD (1)(<(<   $I}  $ 2 ? ^ ^!(!(!(!! +4M*B*B..&Hh 01\AA' 299(CCC(A-( . &y(NK     000s A1B<<CCc tjt|jd}|d|_dS#YnxYwdS)z] Determine is background process already working :return: True|False rr]TF)jsonloadr)r;r8)r=r@s r(rbz9CloudlinuxSelector._is_background_process_already_running+sH  9U4#6<<==D%).%9D "4  Dus48<c|jdtkrdS|j|}|j|}|}|r ||jkrdSdS)z Checks if NodeJS version blocked by background operation :param nj_version: NodeJS version to check :return: True - version is locked, False - not locked r@FT)r0rr1resolve_versionr\rbr8)r= nj_versionis_bkg_process_presents r(rz;CloudlinuxSelector._is_version_locked_by_background_process9sx :o && 0 05'77 CC 'DDZPP !%!L!L!N!N ! jD4J&J&J4ur*c *tjtjt |t |||t t jdt|jdtj |jddS)a Creates pid file for background process move version from version to version :param from_version: Move from NJ version :param to_version: Move to NJ version :param total_apps_count: Total application count to move :return: None )pidr]r^rrrFwN) rdumpr2getpidrfloatrFr)r;chmod)r=r]r^rs r(rkz"CloudlinuxSelector._write_pid_fileIs 9;; --j// 0$4$)++&&    $c * * , , , $e,,,,,r*ct|jd}tj|}||S)zc Reads pid file and returns it's content as dictionary :return: Dictionary r)r)r;rrcloser=fpid_datas r(_read_pid_filez!CloudlinuxSelector._read_pid_file\s5 $%s + +9Q<<  r*cT |}||d<tt\}}tj|t |dt j||jt j |jddS#tttf$rYdSwxYw)z Creates pid file for background process move version from version to version :param remaining_apps_count: Remaining application count to move :return: None r)dirrrN) rrrrrr)r2renamer;rOSErrorrcrw)r=rrrjtemp_file_names r(rqz#CloudlinuxSelector._change_pid_filefs **,,H/CH+ , 'J 7 7 7 A~ Ihnc : : ; ; ; Ind&9 : : : HT(% 0 0 0 0 0(+    66 sBB B'&B'c t|jd}tj|}||d|dfS#t t tf$rYdSwxYw)z Retrieves application counts from pid file :return: Cortege (remaining_apps_count, total_apps_count) If no background process started, returns None, None rrr)NN)r)r;rrrrrcrwrs r(r z0CloudlinuxSelector._get_apps_count_from_pid_filexss  d)3//Ay||H GGIII23X>P5QQ Q(+   :: sA AA*)A*ct}||} t|sdStj|rdS|tjjs tj||}tj |}||tjzrQtj |}tj |st|d|fSn2#ttf$r}dt|zdfcYd}~Sd}~wwxYwdS)a Validates passenger log file name :param username: User's name :param log_filename: passenger log file name to validate :return: tuple: (message, log_filename). message: "OK" - filename is valid, any other string - invalid, error text log_filename: corrected log filename - simlink dereferencing, appends user's homedir for relative paths, etc )zAERROR: Passenger log filename should contain only english lettersN)zDERROR: Passenger log file should be a filename, not a directory nameNrz%sN)z9ERROR: Passenger log file should be placed in user's homeN)r get_homedirr r2r9r; startswithsepr:realpathdirnamer\rrrcr)rhrrA user_homedir log_realpathrexcs r(rz4CloudlinuxSelector._passenger_log_filename_validatorsPggx00  )"<00 a``w}}\** dcc**27;77 H!w||L,GG 7++L99L&&|BF':;; *'//,77w~~g..%G$$$\))  * ! ) ) )#c((?D( ( ( ( ( ( ( )PPs)D.D.CD..E?EEEN)FF)r)Fr7)3__name__ __module__ __qualname__r>rSrnrqrp staticmethodrrrrrrrrrrrrrrrrrrrrrrrpropertyrrrW contextlibcontextmanagerrr_rerrlrjrbrrkrrqr rrr*r(r,r,?s5 V V V@%*$)88888%%%@SS\S CCCJ@@@0,,,777rGGG===&&&6!!!FOOOMMMOOOLLL''''''           222 999v$\<<<<:==X===X=    ( ( (((($OOO8,111@    ---&$   QQ\QQQr*r,)D __future__rrrr^rrFrdclcommon.cpapirsrrr2rrtypingr future.utilsrclcommonrclcommon.clexceptionr clcommon.mail_helperr clcommon.clfuncr cllicenser clselectr clselect.utilsrrrclselect.baseclselectrr cli_utilsrrclselect.clselectnodejsr"clselect.clselectnodejs.pkgmanagerr clselector.clpassenger_detectlibr collectionsremail.mime.textrtempfilercl_selector_arg_parserrrr selectorlibr r!r"clselect.clselectexceptrr]r)objectr,rr*r(rs&%%%%%&&&&&&  """"""333333++++++++++++****** FFFFFFFFFFPPPPPPPP66666666......999999BBBBBB######$$$$$$6666666666AAAAAAKKKKKKKKKKHHHHHH!!!b Qb Qb Qb Qb Qb Qb Qb Qb Qb Qr*