Merge pull request #65485 from s0undt3ch/hotfix/merge-forward

[master] Merge 3006.x into master
This commit is contained in:
Pedro Algarvio 2023-10-31 09:31:41 +00:00 committed by GitHub
commit 53f54d08d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
78 changed files with 3692 additions and 2595 deletions

View file

@ -7,6 +7,31 @@ Versions are `MAJOR.PATCH`.
# Changelog
## 3006.4 (2023-10-16)
### Security
- Fix CVE-2023-34049 by ensuring we do not use a predictable name for the script and correctly check returncode of scp command.
This only impacts salt-ssh users using the pre-flight option. [#cve-2023-34049](https://github.com/saltstack/salt/issues/cve-2023-34049)
- Update to `gitpython>=3.1.35` due to https://github.com/advisories/GHSA-wfm5-v35h-vwf4 and https://github.com/advisories/GHSA-cwvm-v4w8-q58c [#65163](https://github.com/saltstack/salt/issues/65163)
- Bump to `cryptography==41.0.4` due to https://github.com/advisories/GHSA-v8gr-m533-ghj9 [#65268](https://github.com/saltstack/salt/issues/65268)
- Upgrade relenv to 0.13.12 to address CVE-2023-4807 [#65316](https://github.com/saltstack/salt/issues/65316)
- Bump to `urllib3==1.26.17` or `urllib3==2.0.6` due to https://github.com/advisories/GHSA-v845-jxx5-vc9f [#65334](https://github.com/saltstack/salt/issues/65334)
- Bump to `gitpython==3.1.37` due to https://github.com/advisories/GHSA-cwvm-v4w8-q58c [#65383](https://github.com/saltstack/salt/issues/65383)
## 3005.4 (2023-10-16)
### Security
- Fix CVE-2023-34049 by ensuring we do not use a predictable name for the script and correctly check returncode of scp command.
This only impacts salt-ssh users using the pre-flight option. (cve-2023-34049)
- Bump to `cryptography==41.0.4` due to https://github.com/advisories/GHSA-v8gr-m533-ghj9 (#65267)
- Bump to `urllib3==1.26.17` or `urllib3==2.0.6` due to https://github.com/advisories/GHSA-v845-jxx5-vc9f (#65334)
- Bump to `gitpython==3.1.37` due to https://github.com/advisories/GHSA-cwvm-v4w8-q58c (#65383)
## Salt v3005.3 (2023-09-14)
### Fixed

1
changelog/64572.fixed.md Normal file
View file

@ -0,0 +1 @@
Move salt.ufw to correct location /etc/ufw/applications.d/

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT-API" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT-API" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt-api \- salt-api Command
.sp

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT-CALL" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT-CALL" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt-call \- salt-call Documentation
.SH SYNOPSIS

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT-CLOUD" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT-CLOUD" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt-cloud \- Salt Cloud Command
.sp

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT-CP" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT-CP" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt-cp \- salt-cp Documentation
.sp

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT-KEY" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT-KEY" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt-key \- salt-key Documentation
.SH SYNOPSIS

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT-MASTER" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT-MASTER" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt-master \- salt-master Documentation
.sp

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT-MINION" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT-MINION" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt-minion \- salt-minion Documentation
.sp

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT-PROXY" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT-PROXY" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt-proxy \- salt-proxy Documentation
.sp

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT-RUN" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT-RUN" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt-run \- salt-run Documentation
.sp

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT-SSH" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT-SSH" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt-ssh \- salt-ssh Documentation
.SH SYNOPSIS

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT-SYNDIC" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT-SYNDIC" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt-syndic \- salt-syndic Documentation
.sp

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt \- salt
.SH SYNOPSIS

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SALT" "7" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SALT" "7" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
salt \- Salt Documentation
.SH SALT PROJECT
@ -194128,7 +194128,7 @@ Passes through all the parameters described in the
\fI\%utils.http.query function\fP:
.INDENT 7.0
.TP
.B salt.utils.http.query(url, method=\(aqGET\(aq, params=None, data=None, data_file=None, header_dict=None, header_list=None, header_file=None, username=None, password=None, auth=None, decode=False, decode_type=\(aqauto\(aq, status=False, headers=False, text=False, cookies=None, cookie_jar=None, cookie_format=\(aqlwp\(aq, persist_session=False, session_cookie_jar=None, data_render=False, data_renderer=None, header_render=False, header_renderer=None, template_dict=None, test=False, test_url=None, node=\(aqminion\(aq, port=80, opts=None, backend=None, ca_bundle=None, verify_ssl=None, cert=None, text_out=None, headers_out=None, decode_out=None, stream=False, streaming_callback=None, header_callback=None, handle=False, agent=\(aqSalt/3006.3\(aq, hide_fields=None, raise_error=True, formdata=False, formdata_fieldname=None, formdata_filename=None, decode_body=True, **kwargs)
.B salt.utils.http.query(url, method=\(aqGET\(aq, params=None, data=None, data_file=None, header_dict=None, header_list=None, header_file=None, username=None, password=None, auth=None, decode=False, decode_type=\(aqauto\(aq, status=False, headers=False, text=False, cookies=None, cookie_jar=None, cookie_format=\(aqlwp\(aq, persist_session=False, session_cookie_jar=None, data_render=False, data_renderer=None, header_render=False, header_renderer=None, template_dict=None, test=False, test_url=None, node=\(aqminion\(aq, port=80, opts=None, backend=None, ca_bundle=None, verify_ssl=None, cert=None, text_out=None, headers_out=None, decode_out=None, stream=False, streaming_callback=None, header_callback=None, handle=False, agent=\(aqSalt/3006.4\(aq, hide_fields=None, raise_error=True, formdata=False, formdata_fieldname=None, formdata_filename=None, decode_body=True, **kwargs)
Query a resource, and decode the return data
.UNINDENT
.INDENT 7.0
@ -457626,7 +457626,7 @@ installed2
.UNINDENT
.INDENT 0.0
.TP
.B salt.states.zcbuildout.installed(name, config=\(aqbuildout.cfg\(aq, quiet=False, parts=None, user=None, env=(), buildout_ver=None, test_release=False, distribute=None, new_st=None, offline=False, newest=False, python=\(aq/opt/actions\-runner/_work/salt/salt/.tools\-venvs/py3.10/docs/bin/python\(aq, debug=False, verbose=False, unless=None, onlyif=None, use_vt=False, loglevel=\(aqdebug\(aq, **kwargs)
.B salt.states.zcbuildout.installed(name, config=\(aqbuildout.cfg\(aq, quiet=False, parts=None, user=None, env=(), buildout_ver=None, test_release=False, distribute=None, new_st=None, offline=False, newest=False, python=\(aq/opt/actions\-runner/_work/salt\-priv/salt\-priv/.tools\-venvs/py3.10/docs/bin/python\(aq, debug=False, verbose=False, unless=None, onlyif=None, use_vt=False, loglevel=\(aqdebug\(aq, **kwargs)
Install buildout in a specific directory
.sp
It is a thin wrapper to modules.buildout.buildout
@ -477556,6 +477556,25 @@ Addresses multiple CVEs in Python\(aqs dependencies: \fI\%https://docs.python.or
.IP \(bu 2
Update to \fBgitpython>=3.1.32\fP due to \fI\%https://github.com/advisories/GHSA\-pr76\-5cm5\-w9cj\fP \fI\%#64988\fP
.UNINDENT
(release\-3006.4)=
.SS Salt 3006.4 release notes
.SS Changelog
.SS Security
.INDENT 0.0
.IP \(bu 2
Fix CVE\-2023\-34049 by ensuring we do not use a predictable name for the script and correctly check returncode of scp command.
This only impacts salt\-ssh users using the pre\-flight option. \fI\%#cve\-2023\-34049\fP
.IP \(bu 2
Update to \fBgitpython>=3.1.35\fP due to \fI\%https://github.com/advisories/GHSA\-wfm5\-v35h\-vwf4\fP and \fI\%https://github.com/advisories/GHSA\-cwvm\-v4w8\-q58c\fP \fI\%#65163\fP
.IP \(bu 2
Bump to \fBcryptography==41.0.4\fP due to \fI\%https://github.com/advisories/GHSA\-v8gr\-m533\-ghj9\fP \fI\%#65268\fP
.IP \(bu 2
Upgrade relenv to 0.13.12 to address CVE\-2023\-4807 \fI\%#65316\fP
.IP \(bu 2
Bump to \fBurllib3==1.26.17\fP or \fBurllib3==2.0.6\fP due to \fI\%https://github.com/advisories/GHSA\-v845\-jxx5\-vc9f\fP \fI\%#65334\fP
.IP \(bu 2
Bump to \fBgitpython==3.1.37\fP due to \fI\%https://github.com/advisories/GHSA\-cwvm\-v4w8\-q58c\fP \fI\%#65383\fP
.UNINDENT
.sp
See \fI\%Install a release candidate\fP
for more information about installing an RC when one is available.

View file

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "SPM" "1" "Generated on September 06, 2023 at 04:52:57 PM UTC." "3006.3" "Salt"
.TH "SPM" "1" "Generated on October 16, 2023 at 05:24:47 PM UTC." "3006.4" "Salt"
.SH NAME
spm \- Salt Package Manager Command
.sp

View file

@ -0,0 +1,17 @@
.. _release-3005-4:
=========================
Salt 3005.4 Release Notes
=========================
Version 3005.4 is a CVE security fix release for :ref:`3005 <release-3005>`.
Security
--------
- Fix CVE-2023-34049 by ensuring we do not use a predictable name for the script and correctly check returncode of scp command.
This only impacts salt-ssh users using the pre-flight option. (cve-2023-34049)
- Bump to `cryptography==41.0.4` due to https://github.com/advisories/GHSA-v8gr-m533-ghj9 (#65267)
- Bump to `urllib3==1.26.17` or `urllib3==2.0.6` due to https://github.com/advisories/GHSA-v845-jxx5-vc9f (#65334)
- Bump to `gitpython==3.1.37` due to https://github.com/advisories/GHSA-cwvm-v4w8-q58c (#65383)

View file

@ -0,0 +1,29 @@
(release-3006.4)=
# Salt 3006.4 release notes
<!---
Do not edit this file. This is auto generated.
Edit the templates in doc/topics/releases/templates/
for a given release.
-->
<!--
Add release specific details below
-->
<!--
Do not edit the changelog below.
This is auto generated.
-->
## Changelog
### Security
- Fix CVE-2023-34049 by ensuring we do not use a predictable name for the script and correctly check returncode of scp command.
This only impacts salt-ssh users using the pre-flight option. [#cve-2023-34049](https://github.com/saltstack/salt/issues/cve-2023-34049)
- Update to `gitpython>=3.1.35` due to https://github.com/advisories/GHSA-wfm5-v35h-vwf4 and https://github.com/advisories/GHSA-cwvm-v4w8-q58c [#65163](https://github.com/saltstack/salt/issues/65163)
- Bump to `cryptography==41.0.4` due to https://github.com/advisories/GHSA-v8gr-m533-ghj9 [#65268](https://github.com/saltstack/salt/issues/65268)
- Upgrade relenv to 0.13.12 to address CVE-2023-4807 [#65316](https://github.com/saltstack/salt/issues/65316)
- Bump to `urllib3==1.26.17` or `urllib3==2.0.6` due to https://github.com/advisories/GHSA-v845-jxx5-vc9f [#65334](https://github.com/saltstack/salt/issues/65334)
- Bump to `gitpython==3.1.37` due to https://github.com/advisories/GHSA-cwvm-v4w8-q58c [#65383](https://github.com/saltstack/salt/issues/65383)

View file

@ -0,0 +1,14 @@
(release-3006.4)=
# Salt 3006.4 release notes{{ unreleased }}
{{ warning }}
<!--
Add release specific details below
-->
<!--
Do not edit the changelog below.
This is auto generated.
-->
## Changelog
{{ changelog }}

View file

@ -1,3 +1,19 @@
salt (3006.4) stable; urgency=medium
# Security
* Fix CVE-2023-34049 by ensuring we do not use a predictable name for the script and correctly check returncode of scp command.
This only impacts salt*ssh users using the pre-flight option. [#cve-2023-34049](https://github.com/saltstack/salt/issues/cve-2023-34049)
* Update to `gitpython>=3.1.35` due to https://github.com/advisories/GHSA-wfm5-v35h-vwf4 and https://github.com/advisories/GHSA-cwvm-v4w8-q58c [#65163](https://github.com/saltstack/salt/issues/65163)
* Bump to `cryptography==41.0.4` due to https://github.com/advisories/GHSA-v8gr-m533-ghj9 [#65268](https://github.com/saltstack/salt/issues/65268)
* Upgrade relenv to 0.13.12 to address CVE-2023-4807 [#65316](https://github.com/saltstack/salt/issues/65316)
* Bump to `urllib3==1.26.17` or `urllib3==2.0.6` due to https://github.com/advisories/GHSA-v845-jxx5-vc9f [#65334](https://github.com/saltstack/salt/issues/65334)
* Bump to `gitpython==3.1.37` due to https://github.com/advisories/GHSA-cwvm-v4w8-q58c [#65383](https://github.com/saltstack/salt/issues/65383)
-- Salt Project Packaging <saltproject-packaging@vmware.com> Mon, 16 Oct 2023 17:22:41 +0000
salt (3006.3) stable; urgency=medium

View file

@ -1,5 +1,4 @@
/etc/salt/master.d
/etc/ufw/applications.d/salt-master
/etc/salt/pki/master/minions
/etc/salt/pki/master/minions_autosign
/etc/salt/pki/master/minions_denied

View file

@ -1,2 +1,2 @@
pkg/common/salt-master.service /lib/systemd/system
pkg/common/salt.ufw /etc/ufw/applications.d/salt-master
pkg/common/salt.ufw /etc/ufw/applications.d

View file

@ -31,7 +31,7 @@
%define fish_dir %{_datadir}/fish/vendor_functions.d
Name: salt
Version: 3006.3
Version: 3006.4
Release: 0
Summary: A parallel remote execution system
Group: System Environment/Daemons
@ -563,6 +563,19 @@ fi
%changelog
* Mon Oct 16 2023 Salt Project Packaging <saltproject-packaging@vmware.com> - 3006.4
# Security
- Fix CVE-2023-34049 by ensuring we do not use a predictable name for the script and correctly check returncode of scp command.
This only impacts salt-ssh users using the pre-flight option. [#cve-2023-34049](https://github.com/saltstack/salt/issues/cve-2023-34049)
- Update to `gitpython>=3.1.35` due to https://github.com/advisories/GHSA-wfm5-v35h-vwf4 and https://github.com/advisories/GHSA-cwvm-v4w8-q58c [#65163](https://github.com/saltstack/salt/issues/65163)
- Bump to `cryptography==41.0.4` due to https://github.com/advisories/GHSA-v8gr-m533-ghj9 [#65268](https://github.com/saltstack/salt/issues/65268)
- Upgrade relenv to 0.13.12 to address CVE-2023-4807 [#65316](https://github.com/saltstack/salt/issues/65316)
- Bump to `urllib3==1.26.17` or `urllib3==2.0.6` due to https://github.com/advisories/GHSA-v845-jxx5-vc9f [#65334](https://github.com/saltstack/salt/issues/65334)
- Bump to `gitpython==3.1.37` due to https://github.com/advisories/GHSA-cwvm-v4w8-q58c [#65383](https://github.com/saltstack/salt/issues/65383)
* Wed Sep 06 2023 Salt Project Packaging <saltproject-packaging@vmware.com> - 3006.3
# Removed

View file

@ -0,0 +1,38 @@
import pathlib
import pytest
@pytest.mark.skip_on_windows
@pytest.mark.skip_if_binaries_missing("ufw")
def test_salt_ufw(salt_master, salt_call_cli, install_salt):
"""
Test salt.ufw for Debian/Ubuntu salt-master
"""
if install_salt.distro_id not in ("debian", "ubuntu"):
pytest.skip("Only tests Debian / Ubuntu packages")
# check that the salt_master is running
assert salt_master.is_running()
ufw_master_path = pathlib.Path("/etc/ufw/applications.d/salt.ufw")
assert ufw_master_path.exists()
assert ufw_master_path.is_file()
ufw_list_cmd = "/usr/sbin/ufw app list"
ret = salt_call_cli.run("--local", "cmd.run", ufw_list_cmd)
assert "Available applications" in ret.stdout
assert "Salt" in ret.stdout
ufw_upd_cmd = "/usr/sbin/ufw app update Salt"
ret = salt_call_cli.run("--local", "cmd.run", ufw_upd_cmd)
assert ret.returncode == 0
expected_info = """Profile: Salt
Title: salt
Description: fast and powerful configuration management and remote
execution
Ports:
4505,4506/tcp"""
ufw_info_cmd = "/usr/sbin/ufw app info Salt"
ret = salt_call_cli.run("--local", "cmd.run", ufw_info_cmd)
assert expected_info in ret.data

View file

@ -6,7 +6,7 @@ apache-libcloud>=2.4.0
cherrypy>=17.4.1
gitpython>=3.1.35
cryptography>=41.0.3
gitpython>=3.1.30
gitpython>=3.1.37
idna>=2.8
linode-python>=1.1.1
pyasn1>=0.4.8

View file

@ -15,7 +15,7 @@ clustershell
croniter>=0.3.0,!=0.3.22"; sys_platform != 'win32'
dnspython
etcd3-py==0.1.6
gitpython>=3.1.35
gitpython>=3.1.37
jmespath
jsonschema
junos-eznc; sys_platform != 'win32'

View file

@ -67,7 +67,7 @@ smbprotocol==1.10.1
# via
# -r requirements/static/ci/cloud.in
# pypsexec
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/py3.10/linux.txt
# requests

View file

@ -140,7 +140,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
# gitpython
gitpython==3.1.35
gitpython==3.1.40
# via
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
# -r requirements/darwin.txt
@ -480,7 +480,7 @@ six==1.16.0
# transitions
# vcert
# websocket-client
smmap==3.0.2
smmap==5.0.0
# via
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
# gitdb
@ -519,14 +519,14 @@ ttp==0.9.5
# ttp-templates
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
# botocore

View file

@ -146,13 +146,13 @@ tempora==5.3.0
# via
# -c requirements/static/ci/py3.10/linux.txt
# portend
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/py3.10/linux.txt
# pydantic
uc-micro-py==1.0.2
# via linkify-it-py
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/py3.10/linux.txt
# requests

View file

@ -135,7 +135,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -509,14 +509,14 @@ ttp==0.9.5
# ttp-templates
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.10/freebsd.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.10/freebsd.txt
# botocore

View file

@ -151,7 +151,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -573,14 +573,14 @@ twilio==8.2.2
# via -r requirements/static/ci/linux.in
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.10/linux.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.10/linux.txt
# botocore

View file

@ -52,9 +52,9 @@ s3transfer==0.6.1
# via boto3
six==1.16.0
# via python-dateutil
typing-extensions==4.6.3
typing-extensions==4.8.0
# via python-tools-scripts
urllib3==1.26.14
urllib3==1.26.18
# via
# botocore
# requests

View file

@ -133,7 +133,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# gitpython
gitpython==3.1.35
gitpython==3.1.40
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# -r requirements/static/ci/common.in
@ -434,7 +434,7 @@ six==1.15.0
# pyvmomi
# pywinrm
# websocket-client
smmap==4.0.0
smmap==5.0.0
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# gitdb
@ -460,13 +460,13 @@ tornado==6.3.3
# -r requirements/base.txt
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# -r requirements/windows.txt

View file

@ -67,7 +67,7 @@ smbprotocol==1.10.1
# via
# -r requirements/static/ci/cloud.in
# pypsexec
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/py3.11/linux.txt
# requests

View file

@ -138,7 +138,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.11/darwin.txt
# gitpython
gitpython==3.1.35
gitpython==3.1.40
# via
# -c requirements/static/ci/../pkg/py3.11/darwin.txt
# -r requirements/darwin.txt
@ -476,7 +476,7 @@ six==1.16.0
# transitions
# vcert
# websocket-client
smmap==3.0.2
smmap==5.0.0
# via
# -c requirements/static/ci/../pkg/py3.11/darwin.txt
# gitdb
@ -513,7 +513,7 @@ ttp==0.9.5
# ttp-templates
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.11/darwin.txt
# napalm

View file

@ -146,13 +146,13 @@ tempora==5.3.0
# via
# -c requirements/static/ci/py3.11/linux.txt
# portend
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/py3.11/linux.txt
# pydantic
uc-micro-py==1.0.2
# via linkify-it-py
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/py3.11/linux.txt
# requests

View file

@ -133,7 +133,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -505,14 +505,14 @@ ttp==0.9.5
# ttp-templates
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.11/freebsd.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.11/freebsd.txt
# botocore

View file

@ -147,7 +147,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -567,14 +567,14 @@ twilio==8.2.2
# via -r requirements/static/ci/linux.in
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.11/linux.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.11/linux.txt
# botocore

View file

@ -52,7 +52,7 @@ s3transfer==0.6.1
# via boto3
six==1.16.0
# via python-dateutil
urllib3==1.26.14
urllib3==1.26.18
# via
# botocore
# requests

View file

@ -131,7 +131,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# gitpython
gitpython==3.1.35
gitpython==3.1.40
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# -r requirements/static/ci/common.in
@ -432,7 +432,7 @@ six==1.15.0
# pyvmomi
# pywinrm
# websocket-client
smmap==4.0.0
smmap==5.0.0
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# gitdb
@ -456,13 +456,13 @@ tornado==6.3.3
# -r requirements/base.txt
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# -r requirements/windows.txt

View file

@ -67,7 +67,7 @@ smbprotocol==1.10.1
# via
# -r requirements/static/ci/cloud.in
# pypsexec
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/py3.8/linux.txt
# requests

View file

@ -155,13 +155,13 @@ tempora==5.3.0
# via
# -c requirements/static/ci/py3.8/linux.txt
# portend
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/py3.8/linux.txt
# pydantic
uc-micro-py==1.0.2
# via linkify-it-py
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/py3.8/linux.txt
# requests

View file

@ -135,7 +135,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -513,14 +513,14 @@ ttp==0.9.5
# ttp-templates
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt
# botocore

View file

@ -151,7 +151,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -577,14 +577,14 @@ twilio==8.2.2
# via -r requirements/static/ci/linux.in
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.8/linux.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.8/linux.txt
# botocore

View file

@ -133,7 +133,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# gitpython
gitpython==3.1.35
gitpython==3.1.40
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# -r requirements/static/ci/common.in
@ -439,7 +439,7 @@ six==1.15.0
# pyvmomi
# pywinrm
# websocket-client
smmap==4.0.0
smmap==5.0.0
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# gitdb
@ -465,13 +465,13 @@ tornado==6.3.3
# -r requirements/base.txt
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# -r requirements/windows.txt

View file

@ -67,7 +67,7 @@ smbprotocol==1.10.1
# via
# -r requirements/static/ci/cloud.in
# pypsexec
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/py3.9/linux.txt
# requests

View file

@ -140,7 +140,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# gitpython
gitpython==3.1.35
gitpython==3.1.40
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# -r requirements/darwin.txt
@ -480,7 +480,7 @@ six==1.16.0
# transitions
# vcert
# websocket-client
smmap==3.0.2
smmap==5.0.0
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# gitdb
@ -519,14 +519,14 @@ ttp==0.9.5
# ttp-templates
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# botocore

View file

@ -150,13 +150,13 @@ tempora==5.3.0
# via
# -c requirements/static/ci/py3.9/linux.txt
# portend
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/py3.9/linux.txt
# pydantic
uc-micro-py==1.0.2
# via linkify-it-py
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/py3.9/linux.txt
# requests

View file

@ -135,7 +135,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -509,14 +509,14 @@ ttp==0.9.5
# ttp-templates
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt
# botocore

View file

@ -151,7 +151,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -575,14 +575,14 @@ twilio==8.2.2
# via -r requirements/static/ci/linux.in
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.9/linux.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.9/linux.txt
# botocore

View file

@ -52,9 +52,9 @@ s3transfer==0.6.1
# via boto3
six==1.16.0
# via python-dateutil
typing-extensions==4.6.3
typing-extensions==4.8.0
# via python-tools-scripts
urllib3==1.26.14
urllib3==1.26.18
# via
# botocore
# requests

View file

@ -133,7 +133,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# gitpython
gitpython==3.1.35
gitpython==3.1.40
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# -r requirements/static/ci/common.in
@ -435,7 +435,7 @@ six==1.15.0
# pyvmomi
# pywinrm
# websocket-client
smmap==4.0.0
smmap==5.0.0
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# gitdb
@ -461,13 +461,13 @@ tornado==6.3.3
# -r requirements/base.txt
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.3
typing-extensions==4.8.0
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
urllib3==1.26.14
urllib3==1.26.18
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# -r requirements/windows.txt

View file

@ -29,7 +29,7 @@ distro==1.8.0
# via -r requirements/base.txt
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/darwin.txt
idna==3.4
# via
@ -105,7 +105,7 @@ setproctitle==1.3.2
# via -r requirements/darwin.txt
six==1.16.0
# via python-dateutil
smmap==3.0.2
smmap==5.0.0
# via gitdb
tempora==5.3.0
# via portend
@ -113,9 +113,9 @@ timelib==0.3.0
# via -r requirements/darwin.txt
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via requests
vultr==1.0.1
# via -r requirements/darwin.txt

View file

@ -100,9 +100,9 @@ timelib==0.3.0
# via -r requirements/static/pkg/freebsd.in
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via requests
zc.lockfile==3.0.post1
# via cherrypy

View file

@ -100,9 +100,9 @@ timelib==0.3.0
# via -r requirements/static/pkg/linux.in
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via requests
zc.lockfile==3.0.post1
# via cherrypy

View file

@ -34,7 +34,7 @@ distro==1.8.0
# via -r requirements/base.txt
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/windows.txt
idna==3.4
# via requests
@ -119,7 +119,7 @@ setproctitle==1.3.2
# via -r requirements/windows.txt
six==1.15.0
# via python-dateutil
smmap==4.0.0
smmap==5.0.0
# via gitdb
tempora==5.3.0
# via portend
@ -127,9 +127,9 @@ timelib==0.3.0
# via -r requirements/windows.txt
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via
# -r requirements/windows.txt
# requests

View file

@ -29,7 +29,7 @@ distro==1.8.0
# via -r requirements/base.txt
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/darwin.txt
idna==3.4
# via
@ -105,7 +105,7 @@ setproctitle==1.3.2
# via -r requirements/darwin.txt
six==1.16.0
# via python-dateutil
smmap==3.0.2
smmap==5.0.0
# via gitdb
tempora==5.3.0
# via portend
@ -113,7 +113,7 @@ timelib==0.3.0
# via -r requirements/darwin.txt
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
# via requests

View file

@ -100,9 +100,9 @@ timelib==0.3.0
# via -r requirements/static/pkg/freebsd.in
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via requests
zc.lockfile==3.0.post1
# via cherrypy

View file

@ -100,9 +100,9 @@ timelib==0.3.0
# via -r requirements/static/pkg/linux.in
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via requests
zc.lockfile==3.0.post1
# via cherrypy

View file

@ -34,7 +34,7 @@ distro==1.8.0
# via -r requirements/base.txt
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/windows.txt
idna==3.4
# via requests
@ -119,7 +119,7 @@ setproctitle==1.3.2
# via -r requirements/windows.txt
six==1.15.0
# via python-dateutil
smmap==4.0.0
smmap==5.0.0
# via gitdb
tempora==5.3.0
# via portend
@ -127,9 +127,9 @@ timelib==0.3.0
# via -r requirements/windows.txt
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via
# -r requirements/windows.txt
# requests

View file

@ -102,9 +102,9 @@ timelib==0.3.0
# via -r requirements/static/pkg/freebsd.in
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via requests
zc.lockfile==3.0.post1
# via cherrypy

View file

@ -102,9 +102,9 @@ timelib==0.3.0
# via -r requirements/static/pkg/linux.in
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via requests
zc.lockfile==3.0.post1
# via cherrypy

View file

@ -34,7 +34,7 @@ distro==1.8.0
# via -r requirements/base.txt
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/windows.txt
idna==3.4
# via requests
@ -122,7 +122,7 @@ setproctitle==1.3.2
# via -r requirements/windows.txt
six==1.15.0
# via python-dateutil
smmap==4.0.0
smmap==5.0.0
# via gitdb
tempora==5.3.0
# via portend
@ -130,9 +130,9 @@ timelib==0.3.0
# via -r requirements/windows.txt
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via
# -r requirements/windows.txt
# requests

View file

@ -29,7 +29,7 @@ distro==1.8.0
# via -r requirements/base.txt
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/darwin.txt
idna==3.4
# via
@ -105,7 +105,7 @@ setproctitle==1.3.2
# via -r requirements/darwin.txt
six==1.16.0
# via python-dateutil
smmap==3.0.2
smmap==5.0.0
# via gitdb
tempora==5.3.0
# via portend
@ -113,9 +113,9 @@ timelib==0.3.0
# via -r requirements/darwin.txt
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via requests
vultr==1.0.1
# via -r requirements/darwin.txt

View file

@ -100,9 +100,9 @@ timelib==0.3.0
# via -r requirements/static/pkg/freebsd.in
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via requests
zc.lockfile==3.0.post1
# via cherrypy

View file

@ -100,9 +100,9 @@ timelib==0.3.0
# via -r requirements/static/pkg/linux.in
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via requests
zc.lockfile==3.0.post1
# via cherrypy

View file

@ -34,7 +34,7 @@ distro==1.8.0
# via -r requirements/base.txt
gitdb==4.0.10
# via gitpython
gitpython==3.1.35
gitpython==3.1.40
# via -r requirements/windows.txt
idna==3.4
# via requests
@ -120,7 +120,7 @@ setproctitle==1.3.2
# via -r requirements/windows.txt
six==1.15.0
# via python-dateutil
smmap==4.0.0
smmap==5.0.0
# via gitdb
tempora==5.3.0
# via portend
@ -128,9 +128,9 @@ timelib==0.3.0
# via -r requirements/windows.txt
tornado==6.3.3
# via -r requirements/base.txt
typing-extensions==4.6.3
typing-extensions==4.8.0
# via pydantic
urllib3==1.26.14
urllib3==1.26.18
# via
# -r requirements/windows.txt
# requests

View file

@ -9,7 +9,7 @@ pythonnet>=3.0.1
certifi>=2022.12.07
cffi>=1.14.5
cherrypy>=18.6.1
gitpython>=3.1.35
gitpython>=3.1.37
cryptography>=41.0.3
lxml>=4.6.3
pyasn1>=0.4.8

View file

@ -11,9 +11,11 @@ import hashlib
import logging
import multiprocessing
import os
import pathlib
import queue
import re
import shlex
import shutil
import subprocess
import sys
import tarfile
@ -467,7 +469,14 @@ class SSH(MultiprocessingStateMixin):
if target.get("passwd", False) or self.opts["ssh_passwd"]:
self._key_deploy_run(host, target, False)
return ret
if ret[host].get("stderr", "").count("Permission denied"):
stderr = ret[host].get("stderr", "")
# -failed to upload file- is detecting scp errors
# Errors to ignore when Permission denied is in the stderr. For example
# scp can get a permission denied on the target host, but they where
# able to accurate authenticate against the box
ignore_err = ["failed to upload file"]
check_err = [x for x in ignore_err if stderr.count(x)]
if "Permission denied" in stderr and not check_err:
target = self.targets[host]
# permission denied, attempt to auto deploy ssh key
print(
@ -1007,11 +1016,30 @@ class Single:
"""
Run our pre_flight script before running any ssh commands
"""
script = os.path.join(tempfile.gettempdir(), self.ssh_pre_file)
with tempfile.NamedTemporaryFile() as temp:
# ensure we use copyfile to not copy the file attributes
# we want to ensure we use the perms set by the secure
# NamedTemporaryFile
try:
shutil.copyfile(self.ssh_pre_flight, temp.name)
except OSError as err:
return (
"",
"Could not copy pre flight script to temporary path",
1,
)
target_script = f".{pathlib.Path(temp.name).name}"
log.trace("Copying the pre flight script to target")
stdout, stderr, retcode = self.shell.send(temp.name, target_script)
if retcode != 0:
# We could not copy the script to the target
log.error("Could not copy the pre flight script to target")
return stdout, stderr, retcode
self.shell.send(self.ssh_pre_flight, script)
return self.execute_script(script, script_args=self.ssh_pre_flight_args)
log.trace("Executing the pre flight script on target")
return self.execute_script(
target_script, script_args=self.ssh_pre_flight_args
)
def check_thin_dir(self):
"""
@ -1388,18 +1416,20 @@ ARGS = {arguments}\n'''.format(
return self.shell.exec_cmd(cmd_str)
# Write the shim to a temporary file in the default temp directory
with tempfile.NamedTemporaryFile(
mode="w+b", prefix="shim_", delete=False
) as shim_tmp_file:
with tempfile.NamedTemporaryFile(mode="w+b", delete=False) as shim_tmp_file:
shim_tmp_file.write(salt.utils.stringutils.to_bytes(cmd_str))
# Copy shim to target system, under $HOME/.<randomized name>
target_shim_file = ".{}.{}".format(
binascii.hexlify(os.urandom(6)).decode("ascii"), extension
)
target_shim_file = f".{pathlib.Path(shim_tmp_file.name).name}"
if self.winrm:
target_shim_file = saltwinshell.get_target_shim_file(self, target_shim_file)
self.shell.send(shim_tmp_file.name, target_shim_file, makedirs=True)
stdout, stderr, retcode = self.shell.send(
shim_tmp_file.name, target_shim_file, makedirs=True
)
if retcode != 0:
log.error("Could not copy the shim script to target")
return stdout, stderr, retcode
# Remove our shim file
try:

View file

@ -1,132 +0,0 @@
"""
Test for ssh_pre_flight roster option
"""
import os
import pytest
import salt.utils.files
from tests.support.case import SSHCase
from tests.support.runtests import RUNTIME_VARS
class SSHPreFlightTest(SSHCase):
"""
Test ssh_pre_flight roster option
"""
def setUp(self):
super().setUp()
self.roster = os.path.join(RUNTIME_VARS.TMP, "pre_flight_roster")
self.data = {
"ssh_pre_flight": os.path.join(RUNTIME_VARS.TMP, "ssh_pre_flight.sh")
}
self.test_script = os.path.join(
RUNTIME_VARS.TMP, "test-pre-flight-script-worked.txt"
)
def _create_roster(self, pre_flight_script_args=None):
data = dict(self.data)
if pre_flight_script_args:
data["ssh_pre_flight_args"] = pre_flight_script_args
self.custom_roster(self.roster, data)
with salt.utils.files.fopen(data["ssh_pre_flight"], "w") as fp_:
fp_.write("touch {}".format(self.test_script))
@pytest.mark.slow_test
def test_ssh_pre_flight(self):
"""
test ssh when ssh_pre_flight is set
ensure the script runs successfully
"""
self._create_roster()
assert self.run_function("test.ping", roster_file=self.roster)
assert os.path.exists(self.test_script)
@pytest.mark.slow_test
def test_ssh_run_pre_flight(self):
"""
test ssh when --pre-flight is passed to salt-ssh
to ensure the script runs successfully
"""
self._create_roster()
# make sure we previously ran a command so the thin dir exists
self.run_function("test.ping", wipe=False)
assert not os.path.exists(self.test_script)
assert self.run_function(
"test.ping", ssh_opts="--pre-flight", roster_file=self.roster, wipe=False
)
assert os.path.exists(self.test_script)
@pytest.mark.slow_test
def test_ssh_run_pre_flight_args(self):
"""
test ssh when --pre-flight is passed to salt-ssh
to ensure the script runs successfully passing some args
"""
self._create_roster(pre_flight_script_args="foobar test")
# make sure we previously ran a command so the thin dir exists
self.run_function("test.ping", wipe=False)
assert not os.path.exists(self.test_script)
assert self.run_function(
"test.ping", ssh_opts="--pre-flight", roster_file=self.roster, wipe=False
)
assert os.path.exists(self.test_script)
@pytest.mark.slow_test
def test_ssh_run_pre_flight_args_prevent_injection(self):
"""
test ssh when --pre-flight is passed to salt-ssh
and evil arguments are used in order to produce shell injection
"""
injected_file = os.path.join(RUNTIME_VARS.TMP, "injection")
self._create_roster(
pre_flight_script_args="foobar; echo injected > {}".format(injected_file)
)
# make sure we previously ran a command so the thin dir exists
self.run_function("test.ping", wipe=False)
assert not os.path.exists(self.test_script)
assert not os.path.isfile(injected_file)
assert self.run_function(
"test.ping", ssh_opts="--pre-flight", roster_file=self.roster, wipe=False
)
assert not os.path.isfile(
injected_file
), "File injection suceeded. This shouldn't happend"
@pytest.mark.slow_test
def test_ssh_run_pre_flight_failure(self):
"""
test ssh_pre_flight when there is a failure
in the script.
"""
self._create_roster()
with salt.utils.files.fopen(self.data["ssh_pre_flight"], "w") as fp_:
fp_.write("exit 2")
ret = self.run_function(
"test.ping", ssh_opts="--pre-flight", roster_file=self.roster, wipe=False
)
assert ret["retcode"] == 2
def tearDown(self):
"""
make sure to clean up any old ssh directories
"""
files = [
self.roster,
self.data["ssh_pre_flight"],
self.test_script,
os.path.join(RUNTIME_VARS.TMP, "injection"),
]
for fp_ in files:
if os.path.exists(fp_):
os.remove(fp_)

View file

@ -0,0 +1,106 @@
import logging
import os
import pytest
import salt._logging.impl as log_impl
from tests.support.mock import MagicMock, patch
pytestmark = [
pytest.mark.skip_on_windows(reason="Temporarily skipped on the newer golden images")
]
log = logging.getLogger(__name__)
@pytest.fixture
def configure_loader_modules():
return {log_impl: {}}
def log_nameToLevel(name):
"""
Return the numeric representation of textual logging level
"""
# log level values
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
_nameToLevel = {
"CRITICAL": CRITICAL,
"FATAL": FATAL,
"ERROR": ERROR,
"WARN": WARNING,
"WARNING": WARNING,
"INFO": INFO,
"DEBUG": DEBUG,
"NOTSET": NOTSET,
}
return _nameToLevel.get(name, None)
def test_lowest_log_level():
ret = log_impl.get_lowest_log_level()
assert ret is None
log_impl.set_lowest_log_level(log_nameToLevel("DEBUG"))
ret = log_impl.get_lowest_log_level()
assert ret is log_nameToLevel("DEBUG")
log_impl.set_lowest_log_level(log_nameToLevel("WARNING"))
ret = log_impl.get_lowest_log_level()
assert ret is log_nameToLevel("WARNING")
opts = {"log_level": "ERROR", "log_level_logfile": "INFO"}
log_impl.set_lowest_log_level_by_opts(opts)
ret = log_impl.get_lowest_log_level()
assert ret is log_nameToLevel("INFO")
def test_get_logging_level_from_string(caplog):
ret = log_impl.get_logging_level_from_string(None)
assert ret is log_nameToLevel("WARNING")
ret = log_impl.get_logging_level_from_string(log_nameToLevel("DEBUG"))
assert ret is log_nameToLevel("DEBUG")
ret = log_impl.get_logging_level_from_string("CRITICAL")
assert ret is log_nameToLevel("CRITICAL")
caplog.clear()
with caplog.at_level(logging.WARNING):
msg = "Could not translate the logging level string 'BADLEVEL' into an actual logging level integer. Returning 'logging.ERROR'."
ret = log_impl.get_logging_level_from_string("BADLEVEL")
assert ret is log_nameToLevel("ERROR")
assert msg in caplog.text
def test_logfile_handler(caplog):
caplog.clear()
with caplog.at_level(logging.WARNING):
ret = log_impl.is_logfile_handler_configured()
assert ret is False
msg = "log_path setting is set to `None`. Nothing else to do"
log_path = None
assert log_impl.setup_logfile_handler(log_path) is None
assert msg in caplog.text
def test_in_mainprocess():
ret = log_impl.in_mainprocess()
assert ret is True
curr_pid = os.getpid()
with patch(
"os.getpid", MagicMock(side_effect=[AttributeError, curr_pid, curr_pid])
):
ret = log_impl.in_mainprocess()
assert ret is True

View file

@ -0,0 +1,315 @@
"""
Test for ssh_pre_flight roster option
"""
try:
import grp
import pwd
except ImportError:
# windows stacktraces on import of these modules
pass
import os
import pathlib
import shutil
import subprocess
import pytest
import yaml
from saltfactories.utils import random_string
import salt.utils.files
pytestmark = pytest.mark.skip_on_windows(reason="Salt-ssh not available on Windows")
def _custom_roster(roster_file, roster_data):
with salt.utils.files.fopen(roster_file, "r") as fp:
data = salt.utils.yaml.safe_load(fp)
for key, item in roster_data.items():
data["localhost"][key] = item
with salt.utils.files.fopen(roster_file, "w") as fp:
yaml.safe_dump(data, fp)
@pytest.fixture
def _create_roster(salt_ssh_roster_file, tmp_path):
ret = {}
ret["roster"] = salt_ssh_roster_file
ret["data"] = {"ssh_pre_flight": str(tmp_path / "ssh_pre_flight.sh")}
ret["test_script"] = str(tmp_path / "test-pre-flight-script-worked.txt")
ret["thin_dir"] = tmp_path / "thin_dir"
with salt.utils.files.fopen(salt_ssh_roster_file, "r") as fp:
data = salt.utils.yaml.safe_load(fp)
pre_flight_script = ret["data"]["ssh_pre_flight"]
data["localhost"]["ssh_pre_flight"] = pre_flight_script
data["localhost"]["thin_dir"] = str(ret["thin_dir"])
with salt.utils.files.fopen(salt_ssh_roster_file, "w") as fp:
yaml.safe_dump(data, fp)
with salt.utils.files.fopen(pre_flight_script, "w") as fp:
fp.write("touch {}".format(ret["test_script"]))
yield ret
if ret["thin_dir"].exists():
shutil.rmtree(ret["thin_dir"])
@pytest.mark.slow_test
def test_ssh_pre_flight(salt_ssh_cli, caplog, _create_roster):
"""
test ssh when ssh_pre_flight is set
ensure the script runs successfully
"""
ret = salt_ssh_cli.run("test.ping")
assert ret.returncode == 0
assert pathlib.Path(_create_roster["test_script"]).exists()
@pytest.mark.slow_test
def test_ssh_run_pre_flight(salt_ssh_cli, _create_roster):
"""
test ssh when --pre-flight is passed to salt-ssh
to ensure the script runs successfully
"""
# make sure we previously ran a command so the thin dir exists
ret = salt_ssh_cli.run("test.ping")
assert pathlib.Path(_create_roster["test_script"]).exists()
# Now remeove the script to ensure pre_flight doesn't run
# without --pre-flight
pathlib.Path(_create_roster["test_script"]).unlink()
assert salt_ssh_cli.run("test.ping").returncode == 0
assert not pathlib.Path(_create_roster["test_script"]).exists()
# Now ensure
ret = salt_ssh_cli.run(
"test.ping",
"--pre-flight",
)
assert ret.returncode == 0
assert pathlib.Path(_create_roster["test_script"]).exists()
@pytest.mark.slow_test
def test_ssh_run_pre_flight_args(salt_ssh_cli, _create_roster):
"""
test ssh when --pre-flight is passed to salt-ssh
to ensure the script runs successfully passing some args
"""
_custom_roster(salt_ssh_cli.roster_file, {"ssh_pre_flight_args": "foobar test"})
# Create pre_flight script that accepts args
test_script = _create_roster["test_script"]
test_script_1 = pathlib.Path(test_script + "-foobar")
test_script_2 = pathlib.Path(test_script + "-test")
with salt.utils.files.fopen(_create_roster["data"]["ssh_pre_flight"], "w") as fp:
fp.write(
f"""
touch {str(test_script)}-$1
touch {str(test_script)}-$2
"""
)
ret = salt_ssh_cli.run("test.ping")
assert ret.returncode == 0
assert test_script_1.exists()
assert test_script_2.exists()
pathlib.Path(test_script_1).unlink()
pathlib.Path(test_script_2).unlink()
ret = salt_ssh_cli.run("test.ping")
assert ret.returncode == 0
assert not test_script_1.exists()
assert not test_script_2.exists()
ret = salt_ssh_cli.run(
"test.ping",
"--pre-flight",
)
assert ret.returncode == 0
assert test_script_1.exists()
assert test_script_2.exists()
@pytest.mark.slow_test
def test_ssh_run_pre_flight_args_prevent_injection(
salt_ssh_cli, _create_roster, tmp_path
):
"""
test ssh when --pre-flight is passed to salt-ssh
and evil arguments are used in order to produce shell injection
"""
injected_file = tmp_path / "injection"
_custom_roster(
salt_ssh_cli.roster_file,
{"ssh_pre_flight_args": f"foobar; echo injected > {str(injected_file)}"},
)
# Create pre_flight script that accepts args
test_script = _create_roster["test_script"]
test_script_1 = pathlib.Path(test_script + "-echo")
test_script_2 = pathlib.Path(test_script + "-foobar;")
with salt.utils.files.fopen(_create_roster["data"]["ssh_pre_flight"], "w") as fp:
fp.write(
f"""
touch {str(test_script)}-$1
touch {str(test_script)}-$2
"""
)
# make sure we previously ran a command so the thin dir exists
ret = salt_ssh_cli.run("test.ping")
assert ret.returncode == 0
assert test_script_1.exists()
assert test_script_2.exists()
test_script_1.unlink()
test_script_2.unlink()
assert not injected_file.is_file()
ret = salt_ssh_cli.run(
"test.ping",
"--pre-flight",
)
assert ret.returncode == 0
assert test_script_1.exists()
assert test_script_2.exists()
assert not pathlib.Path(
injected_file
).is_file(), "File injection suceeded. This shouldn't happend"
@pytest.mark.flaky(max_runs=4)
@pytest.mark.slow_test
def test_ssh_run_pre_flight_failure(salt_ssh_cli, _create_roster):
"""
test ssh_pre_flight when there is a failure
in the script.
"""
with salt.utils.files.fopen(_create_roster["data"]["ssh_pre_flight"], "w") as fp_:
fp_.write("exit 2")
ret = salt_ssh_cli.run(
"test.ping",
"--pre-flight",
)
assert ret.data["retcode"] == 2
@pytest.fixture
def account():
username = random_string("test-account-", uppercase=False)
with pytest.helpers.create_account(username=username) as account:
yield account
@pytest.mark.slow_test
def test_ssh_pre_flight_script(salt_ssh_cli, caplog, _create_roster, tmp_path, account):
"""
Test to ensure user cannot create and run a script
with the expected pre_flight script path on target.
"""
try:
script = pathlib.Path.home() / "hacked"
tmp_preflight = pathlib.Path("/tmp", "ssh_pre_flight.sh")
tmp_preflight.write_text(f"touch {script}")
os.chown(tmp_preflight, account.info.uid, account.info.gid)
ret = salt_ssh_cli.run("test.ping")
assert not script.is_file()
assert ret.returncode == 0
assert ret.stdout == '{\n"localhost": true\n}\n'
finally:
for _file in [script, tmp_preflight]:
if _file.is_file():
_file.unlink()
def demote(user_uid, user_gid):
def result():
# os.setgid does not remove group membership, so we remove them here so they are REALLY non-root
os.setgroups([])
os.setgid(user_gid)
os.setuid(user_uid)
return result
@pytest.mark.slow_test
def test_ssh_pre_flight_perms(salt_ssh_cli, caplog, _create_roster, account):
"""
Test to ensure standard user cannot run pre flight script
on target when user sets wrong permissions (777) on
ssh_pre_flight script.
"""
try:
script = pathlib.Path("/tmp", "itworked")
preflight = pathlib.Path("/ssh_pre_flight.sh")
preflight.write_text(f"touch {str(script)}")
tmp_preflight = pathlib.Path("/tmp", preflight.name)
_custom_roster(salt_ssh_cli.roster_file, {"ssh_pre_flight": str(preflight)})
preflight.chmod(0o0777)
run_script = pathlib.Path("/run_script")
run_script.write_text(
f"""
x=1
while [ $x -le 200000 ]; do
SCRIPT=`bash {str(tmp_preflight)} 2> /dev/null; echo $?`
if [ ${{SCRIPT}} == 0 ]; then
break
fi
x=$(( $x + 1 ))
done
"""
)
run_script.chmod(0o0777)
# pylint: disable=W1509
ret = subprocess.Popen(
["sh", f"{run_script}"],
preexec_fn=demote(account.info.uid, account.info.gid),
stdout=None,
stderr=None,
stdin=None,
universal_newlines=True,
)
# pylint: enable=W1509
ret = salt_ssh_cli.run("test.ping")
assert ret.returncode == 0
# Lets make sure a different user other than root
# Didn't run the script
assert os.stat(script).st_uid != account.info.uid
assert script.is_file()
finally:
for _file in [script, preflight, tmp_preflight, run_script]:
if _file.is_file():
_file.unlink()
@pytest.mark.slow_test
def test_ssh_run_pre_flight_target_file_perms(salt_ssh_cli, _create_roster, tmp_path):
"""
test ssh_pre_flight to ensure the target pre flight script
has the correct perms
"""
perms_file = tmp_path / "perms"
with salt.utils.files.fopen(_create_roster["data"]["ssh_pre_flight"], "w") as fp_:
fp_.write(
f"""
SCRIPT_NAME=$0
stat -L -c "%a %G %U" $SCRIPT_NAME > {perms_file}
"""
)
ret = salt_ssh_cli.run(
"test.ping",
"--pre-flight",
)
assert ret.returncode == 0
with salt.utils.files.fopen(perms_file) as fp:
data = fp.read()
assert data.split()[0] == "600"
uid = os.getuid()
gid = os.getgid()
assert data.split()[1] == grp.getgrgid(gid).gr_name
assert data.split()[2] == pwd.getpwuid(uid).pw_name

View file

@ -1,6 +1,5 @@
import os
import logging
import re
import tempfile
from textwrap import dedent
import pytest
@ -16,6 +15,8 @@ import salt.utils.yaml
from salt.client import ssh
from tests.support.mock import MagicMock, call, patch
log = logging.getLogger(__name__)
@pytest.fixture
def opts(tmp_path):
@ -59,7 +60,7 @@ def test_single_opts(opts, target):
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
**target
**target,
)
assert single.shell._ssh_opts() == ""
@ -87,7 +88,7 @@ def test_run_with_pre_flight(opts, target, tmp_path):
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
**target
**target,
)
cmd_ret = ("Success", "", 0)
@ -122,7 +123,7 @@ def test_run_with_pre_flight_with_args(opts, target, tmp_path):
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
**target
**target,
)
cmd_ret = ("Success", "foobar", 0)
@ -156,7 +157,7 @@ def test_run_with_pre_flight_stderr(opts, target, tmp_path):
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
**target
**target,
)
cmd_ret = ("", "Error running script", 1)
@ -190,7 +191,7 @@ def test_run_with_pre_flight_script_doesnot_exist(opts, target, tmp_path):
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
**target
**target,
)
cmd_ret = ("Success", "", 0)
@ -224,7 +225,7 @@ def test_run_with_pre_flight_thin_dir_exists(opts, target, tmp_path):
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
**target
**target,
)
cmd_ret = ("", "", 0)
@ -242,6 +243,39 @@ def test_run_with_pre_flight_thin_dir_exists(opts, target, tmp_path):
assert ret == cmd_ret
def test_run_ssh_pre_flight(opts, target, tmp_path):
"""
test Single.run_ssh_pre_flight function
"""
target["ssh_pre_flight"] = str(tmp_path / "script.sh")
single = ssh.Single(
opts,
opts["argv"],
"localhost",
mods={},
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
**target,
)
cmd_ret = ("Success", "", 0)
mock_flight = MagicMock(return_value=cmd_ret)
mock_cmd = MagicMock(return_value=cmd_ret)
patch_flight = patch("salt.client.ssh.Single.run_ssh_pre_flight", mock_flight)
patch_cmd = patch("salt.client.ssh.Single.cmd_block", mock_cmd)
patch_exec_cmd = patch(
"salt.client.ssh.shell.Shell.exec_cmd", return_value=("", "", 1)
)
patch_os = patch("os.path.exists", side_effect=[True])
with patch_os, patch_flight, patch_cmd, patch_exec_cmd:
ret = single.run()
mock_cmd.assert_called()
mock_flight.assert_called()
assert ret == cmd_ret
def test_execute_script(opts, target, tmp_path):
"""
test Single.execute_script()
@ -255,7 +289,7 @@ def test_execute_script(opts, target, tmp_path):
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
winrm=False,
**target
**target,
)
exp_ret = ("Success", "", 0)
@ -268,12 +302,12 @@ def test_execute_script(opts, target, tmp_path):
assert ret == exp_ret
assert mock_cmd.call_count == 2
assert [
call("/bin/sh '{}'".format(script)),
call("rm '{}'".format(script)),
call(f"/bin/sh '{script}'"),
call(f"rm '{script}'"),
] == mock_cmd.call_args_list
def test_shim_cmd(opts, target):
def test_shim_cmd(opts, target, tmp_path):
"""
test Single.shim_cmd()
"""
@ -287,7 +321,7 @@ def test_shim_cmd(opts, target):
mine=False,
winrm=False,
tty=True,
**target
**target,
)
exp_ret = ("Success", "", 0)
@ -295,21 +329,24 @@ def test_shim_cmd(opts, target):
patch_cmd = patch("salt.client.ssh.shell.Shell.exec_cmd", mock_cmd)
patch_send = patch("salt.client.ssh.shell.Shell.send", return_value=("", "", 0))
patch_rand = patch("os.urandom", return_value=b"5\xd9l\xca\xc2\xff")
tmp_file = tmp_path / "tmp_file"
mock_tmp = MagicMock()
patch_tmp = patch("tempfile.NamedTemporaryFile", mock_tmp)
mock_tmp.return_value.__enter__.return_value.name = tmp_file
with patch_cmd, patch_rand, patch_send:
with patch_cmd, patch_tmp, patch_send:
ret = single.shim_cmd(cmd_str="echo test")
assert ret == exp_ret
assert [
call("/bin/sh '.35d96ccac2ff.py'"),
call("rm '.35d96ccac2ff.py'"),
call(f"/bin/sh '.{tmp_file.name}'"),
call(f"rm '.{tmp_file.name}'"),
] == mock_cmd.call_args_list
def test_run_ssh_pre_flight(opts, target, tmp_path):
def test_shim_cmd_copy_fails(opts, target, caplog):
"""
test Single.run_ssh_pre_flight
test Single.shim_cmd() when copying the file fails
"""
target["ssh_pre_flight"] = str(tmp_path / "script.sh")
single = ssh.Single(
opts,
opts["argv"],
@ -320,24 +357,202 @@ def test_run_ssh_pre_flight(opts, target, tmp_path):
mine=False,
winrm=False,
tty=True,
**target
**target,
)
exp_ret = ("Success", "", 0)
mock_cmd = MagicMock(return_value=exp_ret)
ret_cmd = ("Success", "", 0)
mock_cmd = MagicMock(return_value=ret_cmd)
patch_cmd = patch("salt.client.ssh.shell.Shell.exec_cmd", mock_cmd)
patch_send = patch("salt.client.ssh.shell.Shell.send", return_value=exp_ret)
exp_tmp = os.path.join(
tempfile.gettempdir(), os.path.basename(target["ssh_pre_flight"])
)
ret_send = ("", "General error in file copy", 1)
patch_send = patch("salt.client.ssh.shell.Shell.send", return_value=ret_send)
patch_rand = patch("os.urandom", return_value=b"5\xd9l\xca\xc2\xff")
with patch_cmd, patch_send:
with patch_cmd, patch_rand, patch_send:
ret = single.shim_cmd(cmd_str="echo test")
assert ret == ret_send
assert "Could not copy the shim script to target" in caplog.text
mock_cmd.assert_not_called()
def test_run_ssh_pre_flight_no_connect(opts, target, tmp_path, caplog):
"""
test Single.run_ssh_pre_flight when you
cannot connect to the target
"""
pre_flight = tmp_path / "script.sh"
pre_flight.write_text("")
target["ssh_pre_flight"] = str(pre_flight)
single = ssh.Single(
opts,
opts["argv"],
"localhost",
mods={},
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
winrm=False,
tty=True,
**target,
)
mock_exec_cmd = MagicMock(return_value=("", "", 1))
patch_exec_cmd = patch("salt.client.ssh.shell.Shell.exec_cmd", mock_exec_cmd)
tmp_file = tmp_path / "tmp_file"
mock_tmp = MagicMock()
patch_tmp = patch("tempfile.NamedTemporaryFile", mock_tmp)
mock_tmp.return_value.__enter__.return_value.name = tmp_file
ret_send = (
"",
"ssh: connect to host 192.168.1.186 port 22: No route to host\nscp: Connection closed\n",
255,
)
send_mock = MagicMock(return_value=ret_send)
patch_send = patch("salt.client.ssh.shell.Shell.send", send_mock)
with caplog.at_level(logging.TRACE):
with patch_send, patch_exec_cmd, patch_tmp:
ret = single.run_ssh_pre_flight()
assert "Copying the pre flight script" in caplog.text
assert "Could not copy the pre flight script to target" in caplog.text
assert ret == ret_send
assert send_mock.call_args_list[0][0][0] == tmp_file
target_script = send_mock.call_args_list[0][0][1]
assert re.search(r".[a-z0-9]+", target_script)
mock_exec_cmd.assert_not_called()
def test_run_ssh_pre_flight_permission_denied(opts, target, tmp_path):
"""
test Single.run_ssh_pre_flight when you
cannot copy script to the target due to
a permission denied error
"""
pre_flight = tmp_path / "script.sh"
pre_flight.write_text("")
target["ssh_pre_flight"] = str(pre_flight)
single = ssh.Single(
opts,
opts["argv"],
"localhost",
mods={},
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
winrm=False,
tty=True,
**target,
)
mock_exec_cmd = MagicMock(return_value=("", "", 1))
patch_exec_cmd = patch("salt.client.ssh.shell.Shell.exec_cmd", mock_exec_cmd)
tmp_file = tmp_path / "tmp_file"
mock_tmp = MagicMock()
patch_tmp = patch("tempfile.NamedTemporaryFile", mock_tmp)
mock_tmp.return_value.__enter__.return_value.name = tmp_file
ret_send = (
"",
'scp: dest open "/tmp/preflight.sh": Permission denied\nscp: failed to upload file /etc/salt/preflight.sh to /tmp/preflight.sh\n',
255,
)
send_mock = MagicMock(return_value=ret_send)
patch_send = patch("salt.client.ssh.shell.Shell.send", send_mock)
with patch_send, patch_exec_cmd, patch_tmp:
ret = single.run_ssh_pre_flight()
assert ret == exp_ret
assert [
call("/bin/sh '{}'".format(exp_tmp)),
call("rm '{}'".format(exp_tmp)),
] == mock_cmd.call_args_list
assert ret == ret_send
assert send_mock.call_args_list[0][0][0] == tmp_file
target_script = send_mock.call_args_list[0][0][1]
assert re.search(r".[a-z0-9]+", target_script)
mock_exec_cmd.assert_not_called()
def test_run_ssh_pre_flight_connect(opts, target, tmp_path, caplog):
"""
test Single.run_ssh_pre_flight when you
can connect to the target
"""
pre_flight = tmp_path / "script.sh"
pre_flight.write_text("")
target["ssh_pre_flight"] = str(pre_flight)
single = ssh.Single(
opts,
opts["argv"],
"localhost",
mods={},
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
winrm=False,
tty=True,
**target,
)
ret_exec_cmd = ("", "", 1)
mock_exec_cmd = MagicMock(return_value=ret_exec_cmd)
patch_exec_cmd = patch("salt.client.ssh.shell.Shell.exec_cmd", mock_exec_cmd)
tmp_file = tmp_path / "tmp_file"
mock_tmp = MagicMock()
patch_tmp = patch("tempfile.NamedTemporaryFile", mock_tmp)
mock_tmp.return_value.__enter__.return_value.name = tmp_file
ret_send = (
"",
"\rroot@192.168.1.187's password: \n\rpreflight.sh 0% 0 0.0KB/s --:-- ETA\rpreflight.sh 100% 20 2.7KB/s 00:00 \n",
0,
)
send_mock = MagicMock(return_value=ret_send)
patch_send = patch("salt.client.ssh.shell.Shell.send", send_mock)
with caplog.at_level(logging.TRACE):
with patch_send, patch_exec_cmd, patch_tmp:
ret = single.run_ssh_pre_flight()
assert "Executing the pre flight script on target" in caplog.text
assert ret == ret_exec_cmd
assert send_mock.call_args_list[0][0][0] == tmp_file
target_script = send_mock.call_args_list[0][0][1]
assert re.search(r".[a-z0-9]+", target_script)
mock_exec_cmd.assert_called()
def test_run_ssh_pre_flight_shutil_fails(opts, target, tmp_path):
"""
test Single.run_ssh_pre_flight when cannot
copyfile with shutil
"""
pre_flight = tmp_path / "script.sh"
pre_flight.write_text("")
target["ssh_pre_flight"] = str(pre_flight)
single = ssh.Single(
opts,
opts["argv"],
"localhost",
mods={},
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
winrm=False,
tty=True,
**target,
)
ret_exec_cmd = ("", "", 1)
mock_exec_cmd = MagicMock(return_value=ret_exec_cmd)
patch_exec_cmd = patch("salt.client.ssh.shell.Shell.exec_cmd", mock_exec_cmd)
tmp_file = tmp_path / "tmp_file"
mock_tmp = MagicMock()
patch_tmp = patch("tempfile.NamedTemporaryFile", mock_tmp)
mock_tmp.return_value.__enter__.return_value.name = tmp_file
send_mock = MagicMock()
mock_shutil = MagicMock(side_effect=IOError("Permission Denied"))
patch_shutil = patch("shutil.copyfile", mock_shutil)
patch_send = patch("salt.client.ssh.shell.Shell.send", send_mock)
with patch_send, patch_exec_cmd, patch_tmp, patch_shutil:
ret = single.run_ssh_pre_flight()
assert ret == (
"",
"Could not copy pre flight script to temporary path",
1,
)
mock_exec_cmd.assert_not_called()
send_mock.assert_not_called()
@pytest.mark.skip_on_windows(reason="SSH_PY_SHIM not set on windows")
@ -355,7 +570,7 @@ def test_cmd_run_set_path(opts, target):
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
**target
**target,
)
ret = single._cmd_str()
@ -376,7 +591,7 @@ def test_cmd_run_not_set_path(opts, target):
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
**target
**target,
)
ret = single._cmd_str()
@ -395,7 +610,7 @@ def test_cmd_block_python_version_error(opts, target):
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
winrm=False,
**target
**target,
)
mock_shim = MagicMock(
return_value=(("", "ERROR: Unable to locate appropriate python command\n", 10))
@ -434,7 +649,9 @@ def test_run_with_pre_flight_args(opts, target, test_opts, tmp_path):
and script successfully runs
"""
opts["ssh_run_pre_flight"] = True
target["ssh_pre_flight"] = str(tmp_path / "script.sh")
pre_flight_script = tmp_path / "script.sh"
pre_flight_script.write_text("")
target["ssh_pre_flight"] = str(pre_flight_script)
if test_opts[0] is not None:
target["ssh_pre_flight_args"] = test_opts[0]
@ -448,7 +665,7 @@ def test_run_with_pre_flight_args(opts, target, test_opts, tmp_path):
fsclient=None,
thin=salt.utils.thin.thin_path(opts["cachedir"]),
mine=False,
**target
**target,
)
cmd_ret = ("Success", "", 0)
@ -456,14 +673,15 @@ def test_run_with_pre_flight_args(opts, target, test_opts, tmp_path):
mock_exec_cmd = MagicMock(return_value=("", "", 0))
patch_cmd = patch("salt.client.ssh.Single.cmd_block", mock_cmd)
patch_exec_cmd = patch("salt.client.ssh.shell.Shell.exec_cmd", mock_exec_cmd)
patch_shell_send = patch("salt.client.ssh.shell.Shell.send", return_value=None)
patch_shell_send = patch(
"salt.client.ssh.shell.Shell.send", return_value=("", "", 0)
)
patch_os = patch("os.path.exists", side_effect=[True])
with patch_os, patch_cmd, patch_exec_cmd, patch_shell_send:
ret = single.run()
assert mock_exec_cmd.mock_calls[0].args[
0
] == "/bin/sh '/tmp/script.sh'{}".format(expected_args)
single.run()
script_args = mock_exec_cmd.mock_calls[0].args[0]
assert re.search(r"\/bin\/sh '.[a-z0-9]+", script_args)
@pytest.mark.slow_test

View file

@ -339,3 +339,113 @@ def test_extra_filerefs(tmp_path, opts):
with patch("salt.roster.get_roster_file", MagicMock(return_value=roster)):
ssh_obj = client._prep_ssh(**ssh_opts)
assert ssh_obj.opts.get("extra_filerefs", None) == "salt://foobar"
def test_key_deploy_permission_denied_scp(tmp_path, opts):
"""
test "key_deploy" function when
permission denied authentication error
when attempting to use scp to copy file
to target
"""
host = "localhost"
passwd = "password"
usr = "ssh-usr"
opts["ssh_user"] = usr
opts["tgt"] = host
ssh_ret = {
host: {
"stdout": "\rroot@192.168.1.187's password: \n\rroot@192.168.1.187's password: \n\rroot@192.168.1.187's password: \n",
"stderr": "Permission denied, please try again.\nPermission denied, please try again.\nroot@192.168.1.187: Permission denied (publickey,gssapi-keyex,gssapi-with-micimport pudb; pu.dbassword).\nscp: Connection closed\n",
"retcode": 255,
}
}
key_run_ret = {
"localhost": {
"jid": "20230922155652279959",
"return": "test",
"retcode": 0,
"id": "test",
"fun": "cmd.run",
"fun_args": ["echo test"],
}
}
patch_roster_file = patch("salt.roster.get_roster_file", MagicMock(return_value=""))
with patch_roster_file:
client = ssh.SSH(opts)
patch_input = patch("builtins.input", side_effect=["y"])
patch_getpass = patch("getpass.getpass", return_value=["password"])
mock_key_run = MagicMock(return_value=key_run_ret)
patch_key_run = patch("salt.client.ssh.SSH._key_deploy_run", mock_key_run)
with patch_input, patch_getpass, patch_key_run:
ret = client.key_deploy(host, ssh_ret)
assert mock_key_run.call_args_list[0][0] == (
host,
{"passwd": [passwd], "host": host, "user": usr},
True,
)
assert ret == key_run_ret
assert mock_key_run.call_count == 1
def test_key_deploy_permission_denied_file_scp(tmp_path, opts):
"""
test "key_deploy" function when permission denied
due to not having access to copy the file to the target
We do not want to deploy the key, because this is not
an authentication to the target error.
"""
host = "localhost"
passwd = "password"
usr = "ssh-usr"
opts["ssh_user"] = usr
opts["tgt"] = host
mock_key_run = MagicMock(return_value=False)
patch_key_run = patch("salt.client.ssh.SSH._key_deploy_run", mock_key_run)
ssh_ret = {
"localhost": {
"stdout": "",
"stderr": 'scp: dest open "/tmp/preflight.sh": Permission denied\nscp: failed to upload file /etc/salt/preflight.sh to /tmp/preflight.sh\n',
"retcode": 1,
}
}
patch_roster_file = patch("salt.roster.get_roster_file", MagicMock(return_value=""))
with patch_roster_file:
client = ssh.SSH(opts)
ret = client.key_deploy(host, ssh_ret)
assert ret == ssh_ret
assert mock_key_run.call_count == 0
def test_key_deploy_no_permission_denied(tmp_path, opts):
"""
test "key_deploy" function when no permission denied
is returned
"""
host = "localhost"
passwd = "password"
usr = "ssh-usr"
opts["ssh_user"] = usr
opts["tgt"] = host
mock_key_run = MagicMock(return_value=False)
patch_key_run = patch("salt.client.ssh.SSH._key_deploy_run", mock_key_run)
ssh_ret = {
"localhost": {
"jid": "20230922161937998385",
"return": "test",
"retcode": 0,
"id": "test",
"fun": "cmd.run",
"fun_args": ["echo test"],
}
}
patch_roster_file = patch("salt.roster.get_roster_file", MagicMock(return_value=""))
with patch_roster_file:
client = ssh.SSH(opts)
ret = client.key_deploy(host, ssh_ret)
assert ret == ssh_ret
assert mock_key_run.call_count == 0

View file

@ -0,0 +1,165 @@
import logging
import pytest
import salt.modules.deb_postgres as deb_postgres
from tests.support.mock import Mock, patch
log = logging.getLogger(__name__)
pytestmark = [
pytest.mark.skip_unless_on_linux(reason="Only supported on Linux family"),
]
@pytest.fixture
def get_lscuster():
return """\
8.4 main 5432 online postgres /srv/8.4/main \
/var/log/postgresql/postgresql-8.4-main.log
9.1 main 5433 online postgres /srv/9.1/main \
/var/log/postgresql/postgresql-9.1-main.log
"""
@pytest.fixture
def configure_loader_modules(get_lscuster):
return {
deb_postgres: {
"__salt__": {
"config.option": Mock(),
"cmd.run_all": Mock(return_value={"stdout": get_lscuster}),
"file.chown": Mock(),
"file.remove": Mock(),
}
}
}
def test_cluster_create():
with patch("salt.utils.path.which", Mock(return_value="/usr/bin/pg_createcluster")):
expected_cmdstr = (
"/usr/bin/pg_createcluster "
"--port 5432 --locale fr_FR --encoding UTF-8 "
"--datadir /opt/postgresql "
"9.3 main"
)
deb_postgres.cluster_create(
"9.3",
"main",
port="5432",
locale="fr_FR",
encoding="UTF-8",
datadir="/opt/postgresql",
)
assert deb_postgres.__salt__["cmd.run_all"].call_args[0][0] == expected_cmdstr
def test_cluster_create_with_initdb_options():
with patch("salt.utils.path.which", Mock(return_value="/usr/bin/pg_createcluster")):
expected_cmdstr = (
"/usr/bin/pg_createcluster "
"--port 5432 --locale fr_FR --encoding UTF-8 "
"--datadir /opt/postgresql "
"11 main "
"-- "
"--allow-group-access "
"--data-checksums "
"--wal-segsize 32"
)
deb_postgres.cluster_create(
"11",
"main",
port="5432",
locale="fr_FR",
encoding="UTF-8",
datadir="/opt/postgresql",
allow_group_access=True,
data_checksums=True,
wal_segsize="32",
)
assert deb_postgres.__salt__["cmd.run_all"].call_args[0][0] == expected_cmdstr
def test_cluster_create_with_float():
with patch("salt.utils.path.which", Mock(return_value="/usr/bin/pg_createcluster")):
expected_cmdstr = (
"/usr/bin/pg_createcluster "
"--port 5432 --locale fr_FR --encoding UTF-8 "
"--datadir /opt/postgresql "
"9.3 main"
)
deb_postgres.cluster_create(
9.3,
"main",
port="5432",
locale="fr_FR",
encoding="UTF-8",
datadir="/opt/postgresql",
)
assert deb_postgres.__salt__["cmd.run_all"].call_args[0][0] == expected_cmdstr
def test_parse_pg_lsclusters(get_lscuster):
with patch("salt.utils.path.which", Mock(return_value="/usr/bin/pg_lsclusters")):
stdout = get_lscuster
maxDiff = None
expected = {
"8.4/main": {
"port": 5432,
"status": "online",
"user": "postgres",
"datadir": "/srv/8.4/main",
"log": "/var/log/postgresql/postgresql-8.4-main.log",
},
"9.1/main": {
"port": 5433,
"status": "online",
"user": "postgres",
"datadir": "/srv/9.1/main",
"log": "/var/log/postgresql/postgresql-9.1-main.log",
},
}
assert deb_postgres._parse_pg_lscluster(stdout) == expected
def test_cluster_list():
with patch("salt.utils.path.which", Mock(return_value="/usr/bin/pg_lsclusters")):
return_list = deb_postgres.cluster_list()
assert (
deb_postgres.__salt__["cmd.run_all"].call_args[0][0]
== "/usr/bin/pg_lsclusters --no-header"
)
return_dict = deb_postgres.cluster_list(verbose=True)
assert isinstance(return_dict, dict)
def test_cluster_exists():
assert deb_postgres.cluster_exists("8.4")
assert deb_postgres.cluster_exists("8.4", "main")
assert not deb_postgres.cluster_exists("3.4", "main")
def test_cluster_delete():
with patch("salt.utils.path.which", Mock(return_value="/usr/bin/pg_dropcluster")):
deb_postgres.cluster_remove("9.3", "main")
assert (
deb_postgres.__salt__["cmd.run_all"].call_args[0][0]
== "/usr/bin/pg_dropcluster 9.3 main"
)
deb_postgres.cluster_remove("9.3", "main", stop=True)
assert (
deb_postgres.__salt__["cmd.run_all"].call_args[0][0]
== "/usr/bin/pg_dropcluster --stop 9.3 main"
)
deb_postgres.cluster_remove(9.3, "main", stop=True)
assert (
deb_postgres.__salt__["cmd.run_all"].call_args[0][0]
== "/usr/bin/pg_dropcluster --stop 9.3 main"
)

File diff suppressed because it is too large Load diff

View file

@ -1,184 +0,0 @@
import salt.modules.deb_postgres as deb_postgres
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.mock import Mock, patch
from tests.support.unit import TestCase
LSCLUSTER = """\
8.4 main 5432 online postgres /srv/8.4/main \
/var/log/postgresql/postgresql-8.4-main.log
9.1 main 5433 online postgres /srv/9.1/main \
/var/log/postgresql/postgresql-9.1-main.log
"""
class PostgresClusterTestCase(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
self.cmd_run_all_mock = Mock(return_value={"stdout": LSCLUSTER})
self.addCleanup(delattr, self, "cmd_run_all_mock")
patcher = patch(
"salt.utils.path.which", Mock(return_value="/usr/bin/pg_createcluster")
)
patcher.start()
self.addCleanup(patcher.stop)
return {
deb_postgres: {
"__salt__": {
"config.option": Mock(),
"cmd.run_all": self.cmd_run_all_mock,
"file.chown": Mock(),
"file.remove": Mock(),
}
}
}
def test_cluster_create(self):
deb_postgres.cluster_create(
"9.3",
"main",
port="5432",
locale="fr_FR",
encoding="UTF-8",
datadir="/opt/postgresql",
)
cmdstr = (
"/usr/bin/pg_createcluster "
"--port 5432 --locale fr_FR --encoding UTF-8 "
"--datadir /opt/postgresql "
"9.3 main"
)
self.assertEqual(cmdstr, self.cmd_run_all_mock.call_args[0][0])
def test_cluster_create_with_initdb_options(self):
deb_postgres.cluster_create(
"11",
"main",
port="5432",
locale="fr_FR",
encoding="UTF-8",
datadir="/opt/postgresql",
allow_group_access=True,
data_checksums=True,
wal_segsize="32",
)
cmdstr = (
"/usr/bin/pg_createcluster "
"--port 5432 --locale fr_FR --encoding UTF-8 "
"--datadir /opt/postgresql "
"11 main "
"-- "
"--allow-group-access "
"--data-checksums "
"--wal-segsize 32"
)
self.assertEqual(cmdstr, self.cmd_run_all_mock.call_args[0][0])
def test_cluster_create_with_float(self):
deb_postgres.cluster_create(
9.3,
"main",
port="5432",
locale="fr_FR",
encoding="UTF-8",
datadir="/opt/postgresql",
)
cmdstr = (
"/usr/bin/pg_createcluster "
"--port 5432 --locale fr_FR --encoding UTF-8 "
"--datadir /opt/postgresql "
"9.3 main"
)
self.assertEqual(cmdstr, self.cmd_run_all_mock.call_args[0][0])
class PostgresLsClusterTestCase(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
self.cmd_run_all_mock = Mock(return_value={"stdout": LSCLUSTER})
self.addCleanup(delattr, self, "cmd_run_all_mock")
patcher = patch(
"salt.utils.path.which", Mock(return_value="/usr/bin/pg_lsclusters")
)
patcher.start()
self.addCleanup(patcher.stop)
return {
deb_postgres: {
"__salt__": {
"config.option": Mock(),
"cmd.run_all": self.cmd_run_all_mock,
"file.chown": Mock(),
"file.remove": Mock(),
}
}
}
def test_parse_pg_lsclusters(self):
stdout = LSCLUSTER
self.maxDiff = None
self.assertDictEqual(
{
"8.4/main": {
"port": 5432,
"status": "online",
"user": "postgres",
"datadir": "/srv/8.4/main",
"log": "/var/log/postgresql/postgresql-8.4-main.log",
},
"9.1/main": {
"port": 5433,
"status": "online",
"user": "postgres",
"datadir": "/srv/9.1/main",
"log": "/var/log/postgresql/postgresql-9.1-main.log",
},
},
deb_postgres._parse_pg_lscluster(stdout),
)
def test_cluster_list(self):
return_list = deb_postgres.cluster_list()
self.assertEqual(
"/usr/bin/pg_lsclusters --no-header", self.cmd_run_all_mock.call_args[0][0]
)
return_dict = deb_postgres.cluster_list(verbose=True)
self.assertIsInstance(return_dict, dict)
def test_cluster_exists(self):
self.assertTrue(deb_postgres.cluster_exists("8.4") is True)
self.assertTrue(deb_postgres.cluster_exists("8.4", "main") is True)
self.assertFalse(deb_postgres.cluster_exists("3.4", "main"))
class PostgresDeleteClusterTestCase(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
self.cmd_run_all_mock = Mock(return_value={"stdout": LSCLUSTER})
self.addCleanup(delattr, self, "cmd_run_all_mock")
patcher = patch(
"salt.utils.path.which", Mock(return_value="/usr/bin/pg_dropcluster")
)
patcher.start()
self.addCleanup(patcher.stop)
return {
deb_postgres: {
"__salt__": {
"config.option": Mock(),
"cmd.run_all": self.cmd_run_all_mock,
"file.chown": Mock(),
"file.remove": Mock(),
}
}
}
def test_cluster_delete(self):
deb_postgres.cluster_remove("9.3", "main")
self.assertEqual(
"/usr/bin/pg_dropcluster 9.3 main", self.cmd_run_all_mock.call_args[0][0]
)
deb_postgres.cluster_remove("9.3", "main", stop=True)
self.assertEqual(
"/usr/bin/pg_dropcluster --stop 9.3 main",
self.cmd_run_all_mock.call_args[0][0],
)
deb_postgres.cluster_remove(9.3, "main", stop=True)
self.assertEqual(
"/usr/bin/pg_dropcluster --stop 9.3 main",
self.cmd_run_all_mock.call_args[0][0],
)

File diff suppressed because it is too large Load diff