Merge 3006.x into master

Conflicts:
 * requirements/darwin.txt
 * requirements/pytest.txt
 * requirements/static/ci/common.in
 * requirements/static/ci/darwin.in
 * requirements/static/ci/freebsd.in
 * requirements/static/ci/linux.in
 * requirements/static/ci/py3.10/cloud.txt
 * requirements/static/ci/py3.10/darwin.txt
 * requirements/static/ci/py3.10/freebsd.txt
 * requirements/static/ci/py3.10/lint.txt
 * requirements/static/ci/py3.10/linux.txt
 * requirements/static/ci/py3.10/windows.txt
 * requirements/static/ci/py3.11/windows.txt
 * requirements/static/ci/py3.7/cloud.txt
 * requirements/static/ci/py3.7/freebsd.txt
 * requirements/static/ci/py3.7/lint.txt
 * requirements/static/ci/py3.7/linux.txt
 * requirements/static/ci/py3.8/cloud.txt
 * requirements/static/ci/py3.8/freebsd.txt
 * requirements/static/ci/py3.8/lint.txt
 * requirements/static/ci/py3.8/linux.txt
 * requirements/static/ci/py3.8/windows.txt
 * requirements/static/ci/py3.9/cloud.txt
 * requirements/static/ci/py3.9/darwin.txt
 * requirements/static/ci/py3.9/freebsd.txt
 * requirements/static/ci/py3.9/lint.txt
 * requirements/static/ci/py3.9/linux.txt
 * requirements/static/ci/py3.9/windows.txt
 * requirements/static/pkg/freebsd.in
 * requirements/static/pkg/linux.in
 * requirements/static/pkg/py3.10/darwin.txt
 * requirements/static/pkg/py3.10/windows.txt
 * requirements/static/pkg/py3.11/windows.txt
 * requirements/static/pkg/py3.8/windows.txt
 * requirements/static/pkg/py3.9/darwin.txt
 * requirements/static/pkg/py3.9/windows.txt
 * requirements/windows.txt
This commit is contained in:
Pedro Algarvio 2023-09-13 16:09:29 +01:00
commit f389c29473
No known key found for this signature in database
GPG key ID: BB36BF6584A298FF
81 changed files with 1105 additions and 860 deletions

View file

@ -238,7 +238,7 @@ jobs:
SKIP_INITIAL_GH_ACTIONS_FAILURES: "1"
run: |
sudo -E nox --force-color -e ${{ inputs.nox-session }} -- ${{ matrix.test-chunk }} \
${{ contains(matrix.test-chunk, 'upgrade') && format('--prev-version {0}', matrix.version) || ''}}
${{ matrix.version && format('--prev-version {0}', matrix.version) || ''}}
- name: Run Package Tests
env:
@ -252,7 +252,7 @@ jobs:
COVERAGE_CONTEXT: ${{ inputs.distro-slug }}
run: |
sudo -E nox --force-color -e ${{ inputs.nox-session }} -- ${{ matrix.test-chunk }} \
${{ contains(matrix.test-chunk, 'upgrade') && format('--prev-version {0}', matrix.version) || ''}}
${{ matrix.version && format('--prev-version {0}', matrix.version) || ''}}
- name: Fix file ownership
run: |

View file

@ -268,13 +268,13 @@ jobs:
run: |
tools --timestamps --timeout-secs=1800 vm testplan --skip-requirements-install \
--nox-session=${{ inputs.nox-session }} ${{ inputs.distro-slug }} -- ${{ matrix.test-chunk }} \
${{ contains(matrix.test-chunk, 'upgrade') && format('--prev-version {0}', matrix.version) || ''}}
${{ matrix.version && format('--prev-version {0}', matrix.version) || ''}}
- name: Run Package Tests
run: |
tools --timestamps --no-output-timeout-secs=1800 --timeout-secs=14400 vm test --skip-requirements-install \
--nox-session=${{ inputs.nox-session }} --rerun-failures ${{ inputs.distro-slug }} -- ${{ matrix.test-chunk }} \
${{ contains(matrix.test-chunk, 'upgrade') && format('--prev-version {0}', matrix.version) || ''}}
${{ matrix.version && format('--prev-version {0}', matrix.version) || ''}}
- name: Download Test Run Artifacts
id: download-artifacts-from-vm

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

@ -0,0 +1 @@
Fixed some issues in x509_v2 execution module private key functions

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

@ -0,0 +1 @@
Moved gitfs locks to salt working dir to avoid lock wipes

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

@ -0,0 +1 @@
speed up yumpkg list_pkgs by not requiring digest or signature verification on lookup.

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

@ -0,0 +1 @@
Fix pkg.latest failing on windows for winrepo packages where the package is already up to date

View file

@ -12,13 +12,10 @@ for a given release.
Add release specific details below
-->
.. Warning::
Due to a known issue with the newest release of setuptools,
users who use pip to install Salt will experience an install
failure. This issue also impacts pip installs for older versions
of Salt. The core Salt team is currently investigating the issue
and has documented a workaround. To follow the issue and get the
latest workaround, see: https://github.com/saltstack/salt/issues/65149
| **IMPORTANT** |
| ------------- |
| Due to a known issue with the newest release of setuptools, users who use pip to install Salt will experience an install failure. This issue also impacts pip installs for older versions of Salt. The core Salt team is currently investigating the issue and has documented a workaround. To follow the issue and get the latest workaround, see: <https://github.com/saltstack/salt/issues/65149> |
<!--
Do not edit the changelog below.

View file

@ -1843,6 +1843,16 @@ def test_pkgs_onedir(session):
"--no-uninstall",
"pkg/tests/upgrade/",
],
"downgrade": [
"--downgrade",
"--no-uninstall",
"pkg/tests/downgrade/",
],
"downgrade-classic": [
"--downgrade",
"--no-uninstall",
"pkg/tests/downgrade/",
],
"download-pkgs": [
"--download-pkgs",
"pkg/tests/download/",
@ -1884,7 +1894,7 @@ def test_pkgs_onedir(session):
"PKG_TEST_TYPE": chunk,
}
if chunk == "upgrade-classic":
if chunk in ("upgrade-classic", "downgrade-classic"):
cmd_args.append("--classic")
# Workaround for installing and running classic packages from 3005.1
# They can only run with importlib-metadata<5.0.0.
@ -1901,6 +1911,7 @@ def test_pkgs_onedir(session):
+ session.posargs
)
_pytest(session, coverage=False, cmd_args=pytest_args, env=env)
if chunk not in ("install", "download-pkgs"):
cmd_args = chunks["install"]
pytest_args = (
@ -1914,5 +1925,9 @@ def test_pkgs_onedir(session):
]
+ session.posargs
)
if "downgrade" in chunk:
pytest_args.append("--use-prev-version")
if chunk in ("upgrade-classic", "downgrade-classic"):
pytest_args.append("--classic")
_pytest(session, coverage=False, cmd_args=pytest_args, env=env)
sys.exit(0)

View file

@ -77,6 +77,8 @@ Description: remote manager to administer servers via salt
Package: salt-minion
Architecture: amd64 arm64
Replaces: salt-common (<= 3006.1)
Breaks: salt-common (<= 3006.1)
Depends: bsdmainutils,
dctrl-tools,
salt-common (= ${source:Version}),
@ -129,6 +131,7 @@ Description: master-of-masters for salt, the distributed remote execution system
Package: salt-ssh
Architecture: amd64 arm64
Breaks: salt-common (<= 3006.3)
Depends: salt-common (= ${source:Version}),
openssh-client,
${misc:Depends}
@ -157,6 +160,7 @@ Description: remote manager to administer servers via Salt SSH
Package: salt-cloud
Architecture: amd64 arm64
Breaks: salt-common (<= 3006.3)
Depends: salt-common (= ${source:Version}),
${misc:Depends}
Description: public cloud VM management system

View file

@ -0,0 +1 @@
conf/cloud /etc/salt

View file

@ -3,3 +3,4 @@
/var/run/salt
/usr/share/fish/vendor_completions.d
/opt/saltstack/salt
/etc/salt

View file

@ -1,5 +1,3 @@
conf/roster /etc/salt
conf/cloud /etc/salt
pkg/common/salt-common.logrotate /etc/logrotate.d/salt
pkg/common/fish-completions/salt-cp.fish /usr/share/fish/vendor_completions.d
pkg/common/fish-completions/salt-call.fish /usr/share/fish/vendor_completions.d

View file

@ -0,0 +1 @@
conf/roster /etc/salt

View file

@ -6,17 +6,19 @@
# Date: December 2020
#
# Description: This notarizes the macOS Installer Package (.pkg). It uses the
# `altool` xcode utility which is only available in the full
# Xcode package. It is not available in Command Line Tools.
# `notarytool` xcode utility which became available in Xcode 13.
# Xcode 13 requires macOS Big Sur 11.3 or higher. However, the
# notarytool binary can be extracted and run on macOS Catalina
# 10.15.7 and higher. It is not available in Command Line Tools.
#
# This script will upload a copy of the package to Apple and wait
# for the notarization to return. This can take several minutes.
#
# If this command is run with sudo, you need to pass the `-E`
# option to make sure the environment variables pass through to the
# sudo environment. For example:
# This script requires the presence of some environment variables.
# If running this script with sudo, be sure to pass the `-E`
# option.
#
# sudo -E ./notarize.sh
# sudo -E ./notarize.sh salt-3006.2-signed.pkg
#
# Requirements:
# - Full Xcode Installation
@ -31,24 +33,26 @@
# The package that will be notarized (must be signed)
#
# Example:
# The following will notarize the 'salt-3006.1-1-signed.pkg' file
# The following will notarize the 'salt-3006.2-signed.pkg' file:
#
# ./notarize.sh salt-3006.1-1-signed.pkg
# ./notarize.sh salt-3006.2-signed.pkg
#
# Environment Setup:
#
# Define Environment Variables:
# Create two environment variables for the Apple account and the
# app-specific password associated with that account. To generate the
# app-specific password see: https://support.apple.com/en-us/HT204397
# Create three environment variables for the apple account, apple team
# ID, and the app-specific password associated with that account. To
# generate the app-specific password see:
# https://support.apple.com/en-us/HT204397
#
# export APPLE_ACCT="username@domain.com"
# export APPLE_TEAM_ID="AB283DVDS5"
# export APP_SPEC_PWD="abcd-efgh-ijkl-mnop"
#
################################################################################
#-------------------------------------------------------------------------------
# Variables
# Check input parameters
#-------------------------------------------------------------------------------
if [ "$1" == "" ]; then
echo "Must supply a package to notarize"
@ -57,28 +61,9 @@ else
PACKAGE=$1
fi
BUNDLE_ID="com.saltstack.salt"
CMD_OUTPUT=$(mktemp -t cmd.log)
#-------------------------------------------------------------------------------
# Functions
#-------------------------------------------------------------------------------
# _usage
#
# Prints out help text
_usage() {
echo ""
echo "Script to notarize the Salt package:"
echo ""
echo "usage: ${0}"
echo " [-h|--help]"
echo ""
echo " -h, --help this message"
echo ""
echo " To notarize the Salt package:"
echo " example: $0 salt-3006.1-1-signed.pkg"
}
# _msg
#
# Prints the message with a dash... no new line
@ -99,38 +84,32 @@ _success() {
_failure() {
printf "\e[31m%s\e[0m\n" "Failure"
echo "output >>>>>>"
cat "$CMD_OUTPUT" 1>&2
cat "$NOTARIZE_LOG" 1>&2
echo "<<<<<< output"
exit 1
}
#-------------------------------------------------------------------------------
# Get Parameters
# Environment Variables
#-------------------------------------------------------------------------------
while true; do
if [[ -z "$1" ]]; then break; fi
case "$1" in
-h | --help )
_usage
exit 0
;;
-*)
echo "Invalid Option: $1"
echo ""
_usage
exit 1
;;
* )
shift
;;
esac
done
_msg "Setting Variables"
NOTARIZE_LOG=$(mktemp -t notarize-app.log)
NOTARY_TOOL=$(xcrun --find notarytool)
_success
#-------------------------------------------------------------------------------
# Check for notarytool
#-------------------------------------------------------------------------------
if [ ! -f "$NOTARY_TOOL" ]; then
echo "This script requires the NotaryTool binary"
exit 1
fi
#-------------------------------------------------------------------------------
# Delete temporary files on exit
#-------------------------------------------------------------------------------
function finish {
rm "$CMD_OUTPUT"
rm "$NOTARIZE_LOG"
}
trap finish EXIT
@ -139,87 +118,34 @@ trap finish EXIT
#-------------------------------------------------------------------------------
printf "=%.0s" {1..80}; printf "\n"
echo "Notarize Salt Package"
echo "- This can take up to 30 minutes"
printf -- "-%.0s" {1..80}; printf "\n"
#-------------------------------------------------------------------------------
# Submit app for notarization
#-------------------------------------------------------------------------------
_msg "Submitting package for notarization"
if xcrun altool --notarize-app \
--primary-bundle-id "$BUNDLE_ID" \
--username "$APPLE_ACCT" \
--password "$APP_SPEC_PWD" \
-f "$PACKAGE" > "$CMD_OUTPUT" 2>&1; then
_msg "Submitting Package for Notarization"
if $NOTARY_TOOL submit \
--apple-id "$APPLE_ACCT" \
--team-id "$APPLE_TEAM_ID" \
--password "$APP_SPEC_PWD" \
--wait \
"$PACKAGE" > "$NOTARIZE_LOG" 2>&1; then
_success
else
_failure
fi
# Get RequestUUID from the CMD_OUTPUT
# Uncomment for debugging
# cat "$CMD_OUTPUT"
_msg "Verifying successful upload"
if grep -q "No errors uploading" "$CMD_OUTPUT"; then
# Make sure the status is "Accepted", then staple
_msg "Verifying accepted status"
if grep -q "status: Accepted" "$NOTARIZE_LOG"; then
_success
else
echo ">>>>>> Failed Uploading Package <<<<<<" > "$CMD_OUTPUT"
_failure
fi
RequestUUID=$(awk -F ' = ' '/RequestUUID/ {print $2}' "$CMD_OUTPUT")
# Clear CMD_OUTPUT
echo "" > "$CMD_OUTPUT"
echo "- Checking Notarization Status (every 30 seconds):"
echo -n " "
# Though it usually takes 5 minutes, notarization can take up to 30 minutes
# Check status every 30 seconds for 40 minutes
tries=0
while sleep 30; do
((tries++))
echo -n "."
# check notarization status
if ! xcrun altool --notarization-info "$RequestUUID" \
--username "$APPLE_ACCT" \
--password "$APP_SPEC_PWD" > "$CMD_OUTPUT" 2>&1; then
echo ""
cat "$CMD_OUTPUT" 1>&2
exit 1
fi
# Look for Status in the CMD_OUTPUT
# Uncomment for debugging
# cat "$CMD_OUTPUT"
# Continue checking until Status is no longer "in progress"
if ! grep -q "Status: in progress" "$CMD_OUTPUT"; then
echo ""
break
fi
if (( tries > 80 )); then
echo ""
echo "Failed after 40 minutes"
echo "Log: $CMD_OUTPUT"
cat "$CMD_OUTPUT" 1>&2
exit 1
fi
done
# Make sure the result is "success", then staple
if ! grep -q "Status: success" "$CMD_OUTPUT"; then
echo "**** There was a problem notarizing the package"
echo "**** View the log for details:"
awk -F ': ' '/LogFileURL/ {print $2}' "$CMD_OUTPUT"
exit 1
fi
echo " Notarization Complete"
_msg "Stapling notarization to the package"
if xcrun stapler staple "$PACKAGE" > "$CMD_OUTPUT"; then
_msg "Stapling Notarization to the Package"
if xcrun stapler staple "$PACKAGE" > "$NOTARIZE_LOG"; then
_success
else
_failure

View file

@ -31,7 +31,7 @@ def version(install_salt):
"""
get version number from artifact
"""
return install_salt.get_version(version_only=True)
return install_salt.version
@pytest.fixture(scope="session")
@ -87,6 +87,12 @@ def pytest_addoption(parser):
action="store_true",
help="Install previous version and then upgrade then run tests",
)
test_selection_group.addoption(
"--downgrade",
default=False,
action="store_true",
help="Install current version and then downgrade to the previous version and run tests",
)
test_selection_group.addoption(
"--no-install",
default=False,
@ -110,6 +116,11 @@ def pytest_addoption(parser):
action="store",
help="Test an upgrade from the version specified.",
)
test_selection_group.addoption(
"--use-prev-version",
action="store_true",
help="Tells the test suite to validate the version using the previous version (for downgrades)",
)
test_selection_group.addoption(
"--download-pkgs",
default=False,
@ -168,10 +179,12 @@ def install_salt(request, salt_factories_root_dir):
conf_dir=salt_factories_root_dir / "etc" / "salt",
system_service=request.config.getoption("--system-service"),
upgrade=request.config.getoption("--upgrade"),
downgrade=request.config.getoption("--downgrade"),
no_uninstall=request.config.getoption("--no-uninstall"),
no_install=request.config.getoption("--no-install"),
classic=request.config.getoption("--classic"),
prev_version=request.config.getoption("--prev-version"),
use_prev_version=request.config.getoption("--use-prev-version"),
) as fixture:
yield fixture
@ -362,22 +375,20 @@ def salt_master(salt_factories, install_salt, state_tree, pillar_tree):
assert _file.owner() == "salt"
assert _file.group() == "salt"
if (platform.is_windows() or platform.is_darwin()) and install_salt.singlebin:
start_timeout = 240
# For every minion started we have to accept it's key.
# On windows, using single binary, it has to decompress it and run the command. Too slow.
# So, just in this scenario, use open mode
config_overrides["open_mode"] = True
master_script = False
if platform.is_windows():
if install_salt.classic:
master_script = True
# this check will need to be changed to install_salt.relenv
# once the package version returns 3006 and not 3005 on master
if install_salt.relenv:
master_script = True
elif not install_salt.upgrade:
master_script = True
if (
not install_salt.relenv
and install_salt.use_prev_version
and not install_salt.classic
):
master_script = False
if master_script:
salt_factories.system_install = False
@ -439,8 +450,6 @@ def salt_minion(salt_factories, salt_master, install_salt):
Start up a minion
"""
start_timeout = None
if (platform.is_windows() or platform.is_darwin()) and install_salt.singlebin:
start_timeout = 240
minion_id = random_string("minion-")
# Since the daemons are "packaged" with tiamat, the salt plugins provided
# by salt-factories won't be discovered. Provide the required `*_dirs` on
@ -531,8 +540,6 @@ def salt_api(salt_master, install_salt, extras_pypath):
"""
shutil.rmtree(str(extras_pypath), ignore_errors=True)
start_timeout = None
if platform.is_windows() and install_salt.singlebin:
start_timeout = 240
factory = salt_master.salt_api_daemon()
with factory.started(start_timeout=start_timeout):
yield factory

View file

View file

@ -0,0 +1,64 @@
import shutil
import packaging.version
import pytest
from pytestskipmarkers.utils import platform
def test_salt_downgrade(salt_call_cli, install_salt):
"""
Test an upgrade of Salt.
"""
if not install_salt.downgrade:
pytest.skip("Not testing a downgrade, do not run")
is_downgrade_to_relenv = packaging.version.parse(
install_salt.prev_version
) >= packaging.version.parse("3006.0")
if is_downgrade_to_relenv:
original_py_version = install_salt.package_python_version()
# Verify current install version is setup correctly and works
ret = salt_call_cli.run("test.version")
assert ret.returncode == 0
assert packaging.version.parse(ret.data) == packaging.version.parse(
install_salt.artifact_version
)
# Test pip install before a downgrade
dep = "PyGithub==1.56.0"
install = salt_call_cli.run("--local", "pip.install", dep)
assert install.returncode == 0
# Verify we can use the module dependent on the installed package
repo = "https://github.com/saltstack/salt.git"
use_lib = salt_call_cli.run("--local", "github.get_repo_info", repo)
assert "Authentication information could" in use_lib.stderr
# Downgrade Salt to the previous version and test
install_salt.install(downgrade=True)
bin_file = "salt"
if platform.is_windows():
if not is_downgrade_to_relenv:
bin_file = install_salt.install_dir / "salt-call.bat"
else:
bin_file = install_salt.install_dir / "salt-call.exe"
elif platform.is_darwin() and install_salt.classic:
bin_file = install_salt.bin_dir / "salt-call"
ret = install_salt.proc.run(bin_file, "--version")
assert ret.returncode == 0
assert packaging.version.parse(
ret.stdout.strip().split()[1]
) < packaging.version.parse(install_salt.artifact_version)
# Windows does not keep the extras directory around in the same state
# TODO: Fix this problem in windows installers
# TODO: Fix this problem in macos installers
if is_downgrade_to_relenv and not (platform.is_windows() or platform.is_darwin()):
new_py_version = install_salt.package_python_version()
if new_py_version == original_py_version:
# test pip install after a downgrade
use_lib = salt_call_cli.run("--local", "github.get_repo_info", repo)
assert "Authentication information could" in use_lib.stderr

View file

@ -12,6 +12,12 @@ pytestmark = [
log = logging.getLogger(__name__)
@pytest.fixture(autouse=True)
def _skip_on_non_relenv(install_salt):
if not install_salt.relenv:
pytest.skip("This test is for relenv versions of salt")
def test_check_no_import_error(salt_call_cli, salt_master):
"""
Test that we don't have any errors on teardown of python when using a py-rendered sls file

View file

@ -8,9 +8,6 @@ def test_services(install_salt, salt_cli, salt_minion):
"""
Check if Services are enabled/disabled
"""
if install_salt.compressed:
pytest.skip("Skip test on single binary and onedir package")
if install_salt.distro_id in ("ubuntu", "debian"):
services_enabled = ["salt-master", "salt-minion", "salt-syndic", "salt-api"]
services_disabled = []

View file

@ -1,14 +1,31 @@
import subprocess
from pytestskipmarkers.utils import platform
def test_help(install_salt):
"""
Test --help works for all salt cmds
"""
for cmd in install_salt.binary_paths.values():
# TODO: add back salt-cloud and salt-ssh when its fixed
cmd = [str(x) for x in cmd]
if "python" in cmd[0]:
ret = install_salt.proc.run(*cmd, "--version")
if len(cmd) > 1 and "shell" in cmd[1]:
# Singlebin build, unable to get the version
continue
# TODO: Remove this condition once the fixed 3005.x classic packages are released.
if "salt-proxy" in cmd[0] and platform.is_darwin() and install_salt.classic:
continue
if "python" in cmd[0] and len(cmd) == 1:
ret = install_salt.proc.run(
*cmd, "--version", stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
assert "Python" in ret.stdout
else:
ret = install_salt.proc.run(*cmd, "--help")
ret = install_salt.proc.run(
*cmd, "--help", stdout=subprocess.PIPE, stderr=subprocess.PIPE
)
assert "Usage" in ret.stdout
assert ret.returncode == 0

View file

@ -2,6 +2,7 @@ import os
import pathlib
import subprocess
import packaging.version
import psutil
import pytest
@ -10,6 +11,16 @@ pytestmark = [
]
@pytest.fixture(autouse=True)
def _skip_on_less_than_3006_1(install_salt):
if packaging.version.parse(install_salt.version) <= packaging.version.parse(
"3006.1"
):
pytest.skip(
"Multi-minion script only available on versions greater than 3006.1"
)
@pytest.fixture
def mm_script(install_salt):
yield install_salt.ssm_bin.parent / "multi-minion.ps1"

View file

@ -12,10 +12,8 @@ from pytestskipmarkers.utils import platform
def pypath():
if platform.is_windows():
return pathlib.Path(os.getenv("ProgramFiles"), "Salt Project", "Salt")
elif platform.is_darwin():
return pathlib.Path("/opt", "salt", "bin")
else:
return pathlib.Path("/opt", "saltstack", "salt", "bin")
return pathlib.Path("/opt", "saltstack", "salt", "pypath", "bin")
@pytest.fixture(autouse=True)
@ -44,7 +42,7 @@ def wipe_pydeps(shell, install_salt, extras_pypath):
shutil.rmtree(dirname, ignore_errors=True)
def test_pip_install(salt_call_cli):
def test_pip_install(salt_call_cli, install_salt, shell):
"""
Test pip.install and ensure module can use installed library
"""
@ -68,6 +66,8 @@ def test_pip_install_extras(shell, install_salt, extras_pypath_bin):
"""
Test salt-pip installs into the correct directory
"""
if not install_salt.relenv:
pytest.skip("The extras directory is only in relenv versions")
dep = "pep8"
extras_keyword = "extras-3"
if platform.is_windows():
@ -86,7 +86,7 @@ def test_pip_install_extras(shell, install_salt, extras_pypath_bin):
break
else:
pytest.fail(
f"The {dep!r} package was not found installed. Packages Installed: {pkgs_installed}"
f"The {dep!r} package was not found installed. Packages Installed: {ret.data}"
)
show_ret = shell.run(*(install_salt.binary_paths["pip"] + ["show", dep]))
@ -109,8 +109,12 @@ def demote(user_uid, user_gid):
@pytest.mark.skip_on_windows(reason="We can't easily demote users on Windows")
def test_pip_non_root(shell, install_salt, test_account, extras_pypath_bin):
def test_pip_non_root(shell, install_salt, test_account, extras_pypath_bin, pypath):
if install_salt.classic:
pytest.skip("We can install non-root for classic packages")
check_path = extras_pypath_bin / "pep8"
if not install_salt.relenv and not install_salt.classic:
check_path = pypath / "pep8"
# We should be able to issue a --help without being root
ret = subprocess.run(
install_salt.binary_paths["salt"] + ["--help"],
@ -150,7 +154,7 @@ def test_pip_non_root(shell, install_salt, test_account, extras_pypath_bin):
text=True,
)
assert check_path.exists()
assert check_path.exists(), shutil.which("pep8")
assert ret.returncode == 0, ret.stderr
@ -160,6 +164,8 @@ def test_pip_install_salt_extension_in_extras(install_salt, extras_pypath, shell
Test salt-pip installs into the correct directory and the salt extension
is properly loaded.
"""
if not install_salt.relenv:
pytest.skip("The extras directory is only in relenv versions")
dep = "salt-analytics-framework"
dep_version = "0.1.0"

View file

@ -5,11 +5,18 @@ import pytest
from tests.support.helpers import TESTS_DIR
@pytest.fixture
def python_script_bin(install_salt):
# Tiamat builds run scripts via `salt python`
if not install_salt.relenv and not install_salt.classic:
return install_salt.binary_paths["python"][:1] + ["python"]
return install_salt.binary_paths["python"]
@pytest.mark.parametrize("exp_ret,user_arg", [(1, "false"), (0, "true")])
def test_python_script(install_salt, exp_ret, user_arg):
ret = subprocess.run(
install_salt.binary_paths["python"]
+ [str(TESTS_DIR / "files" / "check_python.py"), user_arg],
def test_python_script(install_salt, exp_ret, user_arg, python_script_bin):
ret = install_salt.proc.run(
*(python_script_bin + [str(TESTS_DIR / "files" / "check_python.py"), user_arg]),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False,
@ -19,10 +26,9 @@ def test_python_script(install_salt, exp_ret, user_arg):
assert ret.returncode == exp_ret, ret.stderr
def test_python_script_exception(install_salt):
ret = subprocess.run(
install_salt.binary_paths["python"]
+ [str(TESTS_DIR / "files" / "check_python.py"), "raise"],
def test_python_script_exception(install_salt, python_script_bin):
ret = install_salt.proc.run(
*(python_script_bin + [str(TESTS_DIR / "files" / "check_python.py"), "raise"]),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=False,

View file

@ -7,15 +7,22 @@ pytestmark = [
]
def test_salt_cmd_run(salt_cli, salt_minion):
@pytest.fixture
def cat_file(tmp_path):
fp = tmp_path / "cat-file"
fp.write_text(str(fp))
return fp
def test_salt_cmd_run(salt_cli, salt_minion, cat_file):
"""
Test salt cmd.run 'ipconfig' or 'ls -lah /'
Test salt cmd.run 'ipconfig' or 'cat <file>'
"""
ret = None
if platform.startswith("win"):
ret = salt_cli.run("cmd.run", "ipconfig", minion_tgt=salt_minion.id)
else:
ret = salt_cli.run("cmd.run", "ls -lah /", minion_tgt=salt_minion.id)
ret = salt_cli.run("cmd.run", f"cat {str(cat_file)}", minion_tgt=salt_minion.id)
assert ret
assert ret.stdout

View file

@ -3,10 +3,9 @@ import pathlib
import subprocess
import sys
import packaging.version
import psutil
import pytest
import yaml
from pytestskipmarkers.utils import platform
pytestmark = [
pytest.mark.skip_on_windows,
@ -61,6 +60,12 @@ def pkg_paths_salt_user_exclusions():
return paths
@pytest.fixture(autouse=True)
def _skip_on_non_relenv(install_salt):
if not install_salt.relenv:
pytest.skip("The salt user only exists on relenv versions of salt")
def test_salt_user_master(salt_master, install_salt):
"""
Test the correct user is running the Salt Master
@ -129,6 +134,10 @@ def test_pkg_paths(
"""
Test package paths ownership
"""
if packaging.version.parse(install_salt.version) <= packaging.version.parse(
"3006.2"
):
pytest.skip("Package path ownership was changed in salt 3006.3")
salt_user_subdirs = []
for _path in pkg_paths:
pkg_path = pathlib.Path(_path)

View file

@ -23,6 +23,8 @@ def test_salt_versions_report_master(install_salt):
"""
Test running --versions-report on master
"""
if not install_salt.relenv and not install_salt.classic:
pytest.skip("Unable to get the python version dynamically from tiamat builds")
test_bin = os.path.join(*install_salt.binary_paths["master"])
python_bin = os.path.join(*install_salt.binary_paths["python"])
ret = install_salt.proc.run(test_bin, "--versions-report")
@ -52,14 +54,13 @@ def test_compare_versions(version, binary, install_salt):
"""
Test compare versions
"""
if platform.is_windows() and install_salt.singlebin:
pytest.skip(
"Already tested in `test_salt_version`. No need to repeat for "
"Windows single binary installs."
)
if binary in install_salt.binary_paths:
ret = install_salt.proc.run(*install_salt.binary_paths[binary], "--version")
ret = install_salt.proc.run(
*install_salt.binary_paths[binary],
"--version",
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
ret.stdout.matcher.fnmatch_lines([f"*{version}*"])
else:
if platform.is_windows():
@ -93,11 +94,10 @@ def test_symlinks_created(version, symlink, install_salt):
"""
Test symlinks created
"""
if not install_salt.installer_pkg:
pytest.skip(
"This test is for the installer package only (pkg). It does not "
"apply to the tarball"
)
if install_salt.classic:
pytest.skip("Symlinks not created for classic macos builds, we adjust the path")
if not install_salt.relenv and symlink == "spm":
symlink = "salt-spm"
ret = install_salt.proc.run(pathlib.Path("/usr/local/sbin") / symlink, "--version")
ret.stdout.matcher.fnmatch_lines([f"*{version}*"])

View file

@ -6,11 +6,9 @@ import pathlib
import pprint
import re
import shutil
import tarfile
import textwrap
import time
from typing import TYPE_CHECKING, Any, Dict, List
from zipfile import ZipFile
from typing import TYPE_CHECKING, Dict, List
import attr
import distro
@ -43,13 +41,6 @@ try:
except ImportError:
HAS_PWD = False
try:
import winreg
HAS_WINREG = True
except ImportError:
HAS_WINREG = False
TESTS_DIR = pathlib.Path(__file__).resolve().parent.parent
CODE_DIR = TESTS_DIR.parent
ARTIFACTS_DIR = CODE_DIR / "artifacts"
@ -59,57 +50,52 @@ log = logging.getLogger(__name__)
@attr.s(kw_only=True, slots=True)
class SaltPkgInstall:
conf_dir: pathlib.Path = attr.ib()
system_service: bool = attr.ib(default=False)
proc: Subprocess = attr.ib(init=False, repr=False)
pkgs: List[str] = attr.ib(factory=list)
onedir: bool = attr.ib(default=False)
singlebin: bool = attr.ib(default=False)
compressed: bool = attr.ib(default=False)
hashes: Dict[str, Dict[str, Any]] = attr.ib(repr=False)
system_service: bool = attr.ib(default=False)
# Paths
root: pathlib.Path = attr.ib(default=None)
run_root: pathlib.Path = attr.ib(default=None)
ssm_bin: pathlib.Path = attr.ib(default=None)
bin_dir: pathlib.Path = attr.ib(default=None)
# The artifact is an installer (exe, msi, pkg, rpm, deb)
installer_pkg: bool = attr.ib(default=False)
install_dir: pathlib.Path = attr.ib(init=False)
binary_paths: Dict[str, List[pathlib.Path]] = attr.ib(init=False)
config_path: str = attr.ib(init=False)
conf_dir: pathlib.Path = attr.ib()
# Test selection flags
upgrade: bool = attr.ib(default=False)
# install salt or not. This allows someone
# to test a currently installed version of salt
downgrade: bool = attr.ib(default=False)
classic: bool = attr.ib(default=False)
# Installing flags
no_install: bool = attr.ib(default=False)
no_uninstall: bool = attr.ib(default=False)
# Distribution/system information
distro_id: str = attr.ib(init=False)
distro_codename: str = attr.ib(init=False)
distro_name: str = attr.ib(init=False)
distro_version: str = attr.ib(init=False)
# Package (and management) metadata
pkg_mngr: str = attr.ib(init=False)
rm_pkg: str = attr.ib(init=False)
salt_pkgs: List[str] = attr.ib(init=False)
install_dir: pathlib.Path = attr.ib(init=False)
binary_paths: Dict[str, List[pathlib.Path]] = attr.ib(init=False)
classic: bool = attr.ib(default=False)
prev_version: str = attr.ib()
pkg_version: str = attr.ib(default="1")
repo_data: str = attr.ib(init=False, repr=False)
major: str = attr.ib(init=False)
minor: str = attr.ib(init=False)
relenv: bool = attr.ib(default=True)
pkgs: List[str] = attr.ib(factory=list)
file_ext: bool = attr.ib(default=None)
config_path: str = attr.ib(init=False)
relenv: bool = attr.ib(default=True)
# Version information
prev_version: str = attr.ib()
use_prev_version: str = attr.ib()
artifact_version: str = attr.ib(init=False)
version: str = attr.ib(init=False)
@proc.default
def _default_proc(self):
return Subprocess()
@hashes.default
def _default_hashes(self):
return {
"BLAKE2B": {"file": None, "tool": "-blake2b512"},
"SHA3_512": {"file": None, "tool": "-sha3-512"},
"SHA512": {"file": None, "tool": "-sha512"},
}
@distro_id.default
def _default_distro_id(self):
return distro.id().lower()
@ -166,7 +152,6 @@ class SaltPkgInstall:
os.getenv("ProgramFiles"), "Salt Project", "Salt"
).resolve()
elif platform.is_darwin():
# TODO: Add mac install dir path
install_dir = pathlib.Path("/opt", "salt")
else:
install_dir = pathlib.Path("/opt", "saltstack", "salt")
@ -183,197 +168,99 @@ class SaltPkgInstall:
config_path = pathlib.Path("/etc", "salt")
return config_path
@repo_data.default
def _default_repo_data(self):
@version.default
def _default_version(self):
"""
Query to see the published Salt artifacts
from repo.json
The version to be installed at the start
"""
url = "https://repo.saltproject.io/salt/onedir/repo.json"
ret = requests.get(url)
data = ret.json()
return data
if not self.upgrade and not self.use_prev_version:
version = self.artifact_version
else:
version = self.prev_version
parsed = packaging.version.parse(version)
version = f"{parsed.major}.{parsed.minor}"
if self.distro_id in ("ubuntu", "debian"):
self.stop_services()
return version
def check_relenv(self, version):
@artifact_version.default
def _default_artifact_version(self):
"""
Detects if we are using relenv
onedir build
The version of the local salt artifacts being tested, based on regex matching
"""
relenv = False
if packaging.version.parse(version) >= packaging.version.parse("3006.0"):
relenv = True
return relenv
version = ""
for artifact in ARTIFACTS_DIR.glob("**/*.*"):
version = re.search(
r"([0-9].*)(\-[0-9].fc|\-[0-9].el|\+ds|\_all|\_any|\_amd64|\_arm64|\-[0-9].am|(\-[0-9]-[a-z]*-[a-z]*[0-9_]*.|\-[0-9]*.*)(exe|msi|pkg|rpm|deb))",
artifact.name,
)
if version:
version = version.groups()[0].replace("_", "-").replace("~", "")
version = version.split("-")[0]
break
return version
def update_process_path(self):
# The installer updates the path for the system, but that doesn't
# make it to this python session, so we need to update that
os.environ["PATH"] = ";".join([str(self.install_dir), os.getenv("path")])
# When the MSI installer is run from self.proc.run, it doesn't update
# the registry. When run from a normal command prompt it does. Until we
# figure that out, we will update the process path as above. This
# doesn't really check that the path is being set though... but I see
# no other way around this
# if HAS_WINREG:
# log.debug("Refreshing the path")
# # Get the updated system path from the registry
# path_key = winreg.OpenKeyEx(
# winreg.HKEY_LOCAL_MACHINE,
# r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment",
# )
# current_path = winreg.QueryValueEx(path_key, "path")[0]
# path_key.Close()
# # Update the path for the current running process
# os.environ["PATH"] = current_path
def get_version(self, version_only=False):
"""
Return the version information
needed to install a previous version
of Salt.
"""
prev_version = self.prev_version
pkg_version = None
if not self.upgrade:
# working with local artifact
version = ""
for artifact in ARTIFACTS_DIR.glob("**/*.*"):
version = re.search(
r"([0-9].*)(\-[0-9].fc|\-[0-9].el|\+ds|\_all|\_any|\_amd64|\_arm64|\-[0-9].am|(\-[0-9]-[a-z]*-[a-z]*[0-9_]*.|\-[0-9]*.*)(tar.gz|tar.xz|zip|exe|msi|pkg|rpm|deb))",
artifact.name,
)
if version:
version = version.groups()[0].replace("_", "-").replace("~", "")
version = version.split("-")[0]
# TODO: Remove this clause. This is to handle a versioning difficulty between pre-3006
# dev versions and older salt versions on deb-based distros
if version.startswith("1:"):
version = version[2:]
break
major, minor = version.split(".", 1)
else:
if not prev_version:
# We did not pass in a version, lets detect the latest
# version information of a Salt artifact.
latest = list(self.repo_data["latest"].keys())[0]
version = self.repo_data["latest"][latest]["version"]
if "-" in version:
prev_version, pkg_version = version.split("-")
else:
prev_version, pkg_version = version, None
else:
# We passed in a version, but lets check if the pkg_version
# is defined. Relenv pkgs do not define a pkg build number
if "-" not in prev_version and not self.check_relenv(
version=prev_version
):
pkg_numbers = [
x for x in self.repo_data.keys() if prev_version in x
]
pkg_version = 1
for number in pkg_numbers:
number = int(number.split("-")[1])
if number > pkg_version:
pkg_version = number
major, minor = prev_version.split(".")
if version_only:
return version
return major, minor, prev_version, pkg_version
def __attrs_post_init__(self):
self.major, self.minor, self.prev_version, self.pkg_version = self.get_version()
self.relenv = self.check_relenv(self.major)
file_ext_re = r"tar\.gz"
self.relenv = packaging.version.parse(self.version) >= packaging.version.parse(
"3006.0"
)
file_ext_re = "rpm|deb"
if platform.is_darwin():
file_ext_re = r"tar\.gz|pkg"
file_ext_re = "pkg"
if platform.is_windows():
file_ext_re = "zip|exe|msi"
file_ext_re = "exe|msi"
for f_path in ARTIFACTS_DIR.glob("**/*.*"):
f_path = str(f_path)
if re.search(f"salt-(.*).({file_ext_re})$", f_path, re.IGNORECASE):
# Compressed can be zip, tar.gz, exe, or pkg. All others are
# deb and rpm
self.compressed = True
self.file_ext = os.path.splitext(f_path)[1].strip(".")
if self.file_ext == "gz":
if f_path.endswith("tar.gz"):
self.file_ext = "tar.gz"
self.pkgs.append(f_path)
if platform.is_windows():
self.root = pathlib.Path(os.getenv("LocalAppData")).resolve()
if self.file_ext == "zip":
with ZipFile(f_path, "r") as zip:
first = zip.infolist()[0]
if first.filename == "salt/ssm.exe":
self.onedir = True
self.bin_dir = self.root / "salt" / "salt"
self.run_root = self.bin_dir / "salt.exe"
self.ssm_bin = self.root / "salt" / "ssm.exe"
elif first.filename == "salt.exe":
self.singlebin = True
self.run_root = self.root / "salt.exe"
self.ssm_bin = self.root / "ssm.exe"
else:
log.error(
"Unexpected archive layout. First: %s",
first.filename,
)
elif self.file_ext in ["exe", "msi"]:
self.compressed = False
self.onedir = True
self.installer_pkg = True
if self.file_ext in ["exe", "msi"]:
self.root = self.install_dir.parent
self.bin_dir = self.install_dir
self.ssm_bin = self.install_dir / "ssm.exe"
self.run_root = self.bin_dir / "bin" / "salt.exe"
if not self.relenv and not self.classic:
self.ssm_bin = self.bin_dir / "bin" / "ssm.exe"
else:
log.error("Unexpected file extension: %s", self.file_ext)
else:
if platform.is_darwin():
self.root = pathlib.Path(os.sep, "opt")
else:
self.root = pathlib.Path(os.sep, "usr", "local", "bin")
if self.use_prev_version:
self.bin_dir = self.install_dir / "bin"
self.run_root = self.bin_dir / "salt.exe"
self.ssm_bin = self.bin_dir / "ssm.exe"
if self.file_ext == "msi" or self.relenv:
self.ssm_bin = self.install_dir / "ssm.exe"
if (
self.install_dir / "salt-minion.exe"
).exists() and not self.relenv:
log.debug(
f"Removing {(self.install_dir / 'salt-minion.exe')}"
)
(self.install_dir / "salt-minion.exe").unlink()
elif platform.is_darwin():
self.root = pathlib.Path("/opt")
if self.file_ext == "pkg":
self.compressed = False
self.onedir = True
self.installer_pkg = True
self.bin_dir = self.root / "salt" / "bin"
self.run_root = self.bin_dir / "run"
elif self.file_ext == "tar.gz":
with tarfile.open(f_path) as tar:
# The first item will be called salt
first = next(iter(tar.getmembers()))
if first.name == "salt" and first.isdir():
self.onedir = True
self.bin_dir = self.root / "salt" / "run"
self.run_root = self.bin_dir / "run"
elif first.name == "salt" and first.isfile():
self.singlebin = True
self.run_root = self.root / "salt"
else:
log.error(
"Unexpected archive layout. First: %s (isdir: %s, isfile: %s)",
first.name,
first.isdir(),
first.isfile(),
)
else:
log.error("Unexpected file extension: %s", self.file_ext)
if re.search(
r"salt(.*)(x86_64|all|amd64|aarch64|arm64)\.(rpm|deb)$", f_path
):
self.installer_pkg = True
self.pkgs.append(f_path)
if not self.pkgs:
pytest.fail("Could not find Salt Artifacts")
python_bin = self.install_dir / "bin" / "python3"
if platform.is_windows():
python_bin = self.install_dir / "Scripts" / "python.exe"
if not self.compressed:
if platform.is_windows():
if self.relenv:
self.binary_paths = {
"call": ["salt-call.exe"],
"cp": ["salt-cp.exe"],
@ -381,11 +268,29 @@ class SaltPkgInstall:
"pip": ["salt-pip.exe"],
"python": [python_bin],
}
elif self.classic:
self.binary_paths = {
"call": [self.install_dir / "salt-call.bat"],
"cp": [self.install_dir / "salt-cp.bat"],
"minion": [self.install_dir / "salt-minion.bat"],
"python": [self.bin_dir / "python.exe"],
}
self.binary_paths["pip"] = self.binary_paths["python"] + ["-m", "pip"]
else:
if os.path.exists(self.install_dir / "bin" / "salt"):
install_dir = self.install_dir / "bin"
else:
install_dir = self.install_dir
self.binary_paths = {
"call": [str(self.run_root), "call"],
"cp": [str(self.run_root), "cp"],
"minion": [str(self.run_root), "minion"],
"pip": [str(self.run_root), "pip"],
"python": [str(self.run_root), "shell"],
}
else:
if os.path.exists(self.install_dir / "bin" / "salt"):
install_dir = self.install_dir / "bin"
else:
install_dir = self.install_dir
if self.relenv:
self.binary_paths = {
"salt": [install_dir / "salt"],
"api": [install_dir / "salt-api"],
@ -403,61 +308,56 @@ class SaltPkgInstall:
"pip": [install_dir / "salt-pip"],
"python": [python_bin],
}
else:
if self.run_root and os.path.exists(self.run_root):
if platform.is_windows():
self.binary_paths = {
"call": [str(self.run_root), "call"],
"cp": [str(self.run_root), "cp"],
"minion": [str(self.run_root), "minion"],
"pip": [str(self.run_root), "pip"],
"python": [python_bin],
}
else:
self.binary_paths = {
"salt": [str(self.run_root)],
"api": [str(self.run_root), "api"],
"call": [str(self.run_root), "call"],
"cloud": [str(self.run_root), "cloud"],
"cp": [str(self.run_root), "cp"],
"key": [str(self.run_root), "key"],
"master": [str(self.run_root), "master"],
"minion": [str(self.run_root), "minion"],
"proxy": [str(self.run_root), "proxy"],
"run": [str(self.run_root), "run"],
"ssh": [str(self.run_root), "ssh"],
"syndic": [str(self.run_root), "syndic"],
"spm": [str(self.run_root), "spm"],
"pip": [str(self.run_root), "pip"],
"python": [python_bin],
}
else:
if platform.is_windows():
self.binary_paths = {
"call": [self.install_dir / "salt-call.exe"],
"cp": [self.install_dir / "salt-cp.exe"],
"minion": [self.install_dir / "salt-minion.exe"],
"pip": [self.install_dir / "salt-pip.exe"],
"python": [python_bin],
}
self.binary_paths = {
"salt": [shutil.which("salt")],
"api": [shutil.which("salt-api")],
"call": [shutil.which("salt-call")],
"cloud": [shutil.which("salt-cloud")],
"cp": [shutil.which("salt-cp")],
"key": [shutil.which("salt-key")],
"master": [shutil.which("salt-master")],
"minion": [shutil.which("salt-minion")],
"proxy": [shutil.which("salt-proxy")],
"run": [shutil.which("salt-run")],
"ssh": [shutil.which("salt-ssh")],
"syndic": [shutil.which("salt-syndic")],
"spm": [shutil.which("spm")],
"python": [str(pathlib.Path("/usr/bin/python3"))],
}
if self.classic:
if platform.is_darwin():
# `which` is not catching the right paths on downgrades, explicitly defining them here
self.binary_paths = {
"salt": [self.bin_dir / "salt"],
"api": [self.bin_dir / "salt-api"],
"call": [self.bin_dir / "salt-call"],
"cloud": [self.bin_dir / "salt-cloud"],
"cp": [self.bin_dir / "salt-cp"],
"key": [self.bin_dir / "salt-key"],
"master": [self.bin_dir / "salt-master"],
"minion": [self.bin_dir / "salt-minion"],
"proxy": [self.bin_dir / "salt-proxy"],
"run": [self.bin_dir / "salt-run"],
"ssh": [self.bin_dir / "salt-ssh"],
"syndic": [self.bin_dir / "salt-syndic"],
"spm": [self.bin_dir / "spm"],
"python": [str(self.bin_dir / "python3")],
"pip": [str(self.bin_dir / "pip3")],
}
else:
self.binary_paths["pip"] = [str(pathlib.Path("/usr/bin/pip3"))]
self.proc.run(*self.binary_paths["pip"], "install", "-U", "pip")
self.proc.run(
*self.binary_paths["pip"], "install", "-U", "pyopenssl"
)
else:
self.binary_paths = {
"salt": [self.install_dir / "salt"],
"api": [self.install_dir / "salt-api"],
"call": [self.install_dir / "salt-call"],
"cloud": [self.install_dir / "salt-cloud"],
"cp": [self.install_dir / "salt-cp"],
"key": [self.install_dir / "salt-key"],
"master": [self.install_dir / "salt-master"],
"minion": [self.install_dir / "salt-minion"],
"proxy": [self.install_dir / "salt-proxy"],
"run": [self.install_dir / "salt-run"],
"ssh": [self.install_dir / "salt-ssh"],
"syndic": [self.install_dir / "salt-syndic"],
"spm": [self.install_dir / "spm"],
"pip": [self.install_dir / "salt-pip"],
"python": [python_bin],
}
self.binary_paths["python"] = [shutil.which("salt"), "shell"]
if platform.is_darwin():
self.binary_paths["pip"] = [self.run_root, "pip"]
self.binary_paths["spm"] = [shutil.which("salt-spm")]
else:
self.binary_paths["pip"] = [shutil.which("salt-pip")]
@staticmethod
def salt_factories_root_dir(system_service: bool = False) -> pathlib.Path:
@ -479,79 +379,10 @@ class SaltPkgInstall:
assert ret.returncode == 0
return True
@property
def salt_hashes(self):
for _hash in self.hashes.keys():
for fpath in ARTIFACTS_DIR.glob(f"**/*{_hash}*"):
fpath = str(fpath)
if re.search(f"{_hash}", fpath):
self.hashes[_hash]["file"] = fpath
return self.hashes
def _install_ssm_service(self):
# Register the services
# run_root and ssm_bin are configured in helper.py to point to the
# correct binary location
log.debug("Installing master service")
ret = self.proc.run(
str(self.ssm_bin),
"install",
"salt-master",
str(self.run_root),
"master",
"-c",
str(self.conf_dir),
)
self._check_retcode(ret)
log.debug("Installing minion service")
ret = self.proc.run(
str(self.ssm_bin),
"install",
"salt-minion",
str(self.run_root),
"minion",
"-c",
str(self.conf_dir),
)
self._check_retcode(ret)
log.debug("Installing api service")
ret = self.proc.run(
str(self.ssm_bin),
"install",
"salt-api",
str(self.run_root),
"api",
"-c",
str(self.conf_dir),
)
self._check_retcode(ret)
def _install_compressed(self, upgrade=False):
pkg = self.pkgs[0]
log.info("Installing %s", pkg)
if platform.is_windows():
if pkg.endswith("zip"):
# Extract the files
log.debug("Extracting zip file")
with ZipFile(pkg, "r") as zip:
zip.extractall(path=self.root)
elif pkg.endswith("exe") or pkg.endswith("msi"):
log.error("Not a compressed package type: %s", pkg)
else:
log.error("Unknown package type: %s", pkg)
if self.system_service:
self._install_ssm_service()
elif platform.is_darwin():
log.debug("Extracting tarball into %s", self.root)
with tarfile.open(pkg) as tar: # , "r:gz")
tar.extractall(path=str(self.root))
else:
log.debug("Extracting tarball into %s", self.root)
with tarfile.open(pkg) as tar: # , "r:gz")
tar.extractall(path=str(self.root))
def _install_pkgs(self, upgrade=False):
def _install_pkgs(self, upgrade=False, downgrade=False):
if downgrade:
self.install_previous(downgrade=downgrade)
return True
pkg = self.pkgs[0]
if platform.is_windows():
if upgrade:
@ -586,7 +417,7 @@ class SaltPkgInstall:
self.update_process_path()
elif platform.is_darwin():
daemons_dir = pathlib.Path(os.sep, "Library", "LaunchDaemons")
daemons_dir = pathlib.Path("/Library", "LaunchDaemons")
service_name = "com.saltstack.salt.minion"
plist_file = daemons_dir / f"{service_name}.plist"
log.debug("Installing: %s", str(pkg))
@ -621,18 +452,22 @@ class SaltPkgInstall:
ret = self.proc.run(self.pkg_mngr, "install", "-y", *self.pkgs)
if not platform.is_darwin() and not platform.is_windows():
# Make sure we don't have any trailing references to old package file locations
ret.returncode == 0
assert ret.returncode == 0
assert "/saltstack/salt/run" not in ret.stdout
log.info(ret)
self._check_retcode(ret)
def install(self, upgrade=False):
if self.compressed:
self._install_compressed(upgrade=upgrade)
else:
self._install_pkgs(upgrade=upgrade)
if self.distro_id in ("ubuntu", "debian"):
self.stop_services()
def package_python_version(self):
return self.proc.run(
str(self.binary_paths["python"][0]),
"-c",
"import sys; print('{}.{}'.format(*sys.version_info))",
).stdout.strip()
def install(self, upgrade=False, downgrade=False):
self._install_pkgs(upgrade=upgrade, downgrade=downgrade)
if self.distro_id in ("ubuntu", "debian"):
self.stop_services()
def stop_services(self):
"""
@ -641,29 +476,28 @@ class SaltPkgInstall:
settings we have set. This will also verify the expected
services are up and running.
"""
retval = True
for service in ["salt-syndic", "salt-master", "salt-minion"]:
check_run = self.proc.run("systemctl", "status", service)
if check_run.returncode != 0:
# The system was not started automatically and we
# are expecting it to be on install
log.debug("The service %s was not started on install.", service)
return False
stop_service = self.proc.run("systemctl", "stop", service)
self._check_retcode(stop_service)
return True
retval = False
else:
stop_service = self.proc.run("systemctl", "stop", service)
self._check_retcode(stop_service)
return retval
def install_previous(self):
def install_previous(self, downgrade=False):
"""
Install previous version. This is used for
upgrade tests.
"""
major_ver = self.major
minor_ver = self.minor
pkg_version = self.pkg_version
full_version = f"{self.major}.{self.minor}-{pkg_version}"
relenv = int(major_ver) >= 3006
min_ver = f"{major_ver}"
major_ver = packaging.version.parse(self.prev_version).major
relenv = packaging.version.parse(self.prev_version) >= packaging.version.parse(
"3006.0"
)
distro_name = self.distro_name
if distro_name == "centos" or distro_name == "fedora":
distro_name = "redhat"
@ -672,6 +506,7 @@ class SaltPkgInstall:
root_url = "py3/"
if self.distro_name in ["redhat", "centos", "amazon", "fedora", "vmware"]:
# Removing EPEL repo files
for fp in pathlib.Path("/etc", "yum.repos.d").glob("epel*"):
fp.unlink()
gpg_key = "SALTSTACK-GPG-KEY.pub"
@ -696,10 +531,23 @@ class SaltPkgInstall:
)
ret = self.proc.run(self.pkg_mngr, "clean", "expire-cache")
self._check_retcode(ret)
cmd_action = "downgrade" if downgrade else "install"
pkgs_to_install = self.salt_pkgs.copy()
if self.distro_version == "8" and self.classic:
# centosstream 8 doesn't downgrade properly using the downgrade command for some reason
# So we explicitly install the correct version here
list_ret = self.proc.run(
self.pkg_mngr, "list", "--available", "salt"
).stdout.split("\n")
list_ret = [_.strip() for _ in list_ret]
idx = list_ret.index("Available Packages")
old_ver = list_ret[idx + 1].split()[1]
pkgs_to_install = [f"{pkg}-{old_ver}" for pkg in pkgs_to_install]
cmd_action = "install"
ret = self.proc.run(
self.pkg_mngr,
"install",
*self.salt_pkgs,
cmd_action,
*pkgs_to_install,
"-y",
)
self._check_retcode(ret)
@ -710,7 +558,7 @@ class SaltPkgInstall:
ret = self.proc.run(self.pkg_mngr, "install", "apt-transport-https", "-y")
self._check_retcode(ret)
## only classic 3005 has arm64 support
if self.major >= "3006" and platform.is_aarch64():
if relenv and platform.is_aarch64():
arch = "arm64"
elif platform.is_aarch64() and self.classic:
arch = "arm64"
@ -733,29 +581,65 @@ class SaltPkgInstall:
f"deb [signed-by=/etc/apt/keyrings/{gpg_dest} arch={arch}] "
f"https://repo.saltproject.io/{root_url}{distro_name}/{self.distro_version}/{arch}/{major_ver} {self.distro_codename} main"
)
ret = self.proc.run(self.pkg_mngr, "update")
self._check_retcode(ret)
ret = self.proc.run(
cmd = [
self.pkg_mngr,
"install",
*self.salt_pkgs,
"-y",
)
self._check_retcode(ret)
]
if downgrade:
pref_file = pathlib.Path("/etc", "apt", "preferences.d", "salt.pref")
pref_file.parent.mkdir(exist_ok=True)
pref_file.write_text(
textwrap.dedent(
"""\
Package: salt*
Pin: origin "repo.saltproject.io"
Pin-Priority: 1001
"""
)
)
cmd.append("--allow-downgrades")
env = os.environ.copy()
env["DEBIAN_FRONTEND"] = "noninteractive"
extra_args = [
"-o",
"DPkg::Options::=--force-confdef",
"-o",
"DPkg::Options::=--force-confold",
]
ret = self.proc.run(self.pkg_mngr, "update", *extra_args, env=env)
cmd.extend(extra_args)
ret = self.proc.run(*cmd, env=env)
# Pre-relenv packages down get downgraded to cleanly programmatically
# They work manually, and the install tests after downgrades will catch problems with the install
# Let's not check the returncode if this is the case
if not (
downgrade
and not packaging.version.parse(self.prev_version)
>= packaging.version.parse("3006.0")
):
self._check_retcode(ret)
if downgrade:
pref_file.unlink()
self.stop_services()
elif platform.is_windows():
self.onedir = True
self.installer_pkg = True
self.bin_dir = self.install_dir / "bin"
self.run_root = self.bin_dir / f"salt.exe"
self.run_root = self.bin_dir / "salt.exe"
self.ssm_bin = self.bin_dir / "ssm.exe"
if self.file_ext == "msi" or relenv:
self.ssm_bin = self.install_dir / "ssm.exe"
if not self.classic:
if not relenv:
win_pkg = f"salt-{self.prev_version}-windows-amd64.{self.file_ext}"
win_pkg_url = f"https://repo.saltproject.io/salt/py3/windows/{self.prev_version}/{win_pkg}"
win_pkg = (
f"salt-{self.prev_version}-1-windows-amd64.{self.file_ext}"
)
else:
if self.file_ext == "msi":
win_pkg = (
@ -763,12 +647,14 @@ class SaltPkgInstall:
)
elif self.file_ext == "exe":
win_pkg = f"Salt-Minion-{self.prev_version}-Py3-AMD64-Setup.{self.file_ext}"
win_pkg_url = f"https://repo.saltproject.io/salt/py3/windows/{major_ver}/{win_pkg}"
win_pkg_url = f"https://repo.saltproject.io/salt/py3/windows/{major_ver}/{win_pkg}"
else:
if self.file_ext == "msi":
win_pkg = f"Salt-Minion-{min_ver}-1-Py3-AMD64.{self.file_ext}"
win_pkg = (
f"Salt-Minion-{self.prev_version}-Py3-AMD64.{self.file_ext}"
)
elif self.file_ext == "exe":
win_pkg = f"Salt-Minion-{min_ver}-1-Py3-AMD64-Setup.{self.file_ext}"
win_pkg = f"Salt-Minion-{self.prev_version}-Py3-AMD64-Setup.{self.file_ext}"
win_pkg_url = f"https://repo.saltproject.io/windows/{win_pkg}"
pkg_path = pathlib.Path(r"C:\TEMP", win_pkg)
pkg_path.parent.mkdir(exist_ok=True)
@ -802,11 +688,12 @@ class SaltPkgInstall:
mac_pkg_url = f"https://repo.saltproject.io/osx/{mac_pkg}"
else:
if not relenv:
mac_pkg = f"salt-{self.prev_version}-macos-x86_64.pkg"
mac_pkg_url = f"https://repo.saltproject.io/salt/py3/macos/{self.prev_version}/{mac_pkg}"
mac_pkg = f"salt-{self.prev_version}-1-macos-x86_64.pkg"
else:
mac_pkg = f"salt-{self.prev_version}-py3-x86_64.pkg"
mac_pkg_url = f"https://repo.saltproject.io/salt/py3/macos/{major_ver}/{mac_pkg}"
mac_pkg_url = (
f"https://repo.saltproject.io/salt/py3/macos/{major_ver}/{mac_pkg}"
)
mac_pkg_path = f"/tmp/{mac_pkg}"
if not os.path.exists(mac_pkg_path):
@ -818,28 +705,21 @@ class SaltPkgInstall:
ret = self.proc.run("installer", "-pkg", mac_pkg_path, "-target", "/")
self._check_retcode(ret)
def _uninstall_compressed(self):
def uninstall(self):
pkg = self.pkgs[0]
if platform.is_windows():
if self.system_service:
# Uninstall the services
log.debug("Uninstalling master service")
self.proc.run(str(self.ssm_bin), "stop", "salt-master")
self.proc.run(str(self.ssm_bin), "remove", "salt-master", "confirm")
log.debug("Uninstalling minion service")
self.proc.run(str(self.ssm_bin), "stop", "salt-minion")
self.proc.run(str(self.ssm_bin), "remove", "salt-minion", "confirm")
log.debug("Uninstalling api service")
self.proc.run(str(self.ssm_bin), "stop", "salt-api")
self.proc.run(str(self.ssm_bin), "remove", "salt-api", "confirm")
log.debug("Removing the Salt Service Manager")
if self.ssm_bin:
try:
self.ssm_bin.unlink()
except PermissionError:
atexit.register(self.ssm_bin.unlink)
if platform.is_darwin():
log.info("Uninstalling %s", pkg)
if pkg.endswith("exe"):
uninst = self.install_dir / "uninst.exe"
ret = self.proc.run(uninst, "/S")
self._check_retcode(ret)
elif pkg.endswith("msi"):
ret = self.proc.run("msiexec.exe", "/qn", "/x", pkg)
self._check_retcode(ret)
elif platform.is_darwin():
# From here: https://stackoverflow.com/a/46118276/4581998
daemons_dir = pathlib.Path(os.sep, "Library", "LaunchDaemons")
daemons_dir = pathlib.Path("/Library", "LaunchDaemons")
for service in ("minion", "master", "api", "syndic"):
service_name = f"com.saltstack.salt.{service}"
plist_file = daemons_dir / f"{service_name}.plist"
@ -883,42 +763,13 @@ class SaltPkgInstall:
# Remove receipt
self.proc.run("pkgutil", "--forget", "com.saltstack.salt")
if self.singlebin:
log.debug("Deleting the salt binary: %s", self.run_root)
if self.run_root:
try:
self.run_root.unlink()
except PermissionError:
atexit.register(self.run_root.unlink)
else:
log.debug("Deleting the onedir directory: %s", self.root / "salt")
shutil.rmtree(str(self.root / "salt"))
def _uninstall_pkgs(self):
pkg = self.pkgs[0]
if platform.is_windows():
log.info("Uninstalling %s", pkg)
if pkg.endswith("exe"):
uninst = self.install_dir / "uninst.exe"
ret = self.proc.run(uninst, "/S")
self._check_retcode(ret)
elif pkg.endswith("msi"):
ret = self.proc.run("msiexec.exe", "/qn", "/x", pkg)
self._check_retcode(ret)
elif platform.is_darwin():
self._uninstall_compressed()
else:
log.debug("Un-Installing packages:\n%s", pprint.pformat(self.salt_pkgs))
ret = self.proc.run(self.pkg_mngr, self.rm_pkg, "-y", *self.salt_pkgs)
self._check_retcode(ret)
def uninstall(self):
if self.compressed:
self._uninstall_compressed()
else:
self._uninstall_pkgs()
def assert_uninstalled(self):
"""
Assert that the paths in /opt/saltstack/ were correctly
@ -958,7 +809,7 @@ class SaltPkgInstall:
ret = self.proc.run("launchctl", "list", service_name)
# 113 means it couldn't find a service with that name
if ret.returncode == 113:
daemons_dir = pathlib.Path(os.sep, "Library", "LaunchDaemons")
daemons_dir = pathlib.Path("/Library", "LaunchDaemons")
plist_file = daemons_dir / f"{service_name}.plist"
# Make sure we're using this plist file
if plist_file.exists():
@ -1034,9 +885,7 @@ class SaltPkgInstall:
binary = shutil.which(binary[0]) or binary[0]
elif isinstance(binary, list):
binary = " ".join(binary)
unit_path = pathlib.Path(
os.sep, "etc", "systemd", "system", f"{service}.service"
)
unit_path = pathlib.Path("/etc", "systemd", "system", f"{service}.service")
contents = contents.format(
service=service, tgt=binary, conf_dir=self.conf_dir
)
@ -1077,7 +926,7 @@ class PkgLaunchdSaltDaemonImpl(PkgSystemdSaltDaemonImpl):
@plist_file.default
def _default_plist_file(self):
daemons_dir = pathlib.Path(os.sep, "Library", "LaunchDaemons")
daemons_dir = pathlib.Path("/Library", "LaunchDaemons")
return daemons_dir / f"{self.get_service_name()}.plist"
def get_service_name(self):
@ -1364,11 +1213,7 @@ class PkgMixin:
salt_pkg_install: SaltPkgInstall = attr.ib()
def get_script_path(self):
if self.salt_pkg_install.compressed or (
platform.is_darwin()
and self.salt_pkg_install.classic
and self.salt_pkg_install.upgrade
):
if platform.is_darwin() and self.salt_pkg_install.classic:
if self.salt_pkg_install.run_root and os.path.exists(
self.salt_pkg_install.run_root
):
@ -1379,23 +1224,8 @@ class PkgMixin:
return str(self.salt_pkg_install.install_dir / self.script_name)
return super().get_script_path()
def get_base_script_args(self):
base_script_args = []
if self.salt_pkg_install.run_root and os.path.exists(
self.salt_pkg_install.run_root
):
if self.salt_pkg_install.compressed:
if self.script_name == "spm":
base_script_args.append(self.script_name)
elif self.script_name != "salt":
base_script_args.append(self.script_name.split("salt-")[-1])
base_script_args.extend(super().get_base_script_args())
return base_script_args
def cmdline(self, *args, **kwargs):
_cmdline = super().cmdline(*args, **kwargs)
if self.salt_pkg_install.compressed is False:
return _cmdline
if _cmdline[0] == self.python_executable:
_cmdline.pop(0)
return _cmdline

View file

View file

@ -1,37 +1,44 @@
import packaging.version
import pytest
def test_salt_upgrade(salt_call_cli, salt_minion, install_salt):
def test_salt_upgrade(salt_call_cli, install_salt):
"""
Test upgrade of Salt
Test an upgrade of Salt.
"""
if not install_salt.upgrade:
pytest.skip("Not testing an upgrade, do not run")
# verify previous install version is setup correctly and works
ret = salt_call_cli.run("test.ping")
assert ret.returncode == 0
assert ret.data
# test pip install before an upgrade
if install_salt.relenv:
original_py_version = install_salt.package_python_version()
# Verify previous install version is setup correctly and works
ret = salt_call_cli.run("test.version")
assert ret.returncode == 0
assert packaging.version.parse(ret.data) < packaging.version.parse(
install_salt.artifact_version
)
# Test pip install before an upgrade
dep = "PyGithub==1.56.0"
install = salt_call_cli.run("--local", "pip.install", dep)
assert install.returncode == 0
# Verify we can use the module dependent on the installed package
repo = "https://github.com/saltstack/salt.git"
install = salt_call_cli.run("--local", "pip.install", dep)
assert install.returncode == 0
use_lib = salt_call_cli.run("--local", "github.get_repo_info", repo)
assert "Authentication information could" in use_lib.stderr
# upgrade Salt from previous version and test
# Upgrade Salt from previous version and test
install_salt.install(upgrade=True)
ret = salt_call_cli.run("test.ping")
ret = salt_call_cli.run("test.version")
assert ret.returncode == 0
assert ret.data
assert packaging.version.parse(ret.data) == packaging.version.parse(
install_salt.artifact_version
)
# install dep following upgrade
# TODO: Remove this once we figure out how to
# preserve things installed via PIP between upgrades.
install = salt_call_cli.run("--local", "pip.install", dep)
assert install.returncode == 0
# test pip install after an upgrade
use_lib = salt_call_cli.run("--local", "github.get_repo_info", repo)
assert "Authentication information could" in use_lib.stderr
if install_salt.relenv:
new_py_version = install_salt.package_python_version()
if new_py_version == original_py_version:
# test pip install after an upgrade
use_lib = salt_call_cli.run("--local", "github.get_repo_info", repo)

View file

@ -3,10 +3,9 @@
-r zeromq.txt
apache-libcloud>=2.4.0
backports.ssl_match_hostname>=3.7.0.1; python_version < '3.7'
cherrypy>=17.4.1
gitpython>=3.1.30
cryptography>=41.0.3
gitpython>=3.1.30
idna>=2.8
linode-python>=1.1.1
pyasn1>=0.4.8

View file

@ -2,10 +2,9 @@
--constraint=../pkg/py{py_version}/{platform}.txt
pyiface
pygit2<1.11.0; python_version < '3.8'
pygit2>=1.11.0; python_version >= '3.8'
pygit2>=1.4.0
pymysql>=1.0.2
ansible>=4.4.0,<5.0.1; python_version <= '3.8'
ansible>=4.4.0,<5.0.1; python_version < '3.9'
ansible>=7.0.0; python_version >= '3.9'
twilio
python-telegram-bot>=13.7

View file

@ -36,13 +36,13 @@ bcrypt==4.0.1
# via
# -r requirements/static/ci/common.in
# paramiko
boto3==1.26.152
boto3==1.21.46
# via
# -r requirements/static/ci/common.in
# moto
boto==2.49.0
# via -r requirements/static/ci/common.in
botocore==1.29.152
botocore==1.24.46
# via
# boto3
# moto
@ -140,7 +140,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
# gitpython
gitpython==3.1.32
gitpython==3.1.35
# via
# -c requirements/static/ci/../pkg/py3.10/darwin.txt
# -r requirements/darwin.txt
@ -445,7 +445,7 @@ rfc3987==1.3.8
# via -r requirements/static/ci/common.in
rsa==4.9
# via google-auth
s3transfer==0.6.1
s3transfer==0.5.2
# via boto3
scp==0.14.5
# via

View file

@ -33,13 +33,13 @@ bcrypt==4.0.1
# via
# -r requirements/static/ci/common.in
# paramiko
boto3==1.26.152
boto3==1.21.46
# via
# -r requirements/static/ci/common.in
# moto
boto==2.49.0
# via -r requirements/static/ci/common.in
botocore==1.29.152
botocore==1.24.46
# via
# boto3
# moto
@ -135,7 +135,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.32
gitpython==3.1.35
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -438,7 +438,7 @@ rfc3987==1.3.8
# via -r requirements/static/ci/common.in
rsa==4.9
# via google-auth
s3transfer==0.6.1
s3transfer==0.5.2
# via boto3
scp==0.14.5
# via

View file

@ -14,7 +14,7 @@ mccabe==0.6.1
# via pylint
modernize==0.5
# via saltpylint
pycodestyle==2.10.0
pycodestyle==2.5.0
# via saltpylint
pylint==2.4.4
# via

View file

@ -44,13 +44,13 @@ bcrypt==4.0.1
# via
# -r requirements/static/ci/common.in
# paramiko
boto3==1.26.152
boto3==1.21.46
# via
# -r requirements/static/ci/common.in
# moto
boto==2.49.0
# via -r requirements/static/ci/common.in
botocore==1.29.152
botocore==1.24.46
# via
# boto3
# moto
@ -151,7 +151,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.31
gitpython==3.1.35
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -325,7 +325,7 @@ portend==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.10/linux.txt
# cherrypy
psutil==5.8.0
psutil==5.9.5
# via
# -c requirements/static/ci/../pkg/py3.10/linux.txt
# -r requirements/base.txt
@ -352,15 +352,15 @@ pydantic==1.10.8
# inflect
pyeapi==1.0.0
# via napalm
pygit2==1.12.1 ; python_version >= "3.8"
pygit2==1.12.1
# via -r requirements/static/ci/linux.in
pyiface==0.0.11
# via -r requirements/static/ci/linux.in
pyinotify==0.9.6 ; sys_platform != "win32" and sys_platform != "darwin" and platform_system != "openbsd"
# via -r requirements/static/ci/common.in
pyjwt==2.7.0
pyjwt==2.4.0
# via twilio
pymysql==1.0.3
pymysql==1.0.2
# via -r requirements/static/ci/linux.in
pynacl==1.5.0
# via
@ -490,7 +490,7 @@ rpm-vercmp==0.1.2
# -r requirements/static/pkg/linux.in
rsa==4.9
# via google-auth
s3transfer==0.6.1
s3transfer==0.5.2
# via boto3
scp==0.14.5
# via

View file

@ -25,13 +25,13 @@ autocommand==2.2.2
# jaraco.text
bcrypt==4.0.1
# via -r requirements/static/ci/common.in
boto3==1.26.152
boto3==1.21.46
# via
# -r requirements/static/ci/common.in
# moto
boto==2.49.0
# via -r requirements/static/ci/common.in
botocore==1.29.152
botocore==1.24.46
# via
# boto3
# moto
@ -115,7 +115,7 @@ docker==6.1.3
# via -r requirements/pytest.txt
etcd3-py==0.1.6
# via -r requirements/static/ci/common.in
exceptiongroup==1.1.1
exceptiongroup==1.0.4
# via pytest
filelock==3.12.1
# via virtualenv
@ -133,7 +133,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# gitpython
gitpython==3.1.32
gitpython==3.1.35
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# -r requirements/static/ci/common.in
@ -160,6 +160,10 @@ inflect==6.0.4
# jaraco.text
iniconfig==2.0.0
# via pytest
ioloop==0.1a0
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# -r requirements/windows.txt
ipaddress==1.0.23
# via kubernetes
jaraco.collections==4.1.0
@ -258,7 +262,7 @@ portend==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# cherrypy
psutil==5.8.0
psutil==5.9.5
# via
# -c requirements/static/ci/../pkg/py3.10/windows.txt
# -r requirements/base.txt
@ -408,7 +412,7 @@ rfc3987==1.3.8
# via -r requirements/static/ci/common.in
rsa==4.9
# via google-auth
s3transfer==0.6.1
s3transfer==0.5.2
# via boto3
sed==0.3.1
# via -r requirements/static/ci/windows.in

View file

@ -138,7 +138,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.11/darwin.txt
# gitpython
gitpython==3.1.31
gitpython==3.1.35
# via
# -c requirements/static/ci/../pkg/py3.11/darwin.txt
# -r requirements/darwin.txt

View file

@ -133,7 +133,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.31
gitpython==3.1.35
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes

View file

@ -147,7 +147,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.31
gitpython==3.1.35
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -348,7 +348,7 @@ pydantic==1.10.8
# inflect
pyeapi==1.0.0
# via napalm
pygit2==1.12.1 ; python_version >= "3.8"
pygit2==1.12.1
# via -r requirements/static/ci/linux.in
pyiface==0.0.11
# via -r requirements/static/ci/linux.in

View file

@ -118,7 +118,7 @@ pytest-system-statistics==1.0.2
# via pytest-salt-factories
pytest-tempdir==2019.10.12
# via pytest-salt-factories
pytest==7.3.1
pytest==7.3.2
# via
# pytest-helpers-namespace
# pytest-salt-factories

View file

@ -32,7 +32,7 @@ distro==1.8.0
# via
# -r requirements/base.txt
# pytest-skip-markers
docker==6.1.2
docker==6.1.3
# via -r requirements/static/ci/pkgtests.in
filelock==3.9.0
# via virtualenv
@ -115,7 +115,7 @@ pytest-system-statistics==1.0.2
# via pytest-salt-factories
pytest-tempdir==2019.10.12
# via pytest-salt-factories
pytest==7.3.1
pytest==7.3.2
# via
# pytest-helpers-namespace
# pytest-salt-factories

View file

@ -25,13 +25,13 @@ autocommand==2.2.2
# jaraco.text
bcrypt==4.0.1
# via -r requirements/static/ci/common.in
boto3==1.26.152
boto3==1.21.46
# via
# -r requirements/static/ci/common.in
# moto
boto==2.49.0
# via -r requirements/static/ci/common.in
botocore==1.29.152
botocore==1.24.46
# via
# boto3
# moto
@ -115,7 +115,7 @@ docker==6.1.3
# via -r requirements/pytest.txt
etcd3-py==0.1.6
# via -r requirements/static/ci/common.in
filelock==3.12.1
filelock==3.12.3
# via virtualenv
flaky==3.7.0
# via -r requirements/pytest.txt
@ -131,7 +131,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# gitpython
gitpython==3.1.32
gitpython==3.1.35
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# -r requirements/static/ci/common.in
@ -158,6 +158,10 @@ inflect==6.0.4
# jaraco.text
iniconfig==2.0.0
# via pytest
ioloop==0.1a0
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# -r requirements/windows.txt
ipaddress==1.0.23
# via kubernetes
jaraco.collections==4.1.0
@ -256,7 +260,7 @@ portend==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# cherrypy
psutil==5.8.0
psutil==5.9.5
# via
# -c requirements/static/ci/../pkg/py3.11/windows.txt
# -r requirements/base.txt
@ -406,7 +410,7 @@ rfc3987==1.3.8
# via -r requirements/static/ci/common.in
rsa==4.9
# via google-auth
s3transfer==0.6.1
s3transfer==0.5.2
# via boto3
sed==0.3.1
# via -r requirements/static/ci/windows.in

View file

@ -33,13 +33,13 @@ bcrypt==4.0.1
# via
# -r requirements/static/ci/common.in
# paramiko
boto3==1.26.152
boto3==1.21.46
# via
# -r requirements/static/ci/common.in
# moto
boto==2.49.0
# via -r requirements/static/ci/common.in
botocore==1.29.152
botocore==1.24.46
# via
# boto3
# moto
@ -79,6 +79,8 @@ cherrypy==18.8.0
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt
# -r requirements/static/ci/common.in
# -r requirements/static/pkg/freebsd.in
ciscoconfparse==1.7.24
# via napalm
click==8.1.3
# via geomet
clustershell==1.9.1
@ -99,6 +101,8 @@ cryptography==41.0.3
# paramiko
# pyopenssl
# vcert
deprecat==2.1.1
# via ciscoconfparse
distlib==0.3.6
# via virtualenv
distro==1.8.0
@ -110,6 +114,7 @@ distro==1.8.0
dnspython==2.3.0
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
# python-etcd
docker==6.1.3
# via -r requirements/pytest.txt
@ -135,7 +140,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.32
gitpython==3.1.35
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -217,6 +222,8 @@ kubernetes==3.0.0
# via -r requirements/static/ci/common.in
libnacl==1.8.0 ; sys_platform != "win32" and sys_platform != "darwin"
# via -r requirements/static/ci/common.in
loguru==0.6.0
# via ciscoconfparse
looseversion==1.2.0
# via
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt
@ -258,12 +265,10 @@ multidict==6.0.4
# via
# aiohttp
# yarl
napalm==4.1.0 ; sys_platform != "win32"
napalm==3.1.0 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
ncclient==0.6.13
# via
# junos-eznc
# napalm
# via junos-eznc
netaddr==0.8.0
# via
# junos-eznc
@ -271,8 +276,6 @@ netaddr==0.8.0
# pyeapi
netmiko==4.2.0
# via napalm
netutils==1.4.1
# via napalm
ntc-templates==3.4.0
# via netmiko
oscrypto==1.3.0
@ -292,7 +295,9 @@ paramiko==3.2.0 ; sys_platform != "win32" and sys_platform != "darwin"
# netmiko
# scp
passlib==1.7.4
# via -r requirements/static/ci/common.in
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
pathspec==0.11.1
# via yamllint
platformdirs==3.5.3
@ -442,7 +447,7 @@ rfc3987==1.3.8
# via -r requirements/static/ci/common.in
rsa==4.9
# via google-auth
s3transfer==0.6.1
s3transfer==0.5.2
# via boto3
scp==0.14.5
# via
@ -495,7 +500,9 @@ timelib==0.3.0
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt
# -r requirements/static/pkg/freebsd.in
toml==0.10.2
# via -r requirements/static/ci/common.in
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
tomli==2.0.1
# via pytest
tornado==6.3.2 ; python_version >= "3.8"
@ -504,18 +511,11 @@ tornado==6.3.2 ; python_version >= "3.8"
# -r requirements/base.txt
transitions==0.9.0
# via junos-eznc
ttp-templates==0.3.5
# via napalm
ttp==0.9.4
# via
# napalm
# ttp-templates
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.2
# via
# -c requirements/static/ci/../pkg/py3.8/freebsd.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
@ -547,6 +547,8 @@ werkzeug==2.3.6
# via
# moto
# pytest-httpserver
wrapt==1.15.0
# via deprecat
xmldiff==2.6.3
# via -r requirements/static/ci/common.in
xmltodict==0.13.0

View file

@ -14,7 +14,7 @@ mccabe==0.6.1
# via pylint
modernize==0.5
# via saltpylint
pycodestyle==2.10.0
pycodestyle==2.5.0
# via saltpylint
pylint==2.4.4
# via
@ -31,4 +31,6 @@ toml==0.10.2
# -c requirements/static/ci/py3.8/linux.txt
# -r requirements/static/ci/lint.in
wrapt==1.11.2
# via astroid
# via
# -c requirements/static/ci/py3.8/linux.txt
# astroid

View file

@ -15,7 +15,7 @@ aiosignal==1.3.1
# via aiohttp
ansible-core==2.11.12
# via ansible
ansible==4.10.0 ; python_version <= "3.8"
ansible==4.10.0 ; python_version < "3.9"
# via -r requirements/static/ci/linux.in
anyio==3.7.0
# via httpcore
@ -44,13 +44,13 @@ bcrypt==4.0.1
# via
# -r requirements/static/ci/common.in
# paramiko
boto3==1.26.152
boto3==1.21.46
# via
# -r requirements/static/ci/common.in
# moto
boto==2.49.0
# via -r requirements/static/ci/common.in
botocore==1.29.152
botocore==1.24.46
# via
# boto3
# moto
@ -93,6 +93,8 @@ cherrypy==18.8.0
# -c requirements/static/ci/../pkg/py3.8/linux.txt
# -r requirements/static/ci/common.in
# -r requirements/static/pkg/linux.in
ciscoconfparse==1.7.24
# via napalm
click==8.1.3
# via geomet
clustershell==1.9.1
@ -114,6 +116,8 @@ cryptography==41.0.3
# paramiko
# pyopenssl
# vcert
deprecat==2.1.1
# via ciscoconfparse
distlib==0.3.6
# via virtualenv
distro==1.8.0
@ -124,6 +128,7 @@ distro==1.8.0
dnspython==2.3.0
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
# python-etcd
docker==6.1.3
# via -r requirements/pytest.txt
@ -151,7 +156,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.32
gitpython==3.1.35
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -242,6 +247,8 @@ kubernetes==3.0.0
# via -r requirements/static/ci/common.in
libnacl==1.8.0 ; sys_platform != "win32" and sys_platform != "darwin"
# via -r requirements/static/ci/common.in
loguru==0.6.0
# via ciscoconfparse
looseversion==1.2.0
# via
# -c requirements/static/ci/../pkg/py3.8/linux.txt
@ -283,12 +290,10 @@ multidict==6.0.4
# via
# aiohttp
# yarl
napalm==4.1.0 ; sys_platform != "win32"
napalm==3.1.0 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
ncclient==0.6.13
# via
# junos-eznc
# napalm
# via junos-eznc
netaddr==0.8.0
# via
# junos-eznc
@ -296,8 +301,6 @@ netaddr==0.8.0
# pyeapi
netmiko==4.2.0
# via napalm
netutils==1.4.1
# via napalm
ntc-templates==3.4.0
# via netmiko
oscrypto==1.3.0
@ -318,7 +321,9 @@ paramiko==3.2.0 ; sys_platform != "win32" and sys_platform != "darwin"
# netmiko
# scp
passlib==1.7.4
# via -r requirements/static/ci/common.in
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
pathspec==0.11.1
# via yamllint
platformdirs==3.5.3
@ -356,15 +361,15 @@ pydantic==1.10.8
# inflect
pyeapi==1.0.0
# via napalm
pygit2==1.12.1 ; python_version >= "3.8"
pygit2==1.12.1
# via -r requirements/static/ci/linux.in
pyiface==0.0.11
# via -r requirements/static/ci/linux.in
pyinotify==0.9.6 ; sys_platform != "win32" and sys_platform != "darwin" and platform_system != "openbsd"
# via -r requirements/static/ci/common.in
pyjwt==2.7.0
pyjwt==2.4.0
# via twilio
pymysql==1.0.3
pymysql==1.0.2
# via -r requirements/static/ci/linux.in
pynacl==1.5.0
# via
@ -494,7 +499,7 @@ rpm-vercmp==0.1.2
# -r requirements/static/pkg/linux.in
rsa==4.9
# via google-auth
s3transfer==0.6.1
s3transfer==0.5.2
# via boto3
scp==0.14.5
# via
@ -557,7 +562,9 @@ timelib==0.3.0
# -c requirements/static/ci/../pkg/py3.8/linux.txt
# -r requirements/static/pkg/linux.in
toml==0.10.2
# via -r requirements/static/ci/common.in
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
tomli==2.0.1
# via pytest
tornado==6.3.2 ; python_version >= "3.8"
@ -566,12 +573,6 @@ tornado==6.3.2 ; python_version >= "3.8"
# -r requirements/base.txt
transitions==0.9.0
# via junos-eznc
ttp-templates==0.3.5
# via napalm
ttp==0.9.4
# via
# napalm
# ttp-templates
twilio==8.2.2
# via -r requirements/static/ci/linux.in
types-pyyaml==6.0.1
@ -579,7 +580,6 @@ types-pyyaml==6.0.1
typing-extensions==4.6.2
# via
# -c requirements/static/ci/../pkg/py3.8/linux.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
@ -611,6 +611,8 @@ werkzeug==2.3.6
# via
# moto
# pytest-httpserver
wrapt==1.11.2
# via deprecat
xmldiff==2.6.3
# via -r requirements/static/ci/common.in
xmltodict==0.13.0

View file

@ -25,13 +25,13 @@ autocommand==2.2.2
# jaraco.text
bcrypt==4.0.1
# via -r requirements/static/ci/common.in
boto3==1.26.152
boto3==1.21.46
# via
# -r requirements/static/ci/common.in
# moto
boto==2.49.0
# via -r requirements/static/ci/common.in
botocore==1.29.152
botocore==1.24.46
# via
# boto3
# moto
@ -115,7 +115,7 @@ docker==6.1.3
# via -r requirements/pytest.txt
etcd3-py==0.1.6
# via -r requirements/static/ci/common.in
exceptiongroup==1.1.1
exceptiongroup==1.0.4
# via pytest
filelock==3.12.1
# via virtualenv
@ -133,7 +133,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# gitpython
gitpython==3.1.32
gitpython==3.1.35
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# -r requirements/static/ci/common.in
@ -164,6 +164,10 @@ inflect==6.0.4
# jaraco.text
iniconfig==2.0.0
# via pytest
ioloop==0.1a0
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# -r requirements/windows.txt
ipaddress==1.0.23
# via kubernetes
jaraco.collections==4.1.0
@ -262,7 +266,7 @@ portend==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# cherrypy
psutil==5.8.0
psutil==5.9.5
# via
# -c requirements/static/ci/../pkg/py3.8/windows.txt
# -r requirements/base.txt
@ -413,7 +417,7 @@ rfc3987==1.3.8
# via -r requirements/static/ci/common.in
rsa==4.9
# via google-auth
s3transfer==0.6.1
s3transfer==0.5.2
# via boto3
sed==0.3.1
# via -r requirements/static/ci/windows.in

View file

@ -36,13 +36,13 @@ bcrypt==4.0.1
# via
# -r requirements/static/ci/common.in
# paramiko
boto3==1.26.152
boto3==1.21.46
# via
# -r requirements/static/ci/common.in
# moto
boto==2.49.0
# via -r requirements/static/ci/common.in
botocore==1.29.152
botocore==1.24.46
# via
# boto3
# moto
@ -83,6 +83,8 @@ cherrypy==18.8.0
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# -r requirements/darwin.txt
# -r requirements/static/ci/common.in
ciscoconfparse==1.7.24
# via napalm
click==8.1.3
# via geomet
clustershell==1.9.1
@ -103,6 +105,8 @@ cryptography==41.0.3
# paramiko
# pyopenssl
# vcert
deprecat==2.1.1
# via ciscoconfparse
distlib==0.3.6
# via virtualenv
distro==1.8.0
@ -113,6 +117,7 @@ distro==1.8.0
dnspython==2.3.0
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
# python-etcd
docker==6.1.3
# via -r requirements/pytest.txt
@ -140,7 +145,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# gitpython
gitpython==3.1.32
gitpython==3.1.35
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# -r requirements/darwin.txt
@ -218,6 +223,8 @@ linode-python==1.1.1
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# -r requirements/darwin.txt
loguru==0.6.0
# via ciscoconfparse
looseversion==1.2.0
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
@ -259,12 +266,10 @@ multidict==6.0.4
# via
# aiohttp
# yarl
napalm==4.1.0 ; sys_platform != "win32"
napalm==3.1.0 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
ncclient==0.6.13
# via
# junos-eznc
# napalm
# via junos-eznc
netaddr==0.8.0
# via
# junos-eznc
@ -272,8 +277,6 @@ netaddr==0.8.0
# pyeapi
netmiko==4.2.0
# via napalm
netutils==1.4.1
# via napalm
ntc-templates==3.4.0
# via netmiko
oscrypto==1.3.0
@ -292,7 +295,9 @@ paramiko==3.2.0
# netmiko
# scp
passlib==1.7.4
# via -r requirements/static/ci/common.in
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
pathspec==0.11.1
# via yamllint
platformdirs==3.5.3
@ -445,7 +450,7 @@ rfc3987==1.3.8
# via -r requirements/static/ci/common.in
rsa==4.9
# via google-auth
s3transfer==0.6.1
s3transfer==0.5.2
# via boto3
scp==0.14.5
# via
@ -499,7 +504,9 @@ timelib==0.3.0
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# -r requirements/darwin.txt
toml==0.10.2
# via -r requirements/static/ci/common.in
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
tomli==2.0.1
# via pytest
tornado==6.3.2 ; python_version >= "3.8"
@ -508,18 +515,11 @@ tornado==6.3.2 ; python_version >= "3.8"
# -r requirements/base.txt
transitions==0.9.0
# via junos-eznc
ttp-templates==0.3.5
# via napalm
ttp==0.9.4
# via
# napalm
# ttp-templates
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.2
# via
# -c requirements/static/ci/../pkg/py3.9/darwin.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
@ -555,6 +555,8 @@ werkzeug==2.3.6
# via
# moto
# pytest-httpserver
wrapt==1.15.0
# via deprecat
xmldiff==2.6.3
# via -r requirements/static/ci/common.in
xmltodict==0.13.0

View file

@ -33,13 +33,13 @@ bcrypt==4.0.1
# via
# -r requirements/static/ci/common.in
# paramiko
boto3==1.26.152
boto3==1.21.46
# via
# -r requirements/static/ci/common.in
# moto
boto==2.49.0
# via -r requirements/static/ci/common.in
botocore==1.29.152
botocore==1.24.46
# via
# boto3
# moto
@ -79,6 +79,8 @@ cherrypy==18.8.0
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt
# -r requirements/static/ci/common.in
# -r requirements/static/pkg/freebsd.in
ciscoconfparse==1.7.24
# via napalm
click==8.1.3
# via geomet
clustershell==1.9.1
@ -99,6 +101,8 @@ cryptography==41.0.3
# paramiko
# pyopenssl
# vcert
deprecat==2.1.1
# via ciscoconfparse
distlib==0.3.6
# via virtualenv
distro==1.8.0
@ -110,6 +114,7 @@ distro==1.8.0
dnspython==2.3.0
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
# python-etcd
docker==6.1.3
# via -r requirements/pytest.txt
@ -135,7 +140,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.32
gitpython==3.1.35
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -213,6 +218,8 @@ kubernetes==3.0.0
# via -r requirements/static/ci/common.in
libnacl==1.8.0 ; sys_platform != "win32" and sys_platform != "darwin"
# via -r requirements/static/ci/common.in
loguru==0.6.0
# via ciscoconfparse
looseversion==1.2.0
# via
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt
@ -254,12 +261,10 @@ multidict==6.0.4
# via
# aiohttp
# yarl
napalm==4.1.0 ; sys_platform != "win32"
napalm==3.1.0 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
ncclient==0.6.13
# via
# junos-eznc
# napalm
# via junos-eznc
netaddr==0.8.0
# via
# junos-eznc
@ -267,8 +272,6 @@ netaddr==0.8.0
# pyeapi
netmiko==4.2.0
# via napalm
netutils==1.4.1
# via napalm
ntc-templates==3.4.0
# via netmiko
oscrypto==1.3.0
@ -288,7 +291,9 @@ paramiko==3.2.0 ; sys_platform != "win32" and sys_platform != "darwin"
# netmiko
# scp
passlib==1.7.4
# via -r requirements/static/ci/common.in
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
pathspec==0.11.1
# via yamllint
platformdirs==3.5.3
@ -438,7 +443,7 @@ rfc3987==1.3.8
# via -r requirements/static/ci/common.in
rsa==4.9
# via google-auth
s3transfer==0.6.1
s3transfer==0.5.2
# via boto3
scp==0.14.5
# via
@ -491,7 +496,9 @@ timelib==0.3.0
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt
# -r requirements/static/pkg/freebsd.in
toml==0.10.2
# via -r requirements/static/ci/common.in
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
tomli==2.0.1
# via pytest
tornado==6.3.2 ; python_version >= "3.8"
@ -500,18 +507,11 @@ tornado==6.3.2 ; python_version >= "3.8"
# -r requirements/base.txt
transitions==0.9.0
# via junos-eznc
ttp-templates==0.3.5
# via napalm
ttp==0.9.4
# via
# napalm
# ttp-templates
types-pyyaml==6.0.1
# via responses
typing-extensions==4.6.2
# via
# -c requirements/static/ci/../pkg/py3.9/freebsd.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
@ -543,6 +543,8 @@ werkzeug==2.3.6
# via
# moto
# pytest-httpserver
wrapt==1.15.0
# via deprecat
xmldiff==2.6.3
# via -r requirements/static/ci/common.in
xmltodict==0.13.0

View file

@ -14,7 +14,7 @@ mccabe==0.6.1
# via pylint
modernize==0.5
# via saltpylint
pycodestyle==2.10.0
pycodestyle==2.5.0
# via saltpylint
pylint==2.4.4
# via
@ -31,4 +31,6 @@ toml==0.10.2
# -c requirements/static/ci/py3.9/linux.txt
# -r requirements/static/ci/lint.in
wrapt==1.11.2
# via astroid
# via
# -c requirements/static/ci/py3.9/linux.txt
# astroid

View file

@ -44,13 +44,13 @@ bcrypt==4.0.1
# via
# -r requirements/static/ci/common.in
# paramiko
boto3==1.26.152
boto3==1.21.46
# via
# -r requirements/static/ci/common.in
# moto
boto==2.49.0
# via -r requirements/static/ci/common.in
botocore==1.29.152
botocore==1.24.46
# via
# boto3
# moto
@ -93,6 +93,8 @@ cherrypy==18.8.0
# -c requirements/static/ci/../pkg/py3.9/linux.txt
# -r requirements/static/ci/common.in
# -r requirements/static/pkg/linux.in
ciscoconfparse==1.7.24
# via napalm
click==8.1.3
# via geomet
clustershell==1.9.1
@ -114,6 +116,8 @@ cryptography==41.0.3
# paramiko
# pyopenssl
# vcert
deprecat==2.1.1
# via ciscoconfparse
distlib==0.3.6
# via virtualenv
distro==1.8.0
@ -124,6 +128,7 @@ distro==1.8.0
dnspython==2.3.0
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
# python-etcd
docker==6.1.3
# via -r requirements/pytest.txt
@ -151,7 +156,7 @@ geomet==0.2.1.post1
# via cassandra-driver
gitdb==4.0.10
# via gitpython
gitpython==3.1.32
gitpython==3.1.35
# via -r requirements/static/ci/common.in
google-auth==2.19.1
# via kubernetes
@ -240,6 +245,8 @@ kubernetes==3.0.0
# via -r requirements/static/ci/common.in
libnacl==1.8.0 ; sys_platform != "win32" and sys_platform != "darwin"
# via -r requirements/static/ci/common.in
loguru==0.6.0
# via ciscoconfparse
looseversion==1.2.0
# via
# -c requirements/static/ci/../pkg/py3.9/linux.txt
@ -281,12 +288,10 @@ multidict==6.0.4
# via
# aiohttp
# yarl
napalm==4.1.0 ; sys_platform != "win32"
napalm==3.1.0 ; sys_platform != "win32"
# via -r requirements/static/ci/common.in
ncclient==0.6.13
# via
# junos-eznc
# napalm
# via junos-eznc
netaddr==0.8.0
# via
# junos-eznc
@ -294,8 +299,6 @@ netaddr==0.8.0
# pyeapi
netmiko==4.2.0
# via napalm
netutils==1.4.1
# via napalm
ntc-templates==3.4.0
# via netmiko
oscrypto==1.3.0
@ -316,7 +319,9 @@ paramiko==3.2.0 ; sys_platform != "win32" and sys_platform != "darwin"
# netmiko
# scp
passlib==1.7.4
# via -r requirements/static/ci/common.in
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
pathspec==0.11.1
# via yamllint
platformdirs==3.5.3
@ -354,15 +359,15 @@ pydantic==1.10.8
# inflect
pyeapi==1.0.0
# via napalm
pygit2==1.12.1 ; python_version >= "3.8"
pygit2==1.12.1
# via -r requirements/static/ci/linux.in
pyiface==0.0.11
# via -r requirements/static/ci/linux.in
pyinotify==0.9.6 ; sys_platform != "win32" and sys_platform != "darwin" and platform_system != "openbsd"
# via -r requirements/static/ci/common.in
pyjwt==2.7.0
pyjwt==2.4.0
# via twilio
pymysql==1.0.3
pymysql==1.0.2
# via -r requirements/static/ci/linux.in
pynacl==1.5.0
# via
@ -492,7 +497,7 @@ rpm-vercmp==0.1.2
# -r requirements/static/pkg/linux.in
rsa==4.9
# via google-auth
s3transfer==0.6.1
s3transfer==0.5.2
# via boto3
scp==0.14.5
# via
@ -555,7 +560,9 @@ timelib==0.3.0
# -c requirements/static/ci/../pkg/py3.9/linux.txt
# -r requirements/static/pkg/linux.in
toml==0.10.2
# via -r requirements/static/ci/common.in
# via
# -r requirements/static/ci/common.in
# ciscoconfparse
tomli==2.0.1
# via pytest
tornado==6.3.2 ; python_version >= "3.8"
@ -564,12 +571,6 @@ tornado==6.3.2 ; python_version >= "3.8"
# -r requirements/base.txt
transitions==0.9.0
# via junos-eznc
ttp-templates==0.3.5
# via napalm
ttp==0.9.4
# via
# napalm
# ttp-templates
twilio==8.2.2
# via -r requirements/static/ci/linux.in
types-pyyaml==6.0.1
@ -577,7 +578,6 @@ types-pyyaml==6.0.1
typing-extensions==4.6.2
# via
# -c requirements/static/ci/../pkg/py3.9/linux.txt
# napalm
# pydantic
# pytest-shell-utilities
# pytest-system-statistics
@ -609,6 +609,8 @@ werkzeug==2.3.6
# via
# moto
# pytest-httpserver
wrapt==1.11.2
# via deprecat
xmldiff==2.6.3
# via -r requirements/static/ci/common.in
xmltodict==0.13.0

View file

@ -25,13 +25,13 @@ autocommand==2.2.2
# jaraco.text
bcrypt==4.0.1
# via -r requirements/static/ci/common.in
boto3==1.26.152
boto3==1.21.46
# via
# -r requirements/static/ci/common.in
# moto
boto==2.49.0
# via -r requirements/static/ci/common.in
botocore==1.29.152
botocore==1.24.46
# via
# boto3
# moto
@ -115,7 +115,7 @@ docker==6.1.3
# via -r requirements/pytest.txt
etcd3-py==0.1.6
# via -r requirements/static/ci/common.in
exceptiongroup==1.1.1
exceptiongroup==1.0.4
# via pytest
filelock==3.12.1
# via virtualenv
@ -133,7 +133,7 @@ gitdb==4.0.10
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# gitpython
gitpython==3.1.32
gitpython==3.1.35
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# -r requirements/static/ci/common.in
@ -160,6 +160,10 @@ inflect==6.0.4
# jaraco.text
iniconfig==2.0.0
# via pytest
ioloop==0.1a0
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# -r requirements/windows.txt
ipaddress==1.0.23
# via kubernetes
jaraco.collections==4.1.0
@ -258,7 +262,7 @@ portend==3.1.0
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# cherrypy
psutil==5.8.0
psutil==5.9.5
# via
# -c requirements/static/ci/../pkg/py3.9/windows.txt
# -r requirements/base.txt
@ -409,7 +413,7 @@ rfc3987==1.3.8
# via -r requirements/static/ci/common.in
rsa==4.9
# via google-auth
s3transfer==0.6.1
s3transfer==0.5.2
# via boto3
sed==0.3.1
# via -r requirements/static/ci/windows.in

View file

@ -2,7 +2,6 @@
# Any non hard dependencies of Salt for FreeBSD can go here
cherrypy
cryptography>=41.0.3
backports.ssl_match_hostname>=3.7.0.1; python_version < '3.7'
pyopenssl>=23.2.0
python-dateutil>=2.8.0
python-gnupg>=0.4.4

View file

@ -1,7 +1,6 @@
# This file only exists to trigger the right static compiled requirements destination.
# Any non hard dependencies of Salt for linux can go here
cherrypy
backports.ssl_match_hostname>=3.7.0.1; python_version < '3.7'
pyopenssl>=23.2.0
python-dateutil>=2.8.0
python-gnupg>=0.4.4

View file

@ -29,7 +29,7 @@ distro==1.8.0
# via -r requirements/base.txt
gitdb==4.0.10
# via gitpython
gitpython==3.1.32
gitpython==3.1.35
# via -r requirements/darwin.txt
idna==3.4
# via

View file

@ -66,7 +66,7 @@ packaging==23.1
# via -r requirements/base.txt
portend==3.1.0
# via cherrypy
psutil==5.8.0
psutil==5.9.5
# via -r requirements/base.txt
pycparser==2.21
# via cffi

View file

@ -34,7 +34,7 @@ distro==1.8.0
# via -r requirements/base.txt
gitdb==4.0.10
# via gitpython
gitpython==3.1.32
gitpython==3.1.35
# via -r requirements/windows.txt
idna==3.4
# via requests
@ -44,6 +44,8 @@ importlib-metadata==6.6.0
# via -r requirements/windows.txt
inflect==6.0.4
# via jaraco.text
ioloop==0.1a0
# via -r requirements/windows.txt
jaraco.collections==4.1.0
# via cherrypy
jaraco.context==4.3.0
@ -79,7 +81,7 @@ packaging==23.1
# via -r requirements/base.txt
portend==3.1.0
# via cherrypy
psutil==5.8.0
psutil==5.9.5
# via -r requirements/base.txt
pyasn1==0.4.8
# via -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.31
gitpython==3.1.35
# via -r requirements/darwin.txt
idna==3.4
# via

View file

@ -34,7 +34,7 @@ distro==1.8.0
# via -r requirements/base.txt
gitdb==4.0.10
# via gitpython
gitpython==3.1.32
gitpython==3.1.35
# via -r requirements/windows.txt
idna==3.4
# via requests
@ -44,6 +44,8 @@ importlib-metadata==6.6.0
# via -r requirements/windows.txt
inflect==6.0.4
# via jaraco.text
ioloop==0.1a0
# via -r requirements/windows.txt
jaraco.collections==4.1.0
# via cherrypy
jaraco.context==4.3.0
@ -79,7 +81,7 @@ packaging==23.1
# via -r requirements/base.txt
portend==3.1.0
# via cherrypy
psutil==5.8.0
psutil==5.9.5
# via -r requirements/base.txt
pyasn1==0.4.8
# via -r requirements/windows.txt

View file

@ -34,7 +34,7 @@ distro==1.8.0
# via -r requirements/base.txt
gitdb==4.0.10
# via gitpython
gitpython==3.1.32
gitpython==3.1.35
# via -r requirements/windows.txt
idna==3.4
# via requests
@ -46,6 +46,8 @@ importlib-resources==5.12.0
# via jaraco.text
inflect==6.0.4
# via jaraco.text
ioloop==0.1a0
# via -r requirements/windows.txt
jaraco.collections==4.1.0
# via cherrypy
jaraco.context==4.3.0
@ -81,7 +83,7 @@ packaging==23.1
# via -r requirements/base.txt
portend==3.1.0
# via cherrypy
psutil==5.8.0
psutil==5.9.5
# via -r requirements/base.txt
pyasn1==0.4.8
# via -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.32
gitpython==3.1.35
# via -r requirements/darwin.txt
idna==3.4
# via

View file

@ -34,7 +34,7 @@ distro==1.8.0
# via -r requirements/base.txt
gitdb==4.0.10
# via gitpython
gitpython==3.1.32
gitpython==3.1.35
# via -r requirements/windows.txt
idna==3.4
# via requests
@ -44,6 +44,8 @@ importlib-metadata==6.6.0
# via -r requirements/windows.txt
inflect==6.0.4
# via jaraco.text
ioloop==0.1a0
# via -r requirements/windows.txt
jaraco.collections==4.1.0
# via cherrypy
jaraco.context==4.3.0
@ -79,7 +81,7 @@ packaging==23.1
# via -r requirements/base.txt
portend==3.1.0
# via cherrypy
psutil==5.8.0
psutil==5.9.5
# via -r requirements/base.txt
pyasn1==0.4.8
# via -r requirements/windows.txt

View file

@ -6,12 +6,13 @@ pywin32>=305
wmi>=1.5.1
pythonnet>=3.0.1
backports.ssl-match-hostname>=3.7.0.1; python_version < '3.7'
certifi>=2022.12.07
cffi>=1.14.5
cherrypy>=18.6.1
gitpython>=3.1.30
cryptography>=41.0.3
gitpython>=3.1.30
ioloop>=0.1a0
lxml>=4.6.3
pyasn1>=0.4.8
pymssql>=2.2.1

View file

@ -255,8 +255,8 @@ def create_certificate(
Instead of returning the certificate, write it to this file path.
overwrite
If ``path`` is specified and the file exists, do not overwrite it.
Defaults to false.
If ``path`` is specified and the file exists, overwrite it.
Defaults to true.
raw
Return the encoded raw bytes instead of a string. Defaults to false.
@ -614,7 +614,7 @@ def _create_certificate_local(
path=os.path.join(copypath, f"{prepend}{cert.serial_number:x}.crt"),
pem_type="CERTIFICATE",
)
return builder.sign(signing_private_key, algorithm=algorithm), private_key_loaded
return cert, private_key_loaded
def encode_certificate(
@ -1196,7 +1196,7 @@ def create_private_key(
keysize
For ``rsa``, specifies the bitlength of the private key (2048, 3072, 4096).
For ``ec``, specifies the NIST curve to use (256, 384, 521).
Irrelevant for Edwards-curve schemes (`ed25519``, ``ed448``).
Irrelevant for Edwards-curve schemes (``ed25519``, ``ed448``).
Defaults to 2048 for RSA and 256 for EC.
passphrase
@ -1246,6 +1246,7 @@ def create_private_key(
raise CommandExecutionError(
f"Invalid value '{encoding}' for encoding. Valid: der, pem, pkcs12"
)
out = encode_private_key(
_generate_pk(algo=algo, keysize=keysize),
encoding=encoding,
@ -1258,7 +1259,9 @@ def create_private_key(
return out
if encoding == "pem":
return write_pem(out.decode(), path, pem_type="(?:RSA )?PRIVATE KEY")
return write_pem(
out.decode(), path, pem_type="(?:(RSA|ENCRYPTED) )?PRIVATE KEY"
)
with salt.utils.files.fopen(path, "wb") as fp_:
fp_.write(out)
return
@ -1268,6 +1271,7 @@ def encode_private_key(
private_key,
encoding="pem",
passphrase=None,
private_key_passphrase=None,
pkcs12_encryption_compat=False,
raw=False,
):
@ -1280,7 +1284,7 @@ def encode_private_key(
salt '*' x509.encode_private_key /etc/pki/my.key der
csr
private_key
The private key to encode.
encoding
@ -1288,6 +1292,23 @@ def encode_private_key(
as a ``pem`` string, base64-encoded ``der`` and base64-encoded ``pkcs12``.
Defaults to ``pem``.
passphrase
If this is specified, the private key will be encrypted using this
passphrase. The encryption algorithm cannot be selected, it will be
determined automatically as the best available one.
private_key_passphrase
.. versionadded:: 3006.2
If the current ``private_key`` is encrypted, the passphrase to
decrypt it.
pkcs12_encryption_compat
Some operating systems are incompatible with the encryption defaults
for PKCS12 used since OpenSSL v3. This switch triggers a fallback to
``PBESv1SHA1And3KeyTripleDESCBC``.
Please consider the `notes on PKCS12 encryption <https://cryptography.io/en/stable/hazmat/primitives/asymmetric/serialization/#cryptography.hazmat.primitives.serialization.pkcs12.serialize_key_and_certificates>`_.
raw
Return the encoded raw bytes instead of a string. Defaults to false.
"""
@ -1295,6 +1316,7 @@ def encode_private_key(
raise CommandExecutionError(
f"Invalid value '{encoding}' for encoding. Valid: der, pem, pkcs12"
)
private_key = x509util.load_privkey(private_key, passphrase=private_key_passphrase)
if passphrase is None:
cipher = serialization.NoEncryption()
else:
@ -1553,7 +1575,7 @@ def get_public_key(key, passphrase=None, asObj=None):
except SaltInvocationError:
pass
raise CommandExecutionError(
"Could not load key as certificate, public key, private key, CSR or CRL"
"Could not load key as certificate, public key, private key or CSR"
)
@ -1940,7 +1962,7 @@ def verify_private_key(private_key, public_key, passphrase=None):
passphrase
If ``private_key`` is encrypted, the passphrase to decrypt it.
"""
privkey = x509util.load_privkey(private_key, passphrase=None)
privkey = x509util.load_privkey(private_key, passphrase=passphrase)
pubkey = x509util.load_pubkey(get_public_key(public_key))
return x509util.is_pair(pubkey, privkey)

View file

@ -747,6 +747,8 @@ def list_pkgs(versions_as_list=False, **kwargs):
cmd = [
"rpm",
"-qa",
"--nodigest",
"--nosignature",
"--queryformat",
salt.utils.pkg.rpm.QUERYFORMAT.replace("%{REPOID}", "(none)") + "\n",
]

View file

@ -1416,7 +1416,7 @@ class Minions(LowDataAdapter):
POST /minions HTTP/1.1
Host: localhost:8000
Accept: application/x-yaml
Content-Type: application/json
Content-Type: application/x-www-form-urlencoded
tgt=*&fun=status.diskusage

View file

@ -2859,7 +2859,8 @@ def latest(
x
for x in targets
if not changes.get(x)
or targets[x] not in changes[x].get("new").split(",")
or changes[x].get("new") is not None
and targets[x] not in changes[x].get("new").split(",")
and targets[x] != "latest"
]
successful = [x for x in targets if x not in failed]

View file

@ -82,7 +82,7 @@ the certificate to the mine, where it can be easily retrieved by other minions.
- keysize: 4096
- backup: true
- require:
- file: /etc/pki
- file: /etc/pki/issued_certs
Create self-signed CA certificate:
x509.certificate_managed:
@ -1274,7 +1274,7 @@ def private_key_managed(
keysize
For ``rsa``, specifies the bitlength of the private key (2048, 3072, 4096).
For ``ec``, specifies the NIST curve to use (256, 384, 521).
Irrelevant for Edwards-curve schemes (`ed25519``, ``ed448``).
Irrelevant for Edwards-curve schemes (``ed25519``, ``ed448``).
Defaults to 2048 for RSA and 256 for EC.
passphrase
@ -1450,7 +1450,7 @@ def private_key_managed(
and algo in ("rsa", "ec")
and current.key_size != check_keysize
):
changes["keysize"] = keysize
changes["keysize"] = check_keysize
if encoding != current_encoding:
changes["encoding"] = encoding
elif file_exists and new:

View file

@ -566,7 +566,7 @@ class GitProvider:
return ret
def _get_lock_file(self, lock_type="update"):
return salt.utils.path.join(self.gitdir, lock_type + ".lk")
return salt.utils.path.join(self._salt_working_dir, lock_type + ".lk")
@classmethod
def add_conf_overlay(cls, name):
@ -858,7 +858,6 @@ class GitProvider:
self.id,
desired_ssl_verify,
)
self._ssl_verfiy = self.opts.get(f"{self.role}_ssl_verify", None)
conf_changed = True
# Write changes, if necessary

View file

@ -1424,13 +1424,20 @@ def test_create_private_key_pkcs12(x509, passphrase):
@pytest.mark.parametrize("encoding", ["pem", "der"])
def test_create_private_key_write_to_path(x509, encoding, tmp_path):
tgt = tmp_path / "csr"
tgt = tmp_path / "pk"
x509.create_private_key(encoding=encoding, path=str(tgt))
assert tgt.exists()
if encoding == "pem":
assert tgt.read_text().startswith("-----BEGIN PRIVATE KEY-----")
def test_create_private_key_write_to_path_encrypted(x509, tmp_path):
tgt = tmp_path / "pk"
x509.create_private_key(path=str(tgt), passphrase="hunter1")
assert tgt.exists()
assert tgt.read_text().startswith("-----BEGIN ENCRYPTED PRIVATE KEY-----")
@pytest.mark.parametrize("encoding", ["pem", "der"])
def test_create_private_key_write_to_path_overwrite(x509, encoding, tmp_path):
tgt = tmp_path / "cert"
@ -1589,8 +1596,32 @@ def test_verify_crl(x509, crl, ca_cert):
assert x509.verify_crl(crl, ca_cert) is True
def test_verify_private_key(x509, ca_key, ca_cert):
assert x509.verify_private_key(ca_key, ca_cert) is True
def test_encode_private_key(x509, rsa_privkey):
pk = x509.create_private_key()
res = x509.encode_private_key(pk)
assert res.strip() == pk.strip()
def test_encode_private_key_encrypted(x509, ca_key, ca_key_enc):
pk = x509.create_private_key()
pk_enc = x509.encode_private_key(pk, passphrase="hunter1")
res = x509.encode_private_key(pk_enc, private_key_passphrase="hunter1")
assert res.strip() == pk.strip()
@pytest.mark.parametrize("privkey,expected", [("ca_key", True), ("rsa_privkey", False)])
def test_verify_private_key(x509, request, privkey, expected, ca_cert):
pk = request.getfixturevalue(privkey)
assert x509.verify_private_key(pk, ca_cert) is expected
def test_verify_private_key_with_passphrase(x509, ca_key_enc, ca_cert):
assert (
x509.verify_private_key(
ca_key_enc, ca_cert, passphrase="correct horse battery staple"
)
is True
)
@pytest.mark.parametrize("algo", ["rsa", "ec", "ed25519", "ed448"])

View file

@ -0,0 +1,41 @@
import pytest
import salt.modules.cmdmod
import salt.modules.pkg_resource
import salt.modules.yumpkg
import salt.utils.pkg.rpm
@pytest.fixture
def configure_loader_modules(minion_opts):
return {
salt.modules.yumpkg: {
"__salt__": {
"cmd.run": salt.modules.cmdmod.run,
"pkg_resource.add_pkg": salt.modules.pkg_resource.add_pkg,
"pkg_resource.format_pkg_list": salt.modules.pkg_resource.format_pkg_list,
},
"__grains__": {"osarch": salt.utils.pkg.rpm.get_osarch()},
},
}
@pytest.mark.slow_test
def test_yum_list_pkgs(grains):
"""
compare the output of rpm -qa vs the return of yumpkg.list_pkgs,
make sure that any changes to ympkg.list_pkgs still returns.
"""
if grains["os_family"] != "RedHat":
pytest.skip("Skip if not RedHat")
cmd = [
"rpm",
"-qa",
"--queryformat",
"%{NAME}\n",
]
known_pkgs = salt.modules.cmdmod.run(cmd, python_shell=False)
listed_pkgs = salt.modules.yumpkg.list_pkgs()
for line in known_pkgs.splitlines():
assert any(line in d for d in listed_pkgs)

View file

@ -2170,6 +2170,21 @@ def test_private_key_managed_existing(x509, pk_args):
_assert_not_changed(ret)
@pytest.mark.usefixtures("existing_pk")
@pytest.mark.parametrize(
"existing_pk",
[
{"algo": "rsa", "keysize": 3072},
],
indirect=True,
)
def test_private_key_managed_existing_keysize_change_to_default(x509, pk_args):
pk_args.pop("keysize")
ret = x509.private_key_managed(**pk_args)
assert ret.changes
assert ret.changes["keysize"] == 2048
@pytest.mark.usefixtures("existing_pk")
def test_private_key_managed_existing_new(x509, pk_args):
cur = _get_privkey(pk_args["name"])

View file

@ -238,3 +238,38 @@ def test_gitpython_remote_map(gitpython_gitfs_opts):
@skipif_no_pygit2
def test_pygit2_remote_map(pygit2_gitfs_opts):
_test_remote_map(pygit2_gitfs_opts)
def _test_lock(opts):
g = _get_gitfs(
opts,
"https://github.com/saltstack/salt-test-pillar-gitfs.git",
)
g.fetch_remotes()
assert len(g.remotes) == 1
repo = g.remotes[0]
assert repo.get_salt_working_dir() in repo._get_lock_file()
assert repo.lock() == (
[
"Set update lock for gitfs remote 'https://github.com/saltstack/salt-test-pillar-gitfs.git'"
],
[],
)
assert os.path.isfile(repo._get_lock_file())
assert repo.clear_lock() == (
[
"Removed update lock for gitfs remote 'https://github.com/saltstack/salt-test-pillar-gitfs.git'"
],
[],
)
assert not os.path.isfile(repo._get_lock_file())
@skipif_no_gitpython
def test_gitpython_lock(gitpython_gitfs_opts):
_test_lock(gitpython_gitfs_opts)
@skipif_no_pygit2
def test_pygit2_lock(pygit2_gitfs_opts):
_test_lock(pygit2_gitfs_opts)

View file

@ -328,3 +328,38 @@ def test_gitpython_remote_map(gitpython_pillar_opts):
@skipif_no_pygit2
def test_pygit2_remote_map(pygit2_pillar_opts):
_test_remote_map(pygit2_pillar_opts)
def _test_lock(opts):
p = _get_pillar(
opts,
"https://github.com/saltstack/salt-test-pillar-gitfs.git",
)
p.fetch_remotes()
assert len(p.remotes) == 1
repo = p.remotes[0]
assert repo.get_salt_working_dir() in repo._get_lock_file()
assert repo.lock() == (
[
"Set update lock for git_pillar remote 'https://github.com/saltstack/salt-test-pillar-gitfs.git'"
],
[],
)
assert os.path.isfile(repo._get_lock_file())
assert repo.clear_lock() == (
[
"Removed update lock for git_pillar remote 'https://github.com/saltstack/salt-test-pillar-gitfs.git'"
],
[],
)
assert not os.path.isfile(repo._get_lock_file())
@skipif_no_gitpython
def test_gitpython_lock(gitpython_pillar_opts):
_test_lock(gitpython_pillar_opts)
@skipif_no_pygit2
def test_pygit2_lock(pygit2_pillar_opts):
_test_lock(pygit2_pillar_opts)

View file

@ -127,3 +127,38 @@ def test_gitpython_remote_map(gitpython_winrepo_opts):
@skipif_no_pygit2
def test_pygit2_remote_map(pygit2_winrepo_opts):
_test_remote_map(pygit2_winrepo_opts)
def _test_lock(opts):
w = _get_winrepo(
opts,
"https://github.com/saltstack/salt-test-pillar-gitfs.git",
)
w.fetch_remotes()
assert len(w.remotes) == 1
repo = w.remotes[0]
assert repo.get_salt_working_dir() in repo._get_lock_file()
assert repo.lock() == (
[
"Set update lock for winrepo remote 'https://github.com/saltstack/salt-test-pillar-gitfs.git'"
],
[],
)
assert os.path.isfile(repo._get_lock_file())
assert repo.clear_lock() == (
[
"Removed update lock for winrepo remote 'https://github.com/saltstack/salt-test-pillar-gitfs.git'"
],
[],
)
assert not os.path.isfile(repo._get_lock_file())
@skipif_no_gitpython
def test_gitpython_lock(gitpython_winrepo_opts):
_test_lock(gitpython_winrepo_opts)
@skipif_no_pygit2
def test_pygit2_lock(pygit2_winrepo_opts):
_test_lock(pygit2_winrepo_opts)

View file

@ -123,9 +123,10 @@ def test_list_pkgs():
"openssh_|-(none)_|-6.6.1p1_|-33.el7_3_|-x86_64_|-(none)_|-1487838485",
"virt-what_|-(none)_|-1.13_|-8.el7_|-x86_64_|-(none)_|-1487838486",
]
cmd_mod = MagicMock(return_value=os.linesep.join(rpm_out))
with patch.dict(yumpkg.__grains__, {"osarch": "x86_64"}), patch.dict(
yumpkg.__salt__,
{"cmd.run": MagicMock(return_value=os.linesep.join(rpm_out))},
{"cmd.run": cmd_mod},
), patch.dict(yumpkg.__salt__, {"pkg_resource.add_pkg": _add_data}), patch.dict(
yumpkg.__salt__,
{"pkg_resource.format_pkg_list": pkg_resource.format_pkg_list},
@ -152,6 +153,18 @@ def test_list_pkgs():
}.items():
assert pkgs.get(pkg_name) is not None
assert pkgs[pkg_name] == [pkg_version]
cmd_mod.assert_called_once_with(
[
"rpm",
"-qa",
"--nodigest",
"--nosignature",
"--queryformat",
"%{NAME}_|-%{EPOCH}_|-%{VERSION}_|-%{RELEASE}_|-%{ARCH}_|-(none)_|-%{INSTALLTIME}\n",
],
output_loglevel="trace",
python_shell=False,
)
def test_list_pkgs_no_context():

View file

@ -1270,3 +1270,24 @@ def test_latest_multiple_versions():
with patch.dict(pkg.__salt__, salt_dict):
ret = pkg.latest(pkg_name)
assert ret.get("result", False) is True
def test_latest_no_change_windows():
"""
Test pkg.latest with no change to the package version for winrepo packages
See: https://github.com/saltstack/salt/issues/65165
"""
pkg_name = "fake_pkg"
version = "1.2.2"
latest_version_mock = MagicMock(return_value={pkg_name: version})
current_version_mock = MagicMock(return_value={pkg_name: version})
install_mock = MagicMock(return_value={pkg_name: {"install status": "success"}})
salt_dict = {
"pkg.latest_version": latest_version_mock,
"pkg.version": current_version_mock,
"pkg.install": install_mock,
}
with patch.dict(pkg.__salt__, salt_dict):
ret = pkg.latest(pkg_name)
assert ret.get("result", False) is True

View file

@ -716,6 +716,7 @@ def pkg_matrix(
# we allow for 3006.0 jobs to run, because then
# we will have arm64 onedir packages to upgrade from
sessions.append("upgrade")
sessions.append("downgrade")
# TODO: Remove this block when we reach version 3009.0, we will no longer be testing upgrades from classic packages
if (
distro_slug
@ -730,12 +731,13 @@ def pkg_matrix(
):
# Packages for these OSs where never built for classic previously
sessions.append("upgrade-classic")
sessions.append("downgrade-classic")
for session in sessions:
versions: list[str | None] = [None]
if session == "upgrade":
if session in ("upgrade", "downgrade"):
versions = [str(version) for version in testing_releases]
elif session == "upgrade-classic":
elif session in ("upgrade-classic", "downgrade-classic"):
versions = [
str(version)
for version in testing_releases
@ -974,7 +976,7 @@ def get_testing_releases(
ctx.exit(1, "The 'GITHUB_OUTPUT' variable is not set.")
else:
# We aren't testing upgrades from anything before 3006.0 except the latest 3005.x
threshold_major = 3006
threshold_major = 3005
parsed_salt_version = tools.utils.Version(salt_version)
# We want the latest 4 major versions, removing the oldest if this version is a new major
num_major_versions = 4
@ -997,16 +999,6 @@ def get_testing_releases(
]
testing_releases.append(minors_of_major[-1])
# TODO: Remove this block when we reach version 3009.0
# Append the latest minor version of 3005 if we don't have enough major versions to test against
if len(testing_releases) != num_major_versions:
url = "https://repo.saltproject.io/salt/onedir/repo.json"
ret = ctx.web.get(url)
repo_data = ret.json()
latest = list(repo_data["latest"].keys())[0]
version = repo_data["latest"][latest]["version"]
testing_releases = [version] + testing_releases
str_releases = [str(version) for version in testing_releases]
with open(github_output, "a", encoding="utf-8") as wfh:

View file

@ -125,7 +125,19 @@ def setup_testsuite(
)
if run_id is None:
ctx.error("Unable to find the appropriate workflow run ID")
run_id = tools.utils.gh.discover_run_id(
ctx,
branch=branch,
nightly=nightly,
pr=pr,
completed_status=False,
)
if run_id is None:
ctx.error("Unable to find the appropriate workflow run ID")
else:
ctx.warn(
f"Looks like we found run_id {run_id} but it's not yet in the completed state"
)
ctx.exit(1)
exitcode = tools.utils.gh.download_onedir_artifact(

View file

@ -217,6 +217,7 @@ def download_file(
auth: str | None = None,
headers: dict[str, str] | None = None,
) -> pathlib.Path:
ctx.info(f"Downloading {dest.name!r} @ {url} ...")
curl = shutil.which("curl")
if curl is not None:
command = [curl, "-sS", "-L"]
@ -243,7 +244,6 @@ def download_file(
ctx.exit(1)
return dest
# NOTE the stream=True parameter below
ctx.info(f"Downloading {url} ...")
with ctx.web as web:
web.headers.update(headers)
with web.get(url, stream=True, auth=auth) as r:

View file

@ -63,6 +63,9 @@ def download_onedir_artifact(
artifact_name += ".zip"
else:
artifact_name += ".tar.xz"
ctx.info(
f"Searching for artifact {artifact_name} from run_id {run_id} in repository {repository} ..."
)
found_artifact_name = download_artifact(
ctx,
dest=artifacts_path,
@ -73,15 +76,24 @@ def download_onedir_artifact(
if found_artifact_name is None:
return ExitCode.FAIL
found_artifact_path = artifacts_path / found_artifact_name
checksum_algo = "sha512"
ctx.info(f"Validating {found_artifact_name!r} {checksum_algo} checksum ...")
artifact_expected_checksum = (
artifacts_path.joinpath(f"{found_artifact_name}.SHA512").read_text().strip()
artifacts_path.joinpath(f"{found_artifact_name}.{checksum_algo.upper()}")
.read_text()
.strip()
)
artifact_checksum = tools.utils.get_file_checksum(
found_artifact_path, checksum_algo
)
artifact_checksum = tools.utils.get_file_checksum(found_artifact_path, "sha512")
if artifact_expected_checksum != artifact_checksum:
ctx.error("The 'sha512' checksum does not match")
ctx.error(f"The {checksum_algo} checksum does not match")
ctx.error(f"{artifact_checksum!r} != {artifact_expected_checksum!r}")
return ExitCode.FAIL
ctx.info(
f"Decompressing {found_artifact_name!r} to {artifacts_path.relative_to(tools.utils.REPO_ROOT)}{os.path.sep} ..."
)
if found_artifact_path.suffix == ".zip":
with zipfile.ZipFile(found_artifact_path) as zfile:
zfile.extractall(path=artifacts_path)
@ -112,6 +124,9 @@ def download_nox_artifact(
)
return ExitCode.SOFT_FAIL
artifact_name = f"nox-{slug}-{nox_env}"
ctx.info(
f"Searching for artifact {artifact_name} from run_id {run_id} in repository {repository} ..."
)
found_artifact_name = download_artifact(
ctx,
dest=tools.utils.REPO_ROOT,
@ -181,6 +196,9 @@ def download_pkgs_artifact(
artifacts_path = tools.utils.REPO_ROOT / "pkg" / "artifacts"
artifacts_path.mkdir(exist_ok=True)
ctx.info(
f"Searching for artifact {artifact_name} from run_id {run_id} in repository {repository} ..."
)
found_artifact_name = download_artifact(
ctx,
dest=artifacts_path,
@ -229,16 +247,18 @@ def download_artifact(
headers = {
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {github_token}",
"X-GitHub-Api-Version": "2022-11-28",
}
web.headers.update(headers)
page = 0
listed_artifacts: set[str] = set()
while True:
if found_artifact is not None:
break
page += 1
params = {
"per_page": 100,
"page": 1,
"page": page,
}
ret = web.get(
f"https://api.github.com/repos/{repository}/actions/runs/{run_id}/artifacts",
@ -250,21 +270,30 @@ def download_artifact(
)
ctx.exit(1)
data = ret.json()
if data["total_count"] <= len(listed_artifacts):
ctx.info("Already gone through all of the listed artifacts:")
ctx.print(sorted(listed_artifacts))
break
ctx.debug(f"Processing artifacts listing (page: {page}) ...")
if not data["artifacts"]:
break
for artifact in data["artifacts"]:
listed_artifacts.add(artifact["name"])
ctx.debug(
f"Checking if {artifact['name']!r} matches {artifact_name!r} "
f"({len(listed_artifacts)}/{data['total_count']}) ..."
)
if fnmatch.fnmatch(artifact["name"], artifact_name):
found_artifact = artifact["name"]
tempdir_path = pathlib.Path(tempfile.gettempdir())
download_url = artifact["archive_download_url"]
ctx.info(f"Downloading {download_url}")
downloaded_artifact = tools.utils.download_file(
ctx,
download_url,
tempdir_path / f"{artifact['name']}.zip",
headers=headers,
)
ctx.info("Downloaded", downloaded_artifact)
ctx.info(f"Downloaded {downloaded_artifact}")
with zipfile.ZipFile(downloaded_artifact) as zfile:
zfile.extractall(path=dest)
break
@ -279,22 +308,25 @@ def discover_run_id(
nightly: str = None,
pr: int = None,
repository: str = "saltstack/salt",
completed_status: bool = True,
) -> int | None:
ctx.info(f"Discovering the run_id({branch=}, {nightly=}, {pr=}, {repository=})")
run_id: int | None = None
with ctx.web as web:
headers = {
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
}
github_token = get_github_token(ctx)
if github_token is not None:
headers["Authorization"] = f"Bearer {github_token}"
web.headers.update(headers)
params = {
params: dict[str, str | int] = {
"per_page": 100,
"status": "completed",
}
if completed_status is True:
params["status"] = "completed"
if branch is not None:
ret = web.get(
f"https://api.github.com/repos/{repository}/git/ref/heads/{branch}"

View file

@ -592,9 +592,19 @@ def sync_cache(
cached_instances = {}
if STATE_DIR.exists():
for state_path in STATE_DIR.iterdir():
instance_id_path = state_path / "instance-id"
if instance_id_path.exists():
instance_id = instance_id_path.read_text()
try:
instance_id = (state_path / "instance-id").read_text()
except FileNotFoundError:
if not delete:
log.info(
f"Would remove {state_path.name} (No valid ID) from cache at {state_path}"
)
else:
shutil.rmtree(state_path)
log.info(
f"REMOVED {state_path.name} (No valid ID) from cache at {state_path}"
)
else:
cached_instances[instance_id] = state_path.name
# Find what instances we are missing in our cached states
@ -1194,7 +1204,7 @@ class VM:
timeout = self.config.terminate_timeout
timeout_progress = 0.0
progress = create_progress_bar()
task = progress.add_task(f"Terminatting {self!r}...", total=timeout)
task = progress.add_task(f"Terminating {self!r}...", total=timeout)
self.instance.terminate()
try:
with progress: