Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[collect] Handle custom node and inherited configs with collections #3852

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions sos/collector/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class SoSCollector(SoSComponent):
'encrypt_pass': '',
'group': None,
'image': '',
'inherit_config_file': False,
'force_pull_image': True,
'skip_cleaning_files': [],
'jobs': 4,
Expand All @@ -102,6 +103,7 @@ class SoSCollector(SoSComponent):
'map_file': '/etc/sos/cleaner/default_mapping',
'primary': '',
'namespaces': None,
'node_config_file': None,
'nodes': [],
'no_env_vars': False,
'no_local': False,
Expand Down Expand Up @@ -362,6 +364,14 @@ def add_parser_options(cls, parser):
dest='become_root',
help='Become root on the remote nodes')
collect_grp.add_argument('--case-id', help='Specify case number')
collect_grp.add_argument('--inherit-config-file', default=False,
action='store_true',
help='Use the config file from the collector '
'for all nodes to use with sos report')
collect_grp.add_argument('--node-config-file', type=str,
default=None,
help='Path to an existing config file on the '
'nodes to use with sos report')
collect_grp.add_argument('--cluster-type',
help='Specify a type of cluster profile')
collect_grp.add_argument('-c', '--cluster-option',
Expand Down
17 changes: 17 additions & 0 deletions sos/collector/sosnode.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ def __init__(self, address, commons, password=None, local_sudo=None,
self.hostlen = commons['hostlen']
self.need_sudo = commons['need_sudo']
self.sos_options = commons['sos_options']
self.node_config_file = self.opts.node_config_file
self.inherit_config_file = self.opts.inherit_config_file
self.local = False
self.host = None
self.cluster = None
Expand Down Expand Up @@ -762,6 +764,21 @@ def execute_sos_command(self):
try:
path = False
checksum = False
config_file_arg = ''
if self.opts.node_config_file:
config_file_arg = f'--config-file={self.opts.node_config_file}'
elif self.opts.inherit_config_file:
if not self.local:
remote_config = f"/tmp/{self.tmpdir.split('/')[-1]}.conf"
self._transport.copy_file_to_remote(
self.opts.config_file,
remote_config)
config_file_arg = f'--config-file={remote_config}'
else:
config_file_arg = (
f'--config-file={self.opts.config_file}')
if config_file_arg:
self.sos_cmd = f"{self.sos_cmd} {config_file_arg}"
res = self.run_command(self.sos_cmd,
timeout=self.opts.timeout,
use_shell=True,
Expand Down
31 changes: 31 additions & 0 deletions sos/collector/transports/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,37 @@ def _get_hostname(self):
self.log_info(f"Hostname set to {self._hostname}")
return self._hostname

def copy_file_to_remote(self, fname, dest):
"""Copy a local file, fname, to dest on the remote node

:param fname: The name of the file to copy
:type fname: ``str``

:param dest: Where to save the file to remotely
:type dest: ``str``

:returns: True if file was successfully copied to remote, or False
:rtype: ``bool``
"""
attempts = 0
try:
while attempts < 3:
attempts += 1
ret = self._copy_file_to_remote(fname, dest)
if ret:
return True
self.log_info(f"File copy attempt {attempts} failed")
self.log_info("File copy failed after 3 attempts")
return False
except Exception as err:
self.log_error("Exception encountered during config copy attempt "
f"{attempts} for {fname}: {err}")
raise err

def _copy_file_to_remote(self, fname, dest):
TrevorBenson marked this conversation as resolved.
Show resolved Hide resolved
raise NotImplementedError(
f"Transport {self.name} does not support file copying")

def retrieve_file(self, fname, dest):
"""Copy a remote file, fname, to dest on the local node

Expand Down
6 changes: 6 additions & 0 deletions sos/collector/transports/control_persist.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ def remote_exec(self):
f"{self.opts.ssh_user}@{self.address}")
return self.ssh_cmd

def _copy_file_to_remote(self, fname, dest):
cmd = (f"/usr/bin/scp -oControlPath={self.control_path} "
f"{fname} {self.opts.ssh_user}@{self.address}:{dest}")
res = sos_get_command_output(cmd, timeout=10)
return res['status'] == 0

def _retrieve_file(self, fname, dest):
cmd = (f"/usr/bin/scp -oControlPath={self.control_path} "
f"{self.opts.ssh_user}@{self.address}:{fname} {dest}")
Expand Down
7 changes: 7 additions & 0 deletions sos/collector/transports/juju.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ def remote_exec(self):
option = f"{model_option} {target_option}"
return f"juju ssh {option}"

def _copy_file_to_remote(self, fname, dest):
model, unit = self.address.split(":")
model_option = f"-m {model}" if model else ""
cmd = f"juju scp {model_option} -- {fname} {unit}:{dest}"
res = sos_get_command_output(cmd, timeout=15)
return res["status"] == 0

def _retrieve_file(self, fname, dest):
self._chmod(fname) # juju scp needs the archive to be world-readable
model, unit = self.address.split(":")
Expand Down
3 changes: 3 additions & 0 deletions sos/collector/transports/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ def _retrieve_file(self, fname, dest):
def _format_cmd_for_exec(self, cmd):
return cmd

def _copy_file_to_remote(self, fname, dest):
return True

def _read_file(self, fname):
if os.path.exists(fname):
with open(fname, 'r', encoding='utf-8') as rfile:
Expand Down
7 changes: 7 additions & 0 deletions sos/collector/transports/oc.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,13 @@ def remote_exec(self):
return (f"oc -n {self.project} exec --request-timeout=0 "
f"{self.pod_name} -- /bin/bash -c")

def _copy_file_to_remote(self, fname, dest):
result = self.run_oc("cp --retries", stderr=True)
flags = '' if "unknown flag" in result["output"] else '--retries=5'
cmd = self.run_oc(f"cp {flags} {fname} {self.pod_name}:{dest}",
timeout=15)
return cmd['status'] == 0

def _retrieve_file(self, fname, dest):
# check if --retries flag is available for given version of oc
result = self.run_oc("cp --retries", stderr=True)
Expand Down
28 changes: 26 additions & 2 deletions sos/collector/transports/saltstack.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ def run_command(self, cmd, timeout=180, need_root=False, env=None,
ret['output'] = self._convert_output_json(ret['output'])
return ret

def _salt_copy_file(self, node, fname, dest):
"""
Execute cp.get_file on the remote host using SaltStack Master
"""
cmd = f"salt-cp {node} {fname} {dest}"
res = sos_get_command_output(cmd, timeout=15)
return res['status'] == 0

def _salt_retrieve_file(self, node, fname, dest):
"""
Execute cp.push on the remote host using SaltStack Master
Expand Down Expand Up @@ -119,12 +127,28 @@ def remote_exec(self):
salt_args = "--out json --static --no-color"
return f"salt {salt_args} {self.address} cmd.shell "

def _copy_file_to_remote(self, fname, dest):
"""Copy a file to the remote host using SaltStack Master

Parameters
fname The path to the file on the master
dest The path to the destination directory on the remote host

Returns
True if the file was copied, else False
"""
return (
self._salt_copy_file(self.address, fname, dest)
if self.connected
else False
)

def _retrieve_file(self, fname, dest):
"""Retrieve a file from the remote host using saltstack

Parameters
fname The path to the file on the remote host
dest The path to the destination directory on the master
fname The path to the file on the remote host
dest The path to the destination directory on the master

Returns
True if the file was retrieved, else False
Expand Down
Loading