3 'ju@sddlZddlZddlZddlZddlZddlmZddlmZddl m Z ddl m Z ddl mZddlmZddlmZdd lmZdd lmZmZmZmZdd lmZeeeee d ZGd ddZdS)N)quote)load) InitSystem)JujuSSH)SSHControlPersist)LocalTransport) OCTransport)SaltStackMaster)CommandTimeoutExceptionConnectionExceptionUnsupportedHostExceptionInvalidTransportException)sos_parse_version)localZcontrol_persistZocZ saltstackZjujuc@seZdZdjddZeddZddZd d Zd d Zed dZ eddZ ddZ ddZ ddZ ddZdkddZeddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zdld0d1Zd2d3Zd4d5Zd6d7Zd8d9Zdmdd?Z d@dAZ!dBdCZ"dDdEZ#dFdGZ$dHdIZ%dJdKZ&dLdMZ'dNdOZ(dPdQZ)dRdSZ*dTdUZ+dVdWZ,dXdYZ-dZd[Z.d\d]Z/d^d_Z0d`daZ1dbdcZ2dddeZ3dfdgZ4dhdiZ5dS)nSosNodeNTcCs|j|_||_|d|_|j|d|_|d|_|d|_|d|_|jj |_ |jj |_ d|_ d|_ d|_ d|_i|_i|_|p|jj|_|jj r|jj r|j|j_|r||j_d|_d|_d|_g|_dgggg|dd|_d |_tjd |_tjd |_|j||_ |j j!r,|j j!d k|_y|j j"|jWn6t#k rt}z|j$d |WYdd}~XnX|j%|_ d|_&|j j|_|j r|jj'rd}|j(r|r|j s|j j)dS|j r|j*rd|j _+|j j+r|j,|j-dS)NZ cmdlineoptstmpdirhostlen need_sudo sos_optionsFsos_cmd)versionenableddisabledoptionspresetsr sosreportZsosZsos_uirootzUnable to open remote session: ).stripaddresscommonsopts_assign_config_optsrrrrnode_config_fileinherit_config_filerhostclusterhostname sos_env_vars _env_varspassword _passwordZ nopasswd_sudoZsudo_pwsos_path retrievedZhash_retrieved file_listsos_infosos_binloggingZ getLoggersoslogui_log_load_remote_transport _transportZ default_userZconnect Exception log_errordetermine_host_policy _sudo_binaryZno_local connected disconnectcheck_in_container containerizedcreate_sos_container_load_sos_info)selfrrr)Z local_sudoZ load_factserrrA/usr/lib/python3.6/sosnode.py__init__,st                  zSosNode.__init__cCs|jr|jjSdS)NT)r4r9)r?rArArBr9rszSosNode.connectedcCs|jjdS)zDWrapper to close the remote session via our transport agent N)r4r:)r?rArArBr:yszSosNode.disconnectcCst|jdkrd|_t|j|S|jjtkrSet the manifest section that this node will write to r&policyZ sos_versionrfinal_sos_commandrGN)manifest add_fieldrKr$os_release_namer.r4name)r?rbrArArBset_node_manifests zSosNode.set_node_manifestcCs<tjjdr|jddStjjddk r8|jddSdS)zV Tries to identify if we are currently running in a container or not. z/run/.containerenvz/Found /run/.containerenv. Running in container.TZ containerNz/Found env var 'container'. Running in containerF)rRpathexists log_debugrSget)r?rArArBr;s   zSosNode.check_in_containercCs|jjr|jj|jj|j|jjd}|j|dd}|ddkr|ddkrd|dkrf|jd t d |dkr|jd t |j|jj dd}|ddkr|j d |jj d dS|jd|dt |jd|dt dS)zJIf the host is containerized, create the container we'll be using )imageZauthZ force_pullT) need_rootrNr}zunable to retrieve auth tokenrOzHCould not pull image. Provide either a username and password or authfilezunknown: Not foundz%Specified image not found on registryzTemporary container z createdz(Could not start container after create: z$Could not create container on host: F)rrm) r$r<r=r rkget_container_authZforce_pull_imagerUr6r5Zrestart_sos_containerlog_infoZsos_container_name)r?cmdresrWrArArBr=s2        zSosNode.create_sos_containercCsB|jjr$|jjdj|jj|jjS|jjdj|jjp>|jjS)zrDetermine what the auth string should be to pull the image used to deploy our temporary container default) r Z registry_userr$ZruntimesZfmt_registry_credentialsZregistry_passwordZfmt_registry_authfileZregistry_authfileZcontainer_authfile)r?rArArBrns    zSosNode.get_container_authFc Cs:y |jd||d}|ddkStk r4dSXdS)z3Checks for the presence of fname on the remote nodezstat )rlrNrFN)rUr5)r?ZfnamerlrqrArArB file_existss  zSosNode.file_existscCs|jrd|jkr|jS|jS)NrD)r&r)r?rArArBrKszSosNode._hostnamecCsd}tj|d|S)zUAttempts to obfuscate sensitive information in log messages such as passwordsz>(?P(pass|key|secret|PASS|KEY|SECRET).*?=)(?P.*?\s)z\g****** )resub)r?rLZregrArArB_sanitize_log_msg szSosNode._sanitize_log_msgcCs|jj|j|dS)z:Format a ui message that includes host name and formattingN)r2inforM)r?rLrArArBui_msgszSosNode.ui_msgcCs8tjdd}d|jd|d|}|jj|dS)z#Used to print and log info messagesrJ[:z] N)inspectstackrKr1rw)r?rLcallerlmsgrArArBroszSosNode.log_infocCs8tjdd}d|jd|d|}|jj|dS)z$Used to print and log error messagesrJryrzr{z] N)r|r}rKr1error)r?rLr~rrArArBr6szSosNode.log_errorcCsB|j|}tjdd}d|jd|d|}|jj|dS)z$Used to print and log debug messagesrJryrzr{z] N)rvr|r}rKr1debug)r?rLr~rArArBri s zSosNode.log_debugcCsX|jjdtjjddk}|jr(|r(|S|jjr>dt|S|jrT|j d|S|S)zIf we need to provide a sudo or root password to a command, then here we prefix the command with the correct bits ZUSERrzsu -c  ) r(rjrRrSrr become_rootrrr^)r?rpZis_rootrArArB _format_cmd's zSosNode._format_cmdc Csd}d}|jjdkrN|jjj|jj}|dk rdj|d}|dr|d}n8|j|jjddd}|ddkr|d jjd \}}}|rt |jdd kr|d 7}y|d |jdd7}Wn2t k r}z|j d |WYdd}~XnX||j d<|j dr"|j d|j dn$|j|jjks<|jdd|_dS|jdrXd|_|jd}|j|ddd}|ddkr|j|d |jdr|jdS)zLQueries the node for information about the installed version of sos N.rreleaseT) use_containerrlrNrrO-z.0z#Unable to fully parse sos release: zsos version is z!sos is not installed on this nodeFz4.0z sos reportz -lz3.6)r$Zcontainer_version_commandpackage_managerZ pkg_versionZ sos_pkg_namejoinrUrrVlenr5rir.rorr Zprimaryr6r9check_sos_versionr/_load_sos_plugins_load_sos_presets) r?verZrelpkgZpkgs_r@rpsosinforArArBr>4sF     "      zSosNode._load_sos_infocCsr|jd}|j|ddd}|ddkrnxD|djD]4}|jjdr6|jddj}|jd j|q6WdS) Nz --list-presetsT)rrlrNrrOzname:rJr)r/rU splitlinesr startswithrVr.append)r?rprqlineZpnamerArArBrhs  zSosNode._load_sos_presetsc Csd}d}d}d}d}|d|}|d|}|d|} |dd} |j|||jd<|j|||jd <|j| ||jd <|j| |d |jd <dS) Nz,The following plugins are currently enabled:z-The following plugins are currently disabled:z4The following options are available for ALL plugins:z+The following plugin options are available:z Profiles:z(.*?)z rrrTZprofiles)_regex_sos_helpr.) r?rZENABLEDZDISABLEDZ ALL_OPTIONSZOPTIONSZPROFILESZ enableregZdisregZoptregZproregrArArBrqs    zSosNode._load_sos_pluginsc Csg}xtj||tjD]}x|jD]z}|sy|j}|rH|j|dWqtk r|}z|jd|WYdd}~XqXq$|jd} |jdd| Dq$WqW|S)NrzError parsing sos help: ,css|]}|jr|jVqdS)N)r).0prArArB sz*SosNode._regex_sos_help..) rtfindallSrrVrr5riextend) r?ZregexrZis_listrqresultrZlsr@rrArArBrs$ zSosNode._regex_sos_helpcCsXy|jd||jj|Stk rR}z|jd|d|dSd}~XnXdS)z1Reads the specified file and returns the contentsz Reading file zException while reading z: raN)ror4 read_filer5r6)r?Zto_readr@rArArBrs  zSosNode.read_filecCsz|jr(|jd|jdj|jdSti|jjtd|jj |j dd}|rh|jd|jd|S|j dt d S) z[Attempts to identify the host installation against supported distributions zusing local policy r_Tz/etc/os-release)cachesysrootZinitZ probe_runtimeZ remote_execZ remote_checkzloaded policy z for hostz4Unable to determine host installation. Ignoring nodeN) rrorrdrr rrr4rUrr6r )r?r$rArArBr7s  zSosNode.determine_host_policycCsPy|jd}t|t|kStk rJ}z|jd|dSd}~XnXdS)aChecks to see if the sos installation on the node is AT LEAST the given ver. This means that if the installed version is greater than ver, this will still return True :param ver: Version number we are trying to verify is installed :type ver: ``str`` :returns: True if installed version is at least ``ver``, else False :rtype: ``bool`` rzError checking sos version: FN)r.rr5r6)r?rZ _node_verr@rArArBrs  zSosNode.check_sos_versioncCs|js dS|jjj|dk S)z2Checks if a given package is installed on the nodeFN)r$rZ pkg_by_name)r?rrArArB is_installedszSosNode.is_installedrFc Cs|j rt|j rt|jdy$|jj|j}|s<|jdtWn4tk rr}z|jd|WYdd}~XnX|r|jj r|jj |}|r|j |}|r|j } | j |}|jj|||||S)aRuns a given cmd, either via the SSH session or locally :param cmd: The full command to be run :type cmd: ``str`` :param timeout: Time in seconds to wait for `cmd` to complete :type timeout: ``int`` :param use_shell: If a shell is needed to run `cmd`, set to True :type use_shell: ``bool`` or ``auto`` for transport-determined :param use_container: Run this command in a container *IF* the host is a containerized host :type use_container: ``bool`` :param env: Pass environment variables to set for this `cmd` :type env: ``dict`` z-Node is disconnected, attempting to reconnectzFailed to reconnect to nodez!Error while trying to reconnect: N)r9rrir4Z reconnectr*r r5r$r<Zformat_container_commandrrZupdaterU) r?rptimeout use_shellrlrenvZ reconnectedr@Z_cmd_envrArArBrUs&      zSosNode.run_commandcCsvy6|j}|r|j|n |jd|jr4|j|_Wn2tk rh}z|jd|WYdd}~XnX|jdS)z.Run an sos report on the node, then collect itz'Unable to determine path of sos archivezError during sos execution: N)execute_sos_commandfinalize_sos_pathr6r+retrieve_sosreportr,r5cleanup)r?rgr@rArArBrs  "zSosNode.sosreportcCs||jdkS)z/Verifies if the given preset exists on the noder)r.)r?presetrArArB_preset_existsszSosNode._preset_existscs&tfdd|jd|jdgDS)z/Verifies if the given plugin exists on the nodec3s|]}|kVqdS)NrA)rs)pluginrArBrsz)SosNode._plugin_exists..rr)anyr.)r?rrA)rrB_plugin_existsszSosNode._plugin_existscCs||jdkS)z6Checks to see if the plugin is default enabled on noder)r.)r?rrArArB_check_enabledszSosNode._check_enabledcCs||jdkS)z7Checks to see if the plugin is default disabled on noder)r.)r?rrArArB_check_disabledszSosNode._check_disabledcCsR|jdd}|j|sdS|j|r6||jjkr6dS|j|rN||jdkSdS)zAttempts to verify that the given option is available on the node. Note that we only get available options for enabled plugins, so if a plugin has been force-enabled we cannot validate if the plugin option is correct or notrrFrT)rVrrr enable_pluginsrr.)r?optplugrArArB_plugin_option_exists s    zSosNode._plugin_option_existscsdjfdd|DS)z^Returns a comma delimited list for sos plugins that are confirmed to exist on the noderc3s|]}j|r|VqdS)N)r)ro)r?rArBr sz,SosNode._fmt_sos_opt_list..)r)r?r rA)r?rB_fmt_sos_opt_listszSosNode._fmt_sos_opt_listcCs ||_dS)zVExpose the node to the cluster profile determined for the environment N)r%)r?r%rArArB set_cluster"szSosNode.set_clusterc s>|jjr0|js|jj|_n|jd|jjd|jjr`x&|jjD]}||jkrB|jj|qBW|jjrx,|jjD] |jkrr|jj|j<qrW|jjrxJ|jjD]>t fdd|j Dsd|jj}|j j|qW|jj |r|jj |jj |WdQRXn |jj |jj|WdQRXdS)a+This is used to modify the sos report command run on the nodes. By default, sos report is run without any options, using this will allow the profile to specify what plugins to run or not and what options to use. This will NOT override user supplied options. zCluster specified preset z> but user has also defined a preset. Using user specification.c3s|]}|kVqdS)NrA)rr)rrArBrDsz2SosNode.update_cmd_from_cluster..rQN)r%Z sos_presetrroZ sos_pluginsrrrZsos_plugin_optionsrplugoptsZcheck_node_is_primarylockZset_primary_optionsZset_node_options)r?rZoptionrA)rrBupdate_cmd_from_cluster(s,     zSosNode.update_cmd_from_clustercCsJt|jj|_t|jj|_t|jj|_t|jj|_t|jj|_dS)zFrom the global opts configuration, assign those values locally to this node so that they may be acted on individually. N)listr only_plugins skip_pluginsrrr)r?rArArBr!Ps zSosNode._assign_config_optscsjd}j}|r*|dt|d}g}jdr`jjdkr`|jdttjjjdrjjr|jdttjjjdr܈jj r|jd jj r|jd jj r|jd tjj jd r8jj r|jd tdj jj jjr8|jdtdj jjjdrjjjrj|jdttjjjdsjdrˆjjdkr|jdjjjjr|jdjjjdrjjr|jdjjjjr|jdj|jdtjj jjj}x:jD]0}j|}|jd|d|rP|ndq,WjrfddjD}|r|jdtdj d d!|Djrjjr|jd"tjnjd#jd$j rfd%dj D}t!|t!j kr@t"t#j t#|}jd&|d'j$j } | rf|jd(t| |ddj |_%j&d)j%j'j(d*j%d+Sj)rfd,dj)D} t!| t!j)krt"t#j)t#| } jd-| d.j$| } | r|jd/t| j*rfd0dj*D}t!|t!j*krvt"t#j*t#|} jd1| d2j$|}|r|jd3t||ddj |_%j&d)j%j'j(d*j%d+S)4zZUse host facts and compare to the cluster type to modify the sos command if neededrrz3.6z --threads=z3.7z--plugin-timeout=z3.8z--allow-system-changesz --no-env-varsz--since=z4.1z--skip-commands=rz --skip-files=z4.2z--cmd-timeout=z4.3z4.2-13rFz--container-runtime=z --namespaces=z4.5.2z--journal-size=z--low-priorityrz--racs8g|]0}j|jddrj|jddr|qS)rrrQ)rrVr)rr)r?rArB sz,SosNode.finalize_sos_cmd..z-k css|] }|VqdS)NrA)rrrArArBrsz+SosNode.finalize_sos_cmd..z --preset=zRequested to enable preset z" but preset does not exist on nodecsg|]}j|r|qSrA)r)rr)r?rArBrszRequested plugins z. were requested to be enabled but do not existz--only-plugins=zFinal sos command set to r`Ncsg|]}j|r|qSrA)r)rr)r?rArBrszRequested to skip plugins z%, but plugins are already not enabledz--skip-plugins=cs.g|]&}|jkrj|rj|r|qSrA)rrr)rr)r?rArBrs zRequested to enable plugins z1, but plugins are already enabled or do not existz--enable-plugins=)+r.determine_sos_labelrrr ZthreadsrstrZplugin_timeoutZallow_system_changesZ no_env_varsZsinceZ skip_commandsrZ skip_filesZ cmd_timeoutZcontainer_runtimeZ namespacesZ journal_sizeZ low_priorityrreplacerRrgr$Z sos_bin_pathr/rrrrrirrrsetrrrorbrcrr)r?rlabelZsos_optsrrYr ZplugsZnot_onlyZonlyskipZnot_skipZskiplnZnot_onenablerA)r?rBfinalize_sos_cmd[s                   &$   zSosNode.finalize_sos_cmdcCsd}||jj|7}|jjr<||s,|jjn d|jj7}|sDdS|jd||jdrdd}nd}|jjdd d|}|d |S) z?Determine what, if any, label should be added to the sos reportrarNzLabel for sos report set to z3.6z--labelz--namerrrQ)r%Zget_node_labelr rrirrrV)r?rZlcmdrArArBrs zSosNode.determine_sos_labelcCs^|jj}|r|j|d}|jd}|jd|||_|jdd|_|jjd|jdS) z\Use host facts to determine if we need to change the sos path we are retrieving fromrarzFinal sos path: r[rJZcollected_archiveNr]) r$Zsos_path_striprrVror+archiverbrc)r?rgZpstriprArArBrs  zSosNode.finalize_sos_pathcCsT|d kr dS|dkr d|kr dS|dkr,dSt|dkrJ|jdddSd |S) NrJz+sos report process received SIGKILL on noder\zsudo attempt failedz4sos report terminated unexpectedly. Check disk spacer zsos exited with code r])rrV)r?ZrcstdoutrArArBdetermine_sos_errors zSosNode.determine_sos_errorcCs:|jdyd}d}d}|jjr2d|jj}nR|jjr|jsvd|jjdd"d}|jj|jj |d|}nd|jj }|r|j d ||_ |j |j |jj d d d |j d }|d d krxZ|djD]J}tj|dr|j}|jd#r|jdd}q|jdr|jd}qW|r|jjd|t|dkrT|jjddn,t|dkrr|jjddn|jjddn|jjddn:|j|d |d}|jd|d d|dt||Stk r|jdYnFtk r4}z(|jd||jd |WYd!d!}~XnXd!S)$z2Run sos report and capture the resulting file pathzGenerating sos report...Fraz--config-file=z/tmp/r[rJz.confrT)rrrlrrrNrrOz*sosreport-*tar* sha256  md5  zThe checksum is: rychecksum Z checksum_typeZmd5@Zsha256unknownzError running sos report. rc = z msg = zTimeout exceededz'Exception during sos report execution: zError running sos report: Nr])rr)rxr r"r#rrrVr4Zcopy_file_to_remoteZ config_filerrUrr'rfnmatchrrrbrcrrrir5r r6ro)r?rgrZconfig_file_argZ remote_configrqrr@rArArBr sd       zSosNode.execute_sos_commandcCs|jd}tjj||jdd }yD|j|rR|jd|d||jj||S|j d|ddSt k r}z|j d|d |dSd }~XnXd S) z7Copies the specified file from the host to our temp dirr[rJzCopying remote z to local zAttempting to copy remote file z%, but it does not exist on filesystemFzFailed to retrieve z: Nr]) rrRrgrrVrsror4 retrieve_filerir5)r?rgZdestdirdestr@rArArBrGs  zSosNode.retrieve_filecCsdj|j}y|t|jddkr8|jd|ddS|j|rv|jd|d|}|j|d d }|d d kS|jd |ddStk r}z|jd|d|dSd}~XnXdS)z|Removes the spciefied file from the host. This should only be used after we have retrieved the file already rar[rzRefusing to remove path z0: appears to be incorrect and possibly dangerousFzRemoving file zrm -f T)rlrNrz!Attempting to remove remote file z%, but it does not exist on filesystemzFailed to remove z: N)rrVrrirsrorUr5)r?rgrprqerArArB remove_fileVs   zSosNode.remove_filecCs|js|jjr>y|j|jWntk r<|jddSX|jd|j|j dy|j |j}Wn*tk r}z|j|dSd}~XnX|r|j d|j j |jj dd d S|j d dS) z,Collect the sos report archive from the nodezFailed to make archive readableFzRetrieving sos report from zRetrieving sos report...Nz!Successfully collected sos reportr[rJTzFailed to retrieve sos reportr])rr rmake_archive_readabler+r5r6rorrxrr-rrV)r?rWr@rArArBrls&     zSosNode.retrieve_sosreportcCsT|jdks|jrdSd|jkr6|jd|jddS|j|j}|sP|jddS)zvRemove the sos report archive from the node, since we have collected it and it would be wasted space otherwiseNrzNode sos report path z/ looks incorrect. Not attempting to remove pathzFailed to remove sos report)r+rrirr6)r?ZremovedrArArBremove_sos_archives  zSosNode.remove_sos_archivecCsN|j|jr.xdD]}|j|j|rPqW|jj}|rJ|j|dddS)zrrrrr7rrrUrrrrrrrrrr!rrrrrrrrrrrrrArArArBr*sj E     (   4    '(   < r)rr|r0rRrtZshlexrZ sos.policiesrZsos.policies.init_systemsrZsos.collector.transports.jujurZ(sos.collector.transports.control_persistrZsos.collector.transports.localrZsos.collector.transports.ocrZ"sos.collector.transports.saltstackr Zsos.collector.exceptionsr r r r Z sos.utilitiesrrHrrArArArB s(