aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJake Hunsaker <jhunsake@redhat.com>2020-04-14 22:11:18 -0400
committerJake Hunsaker <jhunsake@redhat.com>2020-04-22 10:01:01 -0400
commitfc9327371a361954a1a9cade5cb7f206c31c6ad4 (patch)
tree58898c516ee0e98ed4b302ded7f3adebaafbc199
parentf1e27634bfac0f0a28d1a754bb89f7844df405b2 (diff)
downloadsos-fc9327371a361954a1a9cade5cb7f206c31c6ad4.tar.gz
[collector] Fix local collections requiring sudo
Local report generation when running as a non-root user were broken following the transition away from the Configuration() approach. Now, adjust to the new way we execute so that we properly detect non-root runs, prompt for a sudo password if needed, and/or fail appropriately if we cannot use sudo locally for generating the report. Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
-rw-r--r--sos/collector/__init__.py42
-rw-r--r--sos/collector/sosnode.py16
2 files changed, 49 insertions, 9 deletions
diff --git a/sos/collector/__init__.py b/sos/collector/__init__.py
index 74116106..0cac4320 100644
--- a/sos/collector/__init__.py
+++ b/sos/collector/__init__.py
@@ -90,7 +90,11 @@ class SoSCollector(SoSComponent):
self.node_list = []
self.master = False
self.retrieved = 0
- self.need_local_sudo = False
+ self.cluster = None
+ self.cluster_type = None
+ # add a place to set/get the sudo password, but do not expose it via
+ # the CLI, because security is a thing
+ setattr(self.opts, 'sudo_pw', '')
# get the local hostname and addresses to filter from results later
self.hostname = socket.gethostname()
try:
@@ -343,7 +347,8 @@ class SoSCollector(SoSComponent):
'need_sudo': True if self.opts.ssh_user != 'root' else False,
'opts': self.opts,
'tmpdir': self.tmpdir,
- 'hostlen': len(self.opts.master) or len(self.hostname)
+ 'hostlen': len(self.opts.master) or len(self.hostname),
+ 'policy': self.policy
}
def parse_cluster_options(self):
@@ -616,7 +621,32 @@ class SoSCollector(SoSComponent):
self.opts.no_local = True
else:
try:
- self.master = SosNode('localhost', self.commons)
+ can_run_local = True
+ local_sudo = None
+ skip_local_msg = (
+ "Local sos report generation forcibly skipped due "
+ "to lack of root privileges.\nEither use --insecure-sudo, "
+ "run as root, or do not use --batch so that you will be "
+ "prompted for a password\n"
+ )
+ if (not self.opts.no_local and (os.getuid() != 0 and not
+ self.opts.insecure_sudo)):
+ if not self.opts.batch:
+ msg = ("Enter local sudo password to generate local "
+ "sos report: ")
+ local_sudo = getpass(msg)
+ if local_sudo == '':
+ self.ui_log.info(skip_local_msg)
+ can_run_local = False
+ self.opts.no_local = True
+ local_sudo = None
+ else:
+ self.ui_log.info(skip_local_msg)
+ can_run_local = False
+ self.opts.no_local = True
+ self.master = SosNode('localhost', self.commons,
+ local_sudo=local_sudo,
+ load_facts=can_run_local)
except Exception as err:
self.log_debug("Unable to determine local installation: %s" %
err)
@@ -666,9 +696,9 @@ class SoSCollector(SoSComponent):
'installed.\nAborting...')
self.ui_log.info('The following is a list of nodes to collect from:')
- if self.master.connected:
+ if self.master.connected and self.master.hostname is not None:
self.ui_log.info('\t%-*s' % (self.commons['hostlen'],
- self.opts.master))
+ self.master.hostname))
for node in sorted(self.node_list):
self.ui_log.info("\t%-*s" % (self.commons['hostlen'], node))
@@ -731,7 +761,6 @@ class SoSCollector(SoSComponent):
If a list of nodes is given, this is not run, however the cluster
can still be run if the user sets a --cluster-type manually
"""
- self.cluster = None
checks = list(self.clusters.values())
for cluster in self.clusters.values():
checks.remove(cluster)
@@ -767,6 +796,7 @@ class SoSCollector(SoSComponent):
nodes = self.cluster._get_nodes()
self.log_debug('Node list: %s' % nodes)
return nodes
+ return []
def reduce_node_list(self):
"""Reduce duplicate entries of the localhost and/or master node
diff --git a/sos/collector/sosnode.py b/sos/collector/sosnode.py
index b9e9c028..9a845e2a 100644
--- a/sos/collector/sosnode.py
+++ b/sos/collector/sosnode.py
@@ -24,17 +24,22 @@ from sos.collector.exceptions import *
class SosNode():
- def __init__(self, address, commons, password=None,
- force=False, load_facts=True):
+ def __init__(self, address, commons, password=None, local_sudo=None,
+ load_facts=True):
self.address = address.strip()
+ self.commons = commons
self.opts = commons['opts']
self.tmpdir = commons['tmpdir']
self.hostlen = commons['hostlen']
self.need_sudo = commons['need_sudo']
self.local = False
+ self.host = None
self.cluster = None
self.hostname = None
self._password = password or self.opts.password
+ # override local sudo from any other source
+ if local_sudo:
+ self.opts.sudo_pw = local_sudo
self.sos_path = None
self.retrieved = False
self.hash_retrieved = False
@@ -53,7 +58,7 @@ class SosNode():
self.control_path = ("%s/.sos-collector-%s"
% (self.tmpdir, self.address))
self.ssh_cmd = self._create_ssh_command()
- if self.address not in filt or force:
+ if self.address not in filt:
try:
self.connected = self._create_ssh_session()
except Exception as err:
@@ -62,6 +67,7 @@ class SosNode():
else:
self.connected = True
self.local = True
+ self.need_sudo = os.getuid() != 0
if self.connected and load_facts:
self.host = self.determine_host_policy()
if not self.host:
@@ -293,6 +299,8 @@ class SosNode():
"""Attempts to identify the host installation against supported
distributions
"""
+ if self.local:
+ return self.commons['policy']
host = load(cache={}, sysroot=self.opts.sysroot, init=InitSystem(),
probe_runtime=False, remote_exec=self.ssh_cmd,
remote_check=self.read_file('/etc/os-release'))
@@ -311,6 +319,8 @@ class SosNode():
def is_installed(self, pkg):
"""Checks if a given package is installed on the node"""
+ if not self.host:
+ return False
return self.host.package_manager.pkg_by_name(pkg) is not None
def run_command(self, cmd, timeout=180, get_pty=False, need_root=False,