Merge 3006.x into master

Conflicts:
* changelog/64226.fixed.md
* tests/pytests/unit/states/test_pip.py
This commit is contained in:
Pedro Algarvio 2023-05-30 12:59:16 +01:00
commit c10eb79954
No known key found for this signature in database
GPG key ID: BB36BF6584A298FF
19 changed files with 590 additions and 411 deletions

View file

@ -27,6 +27,10 @@ jobs:
matrix:
arch:
- x86_64
source:
- onedir
- src
runs-on:
- macos-12
steps:
@ -100,15 +104,31 @@ jobs:
APPLE_ACCT: "${{ secrets.MAC_SIGN_APPLE_ACCT }}"
APP_SPEC_PWD: "${{ secrets.MAC_SIGN_APP_SPEC_PWD }}"
run: |
tools pkg build macos --onedir salt-${{ inputs.salt-version }}-onedir-darwin-${{ matrix.arch }}.tar.xz \
--salt-version ${{ inputs.salt-version }} ${{
steps.check-pkg-sign.outputs.sign-pkgs == 'true' && '--sign' || ''
}}
tools pkg build macos ${{
matrix.source == 'onedir' &&
format(
'--onedir salt-{0}-onedir-darwin-{1}.tar.xz --salt-version {0} {2}',
inputs.salt-version,
matrix.arch,
steps.check-pkg-sign.outputs.sign-pkgs == 'true' && '--sign' || ''
)
||
format('--salt-version {0}', inputs.salt-version)
}}
- name: Set Artifact Name
id: set-artifact-name
run: |
if [ "${{ matrix.source }}" != "src" ]; then
echo "artifact-name=salt-${{ inputs.salt-version }}-${{ matrix.arch }}-macos" >> "$GITHUB_OUTPUT"
else
echo "artifact-name=salt-${{ inputs.salt-version }}-${{ matrix.arch }}-macos-from-src" >> "$GITHUB_OUTPUT"
fi
- name: Upload ${{ matrix.arch }} Package
uses: actions/upload-artifact@v3
with:
name: salt-${{ inputs.salt-version }}-${{ matrix.arch }}-macos
name: ${{ steps.set-artifact-name.outputs.artifact-name }}
path: pkg/macos/salt-${{ inputs.salt-version }}-py3-*.pkg
retention-days: 7
if-no-files-found: error

View file

@ -29,6 +29,10 @@ jobs:
arch:
- x86
- amd64
source:
- onedir
- src
runs-on:
- windows-latest
env:
@ -95,15 +99,34 @@ jobs:
- name: Build Windows Packages
run: |
tools pkg build windows --onedir salt-${{ inputs.salt-version }}-onedir-windows-${{ matrix.arch }}.zip `
--salt-version ${{ inputs.salt-version }} --arch ${{ matrix.arch }} ${{
tools pkg build windows ${{
matrix.source == 'onedir' &&
format(
'--onedir salt-{0}-onedir-windows-{1}.zip --salt-version {0} --arch {1} {2}',
inputs.salt-version,
matrix.arch,
steps.check-pkg-sign.outputs.sign-pkgs == 'true' && '--sign' || ''
}}
)
||
format('--salt-version {0} --arch {1}', inputs.salt-version, matrix.arch)
}}
- name: Upload ${{ matrix.arch }} Packages
- name: Set Artifact Name
id: set-artifact-name
shell: bash
run: |
if [ "${{ matrix.source }}" != "src" ]; then
echo "artifact-name-nsis=salt-${{ inputs.salt-version }}-${{ matrix.arch }}-NSIS" >> "$GITHUB_OUTPUT"
echo "artifact-name-msi=salt-${{ inputs.salt-version }}-${{ matrix.arch }}-MSI" >> "$GITHUB_OUTPUT"
else
echo "artifact-name-nsis=salt-${{ inputs.salt-version }}-${{ matrix.arch }}-NSIS-from-src" >> "$GITHUB_OUTPUT"
echo "artifact-name-msi=salt-${{ inputs.salt-version }}-${{ matrix.arch }}-MSI-from-src" >> "$GITHUB_OUTPUT"
fi
- name: Upload ${{ matrix.arch }} NSIS Packages
uses: actions/upload-artifact@v3
with:
name: salt-${{ inputs.salt-version }}-${{ matrix.arch }}-NSIS
name: ${{ steps.set-artifact-name.outputs.artifact-name-nsis }}
path: pkg/windows/build/Salt-*.exe
retention-days: 7
if-no-files-found: error
@ -111,7 +134,7 @@ jobs:
- name: Upload ${{ matrix.arch }} MSI Package
uses: actions/upload-artifact@v3
with:
name: salt-${{ inputs.salt-version }}-${{ matrix.arch }}-MSI
name: ${{ steps.set-artifact-name.outputs.artifact-name-msi }}
path: pkg/windows/build/Salt-*.msi
retention-days: 7
if-no-files-found: error

View file

@ -2077,6 +2077,7 @@ jobs:
name: Set the ${{ github.workflow }} Pipeline Exit Status
if: always()
runs-on: ubuntu-latest
environment: nightly
needs:
- workflow-requirements
- trigger-branch-nightly-builds

View file

@ -323,6 +323,9 @@ jobs:
name: Set the ${{ github.workflow }} Pipeline Exit Status
if: always()
runs-on: ubuntu-latest
<%- if workflow_slug == "nightly" %>
environment: <{ workflow_slug }>
<%- endif %>
needs:
<%- for need in prepare_workflow_needs.iter(consume=True) %>
- <{ need }>

View file

@ -1,2 +1 @@
Fixed issue in mac_user.enable_auto_login that caused the user's keychain
to be reset at each boot
Fixed issue in mac_user.enable_auto_login that caused the user's keychain to be reset at each boot

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

@ -0,0 +1 @@
Ensure we return an error when adding the key fails in the pkgrepo state for debian hosts.

View file

@ -0,0 +1 @@
Fedora 36 support was removed because it reached EOL

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

@ -0,0 +1 @@
Remove the `clr.AddReference`, it is causing an `Illegal characters in path` exception

View file

@ -13,7 +13,7 @@ are built with the `relenv <https://github.com/saltstack/relative-environment-fo
Docker Containers
=================
The Salt Project uses docker containers to build our packages. If you are building your own packages you can use
The Salt Project uses docker containers to build our deb and rpm packages. If you are building your own packages you can use
the same containers we build with in the Github piplines. These containers are documented `here <https://github.com/saltstack/salt-ci-containers/tree/main/custom/packaging>`_.
@ -53,6 +53,13 @@ How to build onedir only
How to build rpm packages
=========================
#. Ensure you are in the current Salt cloned git repo:
.. code-block:: bash
cd <path-to-salt-repo>
#. Install the dependencies:
.. code-block:: bash
@ -72,12 +79,6 @@ How to build rpm packages
pip install -r requirements/static/ci/py{python_version}/changelog.txt
#. Ensure you are in the current Salt cloned git repo:
.. code-block:: bash
cd <path-to-salt-repo>
#. (Optional) To build a specific Salt version, run tools and set Salt version:
.. code-block:: bash
@ -93,10 +94,15 @@ How to build rpm packages
tools pkg build rpm --relenv-version <relenv-version> --python-version <python-version> --arch <arch>
How to build deb packages
=========================
#. Ensure you are in the current Salt cloned git repo.:
.. code-block:: bash
cd <path-to-salt-repo>
#. Install the dependencies:
.. code-block:: bash
@ -113,12 +119,6 @@ How to build deb packages
pip install -r requirements/static/ci/py{python_version}/changelog.txt
#. Ensure you are in the current Salt cloned git repo.:
.. code-block:: bash
cd <path-to-salt-repo>
#. (Optional) To build a specific Salt version, run tools and set Salt version:
.. code-block:: bash
@ -135,6 +135,56 @@ How to build deb packages
tools pkg build deb --relenv-version <relenv-version> --python-version <python-version> --arch <arch>
How to build MacOS packages
===========================
#. Ensure you are in the current Salt cloned git repo.:
.. code-block:: bash
cd <path-to-salt-repo>
#. Install the dependencies:
.. code-block:: bash
pip install -r requirements/static/ci/py{python_version}/tools.txt
#. Build the MacOS package:
Only the salt-version argument is required, the rest are optional.
Do note that you will not be able to sign the packages when building them.
.. code-block:: bash
tools pkg build macos --salt-version <salt-version>
How to build Windows packages
=============================
#. Ensure you are in the current Salt cloned git repo.:
.. code-block:: bash
cd <path-to-salt-repo>
#. Install the dependencies:
.. code-block:: bash
pip install -r requirements/static/ci/py{python_version}/tools.txt
#. Build the MacOS package:
Only the arch and salt-version arguments are required, the rest are optional.
Do note that you will not be able to sign the packages when building them.
.. code-block:: bash
tools pkg build windows --salt-version <salt-version> --arch <arch>
How to access python binary
===========================

View file

@ -21,26 +21,6 @@
# The default version to be built
# TODO: The is not selectable via RELENV yet. This has to match whatever relenv
# TODO: is building
PY_VERSION="3.10.9"
# Valid versions supported by macOS
PY_VERSIONS=(
"3.10.9"
"3.10.8"
"3.10.7"
"3.9.16"
"3.9.15"
"3.9.14"
"3.9.13"
"3.9.12"
"3.9.11"
"3.8.16"
"3.8.15"
"3.8.14"
"3.8.13"
"3.8.12"
"3.8.11"
)
# Locations
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@ -65,14 +45,10 @@ _usage() {
echo ""
echo " -h, --help this message"
echo " -b, --build build python instead of fetching"
echo " -v, --version version of python to install"
echo " python version must be one of:"
for i in "${PY_VERSIONS[@]}"; do
echo " - $i"
done
echo " -v, --version version of python to install, must be available with relenv"
echo ""
echo " To build python 3.9.15:"
echo " example: $0 --version 3.9.15"
echo " To build python 3.10.11:"
echo " example: $0 --version 3.10.11"
}
# _msg
@ -129,13 +105,6 @@ while true; do
esac
done
if ! [[ " ${PY_VERSIONS[*]} " =~ " $PY_VERSION " ]]; then
echo "Invalid Python Version: $PY_VERSION"
echo ""
_usage
exit 1
fi
#-------------------------------------------------------------------------------
# Script Start
#-------------------------------------------------------------------------------
@ -231,8 +200,8 @@ else
# We want to suppress the output here so it looks nice
# To see the output, remove the output redirection
_msg "Fetching python (relenv)"
relenv fetch >/dev/null 2>&1
if [ -f "$RELENV_DIR/build/x86_64-macos.tar.xz" ]; then
relenv fetch --python $PY_VERSION >/dev/null 2>&1
if [ -f "$RELENV_DIR/build/$PY_VERSION-x86_64-macos.tar.xz" ]; then
_success
else
_failure

View file

@ -40,7 +40,7 @@ param(
[ValidatePattern("^\d{1,2}.\d{1,2}.\d{1,2}$")]
[ValidateSet(
"3.11.2",
"3.10.10"
"3.10.11"
)]
[Alias("p")]
# The version of Python to be built. Pythonnet only supports up to Python
@ -48,7 +48,7 @@ param(
# supported up to 3.8. So we're pinned to the latest version of Python 3.8.
# We may have to drop support for pycurl.
# Default is: 3.8.16
[String] $PythonVersion = "3.10.10",
[String] $PythonVersion = "3.10.11",
[Parameter(Mandatory=$false)]
[Alias("b")]
@ -167,7 +167,7 @@ if ( ! $SkipInstall ) {
Architecture = $Architecture
}
if ( $Build ) {
$KeywordArguments["Build"] = $true
$KeywordArguments["Build"] = $false
}
if ( $CICD ) {
$KeywordArguments["CICD"] = $true

View file

@ -19,7 +19,7 @@ param(
[ValidatePattern("^\d{1,2}.\d{1,2}.\d{1,2}$")]
[ValidateSet(
"3.11.2",
"3.10.10"
"3.10.11"
)]
[Alias("v")]
# The version of Python to be built. Pythonnet only supports up to Python
@ -27,7 +27,7 @@ param(
# supported up to 3.8. So we're pinned to the latest version of Python 3.8.
# We may have to drop support for pycurl or build it ourselves.
# Default is: 3.8.16
[String] $Version = "3.10.10",
[String] $Version = "3.10.11",
[Parameter(Mandatory=$false)]
[ValidateSet("x64", "x86", "amd64")]

View file

@ -643,7 +643,7 @@ def install(
reinstall=False,
downloadonly=False,
ignore_epoch=False,
**kwargs
**kwargs,
):
"""
.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
@ -2824,13 +2824,17 @@ def mod_repo(repo, saltenv="base", aptkey=True, **kwargs):
else:
if not aptkey:
key_file = kwargs["signedby"]
add_repo_key(
if not add_repo_key(
keyid=key,
keyserver=keyserver,
aptkey=False,
keydir=key_file.parent,
keyfile=key_file,
)
):
raise CommandExecutionError(
f"Error: Could not add key: {key}"
)
else:
cmd = [
"apt-key",
@ -2870,7 +2874,7 @@ def mod_repo(repo, saltenv="base", aptkey=True, **kwargs):
func_kwargs["keydir"] = kwargs.get("signedby").parent
if not add_repo_key(path=str(fn_), aptkey=False, **func_kwargs):
return False
raise CommandExecutionError(f"Error: Could not add key: {str(fn_)}")
else:
cmd = ["apt-key", "add", str(fn_)]
out = __salt__["cmd.run_stdout"](cmd, python_shell=False, **kwargs)

View file

@ -53,7 +53,8 @@ if IS_WINDOWS:
import salt.utils.winapi
else:
# This uses .NET to get network settings and is faster than WMI
import clr
# We need the clr import for the `System.Net` import
import clr # pylint: disable=unused-import
from System.Net import NetworkInformation
# TODO: Should we deprecate support for pythonnet 2.5.2, these enumerations can
@ -312,7 +313,6 @@ def _get_ip_wins_info(i_face):
def _get_network_interfaces():
clr.AddReference("System.Net")
return NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()

View file

@ -10,8 +10,10 @@ import _pytest._version
import attr
import pytest
import salt.modules.aptpkg
import salt.utils.files
from tests.conftest import CODE_DIR
from tests.support.mock import MagicMock, patch
PYTEST_GE_7 = getattr(_pytest._version, "version_tuple", (-1, -1)) >= (7, 0)
@ -789,3 +791,56 @@ def test_adding_repo_file_signedby_alt_file(pkgrepo, states, repo):
assert file_content.endswith("\n")
assert key_file.is_file()
assert repo_content in ret.comment
def test_adding_repo_file_signedby_fail_key_keyid(
pkgrepo, states, repo, subtests, modules
):
"""
Test adding a repo file using pkgrepo.managed
and setting signedby and keyid when adding the key fails
an error is returned
"""
def _run(test=False):
return states.pkgrepo.managed(
name=repo.repo_content,
file=str(repo.repo_file),
clean_file=True,
signedby=str(repo.key_file),
keyid="10857FFDD3F91EAE577A21D664CBBC8173D76B3F1",
keyserver="keyserver.ubuntu.com",
aptkey=False,
test=test,
keydir="/tmp/test",
)
ret = _run()
assert "Failed to configure repo" in ret.comment
assert "Could not add key" in ret.comment
def test_adding_repo_file_signedby_fail_key_keyurl(
pkgrepo, states, repo, subtests, modules
):
"""
Test adding a repo file using pkgrepo.managed
and setting signedby and keyurl when adding the key fails
an error is returned
"""
def _run(test=False):
with patch(
"salt.utils.path.which", MagicMock(side_effect=[True, True, False, False])
):
return states.pkgrepo.managed(
name=repo.repo_content,
file=str(repo.repo_file),
clean_file=True,
key_url="https://repo.saltproject.io/salt/py3/ubuntu/20.04/amd64/latest/SALT-PROJECT-GPG-PUBKEY-2023.pub",
aptkey=False,
)
ret = _run()
assert "Failed to configure repo" in ret.comment
assert "Could not add key" in ret.comment

View file

@ -67,8 +67,4 @@ def test_issue_64169(caplog):
# Confirm that the state continued to install the package as expected.
# Only check the 'pkgs' parameter of pip.install
( # pylint: disable=unpacking-non-sequence
mock_install_call_args,
mock_install_call_kwargs,
) = mock_pip_install.call_args
assert mock_install_call_kwargs["pkgs"] == pkg_to_install
assert mock_pip_install.call_args.kwargs["pkgs"] == pkg_to_install

View file

@ -0,0 +1,337 @@
import pytest
import salt.utils.win_network as win_network
from tests.support.mock import MagicMock, patch
pytestmark = [pytest.mark.skip_unless_on_windows]
class PhysicalAddress:
def __init__(self, address):
self.address = address
def ToString(self):
return str(self.address)
class Interface:
"""
Mocked interface object
"""
def __init__(
self,
i_address="02D5F1DD31E0",
i_description="Dell GigabitEthernet",
i_id="{C5F468C0-DD5F-4C2B-939F-A411DCB5DE16}",
i_name="Ethernet",
i_receive_only=False,
i_status=1,
i_type=6,
):
self.PhysicalAddress = PhysicalAddress(i_address)
self.Description = i_description
self.Id = i_id
self.Name = i_name
self.NetworkInterfaceType = i_type
self.IsReceiveOnly = i_receive_only
self.OperationalStatus = i_status
def GetPhysicalAddress(self):
return self.PhysicalAddress
@pytest.fixture
def mock_ip_base():
return MagicMock(
return_value={
"dns_enabled": False,
"dns_suffix": "",
"dynamic_dns_enabled": False,
}
)
@pytest.fixture
def mock_unicast():
return MagicMock(
return_value={
"ip_addresses": [
{
"address": "172.18.87.49",
"broadcast": "172.18.87.63",
"loopback": "127.0.0.1",
"netmask": "255.255.255.240",
"prefix_length": 28,
"prefix_origin": "Manual",
"suffix_origin": "Manual",
}
],
"ipv6_addresses": [
{
"address": "fe80::e8a4:1224:5548:2b81",
"interface_index": 32,
"prefix_length": 64,
"prefix_origin": "WellKnown",
"suffix_origin": "Router",
}
],
}
)
@pytest.fixture
def mock_gateway():
return MagicMock(
return_value={
"ip_gateways": ["192.168.0.1"],
"ipv6_gateways": ["fe80::208:a2ff:fe0b:de70"],
}
)
@pytest.fixture
def mock_dns():
return MagicMock(
return_value={
"ip_dns": ["10.4.0.1", "10.1.0.1", "8.8.8.8"],
"ipv6_dns": ["2600:740a:1:304::1"],
}
)
@pytest.fixture
def mock_multicast():
return MagicMock(
return_value={
"ip_multicast": [
"224.0.0.1",
"224.0.0.251",
"224.0.0.252",
"230.230.230.230",
"239.0.0.250",
"239.255.255.250",
],
"ipv6_multicast": [
"ff01::1",
"ff02::1",
"ff02::c",
"ff02::fb",
"ff02::1:3",
"ff02::1:ff0f:4c48",
"ff02::1:ffa6:f6e6",
],
}
)
@pytest.fixture
def mock_anycast():
return MagicMock(return_value={"ip_anycast": [], "ipv6_anycast": []})
@pytest.fixture
def mock_wins():
return MagicMock(return_value={"ip_wins": []})
def test_get_interface_info_dot_net(
mock_ip_base,
mock_unicast,
mock_gateway,
mock_dns,
mock_multicast,
mock_anycast,
mock_wins,
):
expected = {
"Ethernet": {
"alias": "Ethernet",
"description": "Dell GigabitEthernet",
"dns_enabled": False,
"dns_suffix": "",
"dynamic_dns_enabled": False,
"id": "{C5F468C0-DD5F-4C2B-939F-A411DCB5DE16}",
"ip_addresses": [
{
"address": "172.18.87.49",
"broadcast": "172.18.87.63",
"loopback": "127.0.0.1",
"netmask": "255.255.255.240",
"prefix_length": 28,
"prefix_origin": "Manual",
"suffix_origin": "Manual",
}
],
"ip_anycast": [],
"ip_dns": ["10.4.0.1", "10.1.0.1", "8.8.8.8"],
"ip_gateways": ["192.168.0.1"],
"ip_multicast": [
"224.0.0.1",
"224.0.0.251",
"224.0.0.252",
"230.230.230.230",
"239.0.0.250",
"239.255.255.250",
],
"ip_wins": [],
"ipv6_addresses": [
{
"address": "fe80::e8a4:1224:5548:2b81",
"interface_index": 32,
"prefix_length": 64,
"prefix_origin": "WellKnown",
"suffix_origin": "Router",
}
],
"ipv6_anycast": [],
"ipv6_dns": ["2600:740a:1:304::1"],
"ipv6_gateways": ["fe80::208:a2ff:fe0b:de70"],
"ipv6_multicast": [
"ff01::1",
"ff02::1",
"ff02::c",
"ff02::fb",
"ff02::1:3",
"ff02::1:ff0f:4c48",
"ff02::1:ffa6:f6e6",
],
"physical_address": "02:D5:F1:DD:31:E0",
"receive_only": False,
"status": "Up",
"type": "Ethernet",
}
}
mock_int = MagicMock(return_value=[Interface()])
with patch.object(win_network, "_get_network_interfaces", mock_int), patch.object(
win_network, "_get_ip_base_properties", mock_ip_base
), patch.object(win_network, "_get_ip_unicast_info", mock_unicast), patch.object(
win_network, "_get_ip_gateway_info", mock_gateway
), patch.object(
win_network, "_get_ip_dns_info", mock_dns
), patch.object(
win_network, "_get_ip_multicast_info", mock_multicast
), patch.object(
win_network, "_get_ip_anycast_info", mock_anycast
), patch.object(
win_network, "_get_ip_wins_info", mock_wins
):
results = win_network.get_interface_info_dot_net()
assert expected == results
def test_get_network_info(
mock_ip_base,
mock_unicast,
mock_gateway,
mock_dns,
mock_multicast,
mock_anycast,
mock_wins,
):
expected = {
"Dell GigabitEthernet": {
"hwaddr": "02:D5:F1:DD:31:E0",
"inet": [
{
"address": "172.18.87.49",
"broadcast": "172.18.87.63",
"gateway": "192.168.0.1",
"label": "Dell GigabitEthernet",
"netmask": "255.255.255.240",
}
],
"inet6": [
{
"address": "fe80::e8a4:1224:5548:2b81",
"gateway": "fe80::208:a2ff:fe0b:de70",
"prefixlen": 64,
}
],
"up": True,
}
}
mock_int = MagicMock(return_value=[Interface()])
with patch.object(win_network, "_get_network_interfaces", mock_int), patch.object(
win_network, "_get_ip_base_properties", mock_ip_base
), patch.object(win_network, "_get_ip_unicast_info", mock_unicast), patch.object(
win_network, "_get_ip_gateway_info", mock_gateway
), patch.object(
win_network, "_get_ip_dns_info", mock_dns
), patch.object(
win_network, "_get_ip_multicast_info", mock_multicast
), patch.object(
win_network, "_get_ip_anycast_info", mock_anycast
), patch.object(
win_network, "_get_ip_wins_info", mock_wins
):
results = win_network.get_interface_info()
assert expected == results
def test__get_base_properties_tap_adapter():
"""
Adapter Type 53 is apparently an undocumented type corresponding to
OpenVPN TAP Adapters and possibly other TAP Adapters. This test makes
sure the win_network util will catch that.
https://github.com/saltstack/salt/issues/56196
https://github.com/saltstack/salt/issues/56275
"""
i_face = Interface(
i_address="03DE4D0713FA",
i_description="Windows TAP Adapter",
i_id="{C5F468C0-DD5F-4C2B-939F-A411DCB5DE16}",
i_name="Windows TAP Adapter",
i_receive_only=False,
i_status=1,
i_type=53,
)
expected = {
"alias": "Windows TAP Adapter",
"description": "Windows TAP Adapter",
"id": "{C5F468C0-DD5F-4C2B-939F-A411DCB5DE16}",
"receive_only": False,
"physical_address": "03:DE:4D:07:13:FA",
"status": "Up",
"type": "TAPAdapter",
}
results = win_network._get_base_properties(i_face=i_face)
assert expected == results
def test__get_base_properties_undefined_adapter():
"""
The Adapter Type 53 may be an arbitrary number assigned by OpenVPN.
This will test the ability to avoid stack tracing on an undefined
adapter type. If one is encountered, just use the description.
"""
i_face = Interface(
i_address="03DE4D0713FA",
i_description="Undefined Adapter",
i_id="{C5F468C0-DD5F-4C2B-939F-A411DCB5DE16}",
i_name="Undefined",
i_receive_only=False,
i_status=1,
i_type=50,
)
expected = {
"alias": "Undefined",
"description": "Undefined Adapter",
"id": "{C5F468C0-DD5F-4C2B-939F-A411DCB5DE16}",
"receive_only": False,
"physical_address": "03:DE:4D:07:13:FA",
"status": "Up",
"type": "Undefined Adapter",
}
results = win_network._get_base_properties(i_face=i_face)
assert expected == results
def test__get_network_interfaces_no_error():
ret = win_network._get_network_interfaces()
assert len(ret) > 0

View file

@ -1,300 +0,0 @@
import pytest
import salt.utils.win_network as win_network
from tests.support.mock import MagicMock, patch
from tests.support.unit import TestCase
class PhysicalAddress:
def __init__(self, address):
self.address = address
def ToString(self):
return str(self.address)
class Interface:
"""
Mocked interface object
"""
def __init__(
self,
i_address="02D5F1DD31E0",
i_description="Dell GigabitEthernet",
i_id="{C5F468C0-DD5F-4C2B-939F-A411DCB5DE16}",
i_name="Ethernet",
i_receive_only=False,
i_status=1,
i_type=6,
):
self.PhysicalAddress = PhysicalAddress(i_address)
self.Description = i_description
self.Id = i_id
self.Name = i_name
self.NetworkInterfaceType = i_type
self.IsReceiveOnly = i_receive_only
self.OperationalStatus = i_status
def GetPhysicalAddress(self):
return self.PhysicalAddress
@pytest.mark.skip_unless_on_windows
class WinNetworkTestCase(TestCase):
def setUp(self):
self.mock_ip_base = MagicMock(
return_value={
"dns_enabled": False,
"dns_suffix": "",
"dynamic_dns_enabled": False,
}
)
self.mock_unicast = MagicMock(
return_value={
"ip_addresses": [
{
"address": "172.18.87.49",
"broadcast": "172.18.87.63",
"loopback": "127.0.0.1",
"netmask": "255.255.255.240",
"prefix_length": 28,
"prefix_origin": "Manual",
"suffix_origin": "Manual",
}
],
"ipv6_addresses": [
{
"address": "fe80::e8a4:1224:5548:2b81",
"interface_index": 32,
"prefix_length": 64,
"prefix_origin": "WellKnown",
"suffix_origin": "Router",
}
],
}
)
self.mock_gateway = MagicMock(
return_value={
"ip_gateways": ["192.168.0.1"],
"ipv6_gateways": ["fe80::208:a2ff:fe0b:de70"],
}
)
self.mock_dns = MagicMock(
return_value={
"ip_dns": ["10.4.0.1", "10.1.0.1", "8.8.8.8"],
"ipv6_dns": ["2600:740a:1:304::1"],
}
)
self.mock_multicast = MagicMock(
return_value={
"ip_multicast": [
"224.0.0.1",
"224.0.0.251",
"224.0.0.252",
"230.230.230.230",
"239.0.0.250",
"239.255.255.250",
],
"ipv6_multicast": [
"ff01::1",
"ff02::1",
"ff02::c",
"ff02::fb",
"ff02::1:3",
"ff02::1:ff0f:4c48",
"ff02::1:ffa6:f6e6",
],
}
)
self.mock_anycast = MagicMock(
return_value={"ip_anycast": [], "ipv6_anycast": []}
)
self.mock_wins = MagicMock(return_value={"ip_wins": []})
def test_get_interface_info_dot_net(self):
expected = {
"Ethernet": {
"alias": "Ethernet",
"description": "Dell GigabitEthernet",
"dns_enabled": False,
"dns_suffix": "",
"dynamic_dns_enabled": False,
"id": "{C5F468C0-DD5F-4C2B-939F-A411DCB5DE16}",
"ip_addresses": [
{
"address": "172.18.87.49",
"broadcast": "172.18.87.63",
"loopback": "127.0.0.1",
"netmask": "255.255.255.240",
"prefix_length": 28,
"prefix_origin": "Manual",
"suffix_origin": "Manual",
}
],
"ip_anycast": [],
"ip_dns": ["10.4.0.1", "10.1.0.1", "8.8.8.8"],
"ip_gateways": ["192.168.0.1"],
"ip_multicast": [
"224.0.0.1",
"224.0.0.251",
"224.0.0.252",
"230.230.230.230",
"239.0.0.250",
"239.255.255.250",
],
"ip_wins": [],
"ipv6_addresses": [
{
"address": "fe80::e8a4:1224:5548:2b81",
"interface_index": 32,
"prefix_length": 64,
"prefix_origin": "WellKnown",
"suffix_origin": "Router",
}
],
"ipv6_anycast": [],
"ipv6_dns": ["2600:740a:1:304::1"],
"ipv6_gateways": ["fe80::208:a2ff:fe0b:de70"],
"ipv6_multicast": [
"ff01::1",
"ff02::1",
"ff02::c",
"ff02::fb",
"ff02::1:3",
"ff02::1:ff0f:4c48",
"ff02::1:ffa6:f6e6",
],
"physical_address": "02:D5:F1:DD:31:E0",
"receive_only": False,
"status": "Up",
"type": "Ethernet",
}
}
mock_int = MagicMock(return_value=[Interface()])
with patch.object(
win_network, "_get_network_interfaces", mock_int
), patch.object(
win_network, "_get_ip_base_properties", self.mock_ip_base
), patch.object(
win_network, "_get_ip_unicast_info", self.mock_unicast
), patch.object(
win_network, "_get_ip_gateway_info", self.mock_gateway
), patch.object(
win_network, "_get_ip_dns_info", self.mock_dns
), patch.object(
win_network, "_get_ip_multicast_info", self.mock_multicast
), patch.object(
win_network, "_get_ip_anycast_info", self.mock_anycast
), patch.object(
win_network, "_get_ip_wins_info", self.mock_wins
):
# ret = win_network._get_base_properties()
results = win_network.get_interface_info_dot_net()
self.assertDictEqual(expected, results)
def test_get_network_info(self):
expected = {
"Dell GigabitEthernet": {
"hwaddr": "02:D5:F1:DD:31:E0",
"inet": [
{
"address": "172.18.87.49",
"broadcast": "172.18.87.63",
"gateway": "192.168.0.1",
"label": "Dell GigabitEthernet",
"netmask": "255.255.255.240",
}
],
"inet6": [
{
"address": "fe80::e8a4:1224:5548:2b81",
"gateway": "fe80::208:a2ff:fe0b:de70",
"prefixlen": 64,
}
],
"up": True,
}
}
mock_int = MagicMock(return_value=[Interface()])
with patch.object(
win_network, "_get_network_interfaces", mock_int
), patch.object(
win_network, "_get_ip_base_properties", self.mock_ip_base
), patch.object(
win_network, "_get_ip_unicast_info", self.mock_unicast
), patch.object(
win_network, "_get_ip_gateway_info", self.mock_gateway
), patch.object(
win_network, "_get_ip_dns_info", self.mock_dns
), patch.object(
win_network, "_get_ip_multicast_info", self.mock_multicast
), patch.object(
win_network, "_get_ip_anycast_info", self.mock_anycast
), patch.object(
win_network, "_get_ip_wins_info", self.mock_wins
):
# ret = win_network._get_base_properties()
results = win_network.get_interface_info()
self.assertDictEqual(expected, results)
def test__get_base_properties_tap_adapter(self):
"""
Adapter Type 53 is apparently an undocumented type corresponding to
OpenVPN TAP Adapters and possibly other TAP Adapters. This test makes
sure the win_network util will catch that.
https://github.com/saltstack/salt/issues/56196
https://github.com/saltstack/salt/issues/56275
"""
i_face = Interface(
i_address="03DE4D0713FA",
i_description="Windows TAP Adapter",
i_id="{C5F468C0-DD5F-4C2B-939F-A411DCB5DE16}",
i_name="Windows TAP Adapter",
i_receive_only=False,
i_status=1,
i_type=53,
)
expected = {
"alias": "Windows TAP Adapter",
"description": "Windows TAP Adapter",
"id": "{C5F468C0-DD5F-4C2B-939F-A411DCB5DE16}",
"receive_only": False,
"physical_address": "03:DE:4D:07:13:FA",
"status": "Up",
"type": "TAPAdapter",
}
results = win_network._get_base_properties(i_face=i_face)
self.assertDictEqual(expected, results)
def test__get_base_properties_undefined_adapter(self):
"""
The Adapter Type 53 may be an arbitrary number assigned by OpenVPN.
This will test the ability to avoid stack tracing on an undefined
adapter type. If one is encountered, just use the description.
"""
i_face = Interface(
i_address="03DE4D0713FA",
i_description="Undefined Adapter",
i_id="{C5F468C0-DD5F-4C2B-939F-A411DCB5DE16}",
i_name="Undefined",
i_receive_only=False,
i_status=1,
i_type=50,
)
expected = {
"alias": "Undefined",
"description": "Undefined Adapter",
"id": "{C5F468C0-DD5F-4C2B-939F-A411DCB5DE16}",
"receive_only": False,
"physical_address": "03:DE:4D:07:13:FA",
"status": "Up",
"type": "Undefined Adapter",
}
results = win_network._get_base_properties(i_face=i_face)
self.assertDictEqual(expected, results)

View file

@ -157,7 +157,6 @@ def rpm(
arguments={
"onedir": {
"help": "The name of the onedir artifact, if given it should be under artifacts/",
"required": True,
},
"salt_version": {
"help": (
@ -182,15 +181,30 @@ def macos(
assert salt_version is not None
checkout = pathlib.Path.cwd()
onedir_artifact = checkout / "artifacts" / onedir
_check_pkg_build_files_exist(ctx, onedir_artifact=onedir_artifact)
if onedir:
onedir_artifact = checkout / "artifacts" / onedir
ctx.info(f"Building package from existing onedir: {str(onedir_artifact)}")
_check_pkg_build_files_exist(ctx, onedir_artifact=onedir_artifact)
build_root = checkout / "pkg" / "macos" / "build" / "opt"
build_root.mkdir(parents=True, exist_ok=True)
ctx.info(f"Extracting the onedir artifact to {build_root}")
with tarfile.open(str(onedir_artifact)) as tarball:
with ctx.chdir(onedir_artifact.parent):
tarball.extractall(path=build_root)
build_root = checkout / "pkg" / "macos" / "build" / "opt"
build_root.mkdir(parents=True, exist_ok=True)
ctx.info(f"Extracting the onedir artifact to {build_root}")
with tarfile.open(str(onedir_artifact)) as tarball:
with ctx.chdir(onedir_artifact.parent):
tarball.extractall(path=build_root)
else:
ctx.info("Building package without an existing onedir")
if not onedir:
# Prep the salt onedir if not building from an existing one
shared_constants = _get_shared_constants()
py_ver = shared_constants["python_version_macos"]
with ctx.chdir(checkout / "pkg" / "macos"):
ctx.info("Fetching relenv python")
ctx.run("./build_python.sh", "--version", py_ver)
ctx.info("Installing salt into the relenv python")
ctx.run("./install_salt.sh")
if sign:
ctx.info("Signing binaries")
@ -219,7 +233,6 @@ def macos(
arguments={
"onedir": {
"help": "The name of the onedir artifact, if given it should be under artifacts/",
"required": True,
},
"salt_version": {
"help": (
@ -234,7 +247,7 @@ def macos(
"required": True,
},
"sign": {
"help": "Sign and notorize built package",
"help": "Sign and notarize built package",
},
},
)
@ -249,28 +262,10 @@ def windows(
Build the Windows package.
"""
if TYPE_CHECKING:
assert onedir is not None
assert salt_version is not None
assert arch is not None
checkout = pathlib.Path.cwd()
onedir_artifact = checkout / "artifacts" / onedir
_check_pkg_build_files_exist(ctx, onedir_artifact=onedir_artifact)
unzip_dir = checkout / "pkg" / "windows"
ctx.info(f"Unzipping the onedir artifact to {unzip_dir}")
with zipfile.ZipFile(onedir_artifact, mode="r") as archive:
archive.extractall(unzip_dir)
move_dir = unzip_dir / "salt"
build_env = unzip_dir / "buildenv"
_check_pkg_build_files_exist(ctx, move_dir=move_dir)
ctx.info(f"Moving {move_dir} directory to the build environment in {build_env}")
shutil.move(move_dir, build_env)
ctx.info("Building the windows package")
ctx.run(
build_cmd = [
"powershell.exe",
"&",
"pkg/windows/build.cmd",
@ -279,8 +274,32 @@ def windows(
"-Version",
salt_version,
"-CICD",
"-SkipInstall",
)
]
checkout = pathlib.Path.cwd()
if onedir:
build_cmd.append("-SkipInstall")
onedir_artifact = checkout / "artifacts" / onedir
ctx.info(f"Building package from existing onedir: {str(onedir_artifact)}")
_check_pkg_build_files_exist(ctx, onedir_artifact=onedir_artifact)
unzip_dir = checkout / "pkg" / "windows"
ctx.info(f"Unzipping the onedir artifact to {unzip_dir}")
with zipfile.ZipFile(onedir_artifact, mode="r") as archive:
archive.extractall(unzip_dir)
move_dir = unzip_dir / "salt"
build_env = unzip_dir / "buildenv"
_check_pkg_build_files_exist(ctx, move_dir=move_dir)
ctx.info(f"Moving {move_dir} directory to the build environment in {build_env}")
shutil.move(move_dir, build_env)
else:
build_cmd.append("-Build")
ctx.info("Building package without an existing onedir")
ctx.info(f"Running: {' '.join(build_cmd)} ...")
ctx.run(*build_cmd)
if sign:
env = os.environ.copy()