From 749b3ee31bebfca9b07abb4e29253d63816f5c6a Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Tue, 1 Feb 2022 15:14:09 -0500 Subject: [PATCH] import sos-4.1-9.el8_5 --- ...os-bz2011349-replace-dropbox-by-sftp.patch | 746 ++++++++++++++++++ SPECS/sos.spec | 13 +- 2 files changed, 758 insertions(+), 1 deletion(-) create mode 100644 SOURCES/sos-bz2011349-replace-dropbox-by-sftp.patch diff --git a/SOURCES/sos-bz2011349-replace-dropbox-by-sftp.patch b/SOURCES/sos-bz2011349-replace-dropbox-by-sftp.patch new file mode 100644 index 0000000..7c26d9b --- /dev/null +++ b/SOURCES/sos-bz2011349-replace-dropbox-by-sftp.patch @@ -0,0 +1,746 @@ +From 5298080d7360202c72b0af2e24994e4bfad72322 Mon Sep 17 00:00:00 2001 +From: Jake Hunsaker +Date: Fri, 14 May 2021 13:10:04 -0400 +Subject: [PATCH] [Policy] Add SFTP upload support + +Adds support for uploading via SFTP. This is done via pexpect calling +the system's locally available SFTP binary. If either that binary or +pexpect are unavailable on the local system, we will exit gracefully and +report the issue. This allows sos to keep python3-pexpect as a +recommends rather than a hard dependency. + +Signed-off-by: Jake Hunsaker +--- + man/en/sos-report.1 | 14 +++++ + sos/collector/__init__.py | 7 ++- + sos/policies/distros/__init__.py | 105 +++++++++++++++++++++++++++++-- + sos/report/__init__.py | 4 ++ + 4 files changed, 125 insertions(+), 5 deletions(-) + +diff --git a/man/en/sos-report.1 b/man/en/sos-report.1 +index c38753d4a..799defafc 100644 +--- a/man/en/sos-report.1 ++++ b/man/en/sos-report.1 +@@ -35,6 +35,7 @@ sosreport \- Collect and package diagnos + [--encrypt-pass PASS]\fR + [--upload] [--upload-url url] [--upload-user user]\fR + [--upload-directory dir] [--upload-pass pass]\fR ++ [--upload-protocol protocol]\fR + [--experimental]\fR + [-h|--help]\fR + +@@ -354,6 +355,19 @@ be used provided all other required valu + Specify a directory to upload to, if one is not specified by a vendor default location + or if your destination server does not allow writes to '/'. + .TP ++.B \--upload-protocol PROTO ++Manually specify the protocol to use for uploading to the target \fBupload-url\fR. ++ ++Normally this is determined via the upload address, assuming that the protocol is part ++of the address provided, e.g. 'https://example.com'. By using this option, sos will skip ++the protocol check and use the method defined for the specified PROTO. ++ ++For RHEL systems, setting this option to \fBsftp\fR will skip the initial attempt to ++upload to the Red Hat Customer Portal, and only attempt an upload to Red Hat's SFTP server, ++which is typically used as a fallback target. ++ ++Valid values for PROTO are: 'auto' (default), 'https', 'ftp', 'sftp'. ++.TP + .B \--experimental + Enable plugins marked as experimental. Experimental plugins may not have + been tested for this port or may still be under active development. +diff --git a/sos/collector/__init__.py b/sos/collector/__init__.py +index 5d1c599ac..1c742cf50 100644 +--- a/sos/collector/__init__.py ++++ b/sos/collector/__init__.py +@@ -106,6 +106,7 @@ class SoSCollector(SoSComponent): + 'upload_directory': None, + 'upload_user': None, + 'upload_pass': None, ++ 'upload_protocol': 'auto' + } + + def __init__(self, parser, parsed_args, cmdline_args): +@@ -383,6 +384,9 @@ class SoSCollector(SoSComponent): + help="Username to authenticate with") + collect_grp.add_argument("--upload-pass", default=None, + help="Password to authenticate with") ++ collect_grp.add_argument("--upload-protocol", default='auto', ++ choices=['auto', 'https', 'ftp', 'sftp'], ++ help="Manually specify the upload protocol") + + # Group the cleaner options together + cleaner_grp = parser.add_argument_group( +diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py +index 4268688c6..9fe31513b 100644 +--- a/sos/policies/distros/__init__.py ++++ b/sos/policies/distros/__init__.py +@@ -20,7 +20,7 @@ + from sos.policies.runtimes.podman import PodmanContainerRuntime + from sos.policies.runtimes.docker import DockerContainerRuntime + +-from sos.utilities import shell_out ++from sos.utilities import shell_out, is_executable + + + try: +@@ -295,7 +295,9 @@ def _determine_upload_type(self): + 'sftp': self.upload_sftp, + 'https': self.upload_https + } +- if '://' not in self.upload_url: ++ if self.commons['cmdlineopts'].upload_protocol in prots.keys(): ++ return prots[self.commons['cmdlineopts'].upload_protocol] ++ elif '://' not in self.upload_url: + raise Exception("Must provide protocol in upload URL") + prot, url = self.upload_url.split('://') + if prot not in prots.keys(): +@@ -361,7 +363,7 @@ def get_upload_password(self): + self.upload_password or + self._upload_password) + +- def upload_sftp(self): ++ def upload_sftp(self, user=None, password=None): + """Attempts to upload the archive to an SFTP location. + + Due to the lack of well maintained, secure, and generally widespread +@@ -371,7 +373,102 @@ def upload_sftp(self): + Do not override this method with one that uses python-paramiko, as the + upstream sos team will reject any PR that includes that dependency. + """ +- raise NotImplementedError("SFTP support is not yet implemented") ++ # if we somehow don't have sftp available locally, fail early ++ if not is_executable('sftp'): ++ raise Exception('SFTP is not locally supported') ++ ++ # soft dependency on python3-pexpect, which we need to use to control ++ # sftp login since as of this writing we don't have a viable solution ++ # via ssh python bindings commonly available among downstreams ++ try: ++ import pexpect ++ except ImportError: ++ raise Exception('SFTP upload requires python3-pexpect, which is ' ++ 'not currently installed') ++ ++ sftp_connected = False ++ ++ if not user: ++ user = self.get_upload_user() ++ if not password: ++ password = self.get_upload_password() ++ ++ # need to strip the protocol prefix here ++ sftp_url = self.get_upload_url().replace('sftp://', '') ++ sftp_cmd = "sftp -oStrictHostKeyChecking=no %s@%s" % (user, sftp_url) ++ ret = pexpect.spawn(sftp_cmd, encoding='utf-8') ++ ++ sftp_expects = [ ++ u'sftp>', ++ u'password:', ++ u'Connection refused', ++ pexpect.TIMEOUT, ++ pexpect.EOF ++ ] ++ ++ idx = ret.expect(sftp_expects, timeout=15) ++ ++ if idx == 0: ++ sftp_connected = True ++ elif idx == 1: ++ ret.sendline(password) ++ pass_expects = [ ++ u'sftp>', ++ u'Permission denied', ++ pexpect.TIMEOUT, ++ pexpect.EOF ++ ] ++ sftp_connected = ret.expect(pass_expects, timeout=10) == 0 ++ if not sftp_connected: ++ ret.close() ++ raise Exception("Incorrect username or password for %s" ++ % self.get_upload_url_string()) ++ elif idx == 2: ++ raise Exception("Connection refused by %s. Incorrect port?" ++ % self.get_upload_url_string()) ++ elif idx == 3: ++ raise Exception("Timeout hit trying to connect to %s" ++ % self.get_upload_url_string()) ++ elif idx == 4: ++ raise Exception("Unexpected error trying to connect to sftp: %s" ++ % ret.before) ++ ++ if not sftp_connected: ++ ret.close() ++ raise Exception("Unable to connect via SFTP to %s" ++ % self.get_upload_url_string()) ++ ++ put_cmd = 'put %s %s' % (self.upload_archive_name, ++ self._get_sftp_upload_name()) ++ ret.sendline(put_cmd) ++ ++ put_expects = [ ++ u'100%', ++ pexpect.TIMEOUT, ++ pexpect.EOF ++ ] ++ ++ put_success = ret.expect(put_expects, timeout=180) ++ ++ if put_success == 0: ++ ret.sendline('bye') ++ return True ++ elif put_success == 1: ++ raise Exception("Timeout expired while uploading") ++ elif put_success == 2: ++ raise Exception("Unknown error during upload: %s" % ret.before) ++ else: ++ raise Exception("Unexpected response from server: %s" % ret.before) ++ ++ def _get_sftp_upload_name(self): ++ """If a specific file name pattern is required by the SFTP server, ++ override this method in the relevant Policy. Otherwise the archive's ++ name on disk will be used ++ ++ :returns: Filename as it will exist on the SFTP server ++ :rtype: ``str`` ++ """ ++ return self.upload_archive_name.split('/')[-1] + + def _upload_https_streaming(self, archive): + """If upload_https() needs to use requests.put(), this method is used +diff --git a/sos/report/__init__.py b/sos/report/__init__.py +index df99186db..d43454092 100644 +--- a/sos/report/__init__.py ++++ b/sos/report/__init__.py +@@ -119,6 +119,7 @@ class SoSReport(SoSComponent): + 'upload_directory': None, + 'upload_user': None, + 'upload_pass': None, ++ 'upload_protocol': 'auto', + 'add_preset': '', + 'del_preset': '' + } +@@ -300,6 +301,9 @@ class SoSReport(SoSComponent): + help="Username to authenticate to server with") + report_grp.add_argument("--upload-pass", default=None, + help="Password to authenticate to server with") ++ report_grp.add_argument("--upload-protocol", default='auto', ++ choices=['auto', 'https', 'ftp', 'sftp'], ++ help="Manually specify the upload protocol") + + # Group to make add/del preset exclusive + preset_grp = report_grp.add_mutually_exclusive_group() +From d5316de87313c3eaf9fe4ce7a5eea3ed8c7d17ce Mon Sep 17 00:00:00 2001 +From: Jake Hunsaker +Date: Fri, 14 May 2021 13:11:27 -0400 +Subject: [PATCH] [Red Hat] Update policy to use SFTP instead of legacy FTP + dropbox + +As the FTP dropbox for Red Hat is being decomissioned and replaced with +an SFTP alternative, update the policy to fallback to the SFTP host and +remove legacy FTP host references. + +The default behavior for --upload remains the same, just targeting a +different location. If a username, password, and case number are given, +the first attempt will be to upload to the Red Hat Customer Portal. If +any are missing, or are invalid, then we will fallback to SFTP. During +the fallback if a valid username and password are not provided, sos will +attempt to obtain an anonymous token for the upload before failing out +entirely. + +Closes: #2467 +Resolves: #2552 + +Signed-off-by: Jake Hunsaker +--- + sos/policies/distros/redhat.py | 115 ++++++++++++++++++++++----------- + 1 file changed, 76 insertions(+), 39 deletions(-) + +diff --git a/sos/policies/distros/redhat.py b/sos/policies/distros/redhat.py +index f37519910..241d3f139 100644 +--- a/sos/policies/distros/redhat.py ++++ b/sos/policies/distros/redhat.py +@@ -8,6 +8,7 @@ + # + # See the LICENSE file in the source distribution for further information. + ++import json + import os + import sys + import re +@@ -20,6 +21,11 @@ + from sos.policies.package_managers.rpm import RpmPackageManager + from sos import _sos as _ + ++try: ++ import requests ++ REQUESTS_LOADED = True ++except ImportError: ++ REQUESTS_LOADED = False + + OS_RELEASE = "/etc/os-release" + RHEL_RELEASE_STR = "Red Hat Enterprise Linux" +@@ -39,9 +45,8 @@ class RedHatPolicy(LinuxPolicy): + _host_sysroot = '/' + default_scl_prefix = '/opt/rh' + name_pattern = 'friendly' +- upload_url = 'dropbox.redhat.com' +- upload_user = 'anonymous' +- upload_directory = '/incoming' ++ upload_url = None ++ upload_user = None + default_container_runtime = 'podman' + sos_pkg_name = 'sos' + sos_bin_path = '/usr/sbin' +@@ -196,7 +201,7 @@ def get_tmp_dir(self, opt_tmp_dir): + """ + + RH_API_HOST = "https://access.redhat.com" +-RH_FTP_HOST = "ftp://dropbox.redhat.com" ++RH_SFTP_HOST = "sftp://sftp.access.redhat.com" + + + class RHELPolicy(RedHatPolicy): +@@ -216,9 +216,7 @@ An archive containing the collected info + generated in %(tmpdir)s and may be provided to a %(vendor)s \ + support representative. + """ + disclaimer_text + "%(vendor_text)s\n") +- _upload_url = RH_FTP_HOST +- _upload_user = 'anonymous' +- _upload_directory = '/incoming' ++ _upload_url = RH_SFTP_HOST + + def __init__(self, sysroot=None, init=None, probe_runtime=True, + remote_exec=None): +@@ -260,33 +263,17 @@ def prompt_for_upload_user(self): + return + if self.case_id and not self.get_upload_user(): + self.upload_user = input(_( +- "Enter your Red Hat Customer Portal username (empty to use " +- "public dropbox): ") ++ "Enter your Red Hat Customer Portal username for uploading [" ++ "empty for anonymous SFTP]: ") + ) +- if not self.upload_user: +- self.upload_url = RH_FTP_HOST +- self.upload_user = self._upload_user +- +- def _upload_user_set(self): +- user = self.get_upload_user() +- return user and (user != 'anonymous') + + def get_upload_url(self): + if self.upload_url: + return self.upload_url +- if self.commons['cmdlineopts'].upload_url: ++ elif self.commons['cmdlineopts'].upload_url: + return self.commons['cmdlineopts'].upload_url +- # anonymous FTP server should be used as fallback when either: +- # - case id is not set, or +- # - upload user isn't set AND batch mode prevents to prompt for it +- if (not self.case_id) or \ +- ((not self._upload_user_set()) and +- self.commons['cmdlineopts'].batch): +- self.upload_user = self._upload_user +- if self.upload_directory is None: +- self.upload_directory = self._upload_directory +- self.upload_password = None +- return RH_FTP_HOST ++ elif self.commons['cmdlineopts'].upload_protocol == 'sftp': ++ return RH_SFTP_HOST + else: + rh_case_api = "/hydra/rest/cases/%s/attachments" + return RH_API_HOST + rh_case_api % self.case_id +@@ -299,27 +286,77 @@ def _get_upload_headers(self): + def get_upload_url_string(self): + if self.get_upload_url().startswith(RH_API_HOST): + return "Red Hat Customer Portal" +- return self.upload_url or RH_FTP_HOST ++ elif self.get_upload_url().startswith(RH_SFTP_HOST): ++ return "Red Hat Secure FTP" ++ return self.upload_url + +- def get_upload_user(self): +- # if this is anything other than dropbox, annonymous won't work +- if self.upload_url != RH_FTP_HOST: +- return os.getenv('SOSUPLOADUSER', None) or self.upload_user +- return self._upload_user ++ def _get_sftp_upload_name(self): ++ """The RH SFTP server will only automatically connect file uploads to ++ cases if the filename _starts_ with the case number ++ """ ++ if self.case_id: ++ return "%s_%s" % (self.case_id, ++ self.upload_archive_name.split('/')[-1]) ++ return self.upload_archive_name ++ ++ def upload_sftp(self): ++ """Override the base upload_sftp to allow for setting an on-demand ++ generated anonymous login for the RH SFTP server if a username and ++ password are not given ++ """ ++ if RH_SFTP_HOST.split('//')[1] not in self.get_upload_url(): ++ return super(RHELPolicy, self).upload_sftp() ++ ++ if not REQUESTS_LOADED: ++ raise Exception("python3-requests is not installed and is required" ++ " for obtaining SFTP auth token.") ++ _token = None ++ _user = None ++ # we have a username and password, but we need to reset the password ++ # to be the token returned from the auth endpoint ++ if self.get_upload_user() and self.get_upload_password(): ++ url = RH_API_HOST + '/hydra/rest/v1/sftp/token' ++ auth = self.get_upload_https_auth() ++ ret = requests.get(url, auth=auth, timeout=10) ++ if ret.status_code == 200: ++ # credentials are valid ++ _user = self.get_upload_user() ++ _token = json.loads(ret.text)['token'] ++ else: ++ print("Unable to retrieve Red Hat auth token using provided " ++ "credentials. Will try anonymous.") ++ # we either do not have a username or password/token, or both ++ if not _token: ++ aurl = RH_API_HOST + '/hydra/rest/v1/sftp/token?isAnonymous=true' ++ anon = requests.get(aurl, timeout=10) ++ if anon.status_code == 200: ++ resp = json.loads(anon.text) ++ _user = resp['username'] ++ _token = resp['token'] ++ print("Using anonymous user %s for upload. Please inform your " ++ "support engineer." % _user) ++ if _user and _token: ++ return super(RHELPolicy, self).upload_sftp(user=_user, ++ password=_token) ++ raise Exception("Could not retrieve valid or anonymous credentials") + + def upload_archive(self, archive): + """Override the base upload_archive to provide for automatic failover + from RHCP failures to the public RH dropbox + """ + try: ++ if not self.get_upload_user() or not self.get_upload_password(): ++ self.upload_url = RH_SFTP_HOST + uploaded = super(RHELPolicy, self).upload_archive(archive) + except Exception: + uploaded = False +- if not uploaded and self.upload_url.startswith(RH_API_HOST): +- print("Upload to Red Hat Customer Portal failed. Trying %s" +- % RH_FTP_HOST) +- self.upload_url = RH_FTP_HOST +- uploaded = super(RHELPolicy, self).upload_archive(archive) ++ if not self.upload_url.startswith(RH_API_HOST): ++ raise ++ else: ++ print("Upload to Red Hat Customer Portal failed. Trying %s" ++ % RH_SFTP_HOST) ++ self.upload_url = RH_SFTP_HOST ++ uploaded = super(RHELPolicy, self).upload_archive(archive) + return uploaded + + def dist_version(self): +From 8a7ae6a3ac69a020758f7b0825a872e44714dbed Mon Sep 17 00:00:00 2001 +From: Jake Hunsaker +Date: Fri, 9 Apr 2021 11:05:47 -0400 +Subject: [PATCH] [ubuntu|Policy] Fix exception when attempting upload + +Fixes an issue where an upload attempt on Ubuntu systems would fail with +a traceback due to the upload archive's name not being available when we +first check to make sure we have an upload location, since the Ubuntu +default location requires an archive/file name. + +Related to this, stop clobbering `upload_archive` and assign the archive +name to an `upload_archive_name` variable instead. + +Closes: #2472 +Resolves: #2479 + +Signed-off-by: Jake Hunsaker +--- + sos/policies/distros/__init__.py | 9 +++++---- + sos/policies/distros/ubuntu.py | 4 +++- + 2 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py +index 022ba7f4c6..a24a0e5beb 100644 +--- a/sos/policies/distros/__init__.py ++++ b/sos/policies/distros/__init__.py +@@ -149,6 +149,7 @@ def pre_work(self): + self.upload_user = cmdline_opts.upload_user + self.upload_directory = cmdline_opts.upload_directory + self.upload_password = cmdline_opts.upload_pass ++ self.upload_archive_name = '' + + if not cmdline_opts.batch and not \ + cmdline_opts.quiet: +@@ -237,7 +238,7 @@ def upload_archive(self, archive): + `get_upload_url_string()` + Print a more human-friendly string than vendor URLs + """ +- self.upload_archive = archive ++ self.upload_archive_name = archive + if not self.upload_url: + self.upload_url = self.get_upload_url() + if not self.upload_url: +@@ -384,7 +385,7 @@ def upload_https(self): + raise Exception("Unable to upload due to missing python requests " + "library") + +- with open(self.upload_archive, 'rb') as arc: ++ with open(self.upload_archive_name, 'rb') as arc: + if not self._use_https_streaming: + r = self._upload_https_no_stream(arc) + else: +@@ -467,9 +468,9 @@ def upload_ftp(self, url=None, directory=None, user=None, password=None): + % str(err)) + + try: +- with open(self.upload_archive, 'rb') as _arcfile: ++ with open(self.upload_archive_name, 'rb') as _arcfile: + session.storbinary( +- "STOR %s" % self.upload_archive.split('/')[-1], ++ "STOR %s" % self.upload_archive_name.split('/')[-1], + _arcfile + ) + session.quit() +diff --git a/sos/policies/distros/ubuntu.py b/sos/policies/distros/ubuntu.py +index 94a4a241b0..308c1e3544 100644 +--- a/sos/policies/distros/ubuntu.py ++++ b/sos/policies/distros/ubuntu.py +@@ -74,7 +74,9 @@ def get_upload_url_string(self): + + def get_upload_url(self): + if not self.upload_url or self.upload_url.startswith(self._upload_url): +- fname = os.path.basename(self.upload_archive) ++ if not self.upload_archive_name: ++ return self._upload_url ++ fname = os.path.basename(self.upload_archive_name) + return self._upload_url + fname + super(UbuntuPolicy, self).get_upload_url() + +From 2e8b5e2d4f30854cce93d149fc7d24b9d9cfd02c Mon Sep 17 00:00:00 2001 +From: Pavel Moravec +Date: Fri, 19 Nov 2021 16:16:07 +0100 +Subject: [PATCH 1/3] [policies] strip path from SFTP upload filename + +When case_id is not supplied, we ask SFTP server to store the uploaded +file under name /var/tmp/, which is confusing. + +Let remove the path from it also in case_id not supplied. + +Related to: #2764 + +Signed-off-by: Pavel Moravec +--- + sos/policies/distros/redhat.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/sos/policies/distros/redhat.py b/sos/policies/distros/redhat.py +index 3476e21fb..8817fc785 100644 +--- a/sos/policies/distros/redhat.py ++++ b/sos/policies/distros/redhat.py +@@ -269,10 +269,10 @@ def _get_sftp_upload_name(self): + """The RH SFTP server will only automatically connect file uploads to + cases if the filename _starts_ with the case number + """ ++ fname = self.upload_archive_name.split('/')[-1] + if self.case_id: +- return "%s_%s" % (self.case_id, +- self.upload_archive_name.split('/')[-1]) +- return self.upload_archive_name ++ return "%s_%s" % (self.case_id, fname) ++ return fname + + def upload_sftp(self): + """Override the base upload_sftp to allow for setting an on-demand + +From 61023b29a656dd7afaa4a0643368b0a53f1a3779 Mon Sep 17 00:00:00 2001 +From: Pavel Moravec +Date: Fri, 19 Nov 2021 17:31:31 +0100 +Subject: [PATCH 2/3] [redhat] update SFTP API version to v2 + +Change API version from v1 to v2, which includes: +- change of URL +- different URI +- POST method for token generation instead of GET + +Resolves: #2764 + +Signed-off-by: Pavel Moravec +--- + sos/policies/distros/redhat.py | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/sos/policies/distros/redhat.py b/sos/policies/distros/redhat.py +index 8817fc785..e4e2b8835 100644 +--- a/sos/policies/distros/redhat.py ++++ b/sos/policies/distros/redhat.py +@@ -175,7 +175,7 @@ def get_tmp_dir(self, opt_tmp_dir): + No changes will be made to system configuration. + """ + +-RH_API_HOST = "https://access.redhat.com" ++RH_API_HOST = "https://api.access.redhat.com" + RH_SFTP_HOST = "sftp://sftp.access.redhat.com" + + +@@ -287,12 +287,12 @@ def upload_sftp(self): + " for obtaining SFTP auth token.") + _token = None + _user = None ++ url = RH_API_HOST + '/support/v2/sftp/token' + # we have a username and password, but we need to reset the password + # to be the token returned from the auth endpoint + if self.get_upload_user() and self.get_upload_password(): +- url = RH_API_HOST + '/hydra/rest/v1/sftp/token' + auth = self.get_upload_https_auth() +- ret = requests.get(url, auth=auth, timeout=10) ++ ret = requests.post(url, auth=auth, timeout=10) + if ret.status_code == 200: + # credentials are valid + _user = self.get_upload_user() +@@ -302,8 +302,8 @@ def upload_sftp(self): + "credentials. Will try anonymous.") + # we either do not have a username or password/token, or both + if not _token: +- aurl = RH_API_HOST + '/hydra/rest/v1/sftp/token?isAnonymous=true' +- anon = requests.get(aurl, timeout=10) ++ adata = {"isAnonymous": True} ++ anon = requests.post(url, data=json.dumps(adata), timeout=10) + if anon.status_code == 200: + resp = json.loads(anon.text) + _user = resp['username'] + +From 267da2156ec61f526dd28e760ff6528408a76c3f Mon Sep 17 00:00:00 2001 +From: Pavel Moravec +Date: Mon, 22 Nov 2021 15:22:32 +0100 +Subject: [PATCH 3/3] [policies] Deal 200 return code as success + +Return code 200 of POST method request must be dealt as success. + +Newly required due to the SFTP API change using POST. + +Related to: #2764 + +Signed-off-by: Pavel Moravec +--- + sos/policies/distros/__init__.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py +index 0906fa779..6f257fdce 100644 +--- a/sos/policies/distros/__init__.py ++++ b/sos/policies/distros/__init__.py +@@ -488,7 +488,7 @@ class LinuxPolicy(Policy): + r = self._upload_https_no_stream(arc) + else: + r = self._upload_https_streaming(arc) +- if r.status_code != 201: ++ if r.status_code != 200 and r.status_code != 201: + if r.status_code == 401: + raise Exception( + "Authentication failed: invalid user credentials" +From 8da1b14246226792c160dd04e5c7c75dd4e8d44b Mon Sep 17 00:00:00 2001 +From: Pavel Moravec +Date: Mon, 22 Nov 2021 10:44:09 +0100 +Subject: [PATCH] [collect] fix moved get_upload_url under Policy class + +SoSCollector does not further declare get_upload_url method +as that was moved under Policy class(es). + +Resolves: #2766 + +Signed-off-by: Pavel Moravec +--- + sos/collector/__init__.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sos/collector/__init__.py b/sos/collector/__init__.py +index 50183e873..42a7731d6 100644 +--- a/sos/collector/__init__.py ++++ b/sos/collector/__init__.py +@@ -1219,7 +1219,7 @@ this utility or remote systems that it c + msg = 'No sosreports were collected, nothing to archive...' + self.exit(msg, 1) + +- if self.opts.upload and self.get_upload_url(): ++ if self.opts.upload and self.policy.get_upload_url(): + try: + self.policy.upload_archive(arc_name) + self.ui_log.info("Uploaded archive successfully") + +From abb2fc65bd14760021c61699ad3113cab3bd4c64 Mon Sep 17 00:00:00 2001 +From: Pavel Moravec +Date: Tue, 30 Nov 2021 11:37:02 +0100 +Subject: [PATCH 1/2] [redhat] Fix broken URI to upload to customer portal + +Revert back the unwanted change in URI of uploading tarball to the +Red Hat Customer portal. + +Related: #2772 + +Signed-off-by: Pavel Moravec +--- + sos/policies/distros/redhat.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sos/policies/distros/redhat.py b/sos/policies/distros/redhat.py +index e4e2b883..eb442407 100644 +--- a/sos/policies/distros/redhat.py ++++ b/sos/policies/distros/redhat.py +@@ -250,7 +250,7 @@ support representative. + elif self.commons['cmdlineopts'].upload_protocol == 'sftp': + return RH_SFTP_HOST + else: +- rh_case_api = "/hydra/rest/cases/%s/attachments" ++ rh_case_api = "/support/v1/cases/%s/attachments" + return RH_API_HOST + rh_case_api % self.case_id + + def _get_upload_headers(self): +-- +2.31.1 + + +From ea4f9e88a412c80a4791396e1bb78ac1e24ece14 Mon Sep 17 00:00:00 2001 +From: Pavel Moravec +Date: Tue, 30 Nov 2021 13:00:26 +0100 +Subject: [PATCH 2/2] [policy] Add error message when FTP upload write failure + +When (S)FTP upload fails to write the destination file, +our "expect" code should detect it sooner than after timeout happens +and write appropriate error message. + +Resolves: #2772 + +Signed-off-by: Pavel Moravec +--- + sos/policies/distros/__init__.py | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py +index 6f257fdc..7bdc81b8 100644 +--- a/sos/policies/distros/__init__.py ++++ b/sos/policies/distros/__init__.py +@@ -473,7 +473,8 @@ class LinuxPolicy(Policy): + put_expects = [ + u'100%', + pexpect.TIMEOUT, +- pexpect.EOF ++ pexpect.EOF, ++ u'No such file or directory' + ] + + put_success = ret.expect(put_expects, timeout=180) +@@ -485,6 +486,8 @@ class LinuxPolicy(Policy): + raise Exception("Timeout expired while uploading") + elif put_success == 2: + raise Exception("Unknown error during upload: %s" % ret.before) ++ elif put_success == 3: ++ raise Exception("Unable to write archive to destination") + else: + raise Exception("Unexpected response from server: %s" % ret.before) + +-- +2.31.1 + diff --git a/SPECS/sos.spec b/SPECS/sos.spec index 30e6657..95931ee 100644 --- a/SPECS/sos.spec +++ b/SPECS/sos.spec @@ -5,7 +5,7 @@ Summary: A set of tools to gather troubleshooting information from a system Name: sos Version: 4.1 -Release: 5%{?dist} +Release: 9%{?dist} Group: Applications/System Source0: https://github.com/sosreport/sos/archive/%{version}/sos-%{version}.tar.gz Source1: sos-audit-%{auditversion}.tgz @@ -20,6 +20,7 @@ Requires: xz Conflicts: vdsm < 4.40 Obsoletes: sos-collector Recommends: python3-pexpect +Recommends: python3-requests Patch1: sos-bz1930181-collect-cleaning-consistency.patch Patch2: sos-bz1935603-manpages-see-also.patch Patch3: sos-bz1937418-add-cmd-timeout.patch @@ -42,6 +43,7 @@ Patch19: sos-bz1985986-potential-issues-static-analyse.patch Patch20: sos-bz1959598-conversions-and-upgrades.patch Patch21: sos-bz1665947-rhui-plugin.patch Patch22: sos-bz1985037-cleaner-AD-users-obfuscation.patch +Patch23: sos-bz2011349-replace-dropbox-by-sftp.patch %description @@ -75,6 +77,7 @@ support technicians and developers. %patch20 -p1 %patch21 -p1 %patch22 -p1 +%patch23 -p1 %build %py3_build @@ -141,6 +144,14 @@ of the system. Currently storage and filesystem commands are audited. %ghost /etc/audit/rules.d/40-sos-storage.rules %changelog +* Tue Nov 30 2021 Pavel Moravec = 4.1-9 +- [redhat] Fix broken URI to upload to customer portal + Resolves: bz2011349 + +* Mon Nov 22 2021 Pavel Moravec = 4.1-8 +- [Red Hat] Update policy to use SFTP, update RHST API to v2 + Resolves: bz2011349 + * Wed Aug 11 2021 Pavel Moravec = 4.1-5 - [report,collect] unify --map-file arguments Resolves: bz1923938