Merge tag 'v3005.1' into merge-forward/3005.1

Version 3005.1
This commit is contained in:
MKLeb 2022-10-04 20:52:23 -04:00
commit 58ec510d26
No known key found for this signature in database
GPG key ID: 089B64EA1A99DDD1
92 changed files with 1940 additions and 710 deletions

View file

@ -10,6 +10,10 @@ on:
description: "Build Man Pages"
default: true
required: false
branch:
description: "Branch to build/push PR"
default: "master"
required: false
permissions:
contents: read
@ -36,6 +40,7 @@ jobs:
- uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.branch }}
fetch-depth: 0
- name: Install Nox
@ -101,6 +106,9 @@ jobs:
apt-get install -y git/buster-backports
- uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.branch }}
- id: changed-files
if: github.event.inputs.manPages == 'true'
@ -163,6 +171,7 @@ jobs:
- uses: actions/checkout@v2
with:
ref: ${{ github.event.inputs.branch }}
fetch-depth: 0
- name: Download salt-man-pages
@ -196,3 +205,4 @@ jobs:
This PR is auto-generated by
[create-pull-request](https://github.com/peter-evans/create-pull-request).
branch: docs_${{ github.event.inputs.saltVersion }}
base: ${{ github.event.inputs.branch }}

View file

@ -7,6 +7,31 @@ Versions are `MAJOR.PATCH`.
# Changelog
Salt 3005.1 (2022-09-26)
========================
Fixed
-----
- Fix arch parsing issue in apt source files (#62247)
- Fixed parsing CDROM apt sources (#62474)
- Use str() method instead of repo_line for when python3-apt is installed or not in aptpkg.py. (#62546)
- Remove the connection_timeout from netmiko_connection_args before netmiko_connection_args is added to __context__["netmiko_device"]["args"] which is passed along to the Netmiko library. (#62547)
- fixes #62553 by checking for disabled master_type before starting master connection and skipping it if set. (#62553)
- Fix runas with cmd module when using the onedir bundled packages (#62565)
- Fix the Pyinstaller hooks to preserve the environment if None is passed. (#62567, #62628)
- pkgrepo.managed sets wrong permissions on keys installed to /etc/apt/keyring (#62569)
- pkgrepo.managed creates zero byte gpg files when dearmoring contents to the same filename (#62570)
- Ensure default values for IPC Buffers are correct type (#62591)
- Fix a hang on salt-ssh when using sudo. (#62603)
- Renderers now have access to the correct set of salt functions. (#62610, #62620)
- Fix including Jinja template from absolute path (#62611)
- include jmespath in package requirements (#62613)
- Fix pkgrepo.managed signed-by in test=true mode (#62662)
- Ensure the status of the service is captured when the beacon function is called, even when the event is not being emitted. (#62675)
- The sub proxies controlled by Deltaproxy need to have their own req_channel otherwise there are timeout exceptions when the __master_req_channel_payload is fired and reacted on. (#62708)
Salt 3005 (2022-08-22)
======================

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-API" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SALT-API" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
salt-api \- salt-api Command
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-CALL" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SALT-CALL" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
salt-call \- salt-call Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-CLOUD" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SALT-CLOUD" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
salt-cloud \- Salt Cloud Command
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-CP" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SALT-CP" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
salt-cp \- salt-cp Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-KEY" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SALT-KEY" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
salt-key \- salt-key Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-MASTER" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SALT-MASTER" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
salt-master \- salt-master Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-MINION" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SALT-MINION" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
salt-minion \- salt-minion Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-PROXY" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SALT-PROXY" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
salt-proxy \- salt-proxy Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-RUN" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SALT-RUN" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
salt-run \- salt-run Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-SSH" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SALT-SSH" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
salt-ssh \- salt-ssh Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT-SYNDIC" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SALT-SYNDIC" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
salt-syndic \- salt-syndic Documentation
.

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SALT" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SALT" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
salt \- salt
.

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
.\" Man page generated from reStructuredText.
.
.TH "SPM" "1" "Jun 30, 2022" "3005" "Salt"
.TH "SPM" "1" "Sep 26, 2022" "3005.1" "Salt"
.SH NAME
spm \- Salt Package Manager Command
.

View file

@ -0,0 +1,30 @@
.. _release-3005-1:
=========================
Salt 3005.1 Release Notes
=========================
Version 3005.1 is a bug fix release for :ref:`3005 <release-3005>`.
Fixed
-----
- Fix arch parsing issue in apt source files (#62247)
- Fixed parsing CDROM apt sources (#62474)
- Use str() method instead of repo_line for when python3-apt is installed or not in aptpkg.py. (#62546)
- Remove the connection_timeout from netmiko_connection_args before netmiko_connection_args is added to __context__["netmiko_device"]["args"] which is passed along to the Netmiko library. (#62547)
- fixes #62553 by checking for disabled master_type before starting master connection and skipping it if set. (#62553)
- Fix runas with cmd module when using the onedir bundled packages (#62565)
- Fix the Pyinstaller hooks to preserve the environment if None is passed. (#62567, #62628)
- pkgrepo.managed sets wrong permissions on keys installed to /etc/apt/keyring (#62569)
- pkgrepo.managed creates zero byte gpg files when dearmoring contents to the same filename (#62570)
- Ensure default values for IPC Buffers are correct type (#62591)
- Fix a hang on salt-ssh when using sudo. (#62603)
- Renderers now have access to the correct set of salt functions. (#62610, #62620)
- Fix including Jinja template from absolute path (#62611)
- include jmespath in package requirements (#62613)
- Fix pkgrepo.managed signed-by in test=true mode (#62662)
- Ensure the status of the service is captured when the beacon function is called, even when the event is not being emitted. (#62675)
- The sub proxies controlled by Deltaproxy need to have their own req_channel otherwise there are timeout exceptions when the __master_req_channel_payload is fired and reacted on. (#62708)

View file

@ -21,6 +21,15 @@ node and the local ``salt-master`` daemon. This gives the Master node control
over the Minion nodes attached to the ``salt-master`` daemon running on the
Syndic node.
.. warning::
Salt does not officially support Syndic and :ref:`external auth or
publisher_acl<acl-eauth>`. It's possible that it might work under certain
circumstances, but comprehensive support is lacking. See `issue #62618 on
GitHub <https://github.com/saltstack/salt/issues/62618>`_ for more
information. Currently Syndic is only expected to work when running Salt as
root, though work is scheduled to fix this in Salt 3006 (Sulfur).
Configuring the Syndic
======================

View file

@ -1,4 +1,5 @@
Jinja2
jmespath
msgpack>=0.5,!=0.5.5
PyYAML
MarkupSafe

View file

@ -463,6 +463,7 @@ jinja2==3.0.3
# moto
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -466,6 +466,7 @@ jinja2==3.1.0
# moto
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -472,6 +472,7 @@ jinja2==3.0.3
# sphinx
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -461,6 +461,7 @@ jinja2==3.1.0
# moto
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -464,6 +464,7 @@ jinja2==3.0.3
# moto
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -478,6 +478,7 @@ jinja2==3.1.0
# moto
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -495,6 +495,7 @@ jinja2==2.11.3
# moto
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -486,6 +486,7 @@ jinja2==3.0.3
# moto
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -495,6 +495,7 @@ jinja2==3.0.3
# sphinx
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -489,6 +489,7 @@ jinja2==3.0.3
# moto
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -501,6 +501,7 @@ jinja2==3.0.3
# moto
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -485,6 +485,7 @@ jinja2==3.0.3
# napalm
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -492,6 +492,7 @@ jinja2==3.0.3
# sphinx
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -484,6 +484,7 @@ jinja2==3.1.0
# napalm
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -486,6 +486,7 @@ jinja2==3.0.3
# napalm
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -499,6 +499,7 @@ jinja2==3.1.0
# napalm
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -159,6 +159,7 @@ jinja2==3.1.0
# moto
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -474,6 +474,7 @@ jinja2==3.0.3
# napalm
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -483,6 +483,7 @@ jinja2==3.0.3
# sphinx
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -474,6 +474,7 @@ jinja2==3.1.0
# napalm
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -477,6 +477,7 @@ jinja2==3.0.3
# napalm
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -489,6 +489,7 @@ jinja2==3.1.0
# napalm
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -147,6 +147,7 @@ jinja2==3.1.0
# moto
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -474,6 +474,7 @@ jinja2==3.0.3
# napalm
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -479,6 +479,7 @@ jinja2==3.1.0
# napalm
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -481,6 +481,7 @@ jinja2==3.0.3
# sphinx
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -474,6 +474,7 @@ jinja2==3.1.0
# napalm
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -475,6 +475,7 @@ jinja2==3.0.3
# napalm
jmespath==0.10.0
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -491,6 +491,7 @@ jinja2==3.1.0
# napalm
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -147,6 +147,7 @@ jinja2==3.1.0
# moto
jmespath==0.9.4
# via
# -r requirements/base.txt
# -r requirements/static/ci/common.in
# boto3
# botocore

View file

@ -47,6 +47,8 @@ jaraco.text==3.5.1
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
linode-python==1.1.1
# via -r requirements/darwin.txt
mako==1.2.2

View file

@ -39,6 +39,8 @@ jaraco.text==3.5.1
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
markupsafe==2.0.1
# via
# -r requirements/base.txt

View file

@ -39,6 +39,8 @@ jaraco.text==3.5.1
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
markupsafe==2.0.1
# via
# -r requirements/base.txt

View file

@ -41,6 +41,8 @@ jaraco.text==3.2.0
# via jaraco.collections
jinja2==2.11.3
# via -r requirements/base.txt
jmespath==0.10.0
# via -r requirements/base.txt
markupsafe==1.1.1
# via
# -r requirements/base.txt

View file

@ -43,6 +43,8 @@ jaraco.text==3.5.1
# via jaraco.collections
jinja2==3.0.3
# via -r requirements/base.txt
jmespath==0.10.0
# via -r requirements/base.txt
markupsafe==2.0.1
# via
# -r requirements/base.txt

View file

@ -41,6 +41,8 @@ jaraco.text==3.5.1
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
markupsafe==2.0.1
# via
# -r requirements/base.txt

View file

@ -39,6 +39,8 @@ jaraco.text==3.5.1
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
markupsafe==2.0.1
# via
# -r requirements/base.txt

View file

@ -53,6 +53,8 @@ jaraco.text==3.5.0
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
libnacl==1.8.0
# via -r requirements/windows.txt
lxml==4.9.1

View file

@ -41,6 +41,8 @@ jaraco.text==3.5.1
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
markupsafe==2.0.1
# via
# -r requirements/base.txt

View file

@ -39,6 +39,8 @@ jaraco.text==3.5.1
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
markupsafe==2.0.1
# via
# -r requirements/base.txt

View file

@ -51,6 +51,8 @@ jaraco.text==3.5.0
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
libnacl==1.8.0
# via -r requirements/windows.txt
lxml==4.9.1

View file

@ -49,6 +49,8 @@ jaraco.text==3.5.1
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
linode-python==1.1.1
# via -r requirements/darwin.txt
mako==1.2.2

View file

@ -41,6 +41,8 @@ jaraco.text==3.5.1
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
markupsafe==2.0.1
# via
# -r requirements/base.txt

View file

@ -39,6 +39,8 @@ jaraco.text==3.5.1
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
markupsafe==2.0.1
# via
# -r requirements/base.txt

View file

@ -51,6 +51,8 @@ jaraco.text==3.5.0
# via jaraco.collections
jinja2==3.1.0
# via -r requirements/base.txt
jmespath==1.0.1
# via -r requirements/base.txt
libnacl==1.8.0
# via -r requirements/windows.txt
lxml==4.9.1

View file

@ -142,9 +142,9 @@ def beacon(config):
)
if "onchangeonly" in service_config and service_config["onchangeonly"] is True:
if service not in LAST_STATUS:
LAST_STATUS[service] = ret_dict[service]
if not service_config["emitatstartup"]:
continue
LAST_STATUS[service] = ret_dict[service]
if service_config["delay"] > 0:
LAST_STATUS[service]["time"] = currtime
else:

View file

@ -23,8 +23,11 @@ SSH_PRIVATE_KEY_PASSWORD_PROMPT_RE = re.compile(r"Enter passphrase for key", re.
# sudo prompt is used to recognize sudo prompting for a password and should
# therefore be fairly recognizable and unique
SUDO_PROMPT = r"[salt:sudo:d11bd4221135c33324a6bdc09674146fbfdf519989847491e34a689369bbce23]passwd:"
SUDO_PROMPT_RE = re.compile(SUDO_PROMPT, re.M)
SUDO_PROMPT = "[salt:sudo:d11bd4221135c33324a6bdc09674146fbfdf519989847491e34a689369bbce23]passwd:"
SUDO_PROMPT_RE = re.compile(
r"\[salt:sudo:d11bd4221135c33324a6bdc09674146fbfdf519989847491e34a689369bbce23\]passwd:",
re.M,
)
# Keep these in sync with ./__init__.py
RSTR = "_edbc7885e4f9aac9b83b35999b68d015148caf467b78fa39c05f669c0ff89878"
@ -379,12 +382,16 @@ class Shell:
if not cmd:
return "", "No command or passphrase", 245
log_sanitize = None
if self.passwd:
log_sanitize = self.passwd
term = salt.utils.vt.Terminal(
self._split_cmd(cmd),
log_stdout=True,
log_stdout_level="trace",
log_stderr=True,
log_stderr_level="trace",
log_sanitize=log_sanitize,
stream_stdout=False,
stream_stderr=False,
)
@ -398,11 +405,15 @@ class Shell:
while term.has_unread_data:
stdout, stderr = term.recv()
if stdout:
if self.passwd:
stdout = stdout.replace(self.passwd, ("*" * 6))
ret_stdout += stdout
buff = old_stdout + stdout
else:
buff = stdout
if stderr:
if self.passwd:
stderr = stderr.replace(self.passwd, ("*" * 6))
ret_stderr += stderr
if buff and RSTR_RE.search(buff):
# We're getting results back, don't try to send passwords

View file

@ -40,7 +40,7 @@ class SSHState(salt.state.State):
"""
Load up the modules for remote compilation via ssh
"""
self.functions = salt.loader.ssh_wrapper(self.opts, None, context=self.context)
self.functions = self.wrapper
self.utils = salt.loader.utils(self.opts)
self.serializers = salt.loader.serializers(self.opts)
locals_ = salt.loader.minion_mods(self.opts, utils=self.utils)

View file

@ -97,9 +97,9 @@ def _gather_buffer_space():
# For the time being this will be a fixed calculation
# TODO: Allow user configuration
_DFLT_IPC_WBUFFER = _gather_buffer_space() * 0.5
_DFLT_IPC_WBUFFER = int(_gather_buffer_space() * 0.5)
# TODO: Reserved for future use
_DFLT_IPC_RBUFFER = _gather_buffer_space() * 0.5
_DFLT_IPC_RBUFFER = int(_gather_buffer_space() * 0.5)
VALID_OPTS = immutabletypes.freeze(
{

View file

@ -372,6 +372,11 @@ def post_master_init(self, master):
)
_proxy_minion.subprocess_list = self.subprocess_list
# a long-running req channel
_proxy_minion.req_channel = salt.transport.client.AsyncReqChannel.factory(
proxyopts, io_loop=self.io_loop
)
# And load the modules
(
_proxy_minion.functions,

View file

@ -1131,7 +1131,8 @@ class MinionManager(MinionBase):
minion.setup_beacons(before_connect=True)
if minion.opts.get("scheduler_before_connect", False):
minion.setup_scheduler(before_connect=True)
yield minion.connect_master(failed=failed)
if minion.opts.get("master_type", "str") != "disable":
yield minion.connect_master(failed=failed)
minion.tune_in(start=False)
self.minions.append(minion)
break
@ -2693,10 +2694,10 @@ class Minion(MinionBase):
notify=data.get("notify", False),
)
elif tag.startswith("__master_req_channel_payload"):
yield self.req_channel.send(
yield _minion.req_channel.send(
data,
timeout=self._return_retry_timer(),
tries=self.opts["return_retry_tries"],
timeout=_minion._return_retry_timer(),
tries=_minion.opts["return_retry_tries"],
)
elif tag.startswith("pillar_refresh"):
yield _minion.pillar_refresh(

View file

@ -146,7 +146,15 @@ def _invalid(line):
comment = line[idx + 1 :]
line = line[:idx]
repo_line = line.strip().split()
cdrom_match = re.match(r"(.*)(cdrom:.*/)(.*)", line.strip())
if cdrom_match:
repo_line = (
[p.strip() for p in cdrom_match.group(1).split()]
+ [cdrom_match.group(2).strip()]
+ [p.strip() for p in cdrom_match.group(3).split()]
)
else:
repo_line = line.strip().split()
if (
not repo_line
or repo_line[0] not in ["deb", "deb-src", "rpm", "rpm-src"]
@ -267,7 +275,7 @@ if not HAS_APT:
opts_count = []
opts_line = ""
if architectures:
architectures = "arch={}".format(" ".join(architectures))
architectures = "arch={}".format(",".join(architectures))
opts_count.append(architectures)
if signedby:
signedby = "signed-by={}".format(signedby)
@ -1719,7 +1727,7 @@ def _get_opts(line):
"""
Return all opts in [] for a repo line
"""
get_opts = re.search(r"\[.*\]", line)
get_opts = re.search(r"\[(.*=.*)\]", line)
ret = {
"arch": {"full": "", "value": "", "index": 0},
"signedby": {"full": "", "value": "", "index": 0},
@ -1851,7 +1859,6 @@ def list_repo_pkgs(*args, **kwargs): # pylint: disable=unused-import
ret = {}
pkg_name = None
skip_pkg = False
new_pkg = re.compile("^Package: (.+)")
for line in salt.utils.itertools.split(out["stdout"], "\n"):
if not line.strip():
@ -2287,13 +2294,11 @@ def _decrypt_key(key):
key,
)
return False
encrypted_key = key
if not pathlib.Path(key).suffix:
encrypted_key = key + ".gpg"
cmd = ["gpg", "--yes", "--output", encrypted_key, "--dearmor", key]
decrypted_key = str(key) + ".decrypted"
cmd = ["gpg", "--yes", "--output", decrypted_key, "--dearmor", key]
if not __salt__["cmd.run_all"](cmd)["retcode"] == 0:
log.error("Failed to decrypt the key %s", key)
return encrypted_key
return decrypted_key
except UnicodeDecodeError:
log.debug("Key is not ASCII Armored. Do not need to decrypt")
return key
@ -2363,7 +2368,13 @@ def add_repo_key(
cmd = ["apt-key"]
kwargs = {}
current_repo_keys = get_repo_keys(aptkey=aptkey, keydir=keydir)
# If the keyid is provided or determined, check it against the existing
# repo key ids to determine whether it needs to be imported.
if keyid:
for current_keyid in get_repo_keys(aptkey=aptkey, keydir=keydir):
if current_keyid[-(len(keyid)) :] == keyid:
log.debug("The keyid '%s' already present: %s", keyid, current_keyid)
return True
if path:
cached_source_path = __salt__["cp.cache_file"](path, saltenv)
@ -2376,7 +2387,13 @@ def add_repo_key(
key = _decrypt_key(cached_source_path)
if not key:
return False
cmd = ["cp", key, str(keydir)]
key = pathlib.Path(str(key))
if not keyfile:
keyfile = key.name
if keyfile.endswith(".decrypted"):
keyfile = keyfile[:-10]
shutil.copyfile(str(key), str(keydir / keyfile))
return True
else:
cmd.extend(["add", cached_source_path])
elif text:
@ -2417,14 +2434,6 @@ def add_repo_key(
"{}() takes at least 1 argument (0 given)".format(add_repo_key.__name__)
)
# If the keyid is provided or determined, check it against the existing
# repo key ids to determine whether it needs to be imported.
if keyid:
for current_keyid in current_repo_keys:
if current_keyid[-(len(keyid)) :] == keyid:
log.debug("The keyid '%s' already present: %s", keyid, current_keyid)
return True
cmd_ret = _call_apt(cmd, **kwargs)
if cmd_ret["retcode"] == 0:
@ -3091,14 +3100,21 @@ def expand_repo_def(**kwargs):
if signedby not in sanitized["line"]:
line = sanitized["line"].split()
repo_opts = _get_opts(repo)
opts_order = [x for x in repo_opts.keys()]
opts_order = [
opt_type
for opt_type, opt_def in repo_opts.items()
if opt_def["full"] != ""
]
for opt in repo_opts:
if "index" in repo_opts[opt]:
idx = repo_opts[opt]["index"]
opts_order[idx] = repo_opts[opt]["full"]
opts = "[" + " ".join(opts_order) + "]"
line[1] = opts
if line[1].startswith("["):
line[1] = opts
else:
line.insert(1, opts)
sanitized["line"] = " ".join(line)
return sanitized

View file

@ -254,7 +254,8 @@ def show(commands, raw_text=True, **kwargs):
Execute one or more show (non-configuration) commands.
commands
The commands to be executed.
The commands to be executed. Multiple commands should
be specified as a list.
raw_text: ``True``
Whether to return raw text or structured data.
@ -290,7 +291,7 @@ def show(commands, raw_text=True, **kwargs):
.. code-block:: bash
salt-call --local nxos_api.show 'show version'
salt '*' nxos_api.show 'show bgp sessions' 'show processes' raw_text=False
salt '*' nxos_api.show "['show bgp sessions','show processes']" raw_text=False
salt 'regular-minion' nxos_api.show 'show interfaces' host=sw01.example.com username=test password=test
"""
ret = []

View file

@ -197,7 +197,7 @@ class SaltCacheLoader(BaseLoader):
}
environment.globals.update(tpldata)
if _template in self.cached:
if _template in self.cached or os.path.exists(_template):
# pylint: disable=cell-var-from-loop
for spath in self.searchpath:
filepath = os.path.join(spath, _template)

View file

@ -17,7 +17,7 @@ def clean_pyinstaller_vars(environ):
Restore or cleanup PyInstaller specific environent variable behavior.
"""
if environ is None:
environ = {}
environ = dict(os.environ)
# When Salt is bundled with tiamat, it MUST NOT contain LD_LIBRARY_PATH
# when shelling out, or, at least the value of LD_LIBRARY_PATH set by
# pyinstaller.

View file

@ -118,6 +118,7 @@ class Terminal:
log_stdout_level="debug",
log_stderr=None,
log_stderr_level="debug",
log_sanitize=None,
# sys.stdXYZ streaming options
stream_stdout=None,
stream_stderr=None,
@ -222,7 +223,16 @@ class Terminal:
self.child_fd,
self.child_fde,
)
if log_sanitize:
if not isinstance(log_sanitize, str):
raise RuntimeError("'log_sanitize' needs to be a str type")
self.log_sanitize = log_sanitize
else:
self.log_sanitize = None
terminal_command = " ".join(self.args)
if self.log_sanitize:
terminal_command = terminal_command.replace(self.log_sanitize, ("*" * 6))
if (
'decode("base64")' in terminal_command
or "base64.b64decode(" in terminal_command
@ -580,6 +590,10 @@ class Terminal:
if self.stderr_logger:
stripped = stderr.rstrip()
if self.log_sanitize:
stripped = stripped.replace(
self.log_sanitize, ("*" * 6)
)
if stripped.startswith(os.linesep):
stripped = stripped[len(os.linesep) :]
if stripped:
@ -613,6 +627,10 @@ class Terminal:
if self.stdout_logger:
stripped = stdout.rstrip()
if self.log_sanitize:
stripped = stripped.replace(
self.log_sanitize, ("*" * 6)
)
if stripped.startswith(os.linesep):
stripped = stripped[len(os.linesep) :]
if stripped:

View file

@ -606,6 +606,8 @@ def delta_proxy_minion_ids():
return [
"dummy_proxy_one",
"dummy_proxy_two",
"dummy_proxy_three",
"dummy_proxy_four",
]

View file

@ -0,0 +1,31 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2
mQENBFOpvpgBCADkP656H41i8fpplEEB8IeLhugyC2rTEwwSclb8tQNYtUiGdna9
m38kb0OS2DDrEdtdQb2hWCnswxaAkUunb2qq18vd3dBvlnI+C4/xu5ksZZkRj+fW
tArNR18V+2jkwcG26m8AxIrT+m4M6/bgnSfHTBtT5adNfVcTHqiT1JtCbQcXmwVw
WbqS6v/LhcsBE//SHne4uBCK/GHxZHhQ5jz5h+3vWeV4gvxS3Xu6v1IlIpLDwUts
kT1DumfynYnnZmWTGc6SYyIFXTPJLtnoWDb9OBdWgZxXfHEcBsKGha+bXO+m2tHA
gNneN9i5f8oNxo5njrL8jkCckOpNpng18BKXABEBAAG0MlNhbHRTdGFjayBQYWNr
YWdpbmcgVGVhbSA8cGFja2FnaW5nQHNhbHRzdGFjay5jb20+iQE4BBMBAgAiBQJT
qb6YAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAOCKFJ3le/vhkqB/0Q
WzELZf4d87WApzolLG+zpsJKtt/ueXL1W1KA7JILhXB1uyvVORt8uA9FjmE083o1
yE66wCya7V8hjNn2lkLXboOUd1UTErlRg1GYbIt++VPscTxHxwpjDGxDB1/fiX2o
nK5SEpuj4IeIPJVE/uLNAwZyfX8DArLVJ5h8lknwiHlQLGlnOu9ulEAejwAKt9CU
4oYTszYM4xrbtjB/fR+mPnYh2fBoQO4d/NQiejIEyd9IEEMd/03AJQBuMux62tjA
/NwvQ9eqNgLw9NisFNHRWtP4jhAOsshv1WW+zPzu3ozoO+lLHixUIz7fqRk38q8Q
9oNR31KvrkSNrFbA3D89uQENBFOpvpgBCADJ79iH10AfAfpTBEQwa6vzUI3Eltqb
9aZ0xbZV8V/8pnuU7rqM7Z+nJgldibFk4gFG2bHCG1C5aEH/FmcOMvTKDhJSFQUx
uhgxttMArXm2c22OSy1hpsnVG68G32Nag/QFEJ++3hNnbyGZpHnPiYgej3FrerQJ
zv456wIsxRDMvJ1NZQB3twoCqwapC6FJE2hukSdWB5yCYpWlZJXBKzlYz/gwD/Fr
GL578WrLhKw3UvnJmlpqQaDKwmV2s7MsoZogC6wkHE92kGPG2GmoRD3ALjmCvN1E
PsIsQGnwpcXsRpYVCoW7e2nW4wUf7IkFZ94yOCmUq6WreWI4NggRcFC5ABEBAAGJ
AR8EGAECAAkFAlOpvpgCGwwACgkQDgihSd5Xv74/NggA08kEdBkiWWwJZUZEy7cK
WWcgjnRuOHd4rPeT+vQbOWGu6x4bxuVf9aTiYkf7ZjVF2lPn97EXOEGFWPZeZbH4
vdRFH9jMtP+rrLt6+3c9j0M8SIJYwBL1+CNpEC/BuHj/Ra/cmnG5ZNhYebm76h5f
T9iPW9fFww36FzFka4VPlvA4oB7ebBtquFg3sdQNU/MmTVV4jPFWXxh4oRDDR+8N
1bcPnbB11b5ary99F/mqr7RgQ+YFF0uKRE3SKa7a+6cIuHEZ7Za+zhPaQlzAOZlx
fuBmScum8uQTrEF5+Um5zkwC7EXTdH1co/+/V/fpOtxIg4XO4kcugZefVm5ERfVS
MA==
=dtMN
-----END PGP PUBLIC KEY BLOCK-----

View file

@ -18,6 +18,11 @@ pytestmark = [
pytest.mark.skip_if_binaries_missing("apt-cache", "grep"),
]
KEY_FILES = (
"salt-archive-keyring.gpg",
"SALTSTACK-GPG-KEY.pub",
)
class Key:
def __init__(self, aptkey=True):
@ -35,13 +40,13 @@ class Key:
@pytest.fixture
def get_key_file(state_tree, functional_files_dir):
def get_key_file(request, state_tree, functional_files_dir):
"""
Create the key file used for the repo
Create the key file used for the repo by file name passed to the test
"""
key = Key()
shutil.copy(str(functional_files_dir / key.keyname), str(state_tree))
yield key.keyname
keyname = request.param
shutil.copy(str(functional_files_dir / keyname), str(state_tree))
yield keyname
@pytest.fixture
@ -267,9 +272,10 @@ def add_key(request, get_key_file):
key.del_key()
@pytest.mark.parametrize("get_key_file", KEY_FILES, indirect=True)
@pytest.mark.parametrize("add_key", [False, True], indirect=True)
@pytest.mark.destructive_test
def test_get_repo_keys(add_key):
def test_get_repo_keys(get_key_file, add_key):
"""
Test aptpkg.get_repo_keys when aptkey is False and True
"""
@ -294,17 +300,21 @@ def test_get_repo_keys_keydir_not_exist(key):
assert ret
@pytest.mark.parametrize("get_key_file", KEY_FILES, indirect=True)
@pytest.mark.parametrize("aptkey", [False, True])
def test_add_del_repo_key(get_key_file, aptkey):
"""
Test both add_repo_key and del_repo_key when
aptkey is both False and True
and using both binary and armored gpg keys
"""
try:
assert aptpkg.add_repo_key("salt://{}".format(get_key_file), aptkey=aptkey)
keyfile = pathlib.Path("/etc", "apt", "keyrings", get_key_file)
if not aptkey:
assert keyfile.is_file()
assert oct(keyfile.stat().st_mode)[-3:] == "644"
assert keyfile.read_bytes()
query_key = aptpkg.get_repo_keys(aptkey=aptkey)
assert (
query_key["0E08A149DE57BFBE"]["uid"]

View file

@ -54,7 +54,7 @@ def test_adding_repo_file(pkgrepo, tmp_path):
@pytest.mark.requires_salt_states("pkgrepo.managed")
def test_adding_repo_file_arch(pkgrepo, tmp_path):
def test_adding_repo_file_arch(pkgrepo, tmp_path, subtests):
"""
test adding a repo file using pkgrepo.managed
and setting architecture
@ -68,6 +68,35 @@ def test_adding_repo_file_arch(pkgrepo, tmp_path):
file_content.strip()
== "deb [arch=amd64] http://www.deb-multimedia.org stable main"
)
with subtests.test("With multiple archs"):
repo_content = (
"deb [arch=amd64,i386 ] http://www.deb-multimedia.org stable main"
)
pkgrepo.managed(name=repo_content, file=repo_file, clean_file=True)
with salt.utils.files.fopen(repo_file, "r") as fp:
file_content = fp.read()
assert (
file_content.strip()
== "deb [arch=amd64,i386] http://www.deb-multimedia.org stable main"
)
@pytest.mark.requires_salt_states("pkgrepo.managed")
def test_adding_repo_file_cdrom(pkgrepo, tmp_path):
"""
test adding a repo file using pkgrepo.managed
The issue is that CDROM installs often have [] in the line, and we
should still add the repo even though it's not setting arch(for example)
"""
repo_file = str(tmp_path / "cdrom.list")
repo_content = "deb cdrom:[Debian GNU/Linux 11.4.0 _Bullseye_ - Official amd64 NETINST 20220709-10:31]/ stable main"
pkgrepo.managed(name=repo_content, file=repo_file, clean_file=True)
with salt.utils.files.fopen(repo_file, "r") as fp:
file_content = fp.read()
assert (
file_content.strip()
== "deb cdrom:[Debian GNU/Linux 11.4.0 _Bullseye_ - Official amd64 NETINST 20220709-10:31]/ stable main"
)
def system_aptsources_ids(value):
@ -576,7 +605,7 @@ class Repo:
fullname = attr.ib()
alt_repo = attr.ib(init=False)
key_file = attr.ib()
tmp_path = attr.ib()
sources_list_file = attr.ib()
repo_file = attr.ib()
repo_content = attr.ib()
key_url = attr.ib()
@ -609,7 +638,7 @@ class Repo:
@repo_file.default
def _default_repo_file(self):
return self.tmp_path / "stable-binary.list"
return self.sources_list_file
@repo_content.default
def _default_repo_content(self):
@ -649,35 +678,43 @@ class Repo:
@pytest.fixture
def repo(request, grains, tmp_path):
def repo(request, grains, sources_list_file):
signedby = False
if "signedby" in request.node.name:
signedby = True
repo = Repo(grains=grains, tmp_path=tmp_path, signedby=signedby)
repo = Repo(grains=grains, sources_list_file=sources_list_file, signedby=signedby)
yield repo
for key in [repo.key_file, repo.key_file.parent / "salt-alt-key.gpg"]:
if key.is_file():
key.unlink()
def test_adding_repo_file_signedby(pkgrepo, states, repo):
def test_adding_repo_file_signedby(pkgrepo, states, repo, subtests):
"""
Test adding a repo file using pkgrepo.managed
and setting signedby
"""
ret = states.pkgrepo.managed(
name=repo.repo_content,
file=str(repo.repo_file),
clean_file=True,
signedby=str(repo.key_file),
key_url=repo.key_url,
aptkey=False,
)
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),
key_url=repo.key_url,
aptkey=False,
test=test,
)
ret = _run()
with salt.utils.files.fopen(str(repo.repo_file), "r") as fp:
file_content = fp.read()
assert file_content.strip() == repo.repo_content
assert repo.key_file.is_file()
assert repo.repo_content in ret.comment
with subtests.test("test=True"):
ret = _run(test=True)
assert ret.changes == {}
def test_adding_repo_file_signedby_keyserver(pkgrepo, states, repo):

View file

@ -0,0 +1,26 @@
import logging
import os
import tempfile
import pytest
import salt.config
pytestmark = [
pytest.mark.windows_whitelisted,
]
log = logging.getLogger(__name__)
def test_minion_config_type_check(caplog):
msg = "Config option 'ipc_write_buffer' with value"
caplog.set_level(logging.WARNING)
fd, path = tempfile.mkstemp()
try:
with os.fdopen(fd, "w") as tmp:
tmp.write("ipc_write_buffer: 'dynamic'\n")
salt.config.minion_config(path)
assert msg not in caplog.text
finally:
os.remove(path)

View file

@ -17,8 +17,8 @@ def envvar(request):
@pytest.fixture
def meipass(envvar):
with mock.patch("salt.utils.pyinstaller.rthooks._overrides.sys") as patched_sys:
patched_sys._MEIPASS = envvar
assert overrides.sys._MEIPASS == envvar
patched_sys._MEIPASS = "{}_VALUE".format(envvar)
assert overrides.sys._MEIPASS == "{}_VALUE".format(envvar)
yield "{}_VALUE".format(envvar)
assert not hasattr(sys, "_MEIPASS")
assert not hasattr(overrides.sys, "_MEIPASS")
@ -116,7 +116,7 @@ def test_vt_terminal_environ_cleanup(envvar, meipass):
def test_vt_terminal_environ_cleanup_passed_directly_not_removed(envvar, meipass):
env = {
envvar: meipass,
envvar: envvar,
}
original_env = dict(os.environ)
@ -139,4 +139,4 @@ def test_vt_terminal_environ_cleanup_passed_directly_not_removed(envvar, meipass
returned_env = json.loads(buffer_o)
assert returned_env != original_env
assert envvar in returned_env
assert returned_env[envvar] == meipass
assert returned_env[envvar] == envvar

View file

@ -18,8 +18,8 @@ def envvar(request):
@pytest.fixture
def meipass(envvar):
with mock.patch("salt.utils.pyinstaller.rthooks._overrides.sys") as patched_sys:
patched_sys._MEIPASS = envvar
assert overrides.sys._MEIPASS == envvar
patched_sys._MEIPASS = "{}_VALUE".format(envvar)
assert overrides.sys._MEIPASS == "{}_VALUE".format(envvar)
yield "{}_VALUE".format(envvar)
assert not hasattr(sys, "_MEIPASS")
assert not hasattr(overrides.sys, "_MEIPASS")
@ -93,7 +93,7 @@ def test_subprocess_popen_environ_cleanup(envvar, meipass):
def test_subprocess_popen_environ_cleanup_passed_directly_not_removed(envvar, meipass):
env = {
envvar: meipass,
envvar: envvar,
}
original_env = dict(os.environ)
@ -108,4 +108,4 @@ def test_subprocess_popen_environ_cleanup_passed_directly_not_removed(envvar, me
returned_env = json.loads(stdout)
assert returned_env != original_env
assert envvar in returned_env
assert returned_env[envvar] == meipass
assert returned_env[envvar] == envvar

View file

@ -16,7 +16,13 @@ def deltaproxy_pillar_tree(salt_master, salt_delta_proxy_factory):
"""
Create the pillar files for controlproxy and two dummy proxy minions
"""
proxy_one, proxy_two = pytest.helpers.proxy.delta_proxy_minion_ids()
(
proxy_one,
proxy_two,
proxy_three,
proxy_four,
) = pytest.helpers.proxy.delta_proxy_minion_ids()
top_file = """
base:
{control}:
@ -25,10 +31,16 @@ def deltaproxy_pillar_tree(salt_master, salt_delta_proxy_factory):
- {one}
{two}:
- {two}
{three}:
- {three}
{four}:
- {four}
""".format(
control=salt_delta_proxy_factory.id,
one=proxy_one,
two=proxy_two,
three=proxy_three,
four=proxy_four,
)
controlproxy_pillar_file = """
proxy:
@ -36,16 +48,16 @@ def deltaproxy_pillar_tree(salt_master, salt_delta_proxy_factory):
ids:
- {}
- {}
- {}
- {}
""".format(
proxy_one, proxy_two
proxy_one,
proxy_two,
proxy_three,
proxy_four,
)
dummy_proxy_one_pillar_file = """
proxy:
proxytype: dummy
"""
dummy_proxy_two_pillar_file = """
dummy_proxy_pillar_file = """
proxy:
proxytype: dummy
"""
@ -55,12 +67,18 @@ def deltaproxy_pillar_tree(salt_master, salt_delta_proxy_factory):
"controlproxy.sls", controlproxy_pillar_file
)
dummy_proxy_one_tempfile = salt_master.pillar_tree.base.temp_file(
"{}.sls".format(proxy_one), dummy_proxy_one_pillar_file
"{}.sls".format(proxy_one), dummy_proxy_pillar_file
)
dummy_proxy_two_tempfile = salt_master.pillar_tree.base.temp_file(
"{}.sls".format(proxy_two), dummy_proxy_two_pillar_file
"{}.sls".format(proxy_two), dummy_proxy_pillar_file
)
with top_tempfile, controlproxy_tempfile, dummy_proxy_one_tempfile, dummy_proxy_two_tempfile:
dummy_proxy_three_tempfile = salt_master.pillar_tree.base.temp_file(
"{}.sls".format(proxy_three), dummy_proxy_pillar_file
)
dummy_proxy_four_tempfile = salt_master.pillar_tree.base.temp_file(
"{}.sls".format(proxy_four), dummy_proxy_pillar_file
)
with top_tempfile, controlproxy_tempfile, dummy_proxy_one_tempfile, dummy_proxy_two_tempfile, dummy_proxy_three_tempfile, dummy_proxy_four_tempfile:
yield

View file

@ -25,7 +25,12 @@ def proxy_id(request, salt_delta_proxy, skip_on_tcp_transport):
return request.param
def test_can_it_ping(salt_cli, proxy_id):
@pytest.fixture
def proxy_ids(request, salt_delta_proxy, skip_on_tcp_transport):
return pytest.helpers.proxy.delta_proxy_minion_ids()
def test_can_it_ping(salt_cli, proxy_id, proxy_ids):
"""
Ensure the proxy can ping
"""
@ -33,6 +38,15 @@ def test_can_it_ping(salt_cli, proxy_id):
assert ret.data is True
def test_can_it_ping_all(salt_cli, proxy_ids):
"""
Ensure the proxy can ping (all proxy minions)
"""
ret = salt_cli.run("-L", "test.ping", minion_tgt=",".join(proxy_ids))
for _id in proxy_ids:
assert ret.data[_id] is True
def test_list_pkgs(salt_cli, proxy_id):
"""
Package test 1, really just tests that the virtual function capability

View file

@ -0,0 +1,30 @@
import pytest
from saltfactories.utils.functional import StateResult
pytestmark = [
pytest.mark.skip_on_windows(reason="salt-ssh not available on Windows"),
]
@pytest.mark.slow_test
def test_echo(salt_ssh_cli, base_env_state_tree_root_dir):
"""
verify salt-ssh can use imported map files in states
"""
name = "echo"
echo = "hello"
state_file = """
ssh_test_echo:
test.show_notification:
- text: {{{{ salt['test.echo']('{echo}') }}}}
""".format(
echo=echo
)
state_tempfile = pytest.helpers.temp_file(
"{}.sls".format(name), state_file, base_env_state_tree_root_dir
)
with state_tempfile:
ret = salt_ssh_cli.run("state.apply", name)
result = StateResult(ret.data)
assert result.comment == echo

View file

@ -7,35 +7,6 @@ pytestmark = [
]
@pytest.fixture(scope="module")
def test_opts_state_tree(base_env_state_tree_root_dir):
top_file = """
base:
'localhost':
- test_opts
"""
state_file = """
{%- set is_test = salt['config.get']('test') %}
config.get check for is_test:
cmd.run:
- name: echo '{{ is_test }}'
opts.get check for test:
cmd.run:
- name: echo '{{ opts.get('test') }}'
"""
top_tempfile = pytest.helpers.temp_file(
"top.sls", top_file, base_env_state_tree_root_dir
)
state_tempfile = pytest.helpers.temp_file(
"test_opts.sls", state_file, base_env_state_tree_root_dir
)
with top_tempfile, state_tempfile:
yield
@pytest.fixture(scope="module")
def state_tree(base_env_state_tree_root_dir):
top_file = """
@ -125,33 +96,6 @@ def test_state_with_import_from_dir(salt_ssh_cli, nested_state_tree):
assert ret.data
@pytest.mark.slow_test
def test_state_opts_test(salt_ssh_cli, test_opts_state_tree):
"""
verify salt-ssh can get the value of test correctly
"""
def _verify_output(ret):
assert ret.returncode == 0
assert (
ret.data["cmd_|-config.get check for is_test_|-echo 'True'_|-run"]["name"]
== "echo 'True'"
)
assert (
ret.data["cmd_|-opts.get check for test_|-echo 'True'_|-run"]["name"]
== "echo 'True'"
)
ret = salt_ssh_cli.run("state.apply", "test_opts", "test=True")
_verify_output(ret)
ret = salt_ssh_cli.run("state.highstate", "test=True")
_verify_output(ret)
ret = salt_ssh_cli.run("state.top", "top.sls", "test=True")
_verify_output(ret)
@pytest.mark.slow_test
def test_state_low(salt_ssh_cli):
"""

View file

@ -12,6 +12,7 @@ from pytestshellutils.utils import ports
import salt.utils.files
import salt.utils.path
import salt.utils.platform
from salt.utils.versions import LooseVersion as _LooseVersion
from tests.support.helpers import SKIP_INITIAL_PHOTONOS_FAILURES
@ -332,6 +333,7 @@ def test_issue_50221(
assert target_path.read_text().replace("\r\n", "\n") == expected_content
@pytest.mark.skip_if_not_root
def test_issue_60426(
salt_master,
salt_call_cli,
@ -1299,3 +1301,45 @@ def test_issue_62117(
assert ret.data
state_run = next(iter(ret.data.values()))
assert state_run["result"] is True
def test_issue_62611(
salt_master,
salt_call_cli,
pillar_tree,
tmp_path,
salt_minion,
):
name = "test_jinja/issue-62611"
jinja_contents = '{% set myvar = "MOOP" -%}'
jinja_file = salt_master.state_tree.base.paths[0] / "{}.jinja".format(name)
if salt.utils.platform.is_windows():
jinja_file = str(jinja_file).replace("\\", "\\\\")
sls_contents = """
{%- from "REPLACEME" import myvar with context %}
test_jinja/issue-62611/cmd.run:
cmd.run:
- name: echo MEEP {{ myvar }}
""".replace(
"REPLACEME", str(jinja_file)
)
jinja_tempfile = salt_master.state_tree.base.temp_file(
"{}.jinja".format(name), jinja_contents
)
sls_tempfile = salt_master.state_tree.base.temp_file(
"{}.sls".format(name), sls_contents
)
with jinja_tempfile, sls_tempfile:
ret = salt_call_cli.run("--local", "state.apply", name.replace("/", "."))
assert ret.returncode == 0
assert ret.data
state_run = next(iter(ret.data.values()))
assert state_run["name"] == "echo MEEP MOOP"
assert state_run["result"] is True

View file

@ -68,14 +68,15 @@ def test_service_running():
assert ret == (True, "Valid beacon configuration")
ret = service_beacon.beacon(config)
assert ret == [
{
"service_name": "salt-master",
"tag": "salt-master",
"salt-master": {"running": True},
}
]
with patch.dict(service_beacon.LAST_STATUS, {}):
ret = service_beacon.beacon(config)
assert ret == [
{
"service_name": "salt-master",
"tag": "salt-master",
"salt-master": {"running": True},
}
]
# When onchangeonly is True and emitatstartup is False ,
# we should not see a return when the beacon is run.
@ -91,8 +92,13 @@ def test_service_running():
assert ret == (True, "Valid beacon configuration")
ret = service_beacon.beacon(config)
assert ret == []
# The return is empty because the beacon did not run
# but the LAST_STATUS should contain the last status
# for the service.
with patch.dict(service_beacon.LAST_STATUS, {}):
ret = service_beacon.beacon(config)
assert "salt-master" in service_beacon.LAST_STATUS
assert ret == []
# When onchangeonly is True and emitatstartup is
# the default value True, we should see a return
@ -103,14 +109,15 @@ def test_service_running():
assert ret == (True, "Valid beacon configuration")
ret = service_beacon.beacon(config)
assert ret == [
{
"service_name": "salt-master",
"tag": "salt-master",
"salt-master": {"running": True},
}
]
with patch.dict(service_beacon.LAST_STATUS, {}):
ret = service_beacon.beacon(config)
assert ret == [
{
"service_name": "salt-master",
"tag": "salt-master",
"salt-master": {"running": True},
}
]
# LAST_STATUS has service name and status has not changed
config = [{"services": {"salt-master": {"onchangeonly": True}}}]
@ -146,6 +153,29 @@ def test_service_running():
}
]
# When onchangeonly is True and emitatstartup is True,
# we should see a return when the beacon is run.
config = [
{"services": {"salt-master": {"emitatstartup": True, "onchangeonly": True}}}
]
ret = service_beacon.validate(config)
assert ret == (True, "Valid beacon configuration")
with patch.dict(service_beacon.LAST_STATUS, {}):
ret = service_beacon.beacon(config)
assert ret == [
{
"salt-master": {"running": True},
"service_name": "salt-master",
"tag": "salt-master",
}
]
ret = service_beacon.beacon(config)
assert ret == []
def test_service_not_running():
with patch.dict(

View file

@ -4,6 +4,7 @@ import types
import pytest
import salt.client.ssh.shell as shell
from tests.support.mock import patch
@pytest.fixture
@ -28,3 +29,26 @@ def test_ssh_shell_key_gen(keys):
timeout=30,
)
assert ret.decode().startswith("ssh-rsa")
@pytest.mark.skip_on_windows(reason="Windows does not support salt-ssh")
@pytest.mark.skip_if_binaries_missing("ssh", "ssh-keygen", check_all=True)
def test_ssh_shell_exec_cmd(caplog):
"""
Test executing a command and ensuring the password
is not in the stdout/stderr logs.
"""
passwd = "12345"
opts = {"_ssh_version": (4, 9)}
host = ""
_shell = shell.Shell(opts=opts, host=host)
_shell.passwd = passwd
with patch.object(_shell, "_split_cmd", return_value=["echo", passwd]):
ret = _shell.exec_cmd("echo {}".format(passwd))
assert not any([x for x in ret if passwd in str(x)])
assert passwd not in caplog.text
with patch.object(_shell, "_split_cmd", return_value=["ls", passwd]):
ret = _shell.exec_cmd("ls {}".format(passwd))
assert not any([x for x in ret if passwd in str(x)])
assert passwd not in caplog.text

View file

@ -853,8 +853,9 @@ def test__skip_source():
assert ret is False
def test__parse_source():
cases = (
@pytest.mark.parametrize(
"case",
(
{"ok": False, "line": "", "invalid": True, "disabled": False},
{"ok": False, "line": "#", "invalid": True, "disabled": True},
{"ok": False, "line": "##", "invalid": True, "disabled": True},
@ -881,19 +882,31 @@ def test__parse_source():
"invalid": False,
"disabled": False,
},
)
{
"ok": True,
"line": (
"# deb cdrom:[Debian GNU/Linux 11.4.0 _Bullseye_ - Official amd64 NETINST 20220709-10:31]/ bullseye main\n"
"\n"
"deb http://httpredir.debian.org/debian bullseye main\n"
"deb-src http://httpredir.debian.org/debian bullseye main\n"
),
"invalid": False,
"disabled": True,
},
),
)
def test__parse_source(case):
with patch.dict("sys.modules", {"aptsources.sourceslist": None}):
importlib.reload(aptpkg)
NoAptSourceEntry = aptpkg.SourceEntry
importlib.reload(aptpkg)
for case in cases:
source = NoAptSourceEntry(case["line"])
ok = source._parse_sources(case["line"])
source = NoAptSourceEntry(case["line"])
ok = source._parse_sources(case["line"])
assert ok is case["ok"]
assert source.invalid is case["invalid"]
assert source.disabled is case["disabled"]
assert ok is case["ok"]
assert source.invalid is case["invalid"]
assert source.disabled is case["disabled"]
def test_normalize_name():
@ -949,16 +962,10 @@ def test_list_repos():
assert repos[source_uri][0]["uri"][-1] == "/"
@pytest.mark.skipif(
HAS_APTSOURCES is False, reason="The 'aptsources' library is missing."
)
def test_expand_repo_def():
"""
Checks results from expand_repo_def
"""
source_type = "deb"
source_uri = "http://cdn-aws.deb.debian.org/debian/"
source_line = "deb http://cdn-aws.deb.debian.org/debian/ stretch main\n"
source_file = "/etc/apt/sources.list"
# Valid source
@ -988,6 +995,40 @@ def test_expand_repo_def():
)
def test_expand_repo_def_cdrom():
"""
Checks results from expand_repo_def
"""
source_file = "/etc/apt/sources.list"
# Valid source
repo = "# deb cdrom:[Debian GNU/Linux 11.4.0 _Bullseye_ - Official amd64 NETINST 20220709-10:31]/ bullseye main\n"
sanitized = aptpkg.expand_repo_def(repo=repo, file=source_file)
log.warning("SAN: %s", sanitized)
assert isinstance(sanitized, dict)
assert "uri" in sanitized
# Make sure last character in of the URI is still a /
assert sanitized["uri"][-1] == "/"
# Pass the architecture and make sure it is added the the line attribute
repo = "deb http://cdn-aws.deb.debian.org/debian/ stretch main\n"
sanitized = aptpkg.expand_repo_def(
repo=repo, file=source_file, architectures="amd64"
)
# Make sure line is in the dict
assert isinstance(sanitized, dict)
assert "line" in sanitized
# Make sure the architecture is in line
assert (
sanitized["line"]
== "deb [arch=amd64] http://cdn-aws.deb.debian.org/debian/ stretch main"
)
def test_list_pkgs():
"""
Test packages listing.

View file

@ -1089,3 +1089,35 @@ def test_valid_ipv4_master_address_ipv6_enabled():
"master_ip": "127.0.0.1",
}
assert salt.minion.resolve_dns(opts) == expected
async def test_master_type_disable():
"""
Tests master_type "disable" to not even attempt connecting to a master.
"""
mock_opts = salt.config.DEFAULT_MINION_OPTS.copy()
mock_opts.update(
{
"master_type": "disable",
"master": None,
"__role": "",
"pub_ret": False,
"file_client": "local",
}
)
minion = salt.minion.Minion(mock_opts)
try:
try:
minion_man = salt.minion.MinionManager(mock_opts)
minion_man._connect_minion(minion)
except RuntimeError:
pytest.fail("_connect_minion(minion) threw an error, This was not expected")
# Make sure beacons and sheduler are initialized
assert "beacons" in minion.periodic_callbacks
assert "schedule" in minion.periodic_callbacks
assert minion.connected is False
finally:
minion.destroy()

View file

@ -27,3 +27,26 @@ def test_isalive_no_child():
aliveness = term.isalive()
assert term.exitstatus == 0
assert aliveness is False
@pytest.mark.parametrize("test_cmd", ["echo", "ls"])
@pytest.mark.skip_on_windows()
def test_log_sanitize(test_cmd, caplog):
"""
test when log_sanitize is passed in
we do not see the password in either
standard out or standard error logs
"""
password = "123456"
cmd = [test_cmd, password]
term = vt.Terminal(
cmd,
log_stdout=True,
log_stderr=True,
log_sanitize=password,
stream_stdout=False,
stream_stderr=False,
)
ret = term.recv()
assert password not in caplog.text
assert "******" in caplog.text